feat: adds a post hook.

This commit is contained in:
Fernandez Ludovic 2019-04-25 23:58:25 +02:00
parent 1001ead866
commit ace6229872
14 changed files with 124 additions and 53 deletions

View File

@ -61,6 +61,7 @@ func init() {
rootCmd.PersistentFlags().Bool("domain-subdir", false, "Use domain as sub-directory.") rootCmd.PersistentFlags().Bool("domain-subdir", false, "Use domain as sub-directory.")
rootCmd.PersistentFlags().Bool("clean", true, "Clean destination folder before dumping content.") rootCmd.PersistentFlags().Bool("clean", true, "Clean destination folder before dumping content.")
rootCmd.PersistentFlags().Bool("watch", false, "Enable watching changes.") rootCmd.PersistentFlags().Bool("watch", false, "Enable watching changes.")
rootCmd.PersistentFlags().String("post-hook", "", "Execute a command only if changes occurs on the data source. (works only with the watch mode)")
} }
// initConfig reads in config file and ENV variables if set. // initConfig reads in config file and ENV variables if set.
@ -174,5 +175,6 @@ func getBaseConfig(cmd *cobra.Command) (*dumper.BaseConfig, error) {
DomainSubDir: subDir, DomainSubDir: subDir,
Clean: clean, Clean: clean,
Watch: watch, Watch: watch,
Hook: cmd.Flag("post-hook").Value.String(),
}, nil }, nil
} }

View File

@ -18,6 +18,7 @@ Dump Let's Encrypt certificates from Traefik.
-h, --help help for traefik-certs-dumper -h, --help help for traefik-certs-dumper
--key-ext string The file extension of the generated private keys. (default ".key") --key-ext string The file extension of the generated private keys. (default ".key")
--key-name string The file name (without extension) of the generated private keys. (default "privatekey") --key-name string The file name (without extension) of the generated private keys. (default "privatekey")
--post-hook string Execute a command only if changes occurs on the data source. (works only with the watch mode)
--watch Enable watching changes. --watch Enable watching changes.
``` ```
@ -27,4 +28,4 @@ Dump Let's Encrypt certificates from Traefik.
* [traefik-certs-dumper kv](traefik-certs-dumper_kv.md) - Dump the content of a KV store. * [traefik-certs-dumper kv](traefik-certs-dumper_kv.md) - Dump the content of a KV store.
* [traefik-certs-dumper version](traefik-certs-dumper_version.md) - Display version * [traefik-certs-dumper version](traefik-certs-dumper_version.md) - Display version
###### Auto generated by spf13/cobra on 22-Apr-2019 ###### Auto generated by spf13/cobra on 25-Apr-2019

View File

@ -28,6 +28,7 @@ traefik-certs-dumper file [flags]
--domain-subdir Use domain as sub-directory. --domain-subdir Use domain as sub-directory.
--key-ext string The file extension of the generated private keys. (default ".key") --key-ext string The file extension of the generated private keys. (default ".key")
--key-name string The file name (without extension) of the generated private keys. (default "privatekey") --key-name string The file name (without extension) of the generated private keys. (default "privatekey")
--post-hook string Execute a command only if changes occurs on the data source. (works only with the watch mode)
--watch Enable watching changes. --watch Enable watching changes.
``` ```
@ -35,4 +36,4 @@ traefik-certs-dumper file [flags]
* [traefik-certs-dumper](traefik-certs-dumper.md) - Dump Let's Encrypt certificates from Traefik. * [traefik-certs-dumper](traefik-certs-dumper.md) - Dump Let's Encrypt certificates from Traefik.
###### Auto generated by spf13/cobra on 22-Apr-2019 ###### Auto generated by spf13/cobra on 25-Apr-2019

View File

