adguardhome-sync/cmd/root.go

186 lines
6.4 KiB
Go
Raw Normal View History

2021-03-28 20:09:31 +08:00
package cmd
import (
"fmt"
"os"
2021-04-06 03:04:01 +08:00
"regexp"
2021-03-28 20:09:31 +08:00
"strings"
"github.com/bakito/adguardhome-sync/pkg/log"
2021-04-06 03:04:01 +08:00
"github.com/bakito/adguardhome-sync/pkg/types"
2022-07-25 00:23:17 +08:00
"github.com/bakito/adguardhome-sync/version"
2021-04-11 20:56:33 +08:00
"github.com/mitchellh/go-homedir"
2021-04-06 03:04:01 +08:00
"github.com/spf13/cobra"
2021-03-28 20:09:31 +08:00
"github.com/spf13/viper"
"go.uber.org/zap"
2021-03-28 20:09:31 +08:00
)
const (
2021-04-19 04:20:08 +08:00
configCron = "cron"
configRunOnStart = "runOnStart"
2021-03-28 22:29:18 +08:00
configAPIPort = "api.port"
configAPIUsername = "api.username"
configAPIPassword = "api.password"
2022-01-31 01:54:22 +08:00
configAPIDarkMode = "api.darkMode"
2021-11-01 15:56:12 +08:00
configFeatureDHCPServerConfig = "features.dhcp.serverConfig"
configFeatureDHCPStaticLeases = "features.dhcp.staticLeases"
2021-11-02 01:20:14 +08:00
configFeatureDNServerConfig = "features.dns.serverConfig"
configFeatureDNSPAccessLists = "features.dns.accessLists"
configFeatureDNSRewrites = "features.dns.rewrites"
configFeatureGeneralSettings = "features.generalSettings"
configFeatureQueryLogConfig = "features.queryLogConfig"
configFeatureStatsConfig = "features.statsConfig"
configFeatureClientSettings = "features.clientSettings"
configFeatureServices = "features.services"
configFeatureFilters = "features.filters"
2021-11-01 15:56:12 +08:00
2021-03-28 20:09:31 +08:00
configOriginURL = "origin.url"
configOriginAPIPath = "origin.apiPath"
configOriginUsername = "origin.username"
configOriginPassword = "origin.password"
configOriginCookie = "origin.cookie"
2021-03-28 20:09:31 +08:00
configOriginInsecureSkipVerify = "origin.insecureSkipVerify"
configReplicaURL = "replica.url"
configReplicaAPIPath = "replica.apiPath"
configReplicaUsername = "replica.username"
configReplicaPassword = "replica.password"
configReplicaCookie = "replica.cookie"
2021-03-28 20:09:31 +08:00
configReplicaInsecureSkipVerify = "replica.insecureSkipVerify"
configReplicaAutoSetup = "replica.autoSetup"
configReplicaInterfaceName = "replica.interfaceName"
2021-04-06 03:04:01 +08:00
2021-08-19 13:50:50 +08:00
envReplicasUsernameFormat = "REPLICA%s_USERNAME" // #nosec G101
envReplicasPasswordFormat = "REPLICA%s_PASSWORD" // #nosec G101
envReplicasCookieFormat = "REPLICA%s_COOKIE" // #nosec G101
2021-04-06 03:04:01 +08:00
envReplicasAPIPathFormat = "REPLICA%s_APIPATH"
envReplicasInsecureSkipVerifyFormat = "REPLICA%s_INSECURESKIPVERIFY"
envReplicasAutoSetup = "REPLICA%s_AUTOSETUP"
envReplicasInterfaceName = "REPLICA%s_INTERFACENAME"
// Deprecated: use envReplicasInterfaceName instead
envReplicasInterfaceNameDeprecated = "REPLICA%s_INTERFACWENAME"
envDHCPServerEnabled = "REPLICA%s_DHCPSERVERENABLED"
2021-03-28 20:09:31 +08:00
)
var (
2021-04-06 03:04:01 +08:00
cfgFile string
logger = log.GetLogger("root")
envReplicasURLPattern = regexp.MustCompile(`^REPLICA(\d+)_URL=(.*)`)
2021-03-28 20:09:31 +08:00
)
// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
2022-07-25 00:23:17 +08:00
Use: "adguardhome-sync",
Short: "Synchronize config from one AdGuardHome instance to another",
Version: version.Version,
2021-03-28 20:09:31 +08:00
}
// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
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.
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.adguardhome-sync.yaml)")
// Cobra also supports local flags, which will only run
// 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")
}
2021-04-06 01:26:35 +08:00
viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_", ".", "_"))
2021-03-28 20:09:31 +08:00
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())
2021-04-06 01:26:35 +08:00
} else if cfgFile != "" {
fmt.Println(err)
os.Exit(1)
2021-03-28 20:09:31 +08:00
}
}
2021-04-06 03:04:01 +08:00
func getConfig(logger *zap.SugaredLogger) (*types.Config, error) {
2021-04-06 03:04:01 +08:00
cfg := &types.Config{}
if err := viper.Unmarshal(cfg); err != nil {
return nil, err
}
if len(cfg.Replicas) == 0 {
cfg.Replicas = append(cfg.Replicas, collectEnvReplicas(logger)...)
2021-04-06 03:04:01 +08:00
}
return cfg, nil
}
// Manually collect replicas from env.
func collectEnvReplicas(logger *zap.SugaredLogger) []types.AdGuardInstance {
2021-04-06 03:04:01 +08:00
var replicas []types.AdGuardInstance
for _, v := range os.Environ() {
if envReplicasURLPattern.MatchString(v) {
sm := envReplicasURLPattern.FindStringSubmatch(v)
re := types.AdGuardInstance{
URL: sm[2],
Username: os.Getenv(fmt.Sprintf(envReplicasUsernameFormat, sm[1])),
Password: os.Getenv(fmt.Sprintf(envReplicasPasswordFormat, sm[1])),
Cookie: os.Getenv(fmt.Sprintf(envReplicasCookieFormat, sm[1])),
2021-04-06 03:04:01 +08:00
APIPath: os.Getenv(fmt.Sprintf(envReplicasAPIPathFormat, sm[1])),
InsecureSkipVerify: strings.EqualFold(os.Getenv(fmt.Sprintf(envReplicasInsecureSkipVerifyFormat, sm[1])), "true"),
AutoSetup: strings.EqualFold(os.Getenv(fmt.Sprintf(envReplicasAutoSetup, sm[1])), "true"),
InterfaceName: os.Getenv(fmt.Sprintf(envReplicasInterfaceName, sm[1])),
2021-04-06 03:04:01 +08:00
}
if re.InterfaceName == "" {
if in, ok := os.LookupEnv(fmt.Sprintf(envReplicasInterfaceNameDeprecated, sm[1])); ok {
logger.
With("correct", envReplicasInterfaceName, "deprecated", envReplicasInterfaceNameDeprecated).
Warn("Deprecated env variable is used, please use the correct one")
re.InterfaceName = in
}
}
if dhcpEnabled, ok := os.LookupEnv(fmt.Sprintf(envDHCPServerEnabled, sm[1])); ok {
if strings.EqualFold(dhcpEnabled, "true") {
re.DHCPServerEnabled = boolPtr(true)
} else if strings.EqualFold(dhcpEnabled, "false") {
re.DHCPServerEnabled = boolPtr(false)
}
}
2021-04-06 03:04:01 +08:00
replicas = append(replicas, re)
}
}
return replicas
}
func boolPtr(b bool) *bool {
return &b
}