From af27b5193b5ce89bb6dc7e3fe2daa719324f14dd Mon Sep 17 00:00:00 2001 From: Ruben Vargas Date: Sun, 17 Nov 2024 23:50:12 -0600 Subject: [PATCH] remove deprecated config component Signed-off-by: Ruben Vargas --- api/config/v1alpha1/projectconfig_types.go | 66 +++++++++++- api/config/v1alpha1/zz_generated.deepcopy.go | 99 +++++++++++++++++ cmd/root/config.go | 30 ++++++ cmd/root/options.go | 108 +++++++++++++++++++ cmd/root/root.go | 20 +--- go.mod | 2 +- internal/upgrade/versions.go | 1 + internal/webhooks/webhook_suite_test.go | 4 +- 8 files changed, 310 insertions(+), 20 deletions(-) create mode 100644 cmd/root/config.go create mode 100644 cmd/root/options.go diff --git a/api/config/v1alpha1/projectconfig_types.go b/api/config/v1alpha1/projectconfig_types.go index 0c4cf32f3..3bb74df2a 100644 --- a/api/config/v1alpha1/projectconfig_types.go +++ b/api/config/v1alpha1/projectconfig_types.go @@ -4,7 +4,7 @@ import ( "os" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - cfg "sigs.k8s.io/controller-runtime/pkg/config/v1alpha1" + configv1alpha1 "k8s.io/component-base/config/v1alpha1" ) const ( @@ -223,14 +223,76 @@ type FeatureGates struct { GrafanaOperator bool `json:"grafanaOperator,omitempty"` } +// ControllerManagerConfigurationSpec defines the desired state of GenericControllerManagerConfiguration. +type ControllerManagerConfigurationSpec struct { + // LeaderElection is the LeaderElection config to be used when configuring + // the manager.Manager leader election + // +optional + LeaderElection *configv1alpha1.LeaderElectionConfiguration `json:"leaderElection,omitempty"` + + // Metrics contains the controller metrics configuration + // +optional + Metrics ControllerMetrics `json:"metrics,omitempty"` + + // Health contains the controller health configuration + // +optional + Health ControllerHealth `json:"health,omitempty"` + + // Webhook contains the controllers webhook configuration + // +optional + Webhook ControllerWebhook `json:"webhook,omitempty"` +} + +// ControllerMetrics defines the metrics configs. +type ControllerMetrics struct { + // BindAddress is the TCP address that the controller should bind to + // for serving prometheus metrics. + // It can be set to "0" to disable the metrics serving. + // +optional + BindAddress string `json:"bindAddress,omitempty"` +} + +// ControllerHealth defines the health configs. +type ControllerHealth struct { + // HealthProbeBindAddress is the TCP address that the controller should bind to + // for serving health probes + // It can be set to "0" or "" to disable serving the health probe. + // +optional + HealthProbeBindAddress string `json:"healthProbeBindAddress,omitempty"` +} + +// ControllerWebhook defines the webhook server for the controller. +type ControllerWebhook struct { + // Port is the port that the webhook server serves at. + // It is used to set webhook.Server.Port. + // +optional + Port *int `json:"port,omitempty"` +} + +//+kubebuilder:object:root=true + +// ControllerManagerConfiguration is the Schema for the GenericControllerManagerConfigurations API. +type ControllerManagerConfiguration struct { + metav1.TypeMeta `json:",inline"` + + // ControllerManagerConfiguration returns the configurations for controllers + ControllerManagerConfigurationSpec `json:",inline"` +} + +// Complete returns the configuration for controller-runtime. +func (c *ControllerManagerConfigurationSpec) Complete() (ControllerManagerConfigurationSpec, error) { + return *c, nil +} + //+kubebuilder:object:root=true //+kubebuilder:subresource:status // ProjectConfig is the Schema for the projectconfigs API. type ProjectConfig struct { metav1.TypeMeta `json:",inline"` + // ControllerManagerConfigurationSpec returns the configurations for controllers - cfg.ControllerManagerConfigurationSpec `json:",inline"` + ControllerManagerConfigurationSpec `json:",inline"` // The images are read from environment variables and not from the configuration file DefaultImages ImagesSpec diff --git a/api/config/v1alpha1/zz_generated.deepcopy.go b/api/config/v1alpha1/zz_generated.deepcopy.go index cc194690b..5630a3320 100644 --- a/api/config/v1alpha1/zz_generated.deepcopy.go +++ b/api/config/v1alpha1/zz_generated.deepcopy.go @@ -6,6 +6,7 @@ package v1alpha1 import ( runtime "k8s.io/apimachinery/pkg/runtime" + configv1alpha1 "k8s.io/component-base/config/v1alpha1" ) // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. @@ -27,6 +28,104 @@ func (in *BuiltInCertManagement) DeepCopy() *BuiltInCertManagement { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ControllerHealth) DeepCopyInto(out *ControllerHealth) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControllerHealth. +func (in *ControllerHealth) DeepCopy() *ControllerHealth { + if in == nil { + return nil + } + out := new(ControllerHealth) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ControllerManagerConfiguration) DeepCopyInto(out *ControllerManagerConfiguration) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ControllerManagerConfigurationSpec.DeepCopyInto(&out.ControllerManagerConfigurationSpec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControllerManagerConfiguration. +func (in *ControllerManagerConfiguration) DeepCopy() *ControllerManagerConfiguration { + if in == nil { + return nil + } + out := new(ControllerManagerConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ControllerManagerConfiguration) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ControllerManagerConfigurationSpec) DeepCopyInto(out *ControllerManagerConfigurationSpec) { + *out = *in + if in.LeaderElection != nil { + in, out := &in.LeaderElection, &out.LeaderElection + *out = new(configv1alpha1.LeaderElectionConfiguration) + (*in).DeepCopyInto(*out) + } + out.Metrics = in.Metrics + out.Health = in.Health + in.Webhook.DeepCopyInto(&out.Webhook) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControllerManagerConfigurationSpec. +func (in *ControllerManagerConfigurationSpec) DeepCopy() *ControllerManagerConfigurationSpec { + if in == nil { + return nil + } + out := new(ControllerManagerConfigurationSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ControllerMetrics) DeepCopyInto(out *ControllerMetrics) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControllerMetrics. +func (in *ControllerMetrics) DeepCopy() *ControllerMetrics { + if in == nil { + return nil + } + out := new(ControllerMetrics) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ControllerWebhook) DeepCopyInto(out *ControllerWebhook) { + *out = *in + if in.Port != nil { + in, out := &in.Port, &out.Port + *out = new(int) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControllerWebhook. +func (in *ControllerWebhook) DeepCopy() *ControllerWebhook { + if in == nil { + return nil + } + out := new(ControllerWebhook) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *FeatureGates) DeepCopyInto(out *FeatureGates) { *out = *in diff --git a/cmd/root/config.go b/cmd/root/config.go new file mode 100644 index 000000000..8a9384c6b --- /dev/null +++ b/cmd/root/config.go @@ -0,0 +1,30 @@ +package root + +import ( + "errors" + "fmt" + "os" + "path/filepath" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/serializer" + + configv1alpha1 "github.com/grafana/tempo-operator/api/config/v1alpha1" +) + +var errConfigFileLoading = errors.New("could not read file at path") + +func loadConfigFile(scheme *runtime.Scheme, outConfig *configv1alpha1.ProjectConfig, configFile string) error { + content, err := os.ReadFile(filepath.Clean(configFile)) + if err != nil { + return fmt.Errorf("%w %s", errConfigFileLoading, configFile) + } + + codecs := serializer.NewCodecFactory(scheme) + + if err = runtime.DecodeInto(codecs.UniversalDecoder(), content, outConfig); err != nil { + return fmt.Errorf("could not decode file into runtime.Object: %w", err) + } + + return nil +} diff --git a/cmd/root/options.go b/cmd/root/options.go new file mode 100644 index 000000000..8ab1a42b6 --- /dev/null +++ b/cmd/root/options.go @@ -0,0 +1,108 @@ +package root + +import ( + "fmt" + "net/http" + "net/http/pprof" + "reflect" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/webhook" + + configv1alpha1 "github.com/grafana/tempo-operator/api/config/v1alpha1" +) + +// LoadConfig initializes the controller configuration, optionally overriding the defaults +// from a provided configuration file. +func LoadConfig(scheme *runtime.Scheme, configFile string) (*configv1alpha1.ProjectConfig, ctrl.Options, error) { + options := ctrl.Options{Scheme: scheme} + ctrlConfig := configv1alpha1.DefaultProjectConfig() + + if configFile == "" { + return &ctrlConfig, options, nil + } + + err := loadConfigFile(scheme, &ctrlConfig, configFile) + if err != nil { + return nil, options, fmt.Errorf("failed to parse controller manager config file: %w", err) + } + + options = mergeOptionsFromFile(options, &ctrlConfig) + return &ctrlConfig, options, nil +} + +func mergeOptionsFromFile(o manager.Options, cfg *configv1alpha1.ProjectConfig) manager.Options { + o = setLeaderElectionConfig(o, cfg.ControllerManagerConfigurationSpec) + + if o.Metrics.BindAddress == "" && cfg.Metrics.BindAddress != "" { + o.Metrics.BindAddress = cfg.Metrics.BindAddress + + endpoints := map[string]http.HandlerFunc{ + "/debug/pprof/": pprof.Index, + "/debug/pprof/cmdline": pprof.Cmdline, + "/debug/pprof/profile": pprof.Profile, + "/debug/pprof/symbol": pprof.Symbol, + "/debug/pprof/trace": pprof.Trace, + } + + if o.Metrics.ExtraHandlers == nil { + o.Metrics.ExtraHandlers = map[string]http.Handler{} + } + + for path, handler := range endpoints { + o.Metrics.ExtraHandlers[path] = handler + } + } + + if o.HealthProbeBindAddress == "" && cfg.Health.HealthProbeBindAddress != "" { + o.HealthProbeBindAddress = cfg.Health.HealthProbeBindAddress + } + + if cfg.Webhook.Port != nil { + o.WebhookServer = webhook.NewServer(webhook.Options{ + Port: *cfg.Webhook.Port, + }) + } + + return o +} + +func setLeaderElectionConfig(o manager.Options, obj configv1alpha1.ControllerManagerConfigurationSpec) manager.Options { + if obj.LeaderElection == nil { + // The source does not have any configuration; noop + return o + } + + if !o.LeaderElection && obj.LeaderElection.LeaderElect != nil { + o.LeaderElection = *obj.LeaderElection.LeaderElect + } + + if o.LeaderElectionResourceLock == "" && obj.LeaderElection.ResourceLock != "" { + o.LeaderElectionResourceLock = obj.LeaderElection.ResourceLock + } + + if o.LeaderElectionNamespace == "" && obj.LeaderElection.ResourceNamespace != "" { + o.LeaderElectionNamespace = obj.LeaderElection.ResourceNamespace + } + + if o.LeaderElectionID == "" && obj.LeaderElection.ResourceName != "" { + o.LeaderElectionID = obj.LeaderElection.ResourceName + } + + if o.LeaseDuration == nil && !reflect.DeepEqual(obj.LeaderElection.LeaseDuration, metav1.Duration{}) { + o.LeaseDuration = &obj.LeaderElection.LeaseDuration.Duration + } + + if o.RenewDeadline == nil && !reflect.DeepEqual(obj.LeaderElection.RenewDeadline, metav1.Duration{}) { + o.RenewDeadline = &obj.LeaderElection.RenewDeadline.Duration + } + + if o.RetryPeriod == nil && !reflect.DeepEqual(obj.LeaderElection.RetryPeriod, metav1.Duration{}) { + o.RetryPeriod = &obj.LeaderElection.RetryPeriod.Duration + } + + return o +} diff --git a/cmd/root/root.go b/cmd/root/root.go index 1ea1c4133..3c7099b06 100644 --- a/cmd/root/root.go +++ b/cmd/root/root.go @@ -2,7 +2,6 @@ package root import ( "context" - "fmt" grafanav1 "github.com/grafana/grafana-operator/v5/api/v1beta1" configv1 "github.com/openshift/api/config/v1" @@ -45,25 +44,16 @@ func init() { //+kubebuilder:scaffold:scheme } +//var errConfigFileLoading = errors.New("could not read file at path") + func readConfig(cmd *cobra.Command, configFile string) error { // default controller configuration - ctrlConfig := configv1alpha1.DefaultProjectConfig() - - var err error - options := ctrl.Options{Scheme: scheme} - if configFile != "" { - options, err = options.AndFrom(ctrl.ConfigFile().AtPath(configFile).OfKind(&ctrlConfig)) - if err != nil { - return fmt.Errorf("unable to load the config file: %w", err) - } - } - - err = ctrlConfig.Validate() + ctrlCfg, options, err := LoadConfig(scheme, configFile) if err != nil { - return fmt.Errorf("controller config validation failed: %w", err) + return err } - cmd.SetContext(context.WithValue(cmd.Context(), RootConfigKey{}, RootConfig{options, ctrlConfig})) + cmd.SetContext(context.WithValue(cmd.Context(), RootConfigKey{}, RootConfig{options, *ctrlCfg})) return nil } diff --git a/go.mod b/go.mod index b48832974..da9e1a33e 100644 --- a/go.mod +++ b/go.mod @@ -31,6 +31,7 @@ require ( k8s.io/apimachinery v0.29.4 k8s.io/apiserver v0.29.4 k8s.io/client-go v0.29.4 + k8s.io/component-base v0.29.4 k8s.io/klog/v2 v2.120.1 sigs.k8s.io/controller-runtime v0.17.3 sigs.k8s.io/yaml v1.4.0 @@ -104,7 +105,6 @@ require ( gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/protobuf v1.34.2 // indirect gopkg.in/inf.v0 v0.9.1 // indirect - k8s.io/component-base v0.29.4 // indirect k8s.io/kube-openapi v0.0.0-20240221221325-2ac9dc51f3f1 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect diff --git a/internal/upgrade/versions.go b/internal/upgrade/versions.go index eb73b4fea..8a1a4bb01 100644 --- a/internal/upgrade/versions.go +++ b/internal/upgrade/versions.go @@ -4,6 +4,7 @@ import ( "context" "github.com/Masterminds/semver/v3" + "github.com/grafana/tempo-operator/api/tempo/v1alpha1" ) diff --git a/internal/webhooks/webhook_suite_test.go b/internal/webhooks/webhook_suite_test.go index 0c0c34cbe..06bd49cdc 100644 --- a/internal/webhooks/webhook_suite_test.go +++ b/internal/webhooks/webhook_suite_test.go @@ -11,7 +11,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - admissionv1beta1 "k8s.io/api/admission/v1beta1" + admissionv1 "k8s.io/api/admission/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/rest" ctrl "sigs.k8s.io/controller-runtime" @@ -67,7 +67,7 @@ var _ = BeforeSuite(func() { err = v1alpha1.AddToScheme(scheme) Expect(err).NotTo(HaveOccurred()) - err = admissionv1beta1.AddToScheme(scheme) + err = admissionv1.AddToScheme(scheme) Expect(err).NotTo(HaveOccurred()) //+kubebuilder:scaffold:scheme