@ -34,6 +34,7 @@ Dump the content of a KV store.
--domain-subdir Use domain as sub-directory. --domain-subdir Use domain as sub-directory.
--key-ext string The file extension of the generated private keys. (default ".key") --key-ext string The file extension of the generated private keys. (default ".key")
--key-name string The file name (without extension) of the generated private keys. (default "privatekey") --key-name string The file name (without extension) of the generated private keys. (default "privatekey")
--post-hook string Execute a command only if changes occurs on the data source. (works only with the watch mode)
--watch Enable watching changes. --watch Enable watching changes.
``` ```
@ -45,4 +46,4 @@ Dump the content of a KV store.
* [traefik-certs-dumper kv etcd](traefik-certs-dumper_kv_etcd.md) - Dump the content of etcd. * [traefik-certs-dumper kv etcd](traefik-certs-dumper_kv_etcd.md) - Dump the content of etcd.
* [traefik-certs-dumper kv zookeeper](traefik-certs-dumper_kv_zookeeper.md) - Dump the content of zookeeper. * [traefik-certs-dumper kv zookeeper](traefik-certs-dumper_kv_zookeeper.md) - Dump the content of zookeeper.
###### Auto generated by spf13/cobra on 22-Apr-2019 ###### Auto generated by spf13/cobra on 25-Apr-2019

View File

@ -32,6 +32,7 @@ traefik-certs-dumper kv boltdb [flags]
--key-ext string The file extension of the generated private keys. (default ".key") --key-ext string The file extension of the generated private keys. (default ".key")
--key-name string The file name (without extension) of the generated private keys. (default "privatekey") --key-name string The file name (without extension) of the generated private keys. (default "privatekey")
--password string Password for connection. --password string Password for connection.
--post-hook string Execute a command only if changes occurs on the data source. (works only with the watch mode)
--prefix string Prefix used for KV store. (default "traefik") --prefix string Prefix used for KV store. (default "traefik")
--tls Enable TLS encryption. --tls Enable TLS encryption.
--tls.ca string Root CA for certificate verification if TLS is enabled --tls.ca string Root CA for certificate verification if TLS is enabled
@ -47,4 +48,4 @@ traefik-certs-dumper kv boltdb [flags]
* [traefik-certs-dumper kv](traefik-certs-dumper_kv.md) - Dump the content of a KV store. * [traefik-certs-dumper kv](traefik-certs-dumper_kv.md) - Dump the content of a KV store.
###### Auto generated by spf13/cobra on 22-Apr-2019 ###### Auto generated by spf13/cobra on 25-Apr-2019

View File

@ -31,6 +31,7 @@ traefik-certs-dumper kv consul [flags]
--key-ext string The file extension of the generated private keys. (default ".key") --key-ext string The file extension of the generated private keys. (default ".key")
--key-name string The file name (without extension) of the generated private keys. (default "privatekey") --key-name string The file name (without extension) of the generated private keys. (default "privatekey")
--password string Password for connection. --password string Password for connection.
--post-hook string Execute a command only if changes occurs on the data source. (works only with the watch mode)
--prefix string Prefix used for KV store. (default "traefik") --prefix string Prefix used for KV store. (default "traefik")
--tls Enable TLS encryption. --tls Enable TLS encryption.
--tls.ca string Root CA for certificate verification if TLS is enabled --tls.ca string Root CA for certificate verification if TLS is enabled
@ -46,4 +47,4 @@ traefik-certs-dumper kv consul [flags]
* [traefik-certs-dumper kv](traefik-certs-dumper_kv.md) - Dump the content of a KV store. * [traefik-certs-dumper kv](traefik-certs-dumper_kv.md) - Dump the content of a KV store.
###### Auto generated by spf13/cobra on 22-Apr-2019 ###### Auto generated by spf13/cobra on 25-Apr-2019

View File

@ -31,6 +31,7 @@ traefik-certs-dumper kv etcd [flags]
--key-ext string The file extension of the generated private keys. (default ".key") --key-ext string The file extension of the generated private keys. (default ".key")
--key-name string The file name (without extension) of the generated private keys. (default "privatekey") --key-name string The file name (without extension) of the generated private keys. (default "privatekey")
--password string Password for connection. --password string Password for connection.
--post-hook string Execute a command only if changes occurs on the data source. (works only with the watch mode)
--prefix string Prefix used for KV store. (default "traefik") --prefix string Prefix used for KV store. (default "traefik")
--tls Enable TLS encryption. --tls Enable TLS encryption.
--tls.ca string Root CA for certificate verification if TLS is enabled --tls.ca string Root CA for certificate verification if TLS is enabled
@ -46,4 +47,4 @@ traefik-certs-dumper kv etcd [flags]
* [traefik-certs-dumper kv](traefik-certs-dumper_kv.md) - Dump the content of a KV store. * [traefik-certs-dumper kv](traefik-certs-dumper_kv.md) - Dump the content of a KV store.
###### Auto generated by spf13/cobra on 22-Apr-2019 ###### Auto generated by spf13/cobra on 25-Apr-2019

