diff --git a/cmd/otel-allocator/config/config.go b/cmd/otel-allocator/config/config.go index 03368d1b60..7d13658e32 100644 --- a/cmd/otel-allocator/config/config.go +++ b/cmd/otel-allocator/config/config.go @@ -36,11 +36,14 @@ import ( ) const ( - DefaultResyncTime = 5 * time.Minute - DefaultConfigFilePath string = "/conf/targetallocator.yaml" - DefaultCRScrapeInterval model.Duration = model.Duration(time.Second * 30) - DefaultAllocationStrategy = "consistent-hashing" - DefaultFilterStrategy = "relabel-config" + DefaultResyncTime = 5 * time.Minute + DefaultConfigFilePath string = "/conf/targetallocator.yaml" + DefaultCRScrapeInterval model.Duration = model.Duration(time.Second * 30) + DefaultAllocationStrategy = "consistent-hashing" + DefaultFilterStrategy = "relabel-config" + DefaultServerCAFilePath = "/conf/tls/ca.crt" + DefaultServerTLSCertFilePath = "/conf/tls/tls.crt" + DefaultServerTLSKeyFilePath = "/conf/tls/tls.key" ) type Config struct { @@ -53,6 +56,7 @@ type Config struct { AllocationStrategy string `yaml:"allocation_strategy,omitempty"` FilterStrategy string `yaml:"filter_strategy,omitempty"` PrometheusCR PrometheusCRConfig `yaml:"prometheus_cr,omitempty"` + HTTPS HTTPSServerConfig `yaml:"https,omitempty"` } type PrometheusCRConfig struct { @@ -64,6 +68,14 @@ type PrometheusCRConfig struct { ScrapeInterval model.Duration `yaml:"scrape_interval,omitempty"` } +type HTTPSServerConfig struct { + Enabled bool `yaml:"enabled,omitempty"` + ListenAddr string `yaml:"listen_addr,omitempty"` + ServerCAFilePath string `yaml:"ca_file_path,omitempty"` + ServerTLSCertFilePath string `yaml:"tls_cert_file_path,omitempty"` + ServerTLSKeyFilePath string `yaml:"tls_key_file_path,omitempty"` +} + func LoadFromFile(file string, target *Config) error { return unmarshal(target, file) } @@ -103,6 +115,16 @@ func LoadFromCLI(target *Config, flagSet *pflag.FlagSet) error { return err } + target.HTTPS.Enabled, err = getHttpsEnabled(flagSet) + if err != nil { + return err + } + + target.HTTPS.ListenAddr, err = getHttpsListenAddr(flagSet) + if err != nil { + return err + } + return nil } diff --git a/cmd/otel-allocator/config/flags.go b/cmd/otel-allocator/config/flags.go index bb7dbbb344..d4bf994998 100644 --- a/cmd/otel-allocator/config/flags.go +++ b/cmd/otel-allocator/config/flags.go @@ -30,6 +30,8 @@ const ( listenAddrFlagName = "listen-addr" prometheusCREnabledFlagName = "enable-prometheus-cr-watcher" kubeConfigPathFlagName = "kubeconfig-path" + listenAddrHttpsFlagName = "listen-addr-https" + httpsEnabledFlagName = "enable-https-server" ) // We can't bind this flag to our FlagSet, so we need to handle it separately. @@ -40,6 +42,8 @@ func getFlagSet(errorHandling pflag.ErrorHandling) *pflag.FlagSet { flagSet.String(configFilePathFlagName, DefaultConfigFilePath, "The path to the config file.") flagSet.String(listenAddrFlagName, ":8080", "The address where this service serves.") flagSet.Bool(prometheusCREnabledFlagName, false, "Enable Prometheus CRs as target sources") + flagSet.Bool(httpsEnabledFlagName, false, "Enable HTTPS additional server") + flagSet.String(listenAddrHttpsFlagName, ":8443", "The address where this service serves over HTTPS.") flagSet.String(kubeConfigPathFlagName, filepath.Join(homedir.HomeDir(), ".kube", "config"), "absolute path to the KubeconfigPath file") zapFlagSet := flag.NewFlagSet("", flag.ErrorHandling(errorHandling)) zapCmdLineOpts.BindFlags(zapFlagSet) @@ -62,3 +66,11 @@ func getListenAddr(flagSet *pflag.FlagSet) (string, error) { func getPrometheusCREnabled(flagSet *pflag.FlagSet) (bool, error) { return flagSet.GetBool(prometheusCREnabledFlagName) } + +func getHttpsListenAddr(flagSet *pflag.FlagSet) (string, error) { + return flagSet.GetString(listenAddrHttpsFlagName) +} + +func getHttpsEnabled(flagSet *pflag.FlagSet) (bool, error) { + return flagSet.GetBool(httpsEnabledFlagName) +} diff --git a/cmd/otel-allocator/main.go b/cmd/otel-allocator/main.go index cd33424673..cf56f09ed6 100644 --- a/cmd/otel-allocator/main.go +++ b/cmd/otel-allocator/main.go @@ -86,7 +86,11 @@ func main() { setupLog.Error(err, "Unable to initialize allocation strategy") os.Exit(1) } - srv := server.NewServer(log, allocator, cfg.ListenAddr, server.WithTLS("/certs/ca.crt", "/certs/server.crt", "/certs/server.key", ":8443")) + + srv := server.NewServer(log, allocator, cfg.ListenAddr) + if cfg.HTTPS.Enabled { + srv = server.NewServer(log, allocator, cfg.ListenAddr, server.WithTLSServer("/certs/ca.crt", "/certs/server.crt", "/certs/server.key", cfg.HTTPS.ListenAddr)) + } discoveryCtx, discoveryCancel := context.WithCancel(ctx) sdMetrics, err := discovery.CreateAndRegisterSDMetrics(prometheus.DefaultRegisterer) diff --git a/cmd/otel-allocator/server/server.go b/cmd/otel-allocator/server/server.go index 14bd765823..e9d94bbace 100644 --- a/cmd/otel-allocator/server/server.go +++ b/cmd/otel-allocator/server/server.go @@ -67,22 +67,22 @@ type Server struct { logger logr.Logger allocator allocation.Allocator server *http.Server - tlsServer *http.Server + tlsServer *http.Server jsonMarshaller jsoniter.API // Use RWMutex to protect scrapeConfigResponse, since it // will be predominantly read and only written when config // is applied. - mtx sync.RWMutex - scrapeConfigResponse []byte + mtx sync.RWMutex + scrapeConfigResponse []byte tlsScrapeConfigResponse []byte } type ServerOption func(*Server) -// ServerOption to create an additional server with mTLS configuration. +// ServerOption to create an additional server with mTLS configuration. // Used for getting the scrape config with actual secret values. -func WithTLS(caFile, certFile, keyFile, tlsListenAddr string) ServerOption { +func WithTLSServer(caFile, certFile, keyFile, tlsListenAddr string) ServerOption { return func(s *Server) { cert, err := tls.LoadX509KeyPair(certFile, keyFile) if err != nil { @@ -117,12 +117,9 @@ func (s *Server) setRouter(router *gin.Engine, tlsRouter bool) { router.UnescapePathValues = false router.Use(s.PrometheusMiddleware) - if tlsRouter { - router.GET("/scrape_configs", s.ScrapeConfigsTlsHandler) - } else { - router.GET("/scrape_configs", s.ScrapeConfigsHandler) - } - + router.GET("/scrape_configs", func(c *gin.Context) { + s.ScrapeConfigsHandler(c, tlsRouter) + }) router.GET("/jobs", s.JobHandler) router.GET("/jobs/:job_id/targets", s.TargetsHandler) router.GET("/metrics", gin.WrapH(promhttp.Handler())) @@ -219,68 +216,48 @@ func RemoveRegexFromRelabelAction(jsonConfig []byte) ([]byte, error) { // configurations such that the underlying prometheus marshaling is used. After that, the YAML is converted // in to a JSON format for consumers to use. func (s *Server) UpdateScrapeConfigResponse(configs map[string]*promconfig.ScrapeConfig) error { - var configBytes []byte - - config.MarshalSecretValue = false - configBytes, err := yaml.Marshal(configs) - if err != nil { - return err - } - var jsonConfig []byte - jsonConfig, err = yaml2.YAMLToJSON(configBytes) - if err != nil { - return err + marshalSecretValues := []bool{false} + if s.tlsServer != nil { + marshalSecretValues = append(marshalSecretValues, true) } - jsonConfigNew, err := RemoveRegexFromRelabelAction(jsonConfig) - if err != nil { - return err - } + for _, marshalSecretValue := range marshalSecretValues { + config.MarshalSecretValue = marshalSecretValue + configBytes, err := yaml.Marshal(configs) + if err != nil { + return err + } - s.mtx.Lock() - s.scrapeConfigResponse = jsonConfigNew - s.mtx.Unlock() + var jsonConfig []byte + jsonConfig, err = yaml2.YAMLToJSON(configBytes) + if err != nil { + return err + } - // Marshaling with actual secrets values for serving with mTLS - config.MarshalSecretValue = true - configBytes, err = yaml.Marshal(configs) - if err != nil { - return err - } - jsonConfig, err = yaml2.YAMLToJSON(configBytes) - if err != nil { - return err - } + jsonConfigNew, err := RemoveRegexFromRelabelAction(jsonConfig) + if err != nil { + return err + } - jsonConfigNew, err = RemoveRegexFromRelabelAction(jsonConfig) - if err != nil { - return err + s.mtx.Lock() + if marshalSecretValue { + s.tlsScrapeConfigResponse = jsonConfigNew + } else { + s.scrapeConfigResponse = jsonConfigNew + } + s.mtx.Unlock() } - s.mtx.Lock() - s.tlsScrapeConfigResponse = jsonConfigNew - s.mtx.Unlock() return nil } // ScrapeConfigsHandler returns the available scrape configuration discovered by the target allocator. -func (s *Server) ScrapeConfigsHandler(c *gin.Context) { +func (s *Server) ScrapeConfigsHandler(c *gin.Context, tlsRouter bool) { s.mtx.RLock() result := s.scrapeConfigResponse - s.mtx.RUnlock() - - // We don't use the jsonHandler method because we don't want our bytes to be re-encoded - c.Writer.Header().Set("Content-Type", "application/json") - _, err := c.Writer.Write(result) - if err != nil { - s.errorHandler(c.Writer, err) + if tlsRouter { + result = s.tlsScrapeConfigResponse } -} - -// ScrapeConfigsHandler returns the available scrape configuration discovered by the target allocator. -func (s *Server) ScrapeConfigsTlsHandler(c *gin.Context) { - s.mtx.RLock() - result := s.tlsScrapeConfigResponse s.mtx.RUnlock() // We don't use the jsonHandler method because we don't want our bytes to be re-encoded