From 250a391a102d18288ac3578178a092d731c20d75 Mon Sep 17 00:00:00 2001 From: Dennis Hermsmeier Date: Fri, 20 Mar 2020 14:49:31 +0100 Subject: [PATCH] parse config before viper to allow environment variables via gotpl (#5) --- .goreleaser.yml | 1 + Makefile | 2 + README.md | 9 ++++ Dockerfile => build/docker/Dockerfile | 0 cmd/root.go | 69 +++++++++++++++++++++------ 5 files changed, 66 insertions(+), 15 deletions(-) rename Dockerfile => build/docker/Dockerfile (100%) diff --git a/.goreleaser.yml b/.goreleaser.yml index d16bcee..a7a371a 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -44,6 +44,7 @@ dockers: - quay.io/mittwald/brudi:stable binaries: - brudi + dockerfile: build/docker/Dockerfile goos: linux goarch: amd64 goarm: '' \ No newline at end of file diff --git a/Makefile b/Makefile index 53c33a7..c5976d4 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,8 @@ BINARY_NAME = brudi COMMIT_HASH = $(shell git rev-parse --verify HEAD) CURDIR = $(shell pwd) +.PHONY: build + all: dep test lint build dep: diff --git a/README.md b/README.md index 8084d9e..7a85b35 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,15 @@ The docker-image comes with all required binaries. ### Configuration As already mentioned, `brudi` is configured via `.yaml`. The default path for this file is `${HOME}/.brudi.yaml`, but it's adjustable via `-c` or `--config`. +The config file itself can include environment-variables via `go-template`: + +```yaml +restic: + global: + flags: + repo: "{{ .Env.RESTIC_REPOSITORY }}" +``` + Since the configuration provided by the `.yaml`-file is mapped to the corresponding CLI-flags, you can adjust literally every parameter of your source backup. Therefore you can simply refer to the official documentation for explanations on the available flags: diff --git a/Dockerfile b/build/docker/Dockerfile similarity index 100% rename from Dockerfile rename to build/docker/Dockerfile diff --git a/cmd/root.go b/cmd/root.go index 9a722b2..2324110 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -1,6 +1,11 @@ package cmd import ( + "bytes" + "html/template" + "io/ioutil" + "os" + "path" "strings" "github.com/mitchellh/go-homedir" @@ -42,32 +47,66 @@ func Execute() error { } func initConfig() { - if cfgFile != "" { - viper.SetConfigFile(cfgFile) - } else { + if cfgFile == "" { home, err := homedir.Dir() if err != nil { log.WithError(err).Fatal("unable to determine homedir for current user") } - viper.AddConfigPath(home) - viper.SetConfigName(".brudi.yaml") + cfgFile = path.Join(home, ".brudi.yaml") } - viper.SetConfigType("yaml") + logFields := log.WithField("cfgFile", cfgFile) - viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) - viper.AutomaticEnv() + info, err := os.Stat(cfgFile) + if os.IsNotExist(err) { + logFields.Warn("config does not exist") + return + } else if info.IsDir() { + logFields.Warn("config is a directory") + return + } + + var cfgContent []byte + cfgContent, err = ioutil.ReadFile(cfgFile) + if err != nil { + log.WithError(err).Fatal("failed while reading config") + } + + var tpl *template.Template + tpl, err = template.New("").Parse(string(cfgContent)) + if err != nil { + log.WithError(err).Fatal() + } + + type templateData struct { + Env map[string]string + } - if err := viper.ReadInConfig(); err != nil { - if _, ok := err.(viper.ConfigFileNotFoundError); ok { - // cfg file not found; ignore error if desired - } else { - log.WithError(err).Fatal("failed while reading config") + data := templateData{ + Env: make(map[string]string), + } + + for _, e := range os.Environ() { + e := strings.SplitN(e, "=", 2) + if len(e) > 1 { + data.Env[e[0]] = e[1] } } - if len(viper.ConfigFileUsed()) > 0 { - log.WithField("config", viper.ConfigFileUsed()).Info("config loaded") + renderedCfg := new(bytes.Buffer) + err = tpl.Execute(renderedCfg, &data) + if err != nil { + log.WithError(err).Fatal() } + + viper.SetConfigType("yaml") + viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) + viper.AutomaticEnv() + + if err := viper.ReadConfig(renderedCfg); err != nil { + log.WithError(err).Fatal("failed while reading config") + } + + log.WithField("config", cfgFile).Info("config loaded") }