From d8d16a62ac1ceb284061235e16751a43f8486a1d Mon Sep 17 00:00:00 2001 From: Pavol Loffay Date: Tue, 5 Mar 2024 16:45:08 +0100 Subject: [PATCH] Add conversion from v1beta1 to v1alpha1 (#2706) * Add conversion from v1beta1 to v1alpha1 Signed-off-by: Pavol Loffay * Fix Signed-off-by: Pavol Loffay * Fix Signed-off-by: Pavol Loffay * Fix Signed-off-by: Pavol Loffay --------- Signed-off-by: Pavol Loffay --- apis/v1alpha1/convert.go | 184 ++++++++++++++++++++- apis/v1alpha1/convert_test.go | 297 ++++++++++++++++++++++++++++------ 2 files changed, 432 insertions(+), 49 deletions(-) diff --git a/apis/v1alpha1/convert.go b/apis/v1alpha1/convert.go index 6428f12619..ea4d6913c3 100644 --- a/apis/v1alpha1/convert.go +++ b/apis/v1alpha1/convert.go @@ -35,7 +35,7 @@ func Tov1beta1(in OpenTelemetryCollector) (v1beta1.OpenTelemetryCollector, error StatusReplicas: in.Status.Scale.StatusReplicas, }, Version: in.Status.Version, - Image: in.Spec.Image, + Image: in.Status.Image, }, } @@ -108,7 +108,7 @@ func Tov1beta1(in OpenTelemetryCollector) (v1beta1.OpenTelemetryCollector, error out.Spec.OpenTelemetryCommonFields.InitContainers = copy.Spec.InitContainers out.Spec.OpenTelemetryCommonFields.AdditionalContainers = copy.Spec.AdditionalContainers - out.Spec.TargetAllocator = TargetAllocatorEmbedded(copy.Spec.TargetAllocator) + out.Spec.TargetAllocator = tov1beta1TA(copy.Spec.TargetAllocator) out.Spec.Mode = v1beta1.Mode(copy.Spec.Mode) out.Spec.UpgradeStrategy = v1beta1.UpgradeStrategy(copy.Spec.UpgradeStrategy) @@ -132,6 +132,7 @@ func Tov1beta1(in OpenTelemetryCollector) (v1beta1.OpenTelemetryCollector, error } out.Spec.Observability.Metrics.EnableMetrics = copy.Spec.Observability.Metrics.EnableMetrics + out.Spec.Observability.Metrics.DisablePrometheusAnnotations = copy.Spec.Observability.Metrics.DisablePrometheusAnnotations for _, cm := range copy.Spec.ConfigMaps { out.Spec.ConfigMaps = append(out.Spec.ConfigMaps, v1beta1.ConfigMapsSpec{ @@ -146,7 +147,7 @@ func Tov1beta1(in OpenTelemetryCollector) (v1beta1.OpenTelemetryCollector, error return out, nil } -func TargetAllocatorEmbedded(in OpenTelemetryTargetAllocator) v1beta1.TargetAllocatorEmbedded { +func tov1beta1TA(in OpenTelemetryTargetAllocator) v1beta1.TargetAllocatorEmbedded { out := v1beta1.TargetAllocatorEmbedded{} out.Replicas = in.Replicas out.NodeSelector = in.NodeSelector @@ -184,3 +185,180 @@ func TargetAllocatorEmbedded(in OpenTelemetryTargetAllocator) v1beta1.TargetAllo } return out } + +func tov1alpha1(in v1beta1.OpenTelemetryCollector) (*OpenTelemetryCollector, error) { + copy := in.DeepCopy() + configYaml, err := in.Spec.Config.Yaml() + if err != nil { + return nil, err + } + + return &OpenTelemetryCollector{ + ObjectMeta: copy.ObjectMeta, + Status: OpenTelemetryCollectorStatus{ + Scale: ScaleSubresourceStatus{ + Selector: in.Status.Scale.Selector, + Replicas: in.Status.Scale.Replicas, + StatusReplicas: in.Status.Scale.StatusReplicas, + }, + Version: in.Status.Version, + Image: in.Status.Image, + }, + + Spec: OpenTelemetryCollectorSpec{ + ManagementState: ManagementStateType(copy.Spec.ManagementState), + Resources: copy.Spec.Resources, + NodeSelector: copy.Spec.NodeSelector, + Args: copy.Spec.Args, + Replicas: copy.Spec.Replicas, + Autoscaler: tov1alpha1Autoscaler(copy.Spec.Autoscaler), + PodDisruptionBudget: tov1alpha1PodDisruptionBudget(copy.Spec.PodDisruptionBudget), + SecurityContext: copy.Spec.SecurityContext, + PodSecurityContext: copy.Spec.PodSecurityContext, + PodAnnotations: copy.Spec.PodAnnotations, + TargetAllocator: tov1alpha1TA(in.Spec.TargetAllocator), + Mode: Mode(copy.Spec.Mode), + ServiceAccount: copy.Spec.ServiceAccount, + Image: copy.Spec.Image, + UpgradeStrategy: UpgradeStrategy(copy.Spec.UpgradeStrategy), + ImagePullPolicy: copy.Spec.ImagePullPolicy, + Config: configYaml, + VolumeMounts: copy.Spec.VolumeMounts, + Ports: copy.Spec.Ports, + Env: copy.Spec.Env, + EnvFrom: copy.Spec.EnvFrom, + VolumeClaimTemplates: copy.Spec.VolumeClaimTemplates, + Tolerations: copy.Spec.Tolerations, + Volumes: copy.Spec.Volumes, + Ingress: Ingress{ + Type: IngressType(copy.Spec.Ingress.Type), + RuleType: IngressRuleType(copy.Spec.Ingress.RuleType), + Hostname: copy.Spec.Ingress.Hostname, + Annotations: copy.Spec.Ingress.Annotations, + TLS: copy.Spec.Ingress.TLS, + IngressClassName: copy.Spec.Ingress.IngressClassName, + Route: OpenShiftRoute{ + Termination: TLSRouteTerminationType(copy.Spec.Ingress.Route.Termination), + }, + }, + HostNetwork: copy.Spec.HostNetwork, + ShareProcessNamespace: copy.Spec.ShareProcessNamespace, + PriorityClassName: copy.Spec.PriorityClassName, + Affinity: copy.Spec.Affinity, + Lifecycle: copy.Spec.Lifecycle, + TerminationGracePeriodSeconds: copy.Spec.TerminationGracePeriodSeconds, + LivenessProbe: tov1alpha1Probe(copy.Spec.LivenessProbe), + InitContainers: copy.Spec.InitContainers, + AdditionalContainers: copy.Spec.AdditionalContainers, + Observability: ObservabilitySpec{ + Metrics: MetricsConfigSpec{ + EnableMetrics: copy.Spec.Observability.Metrics.EnableMetrics, + DisablePrometheusAnnotations: copy.Spec.Observability.Metrics.DisablePrometheusAnnotations, + }, + }, + TopologySpreadConstraints: copy.Spec.TopologySpreadConstraints, + ConfigMaps: tov1alpha1ConfigMaps(copy.Spec.ConfigMaps), + UpdateStrategy: copy.Spec.DaemonSetUpdateStrategy, + DeploymentUpdateStrategy: copy.Spec.DeploymentUpdateStrategy, + }, + }, nil +} + +func tov1alpha1PodDisruptionBudget(in *v1beta1.PodDisruptionBudgetSpec) *PodDisruptionBudgetSpec { + if in == nil { + return nil + } + return &PodDisruptionBudgetSpec{ + MinAvailable: in.MinAvailable, + MaxUnavailable: in.MaxUnavailable, + } +} + +func tov1alpha1Probe(in *v1beta1.Probe) *Probe { + if in == nil { + return nil + } + return &Probe{ + InitialDelaySeconds: in.InitialDelaySeconds, + TimeoutSeconds: in.TimeoutSeconds, + PeriodSeconds: in.PeriodSeconds, + SuccessThreshold: in.SuccessThreshold, + FailureThreshold: in.FailureThreshold, + TerminationGracePeriodSeconds: in.TerminationGracePeriodSeconds, + } +} + +func tov1alpha1Autoscaler(in *v1beta1.AutoscalerSpec) *AutoscalerSpec { + if in == nil { + return nil + } + + var metrics []MetricSpec + for _, m := range in.Metrics { + metrics = append(metrics, MetricSpec{ + Type: m.Type, + Pods: m.Pods, + }) + } + + return &AutoscalerSpec{ + MinReplicas: in.MinReplicas, + MaxReplicas: in.MaxReplicas, + Behavior: in.Behavior, + Metrics: metrics, + TargetCPUUtilization: in.TargetCPUUtilization, + TargetMemoryUtilization: in.TargetMemoryUtilization, + } +} + +func tov1alpha1ConfigMaps(in []v1beta1.ConfigMapsSpec) []ConfigMapsSpec { + var mapsSpecs []ConfigMapsSpec + for _, m := range in { + mapsSpecs = append(mapsSpecs, ConfigMapsSpec{ + Name: m.Name, + MountPath: m.MountPath, + }) + } + return mapsSpecs +} + +func tov1alpha1TA(in v1beta1.TargetAllocatorEmbedded) OpenTelemetryTargetAllocator { + var podMonitorSelector map[string]string + if in.PrometheusCR.PodMonitorSelector != nil { + podMonitorSelector = in.PrometheusCR.PodMonitorSelector.MatchLabels + } + var serviceMonitorSelector map[string]string + if in.PrometheusCR.ServiceMonitorSelector != nil { + serviceMonitorSelector = in.PrometheusCR.ServiceMonitorSelector.MatchLabels + } + + return OpenTelemetryTargetAllocator{ + Replicas: in.Replicas, + NodeSelector: in.NodeSelector, + Resources: in.Resources, + AllocationStrategy: OpenTelemetryTargetAllocatorAllocationStrategy(in.AllocationStrategy), + FilterStrategy: string(in.FilterStrategy), + ServiceAccount: in.ServiceAccount, + Image: in.Image, + Enabled: in.Enabled, + Affinity: in.Affinity, + PrometheusCR: OpenTelemetryTargetAllocatorPrometheusCR{ + Enabled: in.PrometheusCR.Enabled, + ScrapeInterval: in.PrometheusCR.ScrapeInterval, + PodMonitorSelector: podMonitorSelector, + ServiceMonitorSelector: serviceMonitorSelector, + }, + SecurityContext: in.SecurityContext, + PodSecurityContext: in.PodSecurityContext, + TopologySpreadConstraints: in.TopologySpreadConstraints, + Tolerations: in.Tolerations, + Env: in.Env, + Observability: ObservabilitySpec{ + Metrics: MetricsConfigSpec{ + EnableMetrics: in.Observability.Metrics.EnableMetrics, + DisablePrometheusAnnotations: in.Observability.Metrics.DisablePrometheusAnnotations, + }, + }, + PodDisruptionBudget: tov1alpha1PodDisruptionBudget(in.PodDisruptionBudget), + } +} diff --git a/apis/v1alpha1/convert_test.go b/apis/v1alpha1/convert_test.go index a63a32f79a..ad248d278b 100644 --- a/apis/v1alpha1/convert_test.go +++ b/apis/v1alpha1/convert_test.go @@ -19,8 +19,12 @@ import ( "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "gopkg.in/yaml.v3" + appsv1 "k8s.io/api/apps/v1" + autoscalingv2 "k8s.io/api/autoscaling/v2" v1 "k8s.io/api/core/v1" + networkingv1 "k8s.io/api/networking/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" @@ -28,9 +32,7 @@ import ( "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" ) -func Test_V1Alpha1to2(t *testing.T) { - t.Run("valid config", func(t *testing.T) { - config := `--- +const collectorCfg = `--- receivers: otlp: protocols: @@ -48,9 +50,12 @@ service: processors: [resourcedetection] exporters: [otlp] ` + +func Test_tov1beta1_config(t *testing.T) { + t.Run("valid config", func(t *testing.T) { cfgV1 := OpenTelemetryCollector{ Spec: OpenTelemetryCollectorSpec{ - Config: config, + Config: collectorCfg, Args: map[string]string{ "test": "something", }, @@ -64,7 +69,7 @@ service: yamlCfg, err := yaml.Marshal(&cfgV2.Spec.Config) assert.Nil(t, err) - assert.YAMLEq(t, config, string(yamlCfg)) + assert.YAMLEq(t, collectorCfg, string(yamlCfg)) }) t.Run("invalid config", func(t *testing.T) { config := `!!!` @@ -79,13 +84,252 @@ service: }) } -func Test_TargetAllocator(t *testing.T) { +func Test_tov1alpha1_config(t *testing.T) { + cfg := v1beta1.Config{} + err := yaml.Unmarshal([]byte(collectorCfg), &cfg) + require.NoError(t, err) + + beta1Col := v1beta1.OpenTelemetryCollector{ + Spec: v1beta1.OpenTelemetryCollectorSpec{ + Config: cfg, + }, + } + alpha1Col, err := tov1alpha1(beta1Col) + require.NoError(t, err) + assert.YAMLEq(t, collectorCfg, alpha1Col.Spec.Config) +} + +func Test_tov1beta1AndBack(t *testing.T) { + one := int32(1) + two := int64(2) + intstrAAA := intstr.FromString("aaa") + boolTrue := true + ingressClass := "someClass" + colalpha1 := &OpenTelemetryCollector{ + ObjectMeta: metav1.ObjectMeta{ + Name: "otel", + Namespace: "observability", + Labels: map[string]string{"foo": "bar"}, + Annotations: map[string]string{"bax": "foo"}, + }, + Spec: OpenTelemetryCollectorSpec{ + ManagementState: ManagementStateManaged, + Resources: v1.ResourceRequirements{ + Limits: v1.ResourceList{ + v1.ResourceCPU: resource.MustParse("500m"), + v1.ResourceMemory: resource.MustParse("128Mi"), + }, + Requests: v1.ResourceList{ + v1.ResourceCPU: resource.MustParse("500m"), + v1.ResourceMemory: resource.MustParse("128Mi"), + }, + }, + NodeSelector: map[string]string{"aaa": "ccc"}, + Args: map[string]string{"foo": "bar"}, + Replicas: &one, + Autoscaler: &AutoscalerSpec{ + MinReplicas: &one, + MaxReplicas: &one, + Behavior: &autoscalingv2.HorizontalPodAutoscalerBehavior{ + ScaleUp: &autoscalingv2.HPAScalingRules{ + Policies: []autoscalingv2.HPAScalingPolicy{ + { + Type: "aaa", + Value: 2, + PeriodSeconds: 4, + }, + }, + }, + }, + Metrics: []MetricSpec{ + { + Type: autoscalingv2.ContainerResourceMetricSourceType, + Pods: &autoscalingv2.PodsMetricSource{ + Metric: autoscalingv2.MetricIdentifier{ + Name: "rrrrt", + }, + }, + }, + }, + TargetCPUUtilization: &one, + TargetMemoryUtilization: &one, + }, + PodDisruptionBudget: &PodDisruptionBudgetSpec{ + MinAvailable: &intstrAAA, + MaxUnavailable: &intstrAAA, + }, + SecurityContext: &v1.SecurityContext{ + RunAsUser: &two, + }, + PodSecurityContext: &v1.PodSecurityContext{ + RunAsNonRoot: &boolTrue, + }, + PodAnnotations: map[string]string{"foo": "bar"}, + TargetAllocator: createTA(), + Mode: ModeDeployment, + ServiceAccount: "foo", + Image: "baz/bar:1.0", + UpgradeStrategy: UpgradeStrategyAutomatic, + ImagePullPolicy: v1.PullAlways, + Config: collectorCfg, + VolumeMounts: []v1.VolumeMount{ + { + Name: "aaa", + }, + }, + Ports: []v1.ServicePort{ + { + Name: "otlp", + }, + }, + Env: []v1.EnvVar{ + { + Name: "foo", + Value: "bar", + ValueFrom: &v1.EnvVarSource{ + ResourceFieldRef: &v1.ResourceFieldSelector{ + ContainerName: "bbb", + Resource: "aaa", + Divisor: resource.Quantity{}, + }, + }, + }, + }, + EnvFrom: []v1.EnvFromSource{ + { + Prefix: "aa", + ConfigMapRef: &v1.ConfigMapEnvSource{ + LocalObjectReference: v1.LocalObjectReference{ + Name: "bbb", + }, + }, + }, + }, + VolumeClaimTemplates: []v1.PersistentVolumeClaim{ + { + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{}, + Spec: v1.PersistentVolumeClaimSpec{ + VolumeName: "aaaa", + }, + }, + }, + Tolerations: []v1.Toleration{ + { + Key: "11", + Operator: "33", + Value: "44", + Effect: "55", + }, + }, + Volumes: []v1.Volume{ + { + Name: "cfg", + VolumeSource: v1.VolumeSource{}, + }, + }, + Ingress: Ingress{ + Type: IngressTypeRoute, + RuleType: IngressRuleTypePath, + Hostname: "foo.com", + Annotations: map[string]string{"aa": "bb"}, + TLS: []networkingv1.IngressTLS{ + { + Hosts: []string{"foo"}, + SecretName: "bar", + }, + }, + IngressClassName: &ingressClass, + Route: OpenShiftRoute{ + Termination: TLSRouteTerminationTypeEdge, + }, + }, + HostNetwork: true, + ShareProcessNamespace: true, + PriorityClassName: "foobar", + Affinity: &v1.Affinity{ + NodeAffinity: &v1.NodeAffinity{ + PreferredDuringSchedulingIgnoredDuringExecution: []v1.PreferredSchedulingTerm{{ + Weight: 444, + }}, + }, + }, + Lifecycle: &v1.Lifecycle{ + PostStart: &v1.LifecycleHandler{ + Exec: &v1.ExecAction{ + Command: []string{"/bin"}, + }, + }, + }, + TerminationGracePeriodSeconds: &two, + LivenessProbe: &Probe{ + PeriodSeconds: &one, + }, + InitContainers: []v1.Container{ + { + Name: "init", + }, + }, + AdditionalContainers: []v1.Container{ + { + Name: "some", + }, + }, + Observability: ObservabilitySpec{ + Metrics: MetricsConfigSpec{ + EnableMetrics: true, + DisablePrometheusAnnotations: true, + }, + }, + TopologySpreadConstraints: []v1.TopologySpreadConstraint{ + { + TopologyKey: "key", + }, + }, + ConfigMaps: []ConfigMapsSpec{ + { + Name: "aaa", + MountPath: "bbb", + }, + }, + UpdateStrategy: appsv1.DaemonSetUpdateStrategy{ + Type: appsv1.RollingUpdateDaemonSetStrategyType, + }, + DeploymentUpdateStrategy: appsv1.DeploymentStrategy{ + Type: appsv1.RecreateDeploymentStrategyType, + }, + }, + Status: OpenTelemetryCollectorStatus{ + Scale: ScaleSubresourceStatus{ + Selector: "bar", + Replicas: 1, + StatusReplicas: "foo", + }, + Version: "1.0", + Image: "foo/bar:1.0", + }, + } + + colbeta1, err := Tov1beta1(*colalpha1) + require.NoError(t, err) + colalpha1Converted, err := tov1alpha1(colbeta1) + require.NoError(t, err) + + assert.YAMLEq(t, colalpha1.Spec.Config, colalpha1Converted.Spec.Config) + + // empty the config to enable assertion on the entire objects + colalpha1.Spec.Config = "" + colalpha1Converted.Spec.Config = "" + assert.Equal(t, colalpha1, colalpha1Converted) +} + +func createTA() OpenTelemetryTargetAllocator { replicas := int32(2) runAsNonRoot := true privileged := true runAsUser := int64(1337) runasGroup := int64(1338) - input := OpenTelemetryTargetAllocator{ + return OpenTelemetryTargetAllocator{ Replicas: &replicas, NodeSelector: map[string]string{"key": "value"}, Resources: v1.ResourceRequirements{ @@ -176,43 +420,4 @@ func Test_TargetAllocator(t *testing.T) { }, }, } - - expected := v1beta1.TargetAllocatorEmbedded{ - Replicas: input.Replicas, - NodeSelector: input.NodeSelector, - Resources: input.Resources, - AllocationStrategy: v1beta1.TargetAllocatorAllocationStrategyConsistentHashing, - FilterStrategy: v1beta1.TargetAllocatorFilterStrategyRelabelConfig, - ServiceAccount: input.ServiceAccount, - Image: input.Image, - Enabled: input.Enabled, - Affinity: input.Affinity, - PrometheusCR: v1beta1.TargetAllocatorPrometheusCR{ - Enabled: input.PrometheusCR.Enabled, - ScrapeInterval: input.PrometheusCR.ScrapeInterval, - PodMonitorSelector: &metav1.LabelSelector{ - MatchLabels: input.PrometheusCR.PodMonitorSelector, - }, - ServiceMonitorSelector: &metav1.LabelSelector{ - MatchLabels: input.PrometheusCR.ServiceMonitorSelector, - }, - }, - SecurityContext: input.SecurityContext, - PodSecurityContext: input.PodSecurityContext, - TopologySpreadConstraints: input.TopologySpreadConstraints, - Tolerations: input.Tolerations, - Env: input.Env, - Observability: v1beta1.ObservabilitySpec{ - Metrics: v1beta1.MetricsConfigSpec{ - EnableMetrics: input.Observability.Metrics.EnableMetrics, - DisablePrometheusAnnotations: input.Observability.Metrics.DisablePrometheusAnnotations, - }, - }, - PodDisruptionBudget: &v1beta1.PodDisruptionBudgetSpec{ - MinAvailable: input.PodDisruptionBudget.MinAvailable, - MaxUnavailable: input.PodDisruptionBudget.MaxUnavailable, - }, - } - - assert.Equal(t, expected, TargetAllocatorEmbedded(input)) }