View File

@ -30,6 +30,7 @@ traefik-certs-dumper kv zookeeper [flags]
--key-ext string The file extension of the generated private keys. (default ".key") --key-ext string The file extension of the generated private keys. (default ".key")
--key-name string The file name (without extension) of the generated private keys. (default "privatekey") --key-name string The file name (without extension) of the generated private keys. (default "privatekey")
--password string Password for connection. --password string Password for connection.
--post-hook string Execute a command only if changes occurs on the data source. (works only with the watch mode)
--prefix string Prefix used for KV store. (default "traefik") --prefix string Prefix used for KV store. (default "traefik")
--tls Enable TLS encryption. --tls Enable TLS encryption.
--tls.ca string Root CA for certificate verification if TLS is enabled --tls.ca string Root CA for certificate verification if TLS is enabled
@ -45,4 +46,4 @@ traefik-certs-dumper kv zookeeper [flags]
* [traefik-certs-dumper kv](traefik-certs-dumper_kv.md) - Dump the content of a KV store. * [traefik-certs-dumper kv](traefik-certs-dumper_kv.md) - Dump the content of a KV store.
###### Auto generated by spf13/cobra on 22-Apr-2019 ###### Auto generated by spf13/cobra on 25-Apr-2019

View File

@ -27,6 +27,7 @@ traefik-certs-dumper version [flags]
--domain-subdir Use domain as sub-directory. --domain-subdir Use domain as sub-directory.
--key-ext string The file extension of the generated private keys. (default ".key") --key-ext string The file extension of the generated private keys. (default ".key")
--key-name string The file name (without extension) of the generated private keys. (default "privatekey") --key-name string The file name (without extension) of the generated private keys. (default "privatekey")
--post-hook string Execute a command only if changes occurs on the data source. (works only with the watch mode)
--watch Enable watching changes. --watch Enable watching changes.
``` ```
@ -34,4 +35,4 @@ traefik-certs-dumper version [flags]
* [traefik-certs-dumper](traefik-certs-dumper.md) - Dump Let's Encrypt certificates from Traefik. * [traefik-certs-dumper](traefik-certs-dumper.md) - Dump Let's Encrypt certificates from Traefik.
###### Auto generated by spf13/cobra on 22-Apr-2019 ###### Auto generated by spf13/cobra on 25-Apr-2019

View File

@ -8,4 +8,5 @@ type BaseConfig struct {
DomainSubDir bool DomainSubDir bool
Clean bool Clean bool
Watch bool Watch bool
Hook string
} }

View File

@ -11,6 +11,7 @@ import (
"github.com/fsnotify/fsnotify" "github.com/fsnotify/fsnotify"
"github.com/ldez/traefik-certs-dumper/v2/dumper" "github.com/ldez/traefik-certs-dumper/v2/dumper"
"github.com/ldez/traefik-certs-dumper/v2/hook"
) )
// Dump Dumps "acme.json" file to certificates. // Dump Dumps "acme.json" file to certificates.
@ -68,7 +69,7 @@ func watch(acmeFile string, baseConfig *dumper.BaseConfig) error {
return return
} }
if strings.EqualFold(os.Getenv("TCD_DEBUG"), "true") { if isDebug() {
log.Println("event:", event) log.Println("event:", event)
} }
@ -115,7 +116,7 @@ func manageEvent(watcher *fsnotify.Watcher, event fsnotify.Event, acmeFile strin
} }
if !bytes.Equal(previousHash, hash) { if !bytes.Equal(previousHash, hash) {
if strings.EqualFold(os.Getenv("TCD_DEBUG"), "true") { if isDebug() {
log.Println("detected changes on file:", event.Name) log.Println("detected changes on file:", event.Name)
} }
@ -123,9 +124,13 @@ func manageEvent(watcher *fsnotify.Watcher, event fsnotify.Event, acmeFile strin
return nil, errD return nil, errD
} }
if isDebug() {
log.Println("Dumped new certificate data.") log.Println("Dumped new certificate data.")
} }
hook.Exec(baseConfig.Hook)
}
return hash, nil return hash, nil
} }
@ -156,3 +161,7 @@ func calculateHash(acmeFile string) ([]byte, error) {
return h.Sum(nil), nil return h.Sum(nil), nil
} }
func isDebug() bool {
return strings.EqualFold(os.Getenv("TCD_DEBUG"), "true")
}

