mirror of
https://github.com/bakito/adguardhome-sync.git
synced 2024-09-20 06:46:12 +08:00
Fix config issues with new env library (#273)
* correct config issues #271 #272 * rename type tags * replace env lib * move to config module * read flags * show e2e logs on error * extract env * replace deprecated env var * increment index * check replica numbers do not start with 0 * remove test suite * error handling * refactor flags * flags test * file test * file test * config tests * extend tests * test mixed mode * simplify * simplify * test mask * correct uniqe replicas * Update types_test.go * e2e test with file mode
This commit is contained in:
parent
906dfc680a
commit
4c1e56ccce
7
.github/workflows/e2e.yaml
vendored
7
.github/workflows/e2e.yaml
vendored
|
@ -11,6 +11,11 @@ on:
|
|||
jobs:
|
||||
e2e:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
build:
|
||||
- mode: env
|
||||
- mode: file
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
@ -22,7 +27,7 @@ jobs:
|
|||
run: ./testdata/e2e/bin/build-image.sh
|
||||
|
||||
- name: Install Helm Chart
|
||||
run: ./testdata/e2e/bin/install-chart.sh
|
||||
run: ./testdata/e2e/bin/install-chart.sh ${{ matrix.build.mode }}
|
||||
- name: Wait for sync to finish
|
||||
run: ./testdata/e2e/bin/wait-for-sync.sh
|
||||
- name: Show origin Logs
|
||||
|
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -8,5 +8,5 @@ main
|
|||
.adguardhome-sync.yaml
|
||||
tmp
|
||||
bin
|
||||
config.yaml
|
||||
config*.yaml
|
||||
*.log
|
||||
|
|
1
Makefile
1
Makefile
|
@ -22,6 +22,7 @@ test-ci: mocks tidy
|
|||
|
||||
mocks: mockgen
|
||||
$(MOCKGEN) -package client -destination pkg/mocks/client/mock.go github.com/bakito/adguardhome-sync/pkg/client Client
|
||||
$(MOCKGEN) -package client -destination pkg/mocks/flags/mock.go github.com/bakito/adguardhome-sync/pkg/config Flags
|
||||
|
||||
release: semver goreleaser
|
||||
@version=$$($(LOCALBIN)/semver); \
|
||||
|
|
11
README.md
11
README.md
|
@ -237,16 +237,7 @@ origin:
|
|||
password: password
|
||||
# cookie: Origin-Cookie-Name=CCCOOOKKKIIIEEE
|
||||
|
||||
# replica instance (optional, if only one)
|
||||
replica:
|
||||
# url of the replica instance
|
||||
url: http://192.168.1.3
|
||||
username: username
|
||||
password: password
|
||||
# cookie: Replica-Cookie-Name=CCCOOOKKKIIIEEE
|
||||
# webURL: "https://some-other.url" # used in the web interface (default: <origin-url>
|
||||
|
||||
# replicas instances (optional, if more than one)
|
||||
# replicas instances
|
||||
replicas:
|
||||
# url of the replica instance
|
||||
- url: http://192.168.1.3
|
||||
|
|
221
cmd/root.go
221
cmd/root.go
|
@ -3,65 +3,15 @@ package cmd
|
|||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/log"
|
||||
"github.com/bakito/adguardhome-sync/pkg/types"
|
||||
"github.com/bakito/adguardhome-sync/pkg/utils"
|
||||
"github.com/bakito/adguardhome-sync/version"
|
||||
"github.com/mitchellh/go-homedir"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
const (
|
||||
configCron = "CRON"
|
||||
configRunOnStart = "RUN_ON_START"
|
||||
configPrintConfigOnly = "PRINT_CONFIG_ONLY"
|
||||
configContinueOnError = "CONTINUE_ON_ERROR"
|
||||
|
||||
configAPIPort = "API.PORT"
|
||||
configAPIUsername = "API.USERNAME"
|
||||
configAPIPassword = "API.PASSWORD"
|
||||
configAPIDarkMode = "API.DARK_MODE"
|
||||
|
||||
configFeatureDHCPServerConfig = "FEATURES.DHCP.SERVER_CONFIG"
|
||||
configFeatureDHCPStaticLeases = "FEATURES.DHCP.STATIC_LEASES"
|
||||
configFeatureDNServerConfig = "FEATURES.DNS.SERVER_CONFIG"
|
||||
configFeatureDNSPAccessLists = "FEATURES.DNS.ACCESS_LISTS"
|
||||
configFeatureDNSRewrites = "FEATURES.DNS.rewrites"
|
||||
configFeatureGeneralSettings = "FEATURES.GENERAL_SETTINGS"
|
||||
configFeatureQueryLogConfig = "FEATURES.QUERY_LOG_CONFIG"
|
||||
configFeatureStatsConfig = "FEATURES.STATS_CONFIG"
|
||||
configFeatureClientSettings = "FEATURES.CLIENT_SETTINGS"
|
||||
configFeatureServices = "FEATURES.SERVICES"
|
||||
configFeatureFilters = "FEATURES.FILTERS"
|
||||
|
||||
configOriginURL = "ORIGIN.URL"
|
||||
configOriginWebURL = "ORIGIN.WEB_URL"
|
||||
configOriginAPIPath = "ORIGIN.API_PATH"
|
||||
configOriginUsername = "ORIGIN.USERNAME"
|
||||
configOriginPassword = "ORIGIN.PASSWORD"
|
||||
configOriginCookie = "ORIGIN.COOKIE"
|
||||
configOriginInsecureSkipVerify = "ORIGIN.INSECURE_SKIP_VERIFY"
|
||||
|
||||
configReplicaURL = "REPLICA.URL"
|
||||
configReplicaWebURL = "REPLICA.WEB_URL"
|
||||
configReplicaAPIPath = "REPLICA.API_PATH"
|
||||
configReplicaUsername = "REPLICA.USERNAME"
|
||||
configReplicaPassword = "REPLICA.PASSWORD"
|
||||
configReplicaCookie = "REPLICA.COOKIE"
|
||||
configReplicaInsecureSkipVerify = "REPLICA.INSECURE_SKIP_VERIFY"
|
||||
configReplicaAutoSetup = "REPLICA.AUTO_SETUP"
|
||||
configReplicaInterfaceName = "REPLICA.INTERFACE_NAME"
|
||||
)
|
||||
|
||||
var (
|
||||
cfgFile string
|
||||
logger = log.GetLogger("root")
|
||||
envReplicasURLPattern = regexp.MustCompile(`^REPLICA(\d+)_URL=(.*)`)
|
||||
cfgFile string
|
||||
logger = log.GetLogger("root")
|
||||
)
|
||||
|
||||
// rootCmd represents the base command when called without any subcommands
|
||||
|
@ -81,8 +31,6 @@ func Execute() {
|
|||
}
|
||||
|
||||
func init() {
|
||||
cobra.OnInitialize(initConfig)
|
||||
|
||||
// Here you will define your flags and configuration settings.
|
||||
// Cobra supports persistent flags, which, if defined here,
|
||||
// will be global for your application.
|
||||
|
@ -93,168 +41,3 @@ func init() {
|
|||
// when this action is called directly.
|
||||
rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
|
||||
}
|
||||
|
||||
// initConfig reads in config file and ENV variables if set.
|
||||
func initConfig() {
|
||||
if cfgFile != "" {
|
||||
// Use config file from the flag.
|
||||
viper.SetConfigFile(cfgFile)
|
||||
} else {
|
||||
// Find home directory.
|
||||
home, err := homedir.Dir()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Search config in home directory with name ".adguardhome-sync" (without extension).
|
||||
viper.AddConfigPath(home)
|
||||
viper.SetConfigName(".adguardhome-sync")
|
||||
}
|
||||
viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_", ".", "_"))
|
||||
viper.AutomaticEnv() // read in environment variables that match
|
||||
|
||||
// If a config file is found, read it in.
|
||||
if err := viper.ReadInConfig(); err == nil {
|
||||
logger.Info("Using config file:", viper.ConfigFileUsed())
|
||||
} else if cfgFile != "" {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func getConfig() (*types.Config, error) {
|
||||
cfg := &types.Config{}
|
||||
if err := viper.Unmarshal(cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if cfg.Replica != nil &&
|
||||
cfg.Replica.URL == "" &&
|
||||
cfg.Replica.Username == "" {
|
||||
cfg.Replica = nil
|
||||
}
|
||||
|
||||
if len(cfg.Replicas) == 0 {
|
||||
cfg.Replicas = append(cfg.Replicas, collectEnvReplicas()...)
|
||||
}
|
||||
|
||||
handleDeprecatedEnvVars(cfg)
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func handleDeprecatedEnvVars(cfg *types.Config) {
|
||||
value := checkDeprecatedEnvVar("RUNONSTART", "RUN_ON_START")
|
||||
if value != "" {
|
||||
cfg.RunOnStart, _ = strconv.ParseBool(value)
|
||||
}
|
||||
value = checkDeprecatedEnvVar("API_DARKMODE", "API_DARK_MODE")
|
||||
if value != "" {
|
||||
cfg.API.DarkMode, _ = strconv.ParseBool(value)
|
||||
}
|
||||
value = checkDeprecatedEnvVar("FEATURES_GENERALSETTINGS", "FEATURES_GENERAL_SETTINGS")
|
||||
if value != "" {
|
||||
cfg.Features.GeneralSettings, _ = strconv.ParseBool(value)
|
||||
}
|
||||
value = checkDeprecatedEnvVar("FEATURES_QUERYLOGCONFIG", "FEATURES_QUERY_LOG_CONFIG")
|
||||
if value != "" {
|
||||
cfg.Features.QueryLogConfig, _ = strconv.ParseBool(value)
|
||||
}
|
||||
value = checkDeprecatedEnvVar("FEATURES_STATSCONFIG", "FEATURES_STATS_CONFIG")
|
||||
if value != "" {
|
||||
cfg.Features.StatsConfig, _ = strconv.ParseBool(value)
|
||||
}
|
||||
value = checkDeprecatedEnvVar("FEATURES_CLIENTSETTINGS", "FEATURES_CLIENT_SETTINGS")
|
||||
if value != "" {
|
||||
cfg.Features.ClientSettings, _ = strconv.ParseBool(value)
|
||||
}
|
||||
value = checkDeprecatedEnvVar("FEATURES_DHCP_SERVERCONFIG", "FEATURES_DHCP_SERVER_CONFIG")
|
||||
if value != "" {
|
||||
cfg.Features.DHCP.ServerConfig, _ = strconv.ParseBool(value)
|
||||
}
|
||||
value = checkDeprecatedEnvVar("FEATURES_DHCP_STATICLEASES", "FEATURES_DHCP_STATIC_LEASES")
|
||||
if value != "" {
|
||||
cfg.Features.DHCP.StaticLeases, _ = strconv.ParseBool(value)
|
||||
}
|
||||
value = checkDeprecatedEnvVar("FEATURES_DNS_ACCESSLISTS", "FEATURES_DNS_ACCESS_LISTS")
|
||||
if value != "" {
|
||||
cfg.Features.DNS.AccessLists, _ = strconv.ParseBool(value)
|
||||
}
|
||||
value = checkDeprecatedEnvVar("FEATURES_DNS_SERVERCONFIG", "FEATURES_DNS_SERVER_CONFIG")
|
||||
if value != "" {
|
||||
cfg.Features.DNS.ServerConfig, _ = strconv.ParseBool(value)
|
||||
}
|
||||
|
||||
if cfg.Replica != nil {
|
||||
value = checkDeprecatedEnvVar("REPLICA_WEBURL", "REPLICA_WEB_URL")
|
||||
if value != "" {
|
||||
cfg.Replica.WebURL = value
|
||||
}
|
||||
value = checkDeprecatedEnvVar("REPLICA_AUTOSETUP", "REPLICA_AUTO_SETUP")
|
||||
if value != "" {
|
||||
cfg.Replica.AutoSetup, _ = strconv.ParseBool(value)
|
||||
}
|
||||
value = checkDeprecatedEnvVar("REPLICA_INTERFACENAME", "REPLICA_INTERFACE_NAME")
|
||||
if value != "" {
|
||||
cfg.Replica.InterfaceName = value
|
||||
}
|
||||
value = checkDeprecatedEnvVar("REPLICA_DHCPSERVERENABLED", "REPLICA_DHCP_SERVER_ENABLED")
|
||||
if value != "" {
|
||||
if b, err := strconv.ParseBool(value); err != nil {
|
||||
cfg.Replica.DHCPServerEnabled = utils.Ptr(b)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func checkDeprecatedEnvVar(oldName string, newName string) string {
|
||||
old, oldOK := os.LookupEnv(oldName)
|
||||
if oldOK {
|
||||
logger.With("deprecated", oldName, "replacement", newName).
|
||||
Warn("Deprecated env variable is used, please use the correct one")
|
||||
}
|
||||
new, newOK := os.LookupEnv(newName)
|
||||
if newOK {
|
||||
return new
|
||||
}
|
||||
return old
|
||||
}
|
||||
|
||||
func checkDeprecatedReplicaEnvVar(oldPattern, newPattern, replicaID string) string {
|
||||
return checkDeprecatedEnvVar(fmt.Sprintf(oldPattern, replicaID), fmt.Sprintf(newPattern, replicaID))
|
||||
}
|
||||
|
||||
// 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)
|
||||
index := sm[1]
|
||||
re := types.AdGuardInstance{
|
||||
URL: sm[2],
|
||||
WebURL: os.Getenv(fmt.Sprintf("REPLICA%s_WEB_URL", index)),
|
||||
APIPath: checkDeprecatedReplicaEnvVar("REPLICA%s_APIPATH", "REPLICA%s_API_PATH", index),
|
||||
Username: os.Getenv(fmt.Sprintf("REPLICA%s_USERNAME", index)),
|
||||
Password: os.Getenv(fmt.Sprintf("REPLICA%s_PASSWORD", index)),
|
||||
Cookie: os.Getenv(fmt.Sprintf("REPLICA%s_COOKIE", index)),
|
||||
InsecureSkipVerify: strings.EqualFold(checkDeprecatedReplicaEnvVar("REPLICA%s_INSECURESKIPVERIFY", "REPLICA%s_INSECURE_SKIP_VERIFY", index), "true"),
|
||||
AutoSetup: strings.EqualFold(checkDeprecatedReplicaEnvVar("REPLICA%s_AUTOSETUP", "REPLICA%s_AUTO_SETUP", index), "true"),
|
||||
InterfaceName: checkDeprecatedReplicaEnvVar("REPLICA%s_INTERFACENAME", "REPLICA%s_INTERFACE_NAME", index),
|
||||
}
|
||||
|
||||
dhcpEnabled := checkDeprecatedReplicaEnvVar("REPLICA%s_DHCPSERVERENABLED", "REPLICA%s_DHCP_SERVER_ENABLED", index)
|
||||
if strings.EqualFold(dhcpEnabled, "true") {
|
||||
re.DHCPServerEnabled = utils.Ptr(true)
|
||||
} else if strings.EqualFold(dhcpEnabled, "false") {
|
||||
re.DHCPServerEnabled = utils.Ptr(false)
|
||||
}
|
||||
if re.APIPath == "" {
|
||||
re.APIPath = "/control"
|
||||
}
|
||||
replicas = append(replicas, re)
|
||||
}
|
||||
}
|
||||
|
||||
return replicas
|
||||
}
|
||||
|
|
111
cmd/run.go
111
cmd/run.go
|
@ -1,10 +1,10 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/bakito/adguardhome-sync/pkg/config"
|
||||
"github.com/bakito/adguardhome-sync/pkg/log"
|
||||
"github.com/bakito/adguardhome-sync/pkg/sync"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
|
@ -15,7 +15,7 @@ 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, err := getConfig()
|
||||
cfg, err := config.Get(cfgFile, cmd.Flags())
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
return err
|
||||
|
@ -43,82 +43,47 @@ var doCmd = &cobra.Command{
|
|||
|
||||
func init() {
|
||||
rootCmd.AddCommand(doCmd)
|
||||
doCmd.PersistentFlags().String("cron", "", "The cron expression to run in daemon mode")
|
||||
_ = viper.BindPFlag(configCron, doCmd.PersistentFlags().Lookup("cron"))
|
||||
doCmd.PersistentFlags().Bool("runOnStart", true, "Run the sync job on start.")
|
||||
_ = viper.BindPFlag(configRunOnStart, doCmd.PersistentFlags().Lookup("runOnStart"))
|
||||
doCmd.PersistentFlags().Bool("printConfigOnly", false, "Prints the configuration only and exists. "+
|
||||
doCmd.PersistentFlags().String(config.FlagCron, "", "The cron expression to run in daemon mode")
|
||||
doCmd.PersistentFlags().Bool(config.FlagRunOnStart, true, "Run the sync job on start.")
|
||||
doCmd.PersistentFlags().Bool(config.FlagPrintConfigOnly, false, "Prints the configuration only and exists. "+
|
||||
"Can be used to debug the config E.g: when having authentication issues.")
|
||||
_ = viper.BindPFlag(configPrintConfigOnly, doCmd.PersistentFlags().Lookup("printConfigOnly"))
|
||||
doCmd.PersistentFlags().Bool("continueOnError", false, "If enabled, the synchronisation task "+
|
||||
doCmd.PersistentFlags().Bool(config.FlagContinueOnError, false, "If enabled, the synchronisation task "+
|
||||
"will not fail on single errors, but will log the errors and continue.")
|
||||
_ = viper.BindPFlag(configContinueOnError, doCmd.PersistentFlags().Lookup("continueOnError"))
|
||||
|
||||
doCmd.PersistentFlags().Int("api-port", 8080, "Sync API Port, the API endpoint will be started to enable remote triggering; if 0 port API is disabled.")
|
||||
_ = viper.BindPFlag(configAPIPort, doCmd.PersistentFlags().Lookup("api-port"))
|
||||
doCmd.PersistentFlags().String("api-username", "", "Sync API username")
|
||||
_ = viper.BindPFlag(configAPIUsername, doCmd.PersistentFlags().Lookup("api-username"))
|
||||
doCmd.PersistentFlags().String("api-password", "", "Sync API password")
|
||||
_ = viper.BindPFlag(configAPIPassword, doCmd.PersistentFlags().Lookup("api-password"))
|
||||
doCmd.PersistentFlags().String("api-darkMode", "", "API UI in dark mode")
|
||||
_ = viper.BindPFlag(configAPIDarkMode, doCmd.PersistentFlags().Lookup("api-darkMode"))
|
||||
doCmd.PersistentFlags().Int(config.FlagApiPort, 8080, "Sync API Port, the API endpoint will be started to enable remote triggering; if 0 port API is disabled.")
|
||||
doCmd.PersistentFlags().String(config.FlagApiUsername, "", "Sync API username")
|
||||
doCmd.PersistentFlags().String(config.FlagApiPassword, "", "Sync API password")
|
||||
doCmd.PersistentFlags().String(config.FlagApiDarkMode, "", "API UI in dark mode")
|
||||
|
||||
doCmd.PersistentFlags().Bool("feature-dhcp-server-config", true, "Enable DHCP server config feature")
|
||||
_ = viper.BindPFlag(configFeatureDHCPServerConfig, doCmd.PersistentFlags().Lookup("feature-dhcp-server-config"))
|
||||
doCmd.PersistentFlags().Bool("feature-dhcp-static-leases", true, "Enable DHCP server static leases feature")
|
||||
_ = viper.BindPFlag(configFeatureDHCPStaticLeases, doCmd.PersistentFlags().Lookup("feature-dhcp-static-leases"))
|
||||
doCmd.PersistentFlags().Bool(config.FlagFeatureDhcpServerConfig, true, "Enable DHCP server config feature")
|
||||
doCmd.PersistentFlags().Bool(config.FlagFeatureDhcpStaticLeases, true, "Enable DHCP server static leases feature")
|
||||
|
||||
doCmd.PersistentFlags().Bool("feature-dns-server-config", true, "Enable DNS server config feature")
|
||||
_ = viper.BindPFlag(configFeatureDNServerConfig, doCmd.PersistentFlags().Lookup("feature-dns-server-config"))
|
||||
doCmd.PersistentFlags().Bool("feature-dns-access-lists", true, "Enable DNS server access lists feature")
|
||||
_ = viper.BindPFlag(configFeatureDNSPAccessLists, doCmd.PersistentFlags().Lookup("feature-dns-access-lists"))
|
||||
doCmd.PersistentFlags().Bool("feature-dns-rewrites", true, "Enable DNS rewrites feature")
|
||||
_ = viper.BindPFlag(configFeatureDNSRewrites, doCmd.PersistentFlags().Lookup("feature-dns-rewrites"))
|
||||
doCmd.PersistentFlags().Bool("feature-general-settings", true, "Enable general settings feature")
|
||||
_ = viper.BindPFlag(configFeatureGeneralSettings, doCmd.PersistentFlags().Lookup("feature-general-settings"))
|
||||
_ = viper.BindPFlag("features.generalSettings", doCmd.PersistentFlags().Lookup("feature-general-settings"))
|
||||
doCmd.PersistentFlags().Bool("feature-query-log-config", true, "Enable query log config feature")
|
||||
_ = viper.BindPFlag(configFeatureQueryLogConfig, doCmd.PersistentFlags().Lookup("feature-query-log-config"))
|
||||
doCmd.PersistentFlags().Bool("feature-stats-config", true, "Enable stats config feature")
|
||||
_ = viper.BindPFlag(configFeatureStatsConfig, doCmd.PersistentFlags().Lookup("feature-stats-config"))
|
||||
doCmd.PersistentFlags().Bool("feature-client-settings", true, "Enable client settings feature")
|
||||
_ = viper.BindPFlag(configFeatureClientSettings, doCmd.PersistentFlags().Lookup("feature-client-settings"))
|
||||
doCmd.PersistentFlags().Bool("feature-services", true, "Enable services sync feature")
|
||||
_ = viper.BindPFlag(configFeatureServices, doCmd.PersistentFlags().Lookup("feature-services"))
|
||||
doCmd.PersistentFlags().Bool("feature-filters", true, "Enable filters sync feature")
|
||||
_ = viper.BindPFlag(configFeatureFilters, doCmd.PersistentFlags().Lookup("feature-filters"))
|
||||
doCmd.PersistentFlags().Bool(config.FlagFeatureDnsServerConfig, true, "Enable DNS server config feature")
|
||||
doCmd.PersistentFlags().Bool(config.FlagFeatureDnsAccessLists, true, "Enable DNS server access lists feature")
|
||||
doCmd.PersistentFlags().Bool(config.FlagFeatureDnsRewrites, true, "Enable DNS rewrites feature")
|
||||
|
||||
doCmd.PersistentFlags().String("origin-url", "", "Origin instance url")
|
||||
_ = viper.BindPFlag(configOriginURL, doCmd.PersistentFlags().Lookup("origin-url"))
|
||||
doCmd.PersistentFlags().String("origin-web-url", "", "Origin instance web url used in the web interface (default: <origin-url>)")
|
||||
_ = viper.BindPFlag(configOriginWebURL, doCmd.PersistentFlags().Lookup("origin-web-url"))
|
||||
doCmd.PersistentFlags().String("origin-api-path", "/control", "Origin instance API path")
|
||||
_ = viper.BindPFlag(configOriginAPIPath, doCmd.PersistentFlags().Lookup("origin-api-path"))
|
||||
doCmd.PersistentFlags().String("origin-username", "", "Origin instance username")
|
||||
_ = viper.BindPFlag(configOriginUsername, doCmd.PersistentFlags().Lookup("origin-username"))
|
||||
doCmd.PersistentFlags().String("origin-password", "", "Origin instance password")
|
||||
_ = viper.BindPFlag(configOriginPassword, doCmd.PersistentFlags().Lookup("origin-password"))
|
||||
doCmd.PersistentFlags().String("origin-cookie", "", "If Set, uses a cookie for authentication")
|
||||
_ = viper.BindPFlag(configOriginCookie, doCmd.PersistentFlags().Lookup("origin-cookie"))
|
||||
doCmd.PersistentFlags().Bool("origin-insecure-skip-verify", false, "Enable Origin instance InsecureSkipVerify")
|
||||
_ = viper.BindPFlag(configOriginInsecureSkipVerify, doCmd.PersistentFlags().Lookup("origin-insecure-skip-verify"))
|
||||
doCmd.PersistentFlags().Bool(config.FlagFeatureGeneral, true, "Enable general settings feature")
|
||||
doCmd.PersistentFlags().Bool(config.FlagFeatureQueryLog, true, "Enable query log config feature")
|
||||
doCmd.PersistentFlags().Bool(config.FlagFeatureStats, true, "Enable stats config feature")
|
||||
doCmd.PersistentFlags().Bool(config.FlagFeatureClient, true, "Enable client settings feature")
|
||||
doCmd.PersistentFlags().Bool(config.FlagFeatureServices, true, "Enable services sync feature")
|
||||
doCmd.PersistentFlags().Bool(config.FlagFeatureFilters, true, "Enable filters sync feature")
|
||||
|
||||
doCmd.PersistentFlags().String("replica-url", "", "Replica instance url")
|
||||
_ = viper.BindPFlag(configReplicaURL, doCmd.PersistentFlags().Lookup("replica-url"))
|
||||
doCmd.PersistentFlags().String("replica-web-url", "", "Replica instance web url used in the web interface (default: <replica-url>)")
|
||||
_ = viper.BindPFlag(configReplicaWebURL, doCmd.PersistentFlags().Lookup("replica-web-url"))
|
||||
doCmd.PersistentFlags().String("replica-api-path", "/control", "Replica instance API path")
|
||||
_ = viper.BindPFlag(configReplicaAPIPath, doCmd.PersistentFlags().Lookup("replica-api-path"))
|
||||
doCmd.PersistentFlags().String("replica-username", "", "Replica instance username")
|
||||
_ = viper.BindPFlag(configReplicaUsername, doCmd.PersistentFlags().Lookup("replica-username"))
|
||||
doCmd.PersistentFlags().String("replica-password", "", "Replica instance password")
|
||||
_ = viper.BindPFlag(configReplicaPassword, doCmd.PersistentFlags().Lookup("replica-password"))
|
||||
doCmd.PersistentFlags().String("replica-cookie", "", "If Set, uses a cookie for authentication")
|
||||
_ = viper.BindPFlag(configReplicaCookie, doCmd.PersistentFlags().Lookup("replica-cookie"))
|
||||
doCmd.PersistentFlags().Bool("replica-insecure-skip-verify", false, "Enable Replica instance InsecureSkipVerify")
|
||||
_ = viper.BindPFlag(configReplicaInsecureSkipVerify, doCmd.PersistentFlags().Lookup("replica-insecure-skip-verify"))
|
||||
doCmd.PersistentFlags().Bool("replica-auto-setup", false, "Enable automatic setup of new AdguardHome instances. This replaces the setup wizard.")
|
||||
_ = viper.BindPFlag(configReplicaAutoSetup, doCmd.PersistentFlags().Lookup("replica-auto-setup"))
|
||||
doCmd.PersistentFlags().String("replica-interface-name", "", "Optional change the interface name of the replica if it differs from the master")
|
||||
_ = viper.BindPFlag(configReplicaInterfaceName, doCmd.PersistentFlags().Lookup("replica-interface-name"))
|
||||
doCmd.PersistentFlags().String(config.FlagOriginURL, "", "Origin instance url")
|
||||
doCmd.PersistentFlags().String(config.FlagOriginWebURL, "", "Origin instance web url used in the web interface (default: <origin-url>)")
|
||||
doCmd.PersistentFlags().String(config.FlagOriginApiPath, "/control", "Origin instance API path")
|
||||
doCmd.PersistentFlags().String(config.FlagOriginUsername, "", "Origin instance username")
|
||||
doCmd.PersistentFlags().String(config.FlagOriginPassword, "", "Origin instance password")
|
||||
doCmd.PersistentFlags().String(config.FlagOriginCookie, "", "If Set, uses a cookie for authentication")
|
||||
doCmd.PersistentFlags().Bool(config.FlagOriginISV, false, "Enable Origin instance InsecureSkipVerify")
|
||||
|
||||
doCmd.PersistentFlags().String(config.FlagReplicaURL, "", "Replica instance url")
|
||||
doCmd.PersistentFlags().String(config.FlagReplicaWebURL, "", "Replica instance web url used in the web interface (default: <replica-url>)")
|
||||
doCmd.PersistentFlags().String(config.FlagReplicaApiPath, "/control", "Replica instance API path")
|
||||
doCmd.PersistentFlags().String(config.FlagReplicaUsername, "", "Replica instance username")
|
||||
doCmd.PersistentFlags().String(config.FlagReplicaPassword, "", "Replica instance password")
|
||||
doCmd.PersistentFlags().String(config.FlagReplicaCookie, "", "If Set, uses a cookie for authentication")
|
||||
doCmd.PersistentFlags().Bool(config.FlagReplicaISV, false, "Enable Replica instance InsecureSkipVerify")
|
||||
doCmd.PersistentFlags().Bool(config.FlagReplicaAutoSetup, false, "Enable automatic setup of new AdguardHome instances. This replaces the setup wizard.")
|
||||
doCmd.PersistentFlags().String(config.FlagReplicaInterfaceName, "", "Optional change the interface name of the replica if it differs from the master")
|
||||
}
|
||||
|
|
17
go.mod
17
go.mod
|
@ -3,18 +3,17 @@ module github.com/bakito/adguardhome-sync
|
|||
go 1.21
|
||||
|
||||
require (
|
||||
github.com/caarlos0/env/v10 v10.0.0
|
||||
github.com/gin-gonic/gin v1.9.1
|
||||
github.com/go-resty/resty/v2 v2.9.1
|
||||
github.com/golang/mock v1.6.0
|
||||
github.com/google/uuid v1.5.0
|
||||
github.com/jinzhu/copier v0.4.0
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/oapi-codegen/runtime v1.1.1
|
||||
github.com/onsi/ginkgo/v2 v2.13.2
|
||||
github.com/onsi/gomega v1.30.0
|
||||
github.com/robfig/cron/v3 v3.0.1
|
||||
github.com/spf13/cobra v1.8.0
|
||||
github.com/spf13/viper v1.18.2
|
||||
go.uber.org/zap v1.26.0
|
||||
golang.org/x/mod v0.14.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
|
@ -26,7 +25,7 @@ require (
|
|||
github.com/bytedance/sonic v1.10.2 // indirect
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
|
||||
github.com/chenzhuoyu/iasm v0.9.1 // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/go-logr/logr v1.3.0 // indirect
|
||||
|
@ -39,31 +38,22 @@ require (
|
|||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
|
||||
github.com/leodido/go-urn v1.2.4 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.1.1 // indirect
|
||||
github.com/sagikazarmark/locafero v0.4.0 // indirect
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spf13/afero v1.11.0 // indirect
|
||||
github.com/spf13/cast v1.6.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/arch v0.7.0 // indirect
|
||||
golang.org/x/crypto v0.18.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc // indirect
|
||||
golang.org/x/net v0.19.0 // indirect
|
||||
golang.org/x/sys v0.16.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
|
@ -71,7 +61,6 @@ require (
|
|||
google.golang.org/protobuf v1.32.0 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
k8s.io/klog/v2 v2.110.1 // indirect
|
||||
k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect
|
||||
|
|
36
go.sum
36
go.sum
|
@ -6,6 +6,8 @@ github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1
|
|||
github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM=
|
||||
github.com/bytedance/sonic v1.10.2 h1:GQebETVBxYB7JGWJtLBi07OVzWwt+8dWA00gEVW2ZFE=
|
||||
github.com/bytedance/sonic v1.10.2/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4=
|
||||
github.com/caarlos0/env/v10 v10.0.0 h1:yIHUBZGsyqCnpTkbjk8asUlx6RFhhEs+h7TOBdgdzXA=
|
||||
github.com/caarlos0/env/v10 v10.0.0/go.mod h1:ZfulV76NvVPw3tm591U4SwL3Xx9ldzBP9aGxzeN7G18=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0=
|
||||
|
@ -21,10 +23,6 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
|||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
||||
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
|
@ -63,8 +61,6 @@ github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJY
|
|||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
|
||||
github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
|
@ -79,22 +75,14 @@ github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa02
|
|||
github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc=
|
||||
github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
|
||||
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
|
||||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
|
@ -115,25 +103,11 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI
|
|||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
|
||||
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
|
||||
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
|
||||
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
|
||||
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
|
||||
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
|
||||
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
|
||||
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
|
||||
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
|
||||
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ=
|
||||
github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk=
|
||||
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
|
@ -147,8 +121,6 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o
|
|||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
|
||||
|
@ -173,8 +145,6 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
|
|||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
|
||||
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||
golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc h1:ao2WRsKSzW6KuUY9IWPwWahcHCgR0s52IfwutMfEbdM=
|
||||
golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
|
@ -252,8 +222,6 @@ gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLF
|
|||
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
|
|
84
pkg/config/config.go
Normal file
84
pkg/config/config.go
Normal file
|
@ -0,0 +1,84 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"regexp"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/log"
|
||||
"github.com/bakito/adguardhome-sync/pkg/types"
|
||||
"github.com/caarlos0/env/v10"
|
||||
)
|
||||
|
||||
var (
|
||||
envReplicasURLPattern = regexp.MustCompile(`^REPLICA(\d+)_URL=(.*)`)
|
||||
logger = log.GetLogger("config")
|
||||
)
|
||||
|
||||
func Get(configFile string, flags Flags) (*types.Config, error) {
|
||||
path, err := configFilePath(configFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cfg := initialConfig()
|
||||
|
||||
// read yaml config
|
||||
if err := readFile(cfg, path); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// overwrite from command flags
|
||||
if err := readFlags(cfg, flags); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// overwrite from env vars
|
||||
|
||||
if err := env.Parse(cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := env.ParseWithOptions(&cfg.Origin, env.Options{Prefix: "ORIGIN_"}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := env.ParseWithOptions(cfg.Replica, env.Options{Prefix: "REPLICA_"}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if cfg.Replica != nil &&
|
||||
cfg.Replica.URL == "" &&
|
||||
cfg.Replica.Username == "" {
|
||||
cfg.Replica = nil
|
||||
}
|
||||
|
||||
if len(cfg.Replicas) > 0 && cfg.Replica != nil {
|
||||
return nil, errors.New("mixed replica config in use. " +
|
||||
"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
|
||||
}
|
||||
|
||||
cfg.Replicas, err = enrichReplicasFromEnv(cfg.Replicas)
|
||||
|
||||
return cfg, err
|
||||
}
|
||||
|
||||
func initialConfig() *types.Config {
|
||||
return &types.Config{
|
||||
RunOnStart: true,
|
||||
Origin: types.AdGuardInstance{
|
||||
APIPath: "/control",
|
||||
},
|
||||
Replica: &types.AdGuardInstance{
|
||||
APIPath: "/control",
|
||||
},
|
||||
API: types.API{
|
||||
Port: 8080,
|
||||
},
|
||||
Features: types.NewFeatures(true),
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package cmd_test
|
||||
package config_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
@ -9,5 +9,5 @@ import (
|
|||
|
||||
func TestCmd(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "Cmd Suite")
|
||||
RunSpecs(t, "Config Suite")
|
||||
}
|
194
pkg/config/config_test.go
Normal file
194
pkg/config/config_test.go
Normal file
|
@ -0,0 +1,194 @@
|
|||
package config_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/config"
|
||||
flagsmock "github.com/bakito/adguardhome-sync/pkg/mocks/flags"
|
||||
gm "github.com/golang/mock/gomock"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Config", func() {
|
||||
Context("Get", func() {
|
||||
var (
|
||||
flags *flagsmock.MockFlags
|
||||
mockCtrl *gm.Controller
|
||||
)
|
||||
BeforeEach(func() {
|
||||
mockCtrl = gm.NewController(GinkgoT())
|
||||
flags = flagsmock.NewMockFlags(mockCtrl)
|
||||
})
|
||||
AfterEach(func() {
|
||||
defer mockCtrl.Finish()
|
||||
})
|
||||
Context("Get", func() {
|
||||
Context("Mixed Config", func() {
|
||||
It("should have the origin URL from the config file", func() {
|
||||
flags.EXPECT().Changed(gm.Any()).Return(false).AnyTimes()
|
||||
|
||||
_, err := config.Get("../../testdata/config_test_replicas_and_replica.yaml", flags)
|
||||
Ω(err).Should(HaveOccurred())
|
||||
Ω(err.Error()).Should(ContainSubstring("mixed replica config in use"))
|
||||
})
|
||||
})
|
||||
Context("Origin Url", func() {
|
||||
It("should have the origin URL from the config file", func() {
|
||||
flags.EXPECT().Changed(gm.Any()).Return(false).AnyTimes()
|
||||
|
||||
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(cfg.Origin.URL).Should(Equal("https://origin-file:443"))
|
||||
})
|
||||
It("should have the origin URL from the config flags", func() {
|
||||
flags.EXPECT().Changed(config.FlagOriginURL).Return(true).AnyTimes()
|
||||
flags.EXPECT().Changed(gm.Any()).Return(false).AnyTimes()
|
||||
flags.EXPECT().GetString(config.FlagOriginURL).Return("https://origin-flag:443", nil).AnyTimes()
|
||||
|
||||
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(cfg.Origin.URL).Should(Equal("https://origin-flag:443"))
|
||||
})
|
||||
It("should have the origin URL from the config env var", func() {
|
||||
os.Setenv("ORIGIN_URL", "https://origin-env:443")
|
||||
defer func() {
|
||||
_ = os.Unsetenv("ORIGIN_URL")
|
||||
}()
|
||||
flags.EXPECT().Changed(config.FlagOriginURL).Return(true).AnyTimes()
|
||||
flags.EXPECT().Changed(gm.Any()).Return(false).AnyTimes()
|
||||
flags.EXPECT().GetString(config.FlagOriginURL).Return("https://origin-flag:443", nil).AnyTimes()
|
||||
|
||||
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(cfg.Origin.URL).Should(Equal("https://origin-env:443"))
|
||||
})
|
||||
})
|
||||
Context("Replica insecure skip verify", func() {
|
||||
It("should have the insecure skip verify from the config file", func() {
|
||||
flags.EXPECT().Changed(gm.Any()).Return(false).AnyTimes()
|
||||
|
||||
cfg, err := config.Get("../../testdata/config_test_replica.yaml", flags)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(cfg.Replicas[0].InsecureSkipVerify).Should(BeFalse())
|
||||
})
|
||||
It("should have the insecure skip verify from the config flags", func() {
|
||||
flags.EXPECT().Changed(config.FlagReplicaISV).Return(true).AnyTimes()
|
||||
flags.EXPECT().Changed(gm.Any()).Return(false).AnyTimes()
|
||||
flags.EXPECT().GetBool(config.FlagReplicaISV).Return(true, nil).AnyTimes()
|
||||
|
||||
cfg, err := config.Get("../../testdata/config_test_replica.yaml", flags)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(cfg.Replicas[0].InsecureSkipVerify).Should(BeTrue())
|
||||
})
|
||||
It("should have the insecure skip verify from the config env var", func() {
|
||||
os.Setenv("REPLICA_INSECURE_SKIP_VERIFY", "false")
|
||||
defer func() {
|
||||
_ = os.Unsetenv("REPLICA_INSECURE_SKIP_VERIFY")
|
||||
}()
|
||||
flags.EXPECT().Changed(config.FlagReplicaISV).Return(true).AnyTimes()
|
||||
flags.EXPECT().Changed(gm.Any()).Return(false).AnyTimes()
|
||||
flags.EXPECT().GetBool(config.FlagReplicaISV).Return(true, nil).AnyTimes()
|
||||
|
||||
cfg, err := config.Get("../../testdata/config_test_replica.yaml", flags)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(cfg.Replicas[0].InsecureSkipVerify).Should(BeFalse())
|
||||
})
|
||||
})
|
||||
|
||||
Context("Replica 1 insecure skip verify", func() {
|
||||
It("should have the insecure skip verify from the config file", func() {
|
||||
flags.EXPECT().Changed(gm.Any()).Return(false).AnyTimes()
|
||||
|
||||
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(cfg.Replicas[0].InsecureSkipVerify).Should(BeFalse())
|
||||
})
|
||||
It("should have the insecure skip verify from the config env var", func() {
|
||||
os.Setenv("REPLICA1_INSECURE_SKIP_VERIFY", "true")
|
||||
defer func() {
|
||||
_ = os.Unsetenv("REPLICA1_INSECURE_SKIP_VERIFY")
|
||||
}()
|
||||
flags.EXPECT().Changed(gm.Any()).Return(false).AnyTimes()
|
||||
|
||||
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(cfg.Replicas[0].InsecureSkipVerify).Should(BeTrue())
|
||||
})
|
||||
})
|
||||
Context("API Port", func() {
|
||||
It("should have the api port from the config file", func() {
|
||||
flags.EXPECT().Changed(gm.Any()).Return(false).AnyTimes()
|
||||
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(cfg.API.Port).Should(Equal(9090))
|
||||
})
|
||||
It("should have the api port from the config flags", func() {
|
||||
flags.EXPECT().Changed(config.FlagApiPort).Return(true).AnyTimes()
|
||||
flags.EXPECT().Changed(gm.Any()).Return(false).AnyTimes()
|
||||
flags.EXPECT().GetInt(config.FlagApiPort).Return(9990, nil).AnyTimes()
|
||||
|
||||
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(cfg.API.Port).Should(Equal(9990))
|
||||
})
|
||||
It("should have the api port from the config env var", func() {
|
||||
os.Setenv("API_PORT", "9999")
|
||||
defer func() {
|
||||
_ = os.Unsetenv("API_PORT")
|
||||
}()
|
||||
flags.EXPECT().Changed(config.FlagApiPort).Return(true).AnyTimes()
|
||||
flags.EXPECT().Changed(gm.Any()).Return(false).AnyTimes()
|
||||
flags.EXPECT().GetInt(config.FlagApiPort).Return(9990, nil).AnyTimes()
|
||||
|
||||
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(cfg.API.Port).Should(Equal(9999))
|
||||
})
|
||||
})
|
||||
Context("Feature DNS Server Config", func() {
|
||||
It("should have the feature dns server config from the config file", func() {
|
||||
flags.EXPECT().Changed(gm.Any()).Return(false).AnyTimes()
|
||||
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(cfg.Features.DNS.ServerConfig).Should(BeFalse())
|
||||
})
|
||||
It("should have the feature dns server config from the config flags", func() {
|
||||
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.Features.DNS.ServerConfig).Should(BeTrue())
|
||||
})
|
||||
It("should have the feature dns server config from the config env var", func() {
|
||||
os.Setenv("FEATURES_DNS_SERVER_CONFIG", "false")
|
||||
defer func() {
|
||||
_ = os.Unsetenv("FEATURES_DNS_SERVER_CONFIG")
|
||||
}()
|
||||
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.Features.DNS.ServerConfig).Should(BeFalse())
|
||||
})
|
||||
It("should have the feature dns server config from the config DEPRECATED env var", func() {
|
||||
os.Setenv("FEATURES_DNS_SERVERCONFIG", "false")
|
||||
defer func() {
|
||||
_ = os.Unsetenv("FEATURES_DNS_SERVERCONFIG")
|
||||
}()
|
||||
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.Features.DNS.ServerConfig).Should(BeFalse())
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
|
@ -1,9 +1,10 @@
|
|||
package cmd
|
||||
package config_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/config"
|
||||
"github.com/bakito/adguardhome-sync/pkg/types"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
|
@ -41,22 +42,21 @@ var deprecatedEnvVars = []string{
|
|||
"REPLICA1_DHCPSERVERENABLED",
|
||||
}
|
||||
|
||||
var _ = Describe("Run", func() {
|
||||
var _ = Describe("Config", func() {
|
||||
Context("deprecated", func() {
|
||||
BeforeEach(func() {
|
||||
for _, envVar := range deprecatedEnvVars {
|
||||
Ω(os.Setenv(envVar, "false")).ShouldNot(HaveOccurred())
|
||||
}
|
||||
initConfig()
|
||||
})
|
||||
AfterEach(func() {
|
||||
for _, envVar := range deprecatedEnvVars {
|
||||
Ω(os.Unsetenv(envVar)).ShouldNot(HaveOccurred())
|
||||
}
|
||||
})
|
||||
Context("getConfig", func() {
|
||||
Context("Get", func() {
|
||||
It("features should be false", func() {
|
||||
cfg, err := getConfig()
|
||||
cfg, err := config.Get("", nil)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
verifyFeatures(cfg, false)
|
||||
})
|
||||
|
@ -67,21 +67,20 @@ var _ = Describe("Run", func() {
|
|||
for _, envVar := range envVars {
|
||||
Ω(os.Unsetenv(envVar)).ShouldNot(HaveOccurred())
|
||||
}
|
||||
initConfig()
|
||||
})
|
||||
AfterEach(func() {
|
||||
for _, envVar := range envVars {
|
||||
Ω(os.Unsetenv(envVar)).ShouldNot(HaveOccurred())
|
||||
}
|
||||
})
|
||||
Context("getConfig", func() {
|
||||
Context("Get", func() {
|
||||
It("features should be true by default", func() {
|
||||
cfg, err := getConfig()
|
||||
cfg, err := config.Get("", nil)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
verifyFeatures(cfg, true)
|
||||
})
|
||||
It("features should be true by default", func() {
|
||||
cfg, err := getConfig()
|
||||
cfg, err := config.Get("", nil)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
verifyFeatures(cfg, true)
|
||||
})
|
||||
|
@ -89,7 +88,7 @@ var _ = Describe("Run", func() {
|
|||
for _, envVar := range envVars {
|
||||
Ω(os.Setenv(envVar, "false")).ShouldNot(HaveOccurred())
|
||||
}
|
||||
cfg, err := getConfig()
|
||||
cfg, err := config.Get("", nil)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
verifyFeatures(cfg, false)
|
||||
})
|
||||
|
@ -97,7 +96,7 @@ var _ = Describe("Run", 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 := getConfig()
|
||||
cfg, err := config.Get("", nil)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(cfg.Replicas[0].InterfaceName).Should(Equal("eth0"))
|
||||
})
|
||||
|
@ -106,7 +105,7 @@ var _ = Describe("Run", 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 := getConfig()
|
||||
cfg, err := config.Get("", nil)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(cfg.Replicas[0].DHCPServerEnabled).ShouldNot(BeNil())
|
||||
Ω(*cfg.Replicas[0].DHCPServerEnabled).Should(BeTrue())
|
||||
|
@ -114,7 +113,7 @@ var _ = Describe("Run", func() {
|
|||
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 := getConfig()
|
||||
cfg, err := config.Get("", nil)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(cfg.Replicas[0].DHCPServerEnabled).ShouldNot(BeNil())
|
||||
Ω(*cfg.Replicas[0].DHCPServerEnabled).Should(BeFalse())
|
139
pkg/config/env.go
Normal file
139
pkg/config/env.go
Normal file
|
@ -0,0 +1,139 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/types"
|
||||
"github.com/bakito/adguardhome-sync/pkg/utils"
|
||||
"github.com/caarlos0/env/v10"
|
||||
)
|
||||
|
||||
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 string, 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")
|
||||
}
|
||||
new, newOK := os.LookupEnv(newName)
|
||||
if newOK {
|
||||
return new, true
|
||||
}
|
||||
return old, oldOK
|
||||
}
|
||||
|
||||
func checkDeprecatedReplicaEnvVar(oldPattern string, 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
|
||||
for _, v := range os.Environ() {
|
||||
if envReplicasURLPattern.MatchString(v) {
|
||||
sm := envReplicasURLPattern.FindStringSubmatch(v)
|
||||
id, _ := strconv.Atoi(sm[1])
|
||||
|
||||
if id <= 0 {
|
||||
return nil, fmt.Errorf("numbered replica env variables must have a number id >= 1, got %q", v)
|
||||
}
|
||||
|
||||
if id > len(initialReplicas) {
|
||||
replicas = append(replicas, types.AdGuardInstance{URL: sm[2]})
|
||||
} else {
|
||||
re := initialReplicas[id-1]
|
||||
re.URL = sm[2]
|
||||
replicas = append(replicas, re)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(replicas) == 0 {
|
||||
replicas = initialReplicas
|
||||
}
|
||||
|
||||
for i := range replicas {
|
||||
reID := i + 1
|
||||
|
||||
if err := env.ParseWithOptions(&replicas[i], env.Options{Prefix: fmt.Sprintf("REPLICA%d_", reID)}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
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"
|
||||
}
|
||||
}
|
||||
|
||||
return replicas, nil
|
||||
}
|
25
pkg/config/env_test.go
Normal file
25
pkg/config/env_test.go
Normal file
|
@ -0,0 +1,25 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Config", func() {
|
||||
Context("env", func() {
|
||||
Context("enrichReplicasFromEnv", func() {
|
||||
It("should have the origin URL from the config env var", func() {
|
||||
_ = os.Setenv("REPLICA0_URL", "https://origin-env:443")
|
||||
defer func() {
|
||||
_ = os.Unsetenv("REPLICA0_URL")
|
||||
}()
|
||||
_, err := enrichReplicasFromEnv(nil)
|
||||
|
||||
Ω(err).Should(HaveOccurred())
|
||||
Ω(err.Error()).Should(ContainSubstring("numbered replica env variables must have a number id >= 1"))
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
34
pkg/config/file.go
Normal file
34
pkg/config/file.go
Normal file
|
@ -0,0 +1,34 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/types"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func readFile(cfg *types.Config, path string) error {
|
||||
if _, err := os.Stat(path); err == nil {
|
||||
b, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := yaml.Unmarshal(b, cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func configFilePath(configFile string) (string, error) {
|
||||
if configFile == "" {
|
||||
// Find home directory.
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return filepath.Join(home, ".adguardhome-sync"), nil
|
||||
}
|
||||
return configFile, nil
|
||||
}
|
32
pkg/config/file_test.go
Normal file
32
pkg/config/file_test.go
Normal file
|
@ -0,0 +1,32 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/google/uuid"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Config", func() {
|
||||
var ()
|
||||
BeforeEach(func() {
|
||||
})
|
||||
Context("configFilePath", func() {
|
||||
It("should return the same value", func() {
|
||||
path := uuid.NewString()
|
||||
result, err := configFilePath(path)
|
||||
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(result).Should(Equal(path))
|
||||
})
|
||||
It("should the file in HOME dir", func() {
|
||||
home := os.Getenv("HOME")
|
||||
result, err := configFilePath("")
|
||||
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(result).Should(Equal(filepath.Join(home, "/.adguardhome-sync")))
|
||||
})
|
||||
})
|
||||
})
|
44
pkg/config/flag-names.go
Normal file
44
pkg/config/flag-names.go
Normal file
|
@ -0,0 +1,44 @@
|
|||
package config
|
||||
|
||||
const (
|
||||
FlagCron = "cron"
|
||||
FlagRunOnStart = "runOnStart"
|
||||
FlagPrintConfigOnly = "printConfigOnly"
|
||||
FlagContinueOnError = "continueOnError"
|
||||
|
||||
FlagApiPort = "api-port"
|
||||
FlagApiUsername = "api-username"
|
||||
FlagApiPassword = "api-password"
|
||||
FlagApiDarkMode = "api-dark-mode"
|
||||
|
||||
FlagFeatureDhcpServerConfig = "feature-dhcp-server-config"
|
||||
FlagFeatureDhcpStaticLeases = "feature-dhcp-static-leases"
|
||||
FlagFeatureDnsServerConfig = "feature-dns-server-config"
|
||||
FlagFeatureDnsAccessLists = "feature-dns-access-lists"
|
||||
FlagFeatureDnsRewrites = "feature-dns-rewrites"
|
||||
FlagFeatureGeneral = "feature-general-settings"
|
||||
FlagFeatureQueryLog = "feature-query-log-config"
|
||||
FlagFeatureStats = "feature-stats-config"
|
||||
FlagFeatureClient = "feature-client-settings"
|
||||
FlagFeatureServices = "feature-services"
|
||||
FlagFeatureFilters = "feature-filters"
|
||||
|
||||
FlagOriginURL = "origin-url"
|
||||
FlagOriginWebURL = "origin-web-url"
|
||||
FlagOriginApiPath = "origin-api-path"
|
||||
FlagOriginUsername = "origin-username"
|
||||
|
||||
FlagOriginPassword = "origin-password"
|
||||
FlagOriginCookie = "origin-cookie"
|
||||
FlagOriginISV = "origin-insecure-skip-verify"
|
||||
|
||||
FlagReplicaURL = "replica-url"
|
||||
FlagReplicaWebURL = "replica-web-url"
|
||||
FlagReplicaApiPath = "replica-api-path"
|
||||
FlagReplicaUsername = "replica-username"
|
||||
FlagReplicaPassword = "replica-password"
|
||||
FlagReplicaCookie = "replica-cookie"
|
||||
FlagReplicaISV = "replica-insecure-skip-verify"
|
||||
FlagReplicaAutoSetup = "replica-auto-setup"
|
||||
FlagReplicaInterfaceName = "replica-interface-name"
|
||||
)
|
283
pkg/config/flags.go
Normal file
283
pkg/config/flags.go
Normal file
|
@ -0,0 +1,283 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"github.com/bakito/adguardhome-sync/pkg/types"
|
||||
)
|
||||
|
||||
func readFlags(cfg *types.Config, flags Flags) error {
|
||||
if flags == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
fr := &flagReader{
|
||||
cfg: cfg,
|
||||
flags: flags,
|
||||
}
|
||||
|
||||
if err := fr.readRootFlags(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := fr.readApiFlags(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := fr.readFeatureFlags(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := fr.readOriginFlags(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := fr.readReplicaFlags(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type flagReader struct {
|
||||
cfg *types.Config
|
||||
flags Flags
|
||||
}
|
||||
|
||||
func (fr *flagReader) readReplicaFlags() error {
|
||||
if err := fr.setStringFlag(FlagReplicaURL, func(cgf *types.Config, value string) {
|
||||
fr.cfg.Replica.URL = value
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fr.setStringFlag(FlagReplicaWebURL, func(cgf *types.Config, value string) {
|
||||
fr.cfg.Replica.WebURL = value
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fr.setStringFlag(FlagReplicaApiPath, func(cgf *types.Config, value string) {
|
||||
fr.cfg.Replica.APIPath = value
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fr.setStringFlag(FlagReplicaUsername, func(cgf *types.Config, value string) {
|
||||
fr.cfg.Replica.Username = value
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fr.setStringFlag(FlagReplicaPassword, func(cgf *types.Config, value string) {
|
||||
fr.cfg.Replica.Password = value
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fr.setStringFlag(FlagReplicaCookie, func(cgf *types.Config, value string) {
|
||||
fr.cfg.Replica.Cookie = value
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fr.setBoolFlag(FlagReplicaISV, func(cgf *types.Config, value bool) {
|
||||
fr.cfg.Replica.InsecureSkipVerify = value
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fr.setBoolFlag(FlagReplicaAutoSetup, func(cgf *types.Config, value bool) {
|
||||
fr.cfg.Replica.AutoSetup = value
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fr.setStringFlag(FlagReplicaInterfaceName, func(cgf *types.Config, value string) {
|
||||
fr.cfg.Replica.InterfaceName = value
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fr *flagReader) readOriginFlags() error {
|
||||
if err := fr.setStringFlag(FlagOriginURL, func(cgf *types.Config, value string) {
|
||||
fr.cfg.Origin.URL = value
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fr.setStringFlag(FlagOriginWebURL, func(cgf *types.Config, value string) {
|
||||
fr.cfg.Origin.WebURL = value
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fr.setStringFlag(FlagOriginApiPath, func(cgf *types.Config, value string) {
|
||||
fr.cfg.Origin.APIPath = value
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fr.setStringFlag(FlagOriginUsername, func(cgf *types.Config, value string) {
|
||||
fr.cfg.Origin.Username = value
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fr.setStringFlag(FlagOriginPassword, func(cgf *types.Config, value string) {
|
||||
fr.cfg.Origin.Password = value
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fr.setStringFlag(FlagOriginCookie, func(cgf *types.Config, value string) {
|
||||
fr.cfg.Origin.Cookie = value
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fr.setBoolFlag(FlagOriginISV, func(cgf *types.Config, value bool) {
|
||||
fr.cfg.Origin.InsecureSkipVerify = value
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fr *flagReader) readFeatureFlags() error {
|
||||
if err := fr.setBoolFlag(FlagFeatureDhcpServerConfig, func(cgf *types.Config, value bool) {
|
||||
fr.cfg.Features.DHCP.ServerConfig = value
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fr.setBoolFlag(FlagFeatureDhcpStaticLeases, func(cgf *types.Config, value bool) {
|
||||
fr.cfg.Features.DHCP.StaticLeases = value
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := fr.setBoolFlag(FlagFeatureDnsServerConfig, func(cgf *types.Config, value bool) {
|
||||
fr.cfg.Features.DNS.ServerConfig = value
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fr.setBoolFlag(FlagFeatureDnsAccessLists, func(cgf *types.Config, value bool) {
|
||||
fr.cfg.Features.DNS.AccessLists = value
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fr.setBoolFlag(FlagFeatureDnsRewrites, func(cgf *types.Config, value bool) {
|
||||
fr.cfg.Features.DNS.Rewrites = value
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := fr.setBoolFlag(FlagFeatureGeneral, func(cgf *types.Config, value bool) {
|
||||
fr.cfg.Features.GeneralSettings = value
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fr.setBoolFlag(FlagFeatureQueryLog, func(cgf *types.Config, value bool) {
|
||||
fr.cfg.Features.QueryLogConfig = value
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fr.setBoolFlag(FlagFeatureStats, func(cgf *types.Config, value bool) {
|
||||
fr.cfg.Features.StatsConfig = value
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fr.setBoolFlag(FlagFeatureClient, func(cgf *types.Config, value bool) {
|
||||
fr.cfg.Features.ClientSettings = value
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fr.setBoolFlag(FlagFeatureServices, func(cgf *types.Config, value bool) {
|
||||
fr.cfg.Features.Services = value
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fr.setBoolFlag(FlagFeatureFilters, func(cgf *types.Config, value bool) {
|
||||
fr.cfg.Features.Filters = value
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fr *flagReader) readApiFlags() (err error) {
|
||||
if err = fr.setIntFlag(FlagApiPort, func(cgf *types.Config, value int) {
|
||||
fr.cfg.API.Port = value
|
||||
}); err != nil {
|
||||
return
|
||||
}
|
||||
if err = fr.setStringFlag(FlagApiUsername, func(cgf *types.Config, value string) {
|
||||
fr.cfg.API.Username = value
|
||||
}); err != nil {
|
||||
return
|
||||
}
|
||||
if err = fr.setStringFlag(FlagApiPassword, func(cgf *types.Config, value string) {
|
||||
fr.cfg.API.Password = value
|
||||
}); err != nil {
|
||||
return
|
||||
}
|
||||
if err = fr.setBoolFlag(FlagApiDarkMode, func(cgf *types.Config, value bool) {
|
||||
fr.cfg.API.DarkMode = value
|
||||
}); err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (fr *flagReader) readRootFlags() (err error) {
|
||||
if err = fr.setStringFlag(FlagCron, func(cgf *types.Config, value string) {
|
||||
fr.cfg.Cron = value
|
||||
}); err != nil {
|
||||
return
|
||||
}
|
||||
if err = fr.setBoolFlag(FlagRunOnStart, func(cgf *types.Config, value bool) {
|
||||
fr.cfg.RunOnStart = value
|
||||
}); err != nil {
|
||||
return
|
||||
}
|
||||
if err = fr.setBoolFlag(FlagPrintConfigOnly, func(cgf *types.Config, value bool) {
|
||||
fr.cfg.PrintConfigOnly = value
|
||||
}); err != nil {
|
||||
return
|
||||
}
|
||||
if err = fr.setBoolFlag(FlagContinueOnError, func(cgf *types.Config, value bool) {
|
||||
fr.cfg.ContinueOnError = value
|
||||
}); err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type Flags interface {
|
||||
Changed(name string) bool
|
||||
GetString(name string) (string, error)
|
||||
GetInt(name string) (int, error)
|
||||
GetBool(name string) (bool, error)
|
||||
}
|
||||
|
||||
func (fr *flagReader) setStringFlag(name string, cb callback[string]) (err error) {
|
||||
if fr.flags.Changed(name) {
|
||||
if value, err := fr.flags.GetString(name); err != nil {
|
||||
return err
|
||||
} else {
|
||||
cb(fr.cfg, value)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fr *flagReader) setBoolFlag(name string, cb callback[bool]) (err error) {
|
||||
if fr.flags.Changed(name) {
|
||||
if value, err := fr.flags.GetBool(name); err != nil {
|
||||
return err
|
||||
} else {
|
||||
cb(fr.cfg, value)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fr *flagReader) setIntFlag(name string, cb callback[int]) (err error) {
|
||||
if fr.flags.Changed(name) {
|
||||
if value, err := fr.flags.GetInt(name); err != nil {
|
||||
return err
|
||||
} else {
|
||||
cb(fr.cfg, value)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type callback[T any] func(cgf *types.Config, value T)
|
235
pkg/config/flags_test.go
Normal file
235
pkg/config/flags_test.go
Normal file
|
@ -0,0 +1,235 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
flagsmock "github.com/bakito/adguardhome-sync/pkg/mocks/flags"
|
||||
"github.com/bakito/adguardhome-sync/pkg/types"
|
||||
gm "github.com/golang/mock/gomock"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Config", func() {
|
||||
var (
|
||||
cfg *types.Config
|
||||
flags *flagsmock.MockFlags
|
||||
mockCtrl *gm.Controller
|
||||
)
|
||||
BeforeEach(func() {
|
||||
cfg = &types.Config{
|
||||
Replica: &types.AdGuardInstance{},
|
||||
Features: types.Features{
|
||||
DNS: types.DNS{
|
||||
AccessLists: true,
|
||||
ServerConfig: true,
|
||||
Rewrites: true,
|
||||
},
|
||||
DHCP: types.DHCP{
|
||||
ServerConfig: true,
|
||||
StaticLeases: true,
|
||||
},
|
||||
GeneralSettings: true,
|
||||
QueryLogConfig: true,
|
||||
StatsConfig: true,
|
||||
ClientSettings: true,
|
||||
Services: true,
|
||||
Filters: true,
|
||||
},
|
||||
}
|
||||
mockCtrl = gm.NewController(GinkgoT())
|
||||
flags = flagsmock.NewMockFlags(mockCtrl)
|
||||
})
|
||||
AfterEach(func() {
|
||||
defer mockCtrl.Finish()
|
||||
})
|
||||
Context("readFlags", func() {
|
||||
It("should not change the config with nil flags", func() {
|
||||
clone := cfg.DeepCopy()
|
||||
err := readFlags(cfg, nil)
|
||||
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(cfg).Should(Equal(clone))
|
||||
})
|
||||
It("should not change the config with no changed flags", func() {
|
||||
clone := cfg.DeepCopy()
|
||||
flags.EXPECT().Changed(gm.Any()).Return(false).AnyTimes()
|
||||
err := readFlags(cfg, flags)
|
||||
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(cfg).Should(Equal(clone))
|
||||
})
|
||||
})
|
||||
Context("readFeatureFlags", func() {
|
||||
It("should disable all flags", func() {
|
||||
flags.EXPECT().Changed(gm.Any()).DoAndReturn(func(name string) bool {
|
||||
return strings.HasPrefix(name, "feature")
|
||||
}).AnyTimes()
|
||||
flags.EXPECT().GetBool(gm.Any()).Return(false, nil).AnyTimes()
|
||||
err := readFlags(cfg, flags)
|
||||
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(cfg.Features).Should(Equal(types.Features{
|
||||
DNS: types.DNS{
|
||||
AccessLists: false,
|
||||
ServerConfig: false,
|
||||
Rewrites: false,
|
||||
},
|
||||
DHCP: types.DHCP{
|
||||
ServerConfig: false,
|
||||
StaticLeases: false,
|
||||
},
|
||||
GeneralSettings: false,
|
||||
QueryLogConfig: false,
|
||||
StatsConfig: false,
|
||||
ClientSettings: false,
|
||||
Services: false,
|
||||
Filters: false,
|
||||
}))
|
||||
})
|
||||
})
|
||||
Context("readApiFlags", func() {
|
||||
It("should change all values", func() {
|
||||
cfg.API = types.API{
|
||||
Port: 1111,
|
||||
Username: "2222",
|
||||
Password: "3333",
|
||||
DarkMode: false,
|
||||
}
|
||||
flags.EXPECT().Changed(gm.Any()).DoAndReturn(func(name string) bool {
|
||||
return strings.HasPrefix(name, "api")
|
||||
}).AnyTimes()
|
||||
flags.EXPECT().GetInt(FlagApiPort).Return(9999, nil)
|
||||
flags.EXPECT().GetString(FlagApiUsername).Return("aaaa", nil)
|
||||
flags.EXPECT().GetString(FlagApiPassword).Return("bbbb", nil)
|
||||
flags.EXPECT().GetBool(FlagApiDarkMode).Return(true, nil)
|
||||
err := readFlags(cfg, flags)
|
||||
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(cfg.API).Should(Equal(types.API{
|
||||
Port: 9999,
|
||||
Username: "aaaa",
|
||||
Password: "bbbb",
|
||||
DarkMode: true,
|
||||
}))
|
||||
})
|
||||
})
|
||||
Context("readRootFlags", func() {
|
||||
It("should change all values", func() {
|
||||
cfg.Cron = "*/10 * * * *"
|
||||
cfg.PrintConfigOnly = false
|
||||
cfg.ContinueOnError = false
|
||||
cfg.RunOnStart = false
|
||||
|
||||
flags.EXPECT().Changed(FlagCron).Return(true)
|
||||
flags.EXPECT().Changed(FlagRunOnStart).Return(true)
|
||||
flags.EXPECT().Changed(FlagPrintConfigOnly).Return(true)
|
||||
flags.EXPECT().Changed(FlagContinueOnError).Return(true)
|
||||
flags.EXPECT().Changed(gm.Any()).Return(false).AnyTimes()
|
||||
|
||||
flags.EXPECT().GetString(FlagCron).Return("*/30 * * * *", nil)
|
||||
flags.EXPECT().GetBool(FlagRunOnStart).Return(true, nil)
|
||||
flags.EXPECT().GetBool(FlagPrintConfigOnly).Return(true, nil)
|
||||
flags.EXPECT().GetBool(FlagContinueOnError).Return(true, nil)
|
||||
err := readFlags(cfg, flags)
|
||||
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(cfg.Cron).Should(Equal("*/30 * * * *"))
|
||||
Ω(cfg.RunOnStart).Should(BeTrue())
|
||||
Ω(cfg.PrintConfigOnly).Should(BeTrue())
|
||||
Ω(cfg.ContinueOnError).Should(BeTrue())
|
||||
})
|
||||
})
|
||||
Context("readOriginFlags", func() {
|
||||
It("should change all values", func() {
|
||||
cfg.Origin = types.AdGuardInstance{
|
||||
URL: "1",
|
||||
WebURL: "2",
|
||||
APIPath: "3",
|
||||
Username: "4",
|
||||
Password: "5",
|
||||
Cookie: "6",
|
||||
InsecureSkipVerify: false,
|
||||
}
|
||||
|
||||
flags.EXPECT().Changed(FlagOriginURL).Return(true)
|
||||
flags.EXPECT().Changed(FlagOriginWebURL).Return(true)
|
||||
flags.EXPECT().Changed(FlagOriginApiPath).Return(true)
|
||||
flags.EXPECT().Changed(FlagOriginUsername).Return(true)
|
||||
flags.EXPECT().Changed(FlagOriginPassword).Return(true)
|
||||
flags.EXPECT().Changed(FlagOriginCookie).Return(true)
|
||||
flags.EXPECT().Changed(FlagOriginISV).Return(true)
|
||||
flags.EXPECT().Changed(gm.Any()).Return(false).AnyTimes()
|
||||
|
||||
flags.EXPECT().GetString(FlagOriginURL).Return("a", nil)
|
||||
flags.EXPECT().GetString(FlagOriginWebURL).Return("b", nil)
|
||||
flags.EXPECT().GetString(FlagOriginApiPath).Return("c", nil)
|
||||
flags.EXPECT().GetString(FlagOriginUsername).Return("d", nil)
|
||||
flags.EXPECT().GetString(FlagOriginPassword).Return("e", nil)
|
||||
flags.EXPECT().GetString(FlagOriginCookie).Return("f", nil)
|
||||
flags.EXPECT().GetBool(FlagOriginISV).Return(true, nil)
|
||||
err := readFlags(cfg, flags)
|
||||
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(cfg.Origin).Should(Equal(types.AdGuardInstance{
|
||||
URL: "a",
|
||||
WebURL: "b",
|
||||
APIPath: "c",
|
||||
Username: "d",
|
||||
Password: "e",
|
||||
Cookie: "f",
|
||||
InsecureSkipVerify: true,
|
||||
}))
|
||||
})
|
||||
})
|
||||
Context("readReplicaFlags", func() {
|
||||
It("should change all values", func() {
|
||||
cfg.Replica = &types.AdGuardInstance{
|
||||
URL: "1",
|
||||
WebURL: "2",
|
||||
APIPath: "3",
|
||||
Username: "4",
|
||||
Password: "5",
|
||||
Cookie: "6",
|
||||
InsecureSkipVerify: false,
|
||||
AutoSetup: false,
|
||||
InterfaceName: "7",
|
||||
}
|
||||
|
||||
flags.EXPECT().Changed(FlagReplicaURL).Return(true)
|
||||
flags.EXPECT().Changed(FlagReplicaWebURL).Return(true)
|
||||
flags.EXPECT().Changed(FlagReplicaApiPath).Return(true)
|
||||
flags.EXPECT().Changed(FlagReplicaUsername).Return(true)
|
||||
flags.EXPECT().Changed(FlagReplicaPassword).Return(true)
|
||||
flags.EXPECT().Changed(FlagReplicaCookie).Return(true)
|
||||
flags.EXPECT().Changed(FlagReplicaISV).Return(true)
|
||||
flags.EXPECT().Changed(FlagReplicaAutoSetup).Return(true)
|
||||
flags.EXPECT().Changed(FlagReplicaInterfaceName).Return(true)
|
||||
flags.EXPECT().Changed(gm.Any()).Return(false).AnyTimes()
|
||||
|
||||
flags.EXPECT().GetString(FlagReplicaURL).Return("a", nil)
|
||||
flags.EXPECT().GetString(FlagReplicaWebURL).Return("b", nil)
|
||||
flags.EXPECT().GetString(FlagReplicaApiPath).Return("c", nil)
|
||||
flags.EXPECT().GetString(FlagReplicaUsername).Return("d", nil)
|
||||
flags.EXPECT().GetString(FlagReplicaPassword).Return("e", nil)
|
||||
flags.EXPECT().GetString(FlagReplicaCookie).Return("f", nil)
|
||||
flags.EXPECT().GetBool(FlagReplicaISV).Return(true, nil)
|
||||
flags.EXPECT().GetBool(FlagReplicaAutoSetup).Return(true, nil)
|
||||
flags.EXPECT().GetString(FlagReplicaInterfaceName).Return("g", nil)
|
||||
err := readFlags(cfg, flags)
|
||||
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(cfg.Replica).Should(Equal(&types.AdGuardInstance{
|
||||
URL: "a",
|
||||
WebURL: "b",
|
||||
APIPath: "c",
|
||||
Username: "d",
|
||||
Password: "e",
|
||||
Cookie: "f",
|
||||
InsecureSkipVerify: true,
|
||||
AutoSetup: true,
|
||||
InterfaceName: "g",
|
||||
}))
|
||||
})
|
||||
})
|
||||
})
|
93
pkg/mocks/flags/mock.go
Normal file
93
pkg/mocks/flags/mock.go
Normal file
|
@ -0,0 +1,93 @@
|
|||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/bakito/adguardhome-sync/pkg/config (interfaces: Flags)
|
||||
|
||||
// Package client is a generated GoMock package.
|
||||
package client
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
// MockFlags is a mock of Flags interface.
|
||||
type MockFlags struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockFlagsMockRecorder
|
||||
}
|
||||
|
||||
// MockFlagsMockRecorder is the mock recorder for MockFlags.
|
||||
type MockFlagsMockRecorder struct {
|
||||
mock *MockFlags
|
||||
}
|
||||
|
||||
// NewMockFlags creates a new mock instance.
|
||||
func NewMockFlags(ctrl *gomock.Controller) *MockFlags {
|
||||
mock := &MockFlags{ctrl: ctrl}
|
||||
mock.recorder = &MockFlagsMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockFlags) EXPECT() *MockFlagsMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// Changed mocks base method.
|
||||
func (m *MockFlags) Changed(arg0 string) bool {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Changed", arg0)
|
||||
ret0, _ := ret[0].(bool)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Changed indicates an expected call of Changed.
|
||||
func (mr *MockFlagsMockRecorder) Changed(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Changed", reflect.TypeOf((*MockFlags)(nil).Changed), arg0)
|
||||
}
|
||||
|
||||
// GetBool mocks base method.
|
||||
func (m *MockFlags) GetBool(arg0 string) (bool, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetBool", arg0)
|
||||
ret0, _ := ret[0].(bool)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetBool indicates an expected call of GetBool.
|
||||
func (mr *MockFlagsMockRecorder) GetBool(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBool", reflect.TypeOf((*MockFlags)(nil).GetBool), arg0)
|
||||
}
|
||||
|
||||
// GetInt mocks base method.
|
||||
func (m *MockFlags) GetInt(arg0 string) (int, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetInt", arg0)
|
||||
ret0, _ := ret[0].(int)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetInt indicates an expected call of GetInt.
|
||||
func (mr *MockFlagsMockRecorder) GetInt(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetInt", reflect.TypeOf((*MockFlags)(nil).GetInt), arg0)
|
||||
}
|
||||
|
||||
// GetString mocks base method.
|
||||
func (m *MockFlags) GetString(arg0 string) (string, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetString", arg0)
|
||||
ret0, _ := ret[0].(string)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetString indicates an expected call of GetString.
|
||||
func (mr *MockFlagsMockRecorder) GetString(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetString", reflect.TypeOf((*MockFlags)(nil).GetString), arg0)
|
||||
}
|
|
@ -4,33 +4,61 @@ import (
|
|||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func NewFeatures(enabled bool) Features {
|
||||
return Features{
|
||||
DNS: DNS{
|
||||
AccessLists: enabled,
|
||||
ServerConfig: enabled,
|
||||
Rewrites: enabled,
|
||||
},
|
||||
DHCP: DHCP{
|
||||
ServerConfig: enabled,
|
||||
StaticLeases: enabled,
|
||||
},
|
||||
GeneralSettings: enabled,
|
||||
QueryLogConfig: enabled,
|
||||
StatsConfig: enabled,
|
||||
ClientSettings: enabled,
|
||||
Services: enabled,
|
||||
Filters: enabled,
|
||||
}
|
||||
}
|
||||
|
||||
// Features feature flags
|
||||
type Features struct {
|
||||
DNS DNS `json:"dns" yaml:"dns" mapstructure:"DNS"`
|
||||
DHCP DHCP `json:"dhcp" yaml:"dhcp" mapstructure:"DHCP"`
|
||||
GeneralSettings bool `json:"generalSettings" yaml:"generalSettings" mapstructure:"GENERAL_SETTINGS"`
|
||||
QueryLogConfig bool `json:"queryLogConfig" yaml:"queryLogConfig" mapstructure:"QUERY_LOG_CONFIG"`
|
||||
StatsConfig bool `json:"statsConfig" yaml:"statsConfig" mapstructure:"STATS_CONFIG"`
|
||||
ClientSettings bool `json:"clientSettings" yaml:"clientSettings" mapstructure:"CLIENT_SETTINGS"`
|
||||
Services bool `json:"services" yaml:"services" mapstructure:"SERVICES"`
|
||||
Filters bool `json:"filters" yaml:"filters" mapstructure:"FILTERS"`
|
||||
DNS DNS `json:"dns" yaml:"dns"`
|
||||
DHCP DHCP `json:"dhcp" yaml:"dhcp"`
|
||||
GeneralSettings bool `json:"generalSettings" yaml:"generalSettings" env:"FEATURES_GENERAL_SETTINGS"`
|
||||
QueryLogConfig bool `json:"queryLogConfig" yaml:"queryLogConfig" env:"FEATURES_QUERY_LOG_CONFIG"`
|
||||
StatsConfig bool `json:"statsConfig" yaml:"statsConfig" env:"FEATURES_STATS_CONFIG"`
|
||||
ClientSettings bool `json:"clientSettings" yaml:"clientSettings" env:"FEATURES_CLIENT_SETTINGS"`
|
||||
Services bool `json:"services" yaml:"services" env:"FEATURES_SERVICES"`
|
||||
Filters bool `json:"filters" yaml:"filters" env:"FEATURES_FILTERS"`
|
||||
}
|
||||
|
||||
// DHCP features
|
||||
type DHCP struct {
|
||||
ServerConfig bool `json:"serverConfig" yaml:"serverConfig" mapstructure:"SERVER_CONFIG"`
|
||||
StaticLeases bool `json:"staticLeases" yaml:"staticLeases" mapstructure:"STATIC_LEASES"`
|
||||
ServerConfig bool `json:"serverConfig" yaml:"serverConfig" env:"FEATURES_DHCP_SERVER_CONFIG"`
|
||||
StaticLeases bool `json:"staticLeases" yaml:"staticLeases" env:"FEATURES_DHCP_STATIC_LEASES"`
|
||||
}
|
||||
|
||||
// DNS features
|
||||
type DNS struct {
|
||||
AccessLists bool `json:"accessLists" yaml:"accessLists" mapstructure:"ACCESS_LISTS"`
|
||||
ServerConfig bool `json:"serverConfig" yaml:"serverConfig" mapstructure:"SERVER_CONFIG"`
|
||||
Rewrites bool `json:"rewrites" yaml:"rewrites"`
|
||||
AccessLists bool `json:"accessLists" yaml:"accessLists" env:"FEATURES_DNS_ACCESS_LISTS"`
|
||||
ServerConfig bool `json:"serverConfig" yaml:"serverConfig" env:"FEATURES_DNS_SERVER_CONFIG"`
|
||||
Rewrites bool `json:"rewrites" yaml:"rewrites" env:"FEATURES_DNS_REWRITES"`
|
||||
}
|
||||
|
||||
// LogDisabled log all disabled features
|
||||
func (f *Features) LogDisabled(l *zap.SugaredLogger) {
|
||||
features := f.collectDisabled()
|
||||
|
||||
if len(features) > 0 {
|
||||
l.With("features", features).Info("Disabled features")
|
||||
}
|
||||
}
|
||||
|
||||
func (f *Features) collectDisabled() []string {
|
||||
var features []string
|
||||
if !f.DHCP.ServerConfig {
|
||||
features = append(features, "DHCP.ServerConfig")
|
||||
|
@ -65,8 +93,5 @@ func (f *Features) LogDisabled(l *zap.SugaredLogger) {
|
|||
if !f.Filters {
|
||||
features = append(features, "Filters")
|
||||
}
|
||||
|
||||
if len(features) > 0 {
|
||||
l.With("features", features).Info("Disabled features")
|
||||
}
|
||||
return features
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package types
|
|||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
@ -15,32 +16,44 @@ const (
|
|||
// Config application configuration struct
|
||||
// +k8s:deepcopy-gen=true
|
||||
type Config struct {
|
||||
Origin AdGuardInstance `json:"origin" yaml:"origin" mapstructure:"ORIGIN"`
|
||||
Replica *AdGuardInstance `json:"replica,omitempty" yaml:"replica,omitempty" mapstructure:"REPLICA"`
|
||||
Origin AdGuardInstance `json:"origin" yaml:"origin" env:"ORIGIN"`
|
||||
Replica *AdGuardInstance `json:"replica,omitempty" yaml:"replica,omitempty" env:"REPLICA"`
|
||||
Replicas []AdGuardInstance `json:"replicas,omitempty" yaml:"replicas,omitempty"`
|
||||
Cron string `json:"cron,omitempty" yaml:"cron,omitempty" mapstructure:"CRON"`
|
||||
RunOnStart bool `json:"runOnStart,omitempty" yaml:"runOnStart,omitempty" mapstructure:"RUN_ON_START"`
|
||||
PrintConfigOnly bool `json:"printConfigOnly,omitempty" yaml:"printConfigOnly,omitempty" mapstructure:"PRINT_CONFIG_ONLY"`
|
||||
ContinueOnError bool `json:"continueOnError,omitempty" yaml:"continueOnError,omitempty" mapstructure:"CONTINUE_ON_ERROR"`
|
||||
API API `json:"api,omitempty" yaml:"api,omitempty" mapstructure:"API"`
|
||||
Features Features `json:"features,omitempty" yaml:"features,omitempty" mapstructure:"FEATURES"`
|
||||
Cron string `json:"cron,omitempty" yaml:"cron,omitempty" env:"CRON"`
|
||||
RunOnStart bool `json:"runOnStart,omitempty" yaml:"runOnStart,omitempty" env:"RUN_ON_START"`
|
||||
PrintConfigOnly bool `json:"printConfigOnly,omitempty" yaml:"printConfigOnly,omitempty" env:"PRINT_CONFIG_ONLY"`
|
||||
ContinueOnError bool `json:"continueOnError,omitempty" yaml:"continueOnError,omitempty" env:"CONTINUE_ON_ERROR"`
|
||||
API API `json:"api,omitempty" yaml:"api,omitempty" env:"API"`
|
||||
Features Features `json:"features,omitempty" yaml:"features,omitempty" env:"FEATURES_"`
|
||||
}
|
||||
|
||||
// API configuration
|
||||
type API struct {
|
||||
Port int `json:"port,omitempty" yaml:"port,omitempty" mapstructure:"PORT"`
|
||||
Username string `json:"username,omitempty" yaml:"username,omitempty" mapstructure:"USERNAME"`
|
||||
Password string `json:"password,omitempty" yaml:"password,omitempty" mapstructure:"PASSWORD"`
|
||||
DarkMode bool `json:"darkMode,omitempty" yaml:"darkMode,omitempty" mapstructure:"DARK_MODE"`
|
||||
Port int `json:"port,omitempty" yaml:"port,omitempty" env:"API_PORT"`
|
||||
Username string `json:"username,omitempty" yaml:"username,omitempty" env:"API_USERNAME"`
|
||||
Password string `json:"password,omitempty" yaml:"password,omitempty" env:"API_PASSWORD"`
|
||||
DarkMode bool `json:"darkMode,omitempty" yaml:"darkMode,omitempty" env:"API_DARK_MODE"`
|
||||
}
|
||||
|
||||
// Mask maks username and password
|
||||
func (a *API) Mask() {
|
||||
a.Username = mask(a.Username)
|
||||
a.Password = mask(a.Password)
|
||||
}
|
||||
|
||||
// UniqueReplicas get unique replication instances
|
||||
func (cfg *Config) UniqueReplicas() []AdGuardInstance {
|
||||
dedup := make(map[string]AdGuardInstance)
|
||||
if cfg.Replica != nil && cfg.Replica.URL != "" {
|
||||
if cfg.Replica.APIPath == "" {
|
||||
cfg.Replica.APIPath = DefaultAPIPath
|
||||
}
|
||||
dedup[cfg.Replica.Key()] = *cfg.Replica
|
||||
}
|
||||
for _, replica := range cfg.Replicas {
|
||||
if replica.APIPath == "" {
|
||||
replica.APIPath = DefaultAPIPath
|
||||
}
|
||||
if replica.URL != "" {
|
||||
dedup[replica.Key()] = replica
|
||||
}
|
||||
|
@ -48,9 +61,6 @@ func (cfg *Config) UniqueReplicas() []AdGuardInstance {
|
|||
|
||||
var r []AdGuardInstance
|
||||
for _, replica := range dedup {
|
||||
if replica.APIPath == "" {
|
||||
replica.APIPath = DefaultAPIPath
|
||||
}
|
||||
r = append(r, replica)
|
||||
}
|
||||
return r
|
||||
|
@ -58,6 +68,11 @@ func (cfg *Config) UniqueReplicas() []AdGuardInstance {
|
|||
|
||||
// Log the current config
|
||||
func (cfg *Config) Log(l *zap.SugaredLogger) {
|
||||
c := cfg.mask()
|
||||
l.With("config", c).Debug("Using config")
|
||||
}
|
||||
|
||||
func (cfg *Config) mask() *Config {
|
||||
c := cfg.DeepCopy()
|
||||
c.Origin.Mask()
|
||||
if c.Replica != nil {
|
||||
|
@ -70,7 +85,8 @@ func (cfg *Config) Log(l *zap.SugaredLogger) {
|
|||
for i := range c.Replicas {
|
||||
c.Replicas[i].Mask()
|
||||
}
|
||||
l.With("config", c).Debug("Using config")
|
||||
c.API.Mask()
|
||||
return c
|
||||
}
|
||||
|
||||
func (cfg *Config) Init() error {
|
||||
|
@ -89,16 +105,16 @@ func (cfg *Config) Init() error {
|
|||
// AdGuardInstance AdguardHome config instance
|
||||
// +k8s:deepcopy-gen=true
|
||||
type AdGuardInstance struct {
|
||||
URL string `json:"url" yaml:"url" mapstructure:"URL"`
|
||||
WebURL string `json:"webURL" yaml:"webURL" mapstructure:"WEB_URL"`
|
||||
APIPath string `json:"apiPath,omitempty" yaml:"apiPath,omitempty" mapstructure:"API_PATH"`
|
||||
Username string `json:"username,omitempty" yaml:"username,omitempty" mapstructure:"USERNAME"`
|
||||
Password string `json:"password,omitempty" yaml:"password,omitempty" mapstructure:"PASSWORD"`
|
||||
Cookie string `json:"cookie,omitempty" yaml:"cookie,omitempty" mapstructure:"COOKIE"`
|
||||
InsecureSkipVerify bool `json:"insecureSkipVerify" yaml:"insecureSkipVerify" mapstructure:"INSECURE_SKIP_VERIFY"`
|
||||
AutoSetup bool `json:"autoSetup" yaml:"autoSetup" mapstructure:"AUTO_SETUP"`
|
||||
InterfaceName string `json:"interfaceName,omitempty" yaml:"interfaceName,omitempty" mapstructure:"INTERFACE_NAME"`
|
||||
DHCPServerEnabled *bool `json:"dhcpServerEnabled,omitempty" yaml:"dhcpServerEnabled,omitempty" mapstructure:"DHCP_SERVER_ENABLED"`
|
||||
URL string `json:"url" yaml:"url" env:"URL"`
|
||||
WebURL string `json:"webURL" yaml:"webURL" env:"WEB_URL"`
|
||||
APIPath string `json:"apiPath,omitempty" yaml:"apiPath,omitempty" env:"API_PATH"`
|
||||
Username string `json:"username,omitempty" yaml:"username,omitempty" env:"USERNAME"`
|
||||
Password string `json:"password,omitempty" yaml:"password,omitempty" env:"PASSWORD"`
|
||||
Cookie string `json:"cookie,omitempty" yaml:"cookie,omitempty" env:"COOKIE"`
|
||||
InsecureSkipVerify bool `json:"insecureSkipVerify" yaml:"insecureSkipVerify" env:"INSECURE_SKIP_VERIFY"`
|
||||
AutoSetup bool `json:"autoSetup" yaml:"autoSetup" env:"AUTO_SETUP"`
|
||||
InterfaceName string `json:"interfaceName,omitempty" yaml:"interfaceName,omitempty" env:"INTERFACE_NAME"`
|
||||
DHCPServerEnabled *bool `json:"dhcpServerEnabled,omitempty" yaml:"dhcpServerEnabled,omitempty" env:"DHCP_SERVER_ENABLED"`
|
||||
|
||||
Host string `json:"-" yaml:"-"`
|
||||
WebHost string `json:"-" yaml:"-"`
|
||||
|
@ -139,7 +155,8 @@ func mask(s string) string {
|
|||
if s == "" {
|
||||
return "***"
|
||||
}
|
||||
return fmt.Sprintf("%v***%v", string(s[0]), string(s[len(s)-1]))
|
||||
mask := strings.Repeat("*", len(s)-2)
|
||||
return fmt.Sprintf("%v%s%v", string(s[0]), mask, string(s[len(s)-1]))
|
||||
}
|
||||
|
||||
// Protection API struct
|
||||
|
|
|
@ -1,38 +1,99 @@
|
|||
package types_test
|
||||
package types
|
||||
|
||||
import (
|
||||
"github.com/bakito/adguardhome-sync/pkg/types"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("AdGuardInstance", func() {
|
||||
var inst types.AdGuardInstance
|
||||
var _ = Describe("Types", func() {
|
||||
Context("AdGuardInstance", func() {
|
||||
var inst AdGuardInstance
|
||||
|
||||
BeforeEach(func() {
|
||||
inst = types.AdGuardInstance{}
|
||||
})
|
||||
Context("Init", func() {
|
||||
BeforeEach(func() {
|
||||
inst.URL = "https://localhost:3000"
|
||||
inst = AdGuardInstance{}
|
||||
})
|
||||
It("should correctly set Host and WebHost if only URL is set", func() {
|
||||
err := inst.Init()
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(inst.Host).Should(Equal("localhost:3000"))
|
||||
Ω(inst.WebHost).Should(Equal("localhost:3000"))
|
||||
Ω(inst.URL).Should(Equal("https://localhost:3000"))
|
||||
Ω(inst.WebURL).Should(Equal("https://localhost:3000"))
|
||||
Context("Instance Init", func() {
|
||||
BeforeEach(func() {
|
||||
inst.URL = "https://localhost:3000"
|
||||
})
|
||||
It("should correctly set Host and WebHost if only URL is set", func() {
|
||||
err := inst.Init()
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(inst.Host).Should(Equal("localhost:3000"))
|
||||
Ω(inst.WebHost).Should(Equal("localhost:3000"))
|
||||
Ω(inst.URL).Should(Equal("https://localhost:3000"))
|
||||
Ω(inst.WebURL).Should(Equal("https://localhost:3000"))
|
||||
})
|
||||
It("should correctly set Host and WebHost if URL and WebURL are set", func() {
|
||||
inst.WebURL = "https://127.0.0.1:4000"
|
||||
err := inst.Init()
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(inst.Host).Should(Equal("localhost:3000"))
|
||||
Ω(inst.WebHost).Should(Equal("127.0.0.1:4000"))
|
||||
Ω(inst.WebURL).Should(Equal(inst.WebURL))
|
||||
Ω(inst.URL).Should(Equal("https://localhost:3000"))
|
||||
Ω(inst.WebURL).Should(Equal("https://127.0.0.1:4000"))
|
||||
})
|
||||
})
|
||||
It("should correctly set Host and WebHost if URL and WebURL are set", func() {
|
||||
inst.WebURL = "https://127.0.0.1:4000"
|
||||
err := inst.Init()
|
||||
})
|
||||
Context("Config", func() {
|
||||
Context("init", func() {
|
||||
cfg := Config{
|
||||
Replicas: []AdGuardInstance{
|
||||
{URL: "https://localhost:3000"},
|
||||
},
|
||||
}
|
||||
err := cfg.Init()
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(inst.Host).Should(Equal("localhost:3000"))
|
||||
Ω(inst.WebHost).Should(Equal("127.0.0.1:4000"))
|
||||
Ω(inst.WebURL).Should(Equal(inst.WebURL))
|
||||
Ω(inst.URL).Should(Equal("https://localhost:3000"))
|
||||
Ω(inst.WebURL).Should(Equal("https://127.0.0.1:4000"))
|
||||
Ω(cfg.Replicas[0].Host).Should(Equal("localhost:3000"))
|
||||
Ω(cfg.Replicas[0].WebHost).Should(Equal("localhost:3000"))
|
||||
Ω(cfg.Replicas[0].URL).Should(Equal("https://localhost:3000"))
|
||||
Ω(cfg.Replicas[0].WebURL).Should(Equal("https://localhost:3000"))
|
||||
})
|
||||
Context("UniqueReplicas", func() {
|
||||
It("should return unique replicas in the array", func() {
|
||||
cfg := Config{
|
||||
Replicas: []AdGuardInstance{
|
||||
{URL: "a"},
|
||||
{URL: "a", APIPath: DefaultAPIPath},
|
||||
{URL: "a", APIPath: "foo"},
|
||||
{URL: "b", APIPath: DefaultAPIPath},
|
||||
},
|
||||
Replica: &AdGuardInstance{URL: "b"},
|
||||
}
|
||||
replicas := cfg.UniqueReplicas()
|
||||
Ω(replicas).Should(HaveLen(3))
|
||||
})
|
||||
})
|
||||
Context("mask", func() {
|
||||
It("should mask all names and passwords", func() {
|
||||
cfg := Config{
|
||||
Replicas: []AdGuardInstance{
|
||||
{URL: "a", Username: "user", Password: "pass"},
|
||||
},
|
||||
Replica: &AdGuardInstance{URL: "a", Username: "user", Password: "pass"},
|
||||
API: API{Username: "user", Password: "pass"},
|
||||
}
|
||||
masked := cfg.mask()
|
||||
Ω(masked.Replicas[0].Username).Should(Equal("u**r"))
|
||||
Ω(masked.Replicas[0].Password).Should(Equal("p**s"))
|
||||
Ω(masked.Replica.Username).Should(Equal("u**r"))
|
||||
Ω(masked.Replica.Password).Should(Equal("p**s"))
|
||||
Ω(masked.API.Username).Should(Equal("u**r"))
|
||||
Ω(masked.API.Password).Should(Equal("p**s"))
|
||||
})
|
||||
})
|
||||
})
|
||||
Context("Feature", func() {
|
||||
Context("LogDisabled", func() {
|
||||
It("should log all features", func() {
|
||||
f := NewFeatures(false)
|
||||
Ω(f.collectDisabled()).Should(HaveLen(11))
|
||||
})
|
||||
It("should log no features", func() {
|
||||
f := NewFeatures(true)
|
||||
Ω(f.collectDisabled()).Should(BeEmpty())
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
1
testdata/.gitignore
vendored
1
testdata/.gitignore
vendored
|
@ -1 +1,2 @@
|
|||
docker-compose.yaml
|
||||
!config_test_*.yaml
|
||||
|
|
36
testdata/config_test_replica.yaml
vendored
Normal file
36
testdata/config_test_replica.yaml
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
origin:
|
||||
url: https://origin-file:443
|
||||
webURL: https://origin-file:443
|
||||
apiPath: /control
|
||||
username: foo
|
||||
password: '*********'
|
||||
insecureSkipVerify: true
|
||||
autoSetup: false
|
||||
replica:
|
||||
url: https://replica-file:443
|
||||
webURL: https://replica-file:443
|
||||
apiPath: /control
|
||||
username: bar
|
||||
password: '*********'
|
||||
insecureSkipVerify: false
|
||||
autoSetup: false
|
||||
interfaceName: eth3
|
||||
cron: '*/15 * * * *'
|
||||
runOnStart: true
|
||||
printConfigOnly: true
|
||||
api:
|
||||
port: 9090
|
||||
features:
|
||||
dns:
|
||||
accessLists: true
|
||||
serverConfig: false
|
||||
rewrites: true
|
||||
dhcp:
|
||||
serverConfig: true
|
||||
staticLeases: true
|
||||
generalSettings: true
|
||||
queryLogConfig: true
|
||||
statsConfig: true
|
||||
clientSettings: true
|
||||
services: true
|
||||
filters: true
|
36
testdata/config_test_replicas.yaml
vendored
Normal file
36
testdata/config_test_replicas.yaml
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
origin:
|
||||
url: https://origin-file:443
|
||||
webURL: https://origin-file:443
|
||||
apiPath: /control
|
||||
username: foo
|
||||
password: '*********'
|
||||
insecureSkipVerify: true
|
||||
autoSetup: false
|
||||
replicas:
|
||||
- url: https://replica-file:443
|
||||
webURL: https://replica-file:443
|
||||
apiPath: /control
|
||||
username: bar
|
||||
password: '*********'
|
||||
insecureSkipVerify: false
|
||||
autoSetup: false
|
||||
interfaceName: eth3
|
||||
cron: '*/15 * * * *'
|
||||
runOnStart: true
|
||||
printConfigOnly: true
|
||||
api:
|
||||
port: 9090
|
||||
features:
|
||||
dns:
|
||||
accessLists: true
|
||||
serverConfig: false
|
||||
rewrites: true
|
||||
dhcp:
|
||||
serverConfig: true
|
||||
staticLeases: true
|
||||
generalSettings: true
|
||||
queryLogConfig: true
|
||||
statsConfig: true
|
||||
clientSettings: true
|
||||
services: true
|
||||
filters: true
|
45
testdata/config_test_replicas_and_replica.yaml
vendored
Normal file
45
testdata/config_test_replicas_and_replica.yaml
vendored
Normal file
|
@ -0,0 +1,45 @@
|
|||
origin:
|
||||
url: https://origin-file:443
|
||||
webURL: https://origin-file:443
|
||||
apiPath: /control
|
||||
username: foo
|
||||
password: '*********'
|
||||
insecureSkipVerify: true
|
||||
autoSetup: false
|
||||
replica:
|
||||
url: https://replica-file:443
|
||||
webURL: https://replica-file:443
|
||||
apiPath: /control
|
||||
username: bar
|
||||
password: '*********'
|
||||
insecureSkipVerify: false
|
||||
autoSetup: false
|
||||
interfaceName: eth3
|
||||
replicas:
|
||||
- url: https://replicas-file:443
|
||||
webURL: https://replicas-file:443
|
||||
apiPath: /control
|
||||
username: bar
|
||||
password: '*********'
|
||||
insecureSkipVerify: false
|
||||
autoSetup: false
|
||||
interfaceName: eth3
|
||||
cron: '*/15 * * * *'
|
||||
runOnStart: true
|
||||
printConfigOnly: true
|
||||
api:
|
||||
port: 9090
|
||||
features:
|
||||
dns:
|
||||
accessLists: true
|
||||
serverConfig: false
|
||||
rewrites: true
|
||||
dhcp:
|
||||
serverConfig: true
|
||||
staticLeases: true
|
||||
generalSettings: true
|
||||
queryLogConfig: true
|
||||
statsConfig: true
|
||||
clientSettings: true
|
||||
services: true
|
||||
filters: true
|
2
testdata/e2e/bin/install-chart.sh
vendored
2
testdata/e2e/bin/install-chart.sh
vendored
|
@ -6,4 +6,4 @@ kubectl config set-context --current --namespace=agh-e2e
|
|||
if [[ $(helm list --no-headers -n agh-e2e | grep agh-e2e | wc -l) == "1" ]]; then
|
||||
helm delete agh-e2e -n agh-e2e --wait
|
||||
fi
|
||||
helm install agh-e2e testdata/e2e -n agh-e2e --create-namespace
|
||||
helm install agh-e2e testdata/e2e -n agh-e2e --create-namespace --set mode=${1}
|
||||
|
|
6
testdata/e2e/bin/wait-for-sync.sh
vendored
6
testdata/e2e/bin/wait-for-sync.sh
vendored
|
@ -1,4 +1,8 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
kubectl wait --for=jsonpath='{.status.phase}'=Succeeded pod/adguardhome-sync --timeout=1m
|
||||
RESULT=$?
|
||||
if [[ "${RESULT}" != "0" ]]; then
|
||||
kubectl logs adguardhome-sync
|
||||
fi
|
||||
exit ${RESULT}
|
||||
|
|
18
testdata/e2e/templates/configmap-sync-env.yaml
vendored
Normal file
18
testdata/e2e/templates/configmap-sync-env.yaml
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
{{- if eq .Values.mode "env" }}
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: sync-conf
|
||||
namespace: {{ .Release.Namespace }}
|
||||
data:
|
||||
API_PORT: '0'
|
||||
ORIGIN_URL: 'http://service-origin.{{ $.Release.Namespace }}.svc.cluster.local:3000'
|
||||
ORIGIN_PASSWORD: 'password'
|
||||
ORIGIN_USERNAME: 'username'
|
||||
{{- range $i,$version := .Values.replica.versions }}
|
||||
REPLICA{{ add 1 $i }}_AUTO_SETUP: 'true'
|
||||
REPLICA{{ add 1 $i }}_URL: 'http://service-replica-{{ $version | toString | replace "." "-" }}.{{ $.Release.Namespace }}.svc.cluster.local:3000'
|
||||
REPLICA{{ add 1 $i }}_PASSWORD: 'password'
|
||||
REPLICA{{ add 1 $i }}_USERNAME: 'username'
|
||||
{{- end }}
|
||||
{{- end }}
|
22
testdata/e2e/templates/configmap-sync-file.yaml
vendored
Normal file
22
testdata/e2e/templates/configmap-sync-file.yaml
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
{{- if eq .Values.mode "file" }}
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: sync-conf
|
||||
namespace: {{ .Release.Namespace }}
|
||||
data:
|
||||
config.yaml: |
|
||||
origin:
|
||||
url: 'http://service-origin.{{ $.Release.Namespace }}.svc.cluster.local:3000'
|
||||
username: username
|
||||
password: password
|
||||
api:
|
||||
port: 0
|
||||
replicas:
|
||||
{{- range $i,$version := .Values.replica.versions }}
|
||||
- url: 'http://service-replica-{{ $version | toString | replace "." "-" }}.{{ $.Release.Namespace }}.svc.cluster.local:3000'
|
||||
username: username
|
||||
password: password
|
||||
autoSetup: true
|
||||
{{- end }}
|
||||
{{- end }}
|
17
testdata/e2e/templates/configmap-sync.yaml
vendored
17
testdata/e2e/templates/configmap-sync.yaml
vendored
|
@ -1,17 +0,0 @@
|
|||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: sync-conf
|
||||
namespace: {{ .Release.Namespace }}
|
||||
data:
|
||||
API_PORT: '0'
|
||||
LOG_LEVEL: 'debug'
|
||||
ORIGIN_URL: 'http://service-origin.{{ $.Release.Namespace }}.svc.cluster.local:3000'
|
||||
ORIGIN_PASSWORD: 'password'
|
||||
ORIGIN_USERNAME: 'username'
|
||||
{{ range $i,$version := .Values.replica.versions }}
|
||||
REPLICA{{ $i }}_AUTOSETUP: 'true'
|
||||
REPLICA{{ $i }}_URL: 'http://service-replica-{{ $version | toString | replace "." "-" }}.{{ $.Release.Namespace }}.svc.cluster.local:3000'
|
||||
REPLICA{{ $i }}_PASSWORD: 'password'
|
||||
REPLICA{{ $i }}_USERNAME: 'username'
|
||||
{{- end }}
|
|
@ -1,3 +1,4 @@
|
|||
{{- if eq .Values.mode "env" }}
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
|
@ -7,7 +8,7 @@ spec:
|
|||
serviceAccountName: agh-e2e
|
||||
initContainers:
|
||||
- name: wait-for-others
|
||||
image: bitnami/kubectl:1.24
|
||||
image: {{ .Values.kubectl.repository }}:{{ .Values.kubectl.tag }}
|
||||
command:
|
||||
- /bin/bash
|
||||
- -c
|
||||
|
@ -19,7 +20,11 @@ spec:
|
|||
command:
|
||||
- /opt/go/adguardhome-sync
|
||||
- run
|
||||
env:
|
||||
- name: LOG_LEVEL
|
||||
value: 'debug'
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: sync-conf
|
||||
restartPolicy: Never
|
||||
{{- end }}
|
36
testdata/e2e/templates/pod-adguardhome-sync-file.yaml
vendored
Normal file
36
testdata/e2e/templates/pod-adguardhome-sync-file.yaml
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
{{- if eq .Values.mode "file" }}
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: adguardhome-sync
|
||||
namespace: {{ $.Release.Namespace }}
|
||||
spec:
|
||||
serviceAccountName: agh-e2e
|
||||
initContainers:
|
||||
- name: wait-for-others
|
||||
image: {{ .Values.kubectl.repository }}:{{ .Values.kubectl.tag }}
|
||||
command:
|
||||
- /bin/bash
|
||||
- -c
|
||||
- |
|
||||
{{- .Files.Get "bin/wait-for-agh-pods.sh" | nindent 10}}
|
||||
containers:
|
||||
- name: adguardhome-sync
|
||||
image: localhost:5001/adguardhome-sync:e2e
|
||||
command:
|
||||
- /opt/go/adguardhome-sync
|
||||
- run
|
||||
- '--config'
|
||||
- /etc/go/adguardhome-sync/config.yaml
|
||||
env:
|
||||
- name: LOG_LEVEL
|
||||
value: 'debug'
|
||||
volumeMounts:
|
||||
- name: config
|
||||
mountPath: /etc/go/adguardhome-sync/
|
||||
volumes:
|
||||
- name: config
|
||||
configMap:
|
||||
name: sync-conf
|
||||
restartPolicy: Never
|
||||
{{- end }}
|
6
testdata/e2e/values.yaml
vendored
6
testdata/e2e/values.yaml
vendored
|
@ -3,3 +3,9 @@ replica:
|
|||
- v0.107.40
|
||||
- v0.107.43
|
||||
- latest
|
||||
|
||||
mode: env
|
||||
|
||||
kubectl:
|
||||
repository: bitnami/kubectl
|
||||
tag: 1.27
|
||||
|
|
Loading…
Reference in a new issue