cmd/amazon-cloudwatch-agent-target-allocator/config/config.go (207 lines of code) (raw):

// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package config import ( "context" "crypto/tls" "crypto/x509" "errors" "fmt" "io/fs" "os" "time" "github.com/go-logr/logr" "github.com/prometheus/common/model" promconfig "github.com/prometheus/prometheus/config" _ "github.com/prometheus/prometheus/discovery/install" "github.com/spf13/pflag" "gopkg.in/yaml.v2" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" "k8s.io/klog/v2" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/certwatcher" "sigs.k8s.io/controller-runtime/pkg/log/zap" tamanifest "github.com/aws/amazon-cloudwatch-agent-operator/internal/manifests/targetallocator" ) const ( DefaultResyncTime = 5 * time.Minute DefaultConfigFilePath string = "/conf/targetallocator.yaml" DefaultCRScrapeInterval model.Duration = model.Duration(time.Second * 30) DefaultAllocationStrategy = "consistent-hashing" DefaultFilterStrategy = "relabel-config" DefaultListenAddr = ":8443" DefaultCertMountPath = tamanifest.TACertMountPath DefaultTLSKeyPath = DefaultCertMountPath + "/server.key" DefaultTLSCertPath = DefaultCertMountPath + "/server.crt" DefaultCABundlePath = "" ) type Config struct { ListenAddr string `yaml:"listen_addr,omitempty"` KubeConfigFilePath string `yaml:"kube_config_file_path,omitempty"` ClusterConfig *rest.Config `yaml:"-"` RootLogger logr.Logger `yaml:"-"` ReloadConfig bool `yaml:"-"` LabelSelector map[string]string `yaml:"label_selector,omitempty"` PromConfig *promconfig.Config `yaml:"config"` AllocationStrategy *string `yaml:"allocation_strategy,omitempty"` FilterStrategy *string `yaml:"filter_strategy,omitempty"` PrometheusCR PrometheusCRConfig `yaml:"prometheus_cr,omitempty"` PodMonitorSelector map[string]string `yaml:"pod_monitor_selector,omitempty"` ServiceMonitorSelector map[string]string `yaml:"service_monitor_selector,omitempty"` CollectorSelector *metav1.LabelSelector `yaml:"collector_selector,omitempty"` HTTPS HTTPSServerConfig `yaml:"https,omitempty"` } type PrometheusCRConfig struct { Enabled bool `yaml:"enabled,omitempty"` ScrapeInterval model.Duration `yaml:"scrape_interval,omitempty"` } type HTTPSServerConfig struct { Enabled bool `yaml:"enabled,omitempty"` ListenAddr string `yaml:"listen_addr,omitempty"` CAFilePath string `yaml:"ca_file_path,omitempty"` TLSCertFilePath string `yaml:"tls_cert_file_path,omitempty"` TLSKeyFilePath string `yaml:"tls_key_file_path,omitempty"` } func (c Config) GetAllocationStrategy() string { if c.AllocationStrategy != nil { return *c.AllocationStrategy } return DefaultAllocationStrategy } func (c Config) GetTargetsFilterStrategy() string { if c.FilterStrategy != nil { return *c.FilterStrategy } return "" } func LoadFromFile(file string, target *Config) error { return unmarshal(target, file) } func LoadFromCLI(target *Config, flagSet *pflag.FlagSet) error { var err error // set the rest of the config attributes based on command-line flag values target.RootLogger = zap.New(zap.UseFlagOptions(&zapCmdLineOpts)) klog.SetLogger(target.RootLogger) ctrl.SetLogger(target.RootLogger) target.KubeConfigFilePath, err = getKubeConfigFilePath(flagSet) if err != nil { return err } clusterConfig, err := clientcmd.BuildConfigFromFlags("", target.KubeConfigFilePath) if err != nil { pathError := &fs.PathError{} if ok := errors.As(err, &pathError); !ok { return err } clusterConfig, err = rest.InClusterConfig() if err != nil { return err } target.KubeConfigFilePath = "" } target.ClusterConfig = clusterConfig target.ReloadConfig, err = getConfigReloadEnabled(flagSet) if err != nil { return err } target.HTTPS.Enabled, err = getHttpsEnabled(flagSet) if err != nil { return err } target.HTTPS.ListenAddr, err = getHttpsListenAddr(flagSet) if err != nil { return err } target.HTTPS.CAFilePath, err = getHttpsCAFilePath(flagSet) if err != nil { return err } target.HTTPS.TLSCertFilePath, err = getHttpsTLSCertFilePath(flagSet) if err != nil { return err } target.HTTPS.TLSKeyFilePath, err = getHttpsTLSKeyFilePath(flagSet) if err != nil { return err } return nil } func unmarshal(cfg *Config, configFile string) error { yamlFile, err := os.ReadFile(configFile) if err != nil { return err } if err = yaml.UnmarshalStrict(yamlFile, cfg); err != nil { return fmt.Errorf("error unmarshaling YAML: %w", err) } return nil } func CreateDefaultConfig() Config { var allocation_strategy = DefaultAllocationStrategy return Config{ PrometheusCR: PrometheusCRConfig{ ScrapeInterval: DefaultCRScrapeInterval, }, AllocationStrategy: &allocation_strategy, HTTPS: HTTPSServerConfig{ Enabled: true, ListenAddr: DefaultListenAddr, CAFilePath: DefaultCABundlePath, TLSCertFilePath: DefaultTLSCertPath, TLSKeyFilePath: DefaultTLSKeyPath, }, } } func Load() (*Config, string, error) { var err error flagSet := getFlagSet(pflag.ExitOnError) err = flagSet.Parse(os.Args) if err != nil { return nil, "", err } config := CreateDefaultConfig() // load the config from the config file configFilePath, err := getConfigFilePath(flagSet) if err != nil { return nil, "", err } err = LoadFromFile(configFilePath, &config) if err != nil { return nil, "", err } err = LoadFromCLI(&config, flagSet) if err != nil { return nil, "", err } return &config, configFilePath, nil } // ValidateConfig validates the cli and file configs together. func ValidateConfig(config *Config) error { scrapeConfigsPresent := config.PromConfig != nil && len(config.PromConfig.ScrapeConfigs) > 0 if !(config.PrometheusCR.Enabled || scrapeConfigsPresent) { return fmt.Errorf("at least one scrape config must be defined, or Prometheus CR watching must be enabled") } return nil } func (c HTTPSServerConfig) NewTLSConfig(ctx context.Context) (*tls.Config, error) { tlsConfig := &tls.Config{ MinVersion: tls.VersionTLS13, } certWatcher, err := certwatcher.New(c.TLSCertFilePath, c.TLSKeyFilePath) if err != nil { return nil, err } tlsConfig.GetCertificate = certWatcher.GetCertificate go func() { _ = certWatcher.Start(ctx) }() if c.CAFilePath == "" { return tlsConfig, nil } caCert, err := os.ReadFile(c.CAFilePath) caCertPool := x509.NewCertPool() if err != nil { return nil, err } caCertPool.AppendCertsFromPEM(caCert) tlsConfig.ClientCAs = caCertPool tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert return tlsConfig, nil }