diff --git a/README.md b/README.md index b0b8372..5feb7a1 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,8 @@ docker run -d \ ``` ## docker compose + +### config file ```yaml --- version: "2.1" @@ -66,6 +68,32 @@ services: restart: unless-stopped ``` +### env + +```yaml +--- +version: "2.1" +services: + adguardhome-sync: + image: quay.io/bakito/adguardhome-sync + container_name: adguardhome-sync + environment: + - ORIGIN_URL=https://192.168.1.2:3000 + - ORIGIN_USERNAME=username + - ORIGIN_PASSWORD=password + - REPLICA_URL=http://192.168.1.3 + - REPLICA_USERNAME=username + - REPLICA_PASSWORD=password + - REPLICA1_URL=http://192.168.1.4 + - REPLICA1_USERNAME=username + - REPLICA1_PASSWORD=password + - REPLICA1_APIPATH=/some/path/control + - CRON=*/10 * * * * # run every 10 minutes + ports: + - 8080:8080 + restart: unless-stopped +``` + ### Config file location: $HOME/.adguardhome-sync.yaml diff --git a/cmd/root.go b/cmd/root.go index 24c7de8..f13d563 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -3,13 +3,13 @@ package cmd import ( "fmt" "os" + "regexp" "strings" "github.com/bakito/adguardhome-sync/pkg/log" - - "github.com/spf13/cobra" - + "github.com/bakito/adguardhome-sync/pkg/types" homedir "github.com/mitchellh/go-homedir" + "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -31,11 +31,17 @@ const ( configReplicaUsername = "replica.username" configReplicaPassword = "replica.password" configReplicaInsecureSkipVerify = "replica.insecureSkipVerify" + + envReplicasUsernameFormat = "REPLICA%s_USERNAME" + envReplicasPasswordFormat = "REPLICA%s_PASSWORD" + envReplicasAPIPathFormat = "REPLICA%s_APIPATH" + envReplicasInsecureSkipVerifyFormat = "REPLICA%s_INSECURESKIPVERIFY" ) var ( - cfgFile string - logger = log.GetLogger("root") + cfgFile string + logger = log.GetLogger("root") + envReplicasURLPattern = regexp.MustCompile(`^REPLICA(\d+)_URL=(.*)`) ) // rootCmd represents the base command when called without any subcommands @@ -95,3 +101,35 @@ func initConfig() { os.Exit(1) } } + +func getConfig() (*types.Config, error) { + cfg := &types.Config{} + if err := viper.Unmarshal(cfg); err != nil { + return nil, err + } + + if len(cfg.Replicas) == 0 { + cfg.Replicas = append(cfg.Replicas, collectEnvReplicas()...) + } + return cfg, nil +} + +// Manually collect replicas from env. +func collectEnvReplicas() []types.AdGuardInstance { + var replicas []types.AdGuardInstance + for _, v := range os.Environ() { + if envReplicasURLPattern.MatchString(v) { + sm := envReplicasURLPattern.FindStringSubmatch(v) + re := types.AdGuardInstance{ + URL: sm[2], + Username: os.Getenv(fmt.Sprintf(envReplicasUsernameFormat, sm[1])), + Password: os.Getenv(fmt.Sprintf(envReplicasPasswordFormat, sm[1])), + APIPath: os.Getenv(fmt.Sprintf(envReplicasAPIPathFormat, sm[1])), + InsecureSkipVerify: strings.EqualFold(os.Getenv(fmt.Sprintf(envReplicasInsecureSkipVerifyFormat, sm[1])), "true"), + } + replicas = append(replicas, re) + } + } + + return replicas +} diff --git a/cmd/run.go b/cmd/run.go index c6dca3e..fb2e546 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -3,10 +3,8 @@ package cmd import ( "github.com/bakito/adguardhome-sync/pkg/log" "github.com/bakito/adguardhome-sync/pkg/sync" - "github.com/bakito/adguardhome-sync/pkg/types" - "github.com/spf13/viper" - "github.com/spf13/cobra" + "github.com/spf13/viper" ) // runCmd represents the run command @@ -16,8 +14,8 @@ var doCmd = &cobra.Command{ Long: `Synchronizes the configuration form an origin instance to a replica`, RunE: func(cmd *cobra.Command, args []string) error { logger = log.GetLogger("run") - cfg := &types.Config{} - if err := viper.Unmarshal(cfg); err != nil { + cfg, err := getConfig() + if err != nil { logger.Error(err) return err } diff --git a/pkg/types/types.go b/pkg/types/types.go index 40cc496..5c092ec 100644 --- a/pkg/types/types.go +++ b/pkg/types/types.go @@ -10,7 +10,7 @@ import ( // Config application configuration struct type Config struct { Origin AdGuardInstance `json:"origin" yaml:"origin"` - Replica *AdGuardInstance `json:"replica,omitempty" yaml:"replica,omitempty"` + Replica AdGuardInstance `json:"replica,omitempty" yaml:"replica,omitempty"` Replicas []AdGuardInstance `json:"replicas,omitempty" yaml:"replicas,omitempty"` Cron string `json:"cron,omitempty" yaml:"cron,omitempty"` API API `json:"api,omitempty" yaml:"api,omitempty"` @@ -26,15 +26,20 @@ type API struct { // UniqueReplicas get unique replication instances func (cfg *Config) UniqueReplicas() []AdGuardInstance { dedup := make(map[string]AdGuardInstance) - if cfg.Replica != nil { - dedup[cfg.Replica.Key()] = *cfg.Replica + if cfg.Replica.URL != "" { + dedup[cfg.Replica.Key()] = cfg.Replica } for _, replica := range cfg.Replicas { - dedup[replica.Key()] = replica + if replica.URL != "" { + dedup[replica.Key()] = replica + } } var r []AdGuardInstance for _, replica := range dedup { + if replica.APIPath == "" { + replica.APIPath = "/control" + } r = append(r, replica) } return r