View File

@ -7,10 +7,13 @@ import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"log" "log"
"os"
"strings"
"github.com/abronan/valkeyrie" "github.com/abronan/valkeyrie"
"github.com/abronan/valkeyrie/store" "github.com/abronan/valkeyrie/store"
"github.com/ldez/traefik-certs-dumper/v2/dumper" "github.com/ldez/traefik-certs-dumper/v2/dumper"
"github.com/ldez/traefik-certs-dumper/v2/hook"
) )
const storeKeySuffix = "/acme/account/object" const storeKeySuffix = "/acme/account/object"
@ -55,8 +58,12 @@ func watch(kvStore store.Store, storeKey string, baseConfig *dumper.BaseConfig)
return err return err
} }
if isDebug() {
log.Println("Dumped new certificate data.") log.Println("Dumped new certificate data.")
} }
hook.Exec(baseConfig.Hook)
}
} }
func dumpPair(pair *store.KVPair, baseConfig *dumper.BaseConfig) error { func dumpPair(pair *store.KVPair, baseConfig *dumper.BaseConfig) error {
@ -86,3 +93,7 @@ func getStoredDataFromGzip(pair *store.KVPair) (*dumper.StoredData, error) {
return convertAccountV1ToV2(account), nil return convertAccountV1ToV2(account), nil
} }
func isDebug() bool {
return strings.EqualFold(os.Getenv("TCD_DEBUG"), "true")
}

41
hook/hook.go Normal file
View File

@ -0,0 +1,41 @@
package hook
import (
"context"
"errors"
"fmt"
"os/exec"
"strings"
"time"
)
// Exec Execute a command on a go routine.
func Exec(command string) {
if command == "" {
return
}
go func() {
errH := execute(command)
if errH != nil {
panic(errH)
}
}()
}
func execute(command string) error {
ctxCmd, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
parts := strings.Fields(command)
output, err := exec.CommandContext(ctxCmd, parts[0], parts[1:]...).CombinedOutput()
if len(output) > 0 {
fmt.Println(string(output))
}
if ctxCmd.Err() == context.DeadlineExceeded {
return errors.New("hook timed out")
}
return err
}

View File

@ -18,6 +18,7 @@
- Output formats: - Output formats:
- use domain as sub-directory (allow custom names and extensions) - use domain as sub-directory (allow custom names and extensions)
- flat (domain as filename) - flat (domain as filename)
- Hook (only with watch mode and if the data source changes)
## Installation ## Installation
@ -71,7 +72,6 @@ dump
└──private └──private
├──my.domain.com.crt ├──my.domain.com.crt
└──letsencrypt.key └──letsencrypt.key
``` ```
### Change source and destination ### Change source and destination
@ -84,7 +84,6 @@ test
└──private └──private
├──my.domain.com.crt ├──my.domain.com.crt
└──letsencrypt.key └──letsencrypt.key
``` ```
### Use domain as sub-directory ### Use domain as sub-directory
@ -102,7 +101,7 @@ dump
#### Change file extension #### Change file extension
```console ```console
$ traefik-certs-dumper file --domain-subdir=true --crt-ext=.pem --key-ext=.pem $ traefik-certs-dumper file --domain-subdir --crt-ext=.pem --key-ext=.pem
dump dump
├──my.domain.com ├──my.domain.com
│ ├──certificate.pem │ ├──certificate.pem
@ -114,7 +113,7 @@ dump
#### Change file name #### Change file name
```console ```console
$ traefik-certs-dumper file --domain-subdir=true --crt-name=fullchain --key-name=privkey $ traefik-certs-dumper file --domain-subdir --crt-name=fullchain --key-name=privkey
dump dump
├──my.domain.com ├──my.domain.com
│ ├──fullchain.crt │ ├──fullchain.crt