diff --git a/README.md b/README.md index 1e2e1e4..2890a32 100644 --- a/README.md +++ b/README.md @@ -215,7 +215,7 @@ For Replicas replace `#` with the index number for the replica. E.g.: `REPLICA#_ | RUN_ON_START (bool) | bool | Run the sync on startup | | PRINT_CONFIG_ONLY (bool) | bool | Print current config only and stop the application | | CONTINUE_ON_ERROR (bool) | bool | Continue sync on errors | -| API_PORT (int) | int | API port | +| API_PORT (int) | int | API port (API is disabled if port is set to 0) | | API_USERNAME (string) | string | API username | | API_PASSWORD (string) | string | API password | | API_DARK_MODE (bool) | bool | API dark mode | diff --git a/docs/main.go b/docs/main.go index 02bb473..25aac65 100644 --- a/docs/main.go +++ b/docs/main.go @@ -26,14 +26,7 @@ func main() { var buf strings.Builder _, _ = buf.WriteString("| Name | Type | Description |\n") _, _ = buf.WriteString("| :--- | ---- |:----------- |\n") - oldStdout := os.Stdout - r, w, _ := os.Pipe() - os.Stdout = w - printEnvTags(reflect.TypeOf(types.Config{}), "") - _ = w.Close() - envDoc, _ := io.ReadAll(r) - os.Stdout = oldStdout - _, _ = buf.Write(envDoc) + printEnvTags(&buf, reflect.TypeOf(types.Config{}), "") // Find the markers and replace content between them startMarker := "" @@ -57,7 +50,7 @@ func main() { } // printEnvTags recursively prints all fields with `env` tags. -func printEnvTags(t reflect.Type, prefix string) { +func printEnvTags(w io.Writer, t reflect.Type, prefix string) { if t.Kind() == reflect.Ptr { t = t.Elem() } @@ -92,12 +85,12 @@ func printEnvTags(t reflect.Type, prefix string) { } if ft.Kind() == reflect.Struct && ft.Name() != "Time" { // skip time.Time - printEnvTags(ft, strings.TrimSuffix(combinedTag, "_")) + printEnvTags(w, ft, strings.TrimSuffix(combinedTag, "_")) } else if envTag != "" { envVar := strings.Trim(combinedTag, "_") + " (" + ft.Kind().String() + ")" docs := field.Tag.Get("documentation") - _, _ = fmt.Printf("| %s | %s | %s |\n", envVar, ft.Kind().String(), docs) + _, _ = fmt.Fprintf(w, "| %s | %s | %s |\n", envVar, ft.Kind().String(), docs) } } } diff --git a/pkg/config/config.go b/pkg/config/config.go index acb328e..f09ea46 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -102,8 +102,6 @@ func Get(configFile string, flags Flags) (*AppConfig, error) { "Do not use single replica and numbered (list) replica config combined") } - handleDeprecatedEnvVars(cfg) - if cfg.Replica != nil { cfg.Replicas = []types.AdGuardInstance{*cfg.Replica} cfg.Replica = nil diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index 01e3ea2..c4777de 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -229,16 +229,6 @@ var _ = Describe("Config", func() { flags.EXPECT().Changed(gm.Any()).Return(false).AnyTimes() flags.EXPECT().GetBool(config.FlagFeatureDNSServerConfig).Return(true, nil).AnyTimes() - cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags) - Ω(err).ShouldNot(HaveOccurred()) - Ω(cfg.Get().Features.DNS.ServerConfig).Should(BeFalse()) - }) - It("should have the feature dns server config from the config DEPRECATED env var", func() { - setEnv("FEATURES_DNS_SERVERCONFIG", "false") - flags.EXPECT().Changed(config.FlagFeatureDNSServerConfig).Return(true).AnyTimes() - flags.EXPECT().Changed(gm.Any()).Return(false).AnyTimes() - flags.EXPECT().GetBool(config.FlagFeatureDNSServerConfig).Return(true, nil).AnyTimes() - cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags) Ω(err).ShouldNot(HaveOccurred()) Ω(cfg.Get().Features.DNS.ServerConfig).Should(BeFalse()) diff --git a/pkg/config/deprecated_env_test.go b/pkg/config/deprecated_env_test.go deleted file mode 100644 index aadafa6..0000000 --- a/pkg/config/deprecated_env_test.go +++ /dev/null @@ -1,139 +0,0 @@ -package config_test - -import ( - "fmt" - "os" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "github.com/bakito/adguardhome-sync/pkg/config" -) - -var envVars = []string{ - "FEATURES_GENERAL_SETTINGS", - "FEATURES_QUERY_LOG_CONFIG", - "FEATURES_STATS_CONFIG", - "FEATURES_CLIENT_SETTINGS", - "FEATURES_SERVICES", - "FEATURES_FILTERS", - "FEATURES_THEME", - "FEATURES_DHCP_SERVER_CONFIG", - "FEATURES_DHCP_STATIC_LEASES", - "FEATURES_DNS_SERVER_CONFIG", - "FEATURES_DNS_ACCESS_LISTS", - "FEATURES_DNS_REWRITES", - "REPLICA1_INTERFACE_NAME", - "REPLICA1_DHCP_SERVER_ENABLED", -} - -var deprecatedEnvVars = []string{ - "FEATURES_GENERALSETTINGS", - "FEATURES_QUERYLOGCONFIG", - "FEATURES_STATSCONFIG", - "FEATURES_CLIENTSETTINGS", - "FEATURES_SERVICES", - "FEATURES_FILTERS", - "FEATURES_DHCP_SERVERCONFIG", - "FEATURES_DHCP_STATICLEASES", - "FEATURES_DNS_SERVERCONFIG", - "FEATURES_DNS_ACCESSLISTS", - "FEATURES_DNS_REWRITES", - "REPLICA1_INTERFACENAME", - "REPLICA1_DHCPSERVERENABLED", -} - -var _ = Describe("Config", func() { - Context("deprecated", func() { - BeforeEach(func() { - for _, envVar := range deprecatedEnvVars { - Ω(os.Setenv(envVar, "false")).ShouldNot(HaveOccurred()) - } - }) - AfterEach(func() { - for _, envVar := range deprecatedEnvVars { - Ω(os.Unsetenv(envVar)).ShouldNot(HaveOccurred()) - } - }) - Context("Get", func() { - It("features should be false", func() { - cfg, err := config.Get("", nil) - Ω(err).ShouldNot(HaveOccurred()) - verifyFeatures(cfg, false) - }) - }) - }) - Context("current", func() { - BeforeEach(func() { - for _, envVar := range envVars { - Ω(os.Unsetenv(envVar)).ShouldNot(HaveOccurred()) - } - }) - AfterEach(func() { - for _, envVar := range envVars { - Ω(os.Unsetenv(envVar)).ShouldNot(HaveOccurred()) - } - }) - Context("Get", func() { - It("features should be true by default", func() { - cfg, err := config.Get("", nil) - Ω(err).ShouldNot(HaveOccurred()) - verifyFeatures(cfg, true) - }) - It("features should be true by default", func() { - cfg, err := config.Get("", nil) - Ω(err).ShouldNot(HaveOccurred()) - verifyFeatures(cfg, true) - }) - It("features should be false", func() { - for _, envVar := range envVars { - Ω(os.Setenv(envVar, "false")).ShouldNot(HaveOccurred()) - } - cfg, err := config.Get("", nil) - Ω(err).ShouldNot(HaveOccurred()) - verifyFeatures(cfg, false) - }) - Context("interface name", func() { - It("should set interface name of replica 1", func() { - Ω(os.Setenv("REPLICA1_URL", "https://foo.bar")).ShouldNot(HaveOccurred()) - Ω(os.Setenv(fmt.Sprintf("REPLICA%s_INTERFACE_NAME", "1"), "eth0")).ShouldNot(HaveOccurred()) - cfg, err := config.Get("", nil) - Ω(err).ShouldNot(HaveOccurred()) - Ω(cfg.Get().Replicas[0].InterfaceName).Should(Equal("eth0")) - }) - }) - Context("dhcp server", func() { - It("should enable the dhcp server of replica 1", func() { - Ω(os.Setenv("REPLICA1_URL", "https://foo.bar")).ShouldNot(HaveOccurred()) - Ω(os.Setenv(fmt.Sprintf("REPLICA%s_DHCPSERVERENABLED", "1"), "true")).ShouldNot(HaveOccurred()) - cfg, err := config.Get("", nil) - Ω(err).ShouldNot(HaveOccurred()) - Ω(cfg.Get().Replicas[0].DHCPServerEnabled).ShouldNot(BeNil()) - Ω(*cfg.Get().Replicas[0].DHCPServerEnabled).Should(BeTrue()) - }) - It("should disable the dhcp server of replica 1", func() { - Ω(os.Setenv("REPLICA1_URL", "https://foo.bar")).ShouldNot(HaveOccurred()) - Ω(os.Setenv(fmt.Sprintf("REPLICA%s_DHCPSERVERENABLED", "1"), "false")).ShouldNot(HaveOccurred()) - cfg, err := config.Get("", nil) - Ω(err).ShouldNot(HaveOccurred()) - Ω(cfg.Get().Replicas[0].DHCPServerEnabled).ShouldNot(BeNil()) - Ω(*cfg.Get().Replicas[0].DHCPServerEnabled).Should(BeFalse()) - }) - }) - }) - }) -}) - -func verifyFeatures(cfg *config.AppConfig, value bool) { - Ω(cfg.Get().Features.GeneralSettings).Should(Equal(value)) - Ω(cfg.Get().Features.QueryLogConfig).Should(Equal(value)) - Ω(cfg.Get().Features.StatsConfig).Should(Equal(value)) - Ω(cfg.Get().Features.ClientSettings).Should(Equal(value)) - Ω(cfg.Get().Features.Services).Should(Equal(value)) - Ω(cfg.Get().Features.Filters).Should(Equal(value)) - Ω(cfg.Get().Features.DHCP.ServerConfig).Should(Equal(value)) - Ω(cfg.Get().Features.DHCP.StaticLeases).Should(Equal(value)) - Ω(cfg.Get().Features.DNS.ServerConfig).Should(Equal(value)) - Ω(cfg.Get().Features.DNS.AccessLists).Should(Equal(value)) - Ω(cfg.Get().Features.DNS.Rewrites).Should(Equal(value)) -} diff --git a/pkg/config/env.go b/pkg/config/env.go index 7fd7ac8..03a764e 100644 --- a/pkg/config/env.go +++ b/pkg/config/env.go @@ -4,81 +4,12 @@ import ( "fmt" "os" "strconv" - "strings" "github.com/caarlos0/env/v11" "github.com/bakito/adguardhome-sync/pkg/types" - "github.com/bakito/adguardhome-sync/pkg/utils" ) -func handleDeprecatedEnvVars(cfg *types.Config) { - if val, ok := checkDeprecatedEnvVar("RUNONSTART", "RUN_ON_START"); ok { - cfg.RunOnStart, _ = strconv.ParseBool(val) - } - if val, ok := checkDeprecatedEnvVar("API_DARKMODE", "API_DARK_MODE"); ok { - cfg.API.DarkMode, _ = strconv.ParseBool(val) - } - if val, ok := checkDeprecatedEnvVar("FEATURES_GENERALSETTINGS", "FEATURES_GENERAL_SETTINGS"); ok { - cfg.Features.GeneralSettings, _ = strconv.ParseBool(val) - } - if val, ok := checkDeprecatedEnvVar("FEATURES_QUERYLOGCONFIG", "FEATURES_QUERY_LOG_CONFIG"); ok { - cfg.Features.QueryLogConfig, _ = strconv.ParseBool(val) - } - if val, ok := checkDeprecatedEnvVar("FEATURES_STATSCONFIG", "FEATURES_STATS_CONFIG"); ok { - cfg.Features.StatsConfig, _ = strconv.ParseBool(val) - } - if val, ok := checkDeprecatedEnvVar("FEATURES_CLIENTSETTINGS", "FEATURES_CLIENT_SETTINGS"); ok { - cfg.Features.ClientSettings, _ = strconv.ParseBool(val) - } - if val, ok := checkDeprecatedEnvVar("FEATURES_DHCP_SERVERCONFIG", "FEATURES_DHCP_SERVER_CONFIG"); ok { - cfg.Features.DHCP.ServerConfig, _ = strconv.ParseBool(val) - } - if val, ok := checkDeprecatedEnvVar("FEATURES_DHCP_STATICLEASES", "FEATURES_DHCP_STATIC_LEASES"); ok { - cfg.Features.DHCP.StaticLeases, _ = strconv.ParseBool(val) - } - if val, ok := checkDeprecatedEnvVar("FEATURES_DNS_ACCESSLISTS", "FEATURES_DNS_ACCESS_LISTS"); ok { - cfg.Features.DNS.AccessLists, _ = strconv.ParseBool(val) - } - if val, ok := checkDeprecatedEnvVar("FEATURES_DNS_SERVERCONFIG", "FEATURES_DNS_SERVER_CONFIG"); ok { - cfg.Features.DNS.ServerConfig, _ = strconv.ParseBool(val) - } - - if cfg.Replica != nil { - if val, ok := checkDeprecatedEnvVar("REPLICA_WEBURL", "REPLICA_WEB_URL"); ok { - cfg.Replica.WebURL = val - } - if val, ok := checkDeprecatedEnvVar("REPLICA_AUTOSETUP", "REPLICA_AUTO_SETUP"); ok { - cfg.Replica.AutoSetup, _ = strconv.ParseBool(val) - } - if val, ok := checkDeprecatedEnvVar("REPLICA_INTERFACENAME", "REPLICA_INTERFACE_NAME"); ok { - cfg.Replica.InterfaceName = val - } - if val, ok := checkDeprecatedEnvVar("REPLICA_DHCPSERVERENABLED", "REPLICA_DHCP_SERVER_ENABLED"); ok { - if b, err := strconv.ParseBool(val); err != nil { - cfg.Replica.DHCPServerEnabled = utils.Ptr(b) - } - } - } -} - -func checkDeprecatedEnvVar(oldName, newName string) (string, bool) { - old, oldOK := os.LookupEnv(oldName) - if oldOK { - logger.With("deprecated", oldName, "replacement", newName). - Warn("Deprecated env variable is used, please use the correct one") - } - newVal, newOK := os.LookupEnv(newName) - if newOK { - return newVal, true - } - return old, oldOK -} - -func checkDeprecatedReplicaEnvVar(oldPattern, newPattern string, replicaID int) (string, bool) { - return checkDeprecatedEnvVar(fmt.Sprintf(oldPattern, replicaID), fmt.Sprintf(newPattern, replicaID)) -} - // Manually collect replicas from env. func enrichReplicasFromEnv(initialReplicas []types.AdGuardInstance) ([]types.AdGuardInstance, error) { var replicas []types.AdGuardInstance @@ -108,7 +39,7 @@ func enrichReplicasFromEnv(initialReplicas []types.AdGuardInstance) ([]types.AdG for i := range replicas { reID := i + 1 - // keep previously set value + // keep the previously set value replicaDhcpServer := replicas[i].DHCPServerEnabled replicas[i].DHCPServerEnabled = nil if err := env.ParseWithOptions(&replicas[i], env.Options{Prefix: fmt.Sprintf("REPLICA%d_", reID)}); err != nil { @@ -117,26 +48,6 @@ func enrichReplicasFromEnv(initialReplicas []types.AdGuardInstance) ([]types.AdG if replicas[i].DHCPServerEnabled == nil { replicas[i].DHCPServerEnabled = replicaDhcpServer } - if val, ok := checkDeprecatedReplicaEnvVar("REPLICA%d_APIPATH", "REPLICA%d_API_PATH", reID); ok { - replicas[i].APIPath = val - } - if val, ok := checkDeprecatedReplicaEnvVar("REPLICA%d_INSECURESKIPVERIFY", "REPLICA%d_INSECURE_SKIP_VERIFY", reID); ok { - replicas[i].InsecureSkipVerify = strings.EqualFold(val, "true") - } - if val, ok := checkDeprecatedReplicaEnvVar("REPLICA%d_AUTOSETUP", "REPLICA%d_AUTO_SETUP", reID); ok { - replicas[i].AutoSetup = strings.EqualFold(val, "true") - } - if val, ok := checkDeprecatedReplicaEnvVar("REPLICA%d_INTERFACENAME", "REPLICA%d_INTERFACE_NAME", reID); ok { - replicas[i].InterfaceName = val - } - - if dhcpEnabled, ok := checkDeprecatedReplicaEnvVar("REPLICA%d_DHCPSERVERENABLED", "REPLICA%d_DHCP_SERVER_ENABLED", reID); ok { - if strings.EqualFold(dhcpEnabled, "true") { - replicas[i].DHCPServerEnabled = utils.Ptr(true) - } else if strings.EqualFold(dhcpEnabled, "false") { - replicas[i].DHCPServerEnabled = utils.Ptr(false) - } - } if replicas[i].APIPath == "" { replicas[i].APIPath = "/control" } diff --git a/pkg/types/types.go b/pkg/types/types.go index d8df91d..fef0888 100644 --- a/pkg/types/types.go +++ b/pkg/types/types.go @@ -27,7 +27,7 @@ type Config struct { // Multiple replica instances Replicas []AdGuardInstance `json:"replicas,omitempty" yaml:"replicas,omitempty" faker:"slice_len=2"` Cron string `json:"cron,omitempty" yaml:"cron,omitempty" documentation:"Cron expression for the sync interval" env:"CRON"` - RunOnStart bool `json:"runOnStart,omitempty" yaml:"runOnStart,omitempty" documentation:"Run the sung on startup" env:"RUN_ON_START"` + RunOnStart bool `json:"runOnStart,omitempty" yaml:"runOnStart,omitempty" documentation:"Run the sync on startup" env:"RUN_ON_START"` PrintConfigOnly bool `json:"printConfigOnly,omitempty" yaml:"printConfigOnly,omitempty" documentation:"Print current config only and stop the application" env:"PRINT_CONFIG_ONLY"` ContinueOnError bool `json:"continueOnError,omitempty" yaml:"continueOnError,omitempty" documentation:"Continue sync on errors" env:"CONTINUE_ON_ERROR"` API API `json:"api,omitempty" yaml:"api,omitempty"` @@ -36,12 +36,12 @@ type Config struct { // API configuration. type API struct { - Port int `documentation:"API port" env:"API_PORT" json:"port,omitempty" yaml:"port,omitempty"` - Username string `documentation:"API username" env:"API_USERNAME" json:"username,omitempty" yaml:"username,omitempty"` - Password string `documentation:"API password" env:"API_PASSWORD" json:"password,omitempty" yaml:"password,omitempty"` - DarkMode bool `documentation:"API dark mode" env:"API_DARK_MODE" json:"darkMode,omitempty" yaml:"darkMode,omitempty"` - Metrics Metrics ` json:"metrics,omitempty" yaml:"metrics,omitempty"` - TLS TLS ` json:"tls,omitempty" yaml:"tls,omitempty"` + Port int `documentation:"API port (API is disabled if port is set to 0)" env:"API_PORT" json:"port,omitempty" yaml:"port,omitempty"` + Username string `documentation:"API username" env:"API_USERNAME" json:"username,omitempty" yaml:"username,omitempty"` + Password string `documentation:"API password" env:"API_PASSWORD" json:"password,omitempty" yaml:"password,omitempty"` + DarkMode bool `documentation:"API dark mode" env:"API_DARK_MODE" json:"darkMode,omitempty" yaml:"darkMode,omitempty"` + Metrics Metrics ` json:"metrics,omitempty" yaml:"metrics,omitempty"` + TLS TLS ` json:"tls,omitempty" yaml:"tls,omitempty"` } // Metrics configuration.