From 769c9843728b56af6d2042784716c0a4ebd3c5f2 Mon Sep 17 00:00:00 2001 From: Ben B Date: Mon, 5 Feb 2024 16:16:04 +0100 Subject: [PATCH] internal/manifests/collector: switch internally to v1alpha2 (#2532) * internal/manifests/collector: switch internally to v1alphav2 Signed-off-by: Benedikt Bongartz * internal/manifests/collector: change svc account Signed-off-by: Benedikt Bongartz * internal/api/convert: propagate ver upgrade error Signed-off-by: Benedikt Bongartz * intern/{api,manifests}: directly call yaml unmarshal Signed-off-by: Benedikt Bongartz * internal/api/convert: map DaemonSetUpdateStrategy Signed-off-by: Benedikt Bongartz * internal/manifests/collector: migrate configmap Signed-off-by: Benedikt Bongartz * internal/api/convert: use go-yaml instead of sig-yaml Signed-off-by: Benedikt Bongartz * pkg/sidecar: upgrade internal use from v1alpha2 to v1alpha2 Signed-off-by: Benedikt Bongartz * internal/manifests/collector: adapt cm, svc, ingress & route Signed-off-by: Benedikt Bongartz * internal/api/convert: fix v1alpha1 to v1alpha2 Signed-off-by: Benedikt Bongartz * internal/manifests/collector: evaluate returned error value in tests Signed-off-by: Benedikt Bongartz * apis/v1alpha2: config yaml method Signed-off-by: Benedikt Bongartz * internal/manifests/collector: use v1alpha2.Config yaml method Signed-off-by: Benedikt Bongartz * controllers/builder: adapt ident in unit test Signed-off-by: Benedikt Bongartz * internal/manifests/collector: fix test Signed-off-by: Benedikt Bongartz * tests/e2e: align to new indentation Signed-off-by: Benedikt Bongartz * internal/manifests/collector: cleanup Signed-off-by: Benedikt Bongartz --------- Signed-off-by: Benedikt Bongartz --- apis/v1alpha2/config.go | 14 + apis/v1alpha2/config_test.go | 74 +++++ controllers/builder_test.go | 30 +- internal/api/convert/v1alpha.go | 150 +++++++++ internal/api/convert/v1alpha_test.go | 71 +++++ internal/manifests/collector/annotations.go | 41 ++- .../manifests/collector/annotations_test.go | 77 +++-- internal/manifests/collector/collector.go | 18 +- .../manifests/collector/config_replace.go | 18 +- .../collector/config_replace_test.go | 39 ++- internal/manifests/collector/configmap.go | 15 +- .../manifests/collector/configmap_test.go | 33 +- internal/manifests/collector/container.go | 16 +- .../manifests/collector/container_test.go | 286 ++++++++++-------- internal/manifests/collector/daemonset.go | 46 +-- .../manifests/collector/daemonset_test.go | 61 ++-- internal/manifests/collector/deployment.go | 60 ++-- .../manifests/collector/deployment_test.go | 70 +++-- .../collector/horizontalpodautoscaler.go | 64 ++-- .../collector/horizontalpodautoscaler_test.go | 55 ++-- internal/manifests/collector/ingress.go | 43 +-- internal/manifests/collector/ingress_test.go | 47 +-- .../collector/poddisruptionbudget.go | 30 +- .../collector/poddisruptionbudget_test.go | 4 +- internal/manifests/collector/rbac.go | 51 +++- internal/manifests/collector/rbac_test.go | 13 +- internal/manifests/collector/route.go | 37 ++- internal/manifests/collector/route_test.go | 4 +- internal/manifests/collector/service.go | 67 ++-- internal/manifests/collector/service_test.go | 5 +- .../manifests/collector/serviceaccount.go | 26 +- .../collector/serviceaccount_test.go | 12 +- internal/manifests/collector/statefulset.go | 60 ++-- .../manifests/collector/statefulset_test.go | 67 ++-- .../config_expected_targetallocator.yaml | 5 +- ...elabel_config_expected_with_sd_config.yaml | 5 +- .../testdata/relabel_config_original.yaml | 3 +- internal/manifests/collector/utils.go | 4 +- internal/manifests/collector/volume.go | 4 +- internal/manifests/collector/volume_test.go | 19 +- internal/manifests/collector/volumeclaim.go | 4 +- .../manifests/collector/volumeclaim_test.go | 54 ++-- pkg/sidecar/pod.go | 4 +- pkg/sidecar/pod_test.go | 49 +-- pkg/sidecar/podmutator.go | 7 +- tests/e2e/managed-reconcile/02-assert.yaml | 15 +- .../e2e/smoke-targetallocator/00-assert.yaml | 35 ++- .../00-assert.yaml | 31 +- 48 files changed, 1294 insertions(+), 649 deletions(-) create mode 100644 internal/api/convert/v1alpha.go create mode 100644 internal/api/convert/v1alpha_test.go diff --git a/apis/v1alpha2/config.go b/apis/v1alpha2/config.go index 740237b18e..b437ac3f7f 100644 --- a/apis/v1alpha2/config.go +++ b/apis/v1alpha2/config.go @@ -15,10 +15,13 @@ package v1alpha2 import ( + "bytes" "encoding/json" "fmt" "reflect" "sort" + + "gopkg.in/yaml.v3" ) // AnyConfig represent parts of the config. @@ -84,6 +87,17 @@ type Config struct { Service Service `json:"service" yaml:"service"` } +// Yaml encodes the current object and returns it as a string. +func (c Config) Yaml() (string, error) { + var buf bytes.Buffer + yamlEncoder := yaml.NewEncoder(&buf) + yamlEncoder.SetIndent(2) + if err := yamlEncoder.Encode(&c); err != nil { + return "", err + } + return buf.String(), nil +} + type Service struct { Extensions *[]string `json:"extensions,omitempty" yaml:"extensions,omitempty"` // +kubebuilder:pruning:PreserveUnknownFields diff --git a/apis/v1alpha2/config_test.go b/apis/v1alpha2/config_test.go index a672c4aa3f..a8ebd29b4c 100644 --- a/apis/v1alpha2/config_test.go +++ b/apis/v1alpha2/config_test.go @@ -110,3 +110,77 @@ func TestNullObjects_go_yaml(t *testing.T) { nullObjects := cfg.nullObjects() assert.Equal(t, []string{"connectors.spanmetrics:", "exporters.otlp.endpoint:", "extensions.health_check:", "processors.batch:", "receivers.otlp.protocols.grpc:", "receivers.otlp.protocols.http:"}, nullObjects) } + +func TestConfigYaml(t *testing.T) { + cfg := &Config{ + Receivers: AnyConfig{ + Object: map[string]interface{}{ + "otlp": nil, + }, + }, + Processors: &AnyConfig{ + Object: map[string]interface{}{ + "modify_2000": "enabled", + }, + }, + Exporters: AnyConfig{ + Object: map[string]interface{}{ + "otlp/exporter": nil, + }, + }, + Connectors: &AnyConfig{ + Object: map[string]interface{}{ + "con": "magic", + }, + }, + Extensions: &AnyConfig{ + Object: map[string]interface{}{ + "addon": "option1", + }, + }, + Service: Service{ + Extensions: &[]string{"addon"}, + Telemetry: &AnyConfig{ + Object: map[string]interface{}{ + "insights": "yeah!", + }, + }, + Pipelines: AnyConfig{ + Object: map[string]interface{}{ + "receivers": []string{"otlp"}, + "processors": []string{"modify_2000"}, + "exporters": []string{"otlp/exporter", "con"}, + }, + }, + }, + } + yamlCollector, err := cfg.Yaml() + require.NoError(t, err) + + const expected = `receivers: + otlp: null +exporters: + otlp/exporter: null +processors: + modify_2000: enabled +connectors: + con: magic +extensions: + addon: option1 +service: + extensions: + - addon + telemetry: + insights: yeah! + pipelines: + exporters: + - otlp/exporter + - con + processors: + - modify_2000 + receivers: + - otlp +` + + assert.Equal(t, expected, yamlCollector) +} diff --git a/controllers/builder_test.go b/controllers/builder_test.go index 0444f16f95..054981cd6e 100644 --- a/controllers/builder_test.go +++ b/controllers/builder_test.go @@ -125,7 +125,7 @@ service: "app.kubernetes.io/version": "latest", }, Annotations: map[string]string{ - "opentelemetry-operator-config/sha256": "8188c85abd4aa5e9c798874b4f47d37f08d4778933154e3f7d60246510ed9dd2", + "opentelemetry-operator-config/sha256": "6f6f11da374b2c1e42fc78fbe55e2d9bcc2f5998ab63a631b49c478e8c0f6af8", "prometheus.io/path": "/metrics", "prometheus.io/port": "8888", "prometheus.io/scrape": "true", @@ -147,7 +147,7 @@ service: "app.kubernetes.io/version": "latest", }, Annotations: map[string]string{ - "opentelemetry-operator-config/sha256": "8188c85abd4aa5e9c798874b4f47d37f08d4778933154e3f7d60246510ed9dd2", + "opentelemetry-operator-config/sha256": "6f6f11da374b2c1e42fc78fbe55e2d9bcc2f5998ab63a631b49c478e8c0f6af8", "prometheus.io/path": "/metrics", "prometheus.io/port": "8888", "prometheus.io/scrape": "true", @@ -232,7 +232,7 @@ service: Annotations: nil, }, Data: map[string]string{ - "collector.yaml": "receivers:\n examplereceiver:\n endpoint: \"0.0.0.0:12345\"\nexporters:\n logging:\nservice:\n pipelines:\n metrics:\n receivers: [examplereceiver]\n exporters: [logging]\n", + "collector.yaml": "receivers:\n examplereceiver:\n endpoint: 0.0.0.0:12345\nexporters:\n logging: null\nservice:\n pipelines:\n metrics:\n exporters:\n - logging\n receivers:\n - examplereceiver\n", }, }, &corev1.ServiceAccount{ @@ -369,7 +369,7 @@ service: "app.kubernetes.io/version": "latest", }, Annotations: map[string]string{ - "opentelemetry-operator-config/sha256": "8188c85abd4aa5e9c798874b4f47d37f08d4778933154e3f7d60246510ed9dd2", + "opentelemetry-operator-config/sha256": "6f6f11da374b2c1e42fc78fbe55e2d9bcc2f5998ab63a631b49c478e8c0f6af8", "prometheus.io/path": "/metrics", "prometheus.io/port": "8888", "prometheus.io/scrape": "true", @@ -391,7 +391,7 @@ service: "app.kubernetes.io/version": "latest", }, Annotations: map[string]string{ - "opentelemetry-operator-config/sha256": "8188c85abd4aa5e9c798874b4f47d37f08d4778933154e3f7d60246510ed9dd2", + "opentelemetry-operator-config/sha256": "6f6f11da374b2c1e42fc78fbe55e2d9bcc2f5998ab63a631b49c478e8c0f6af8", "prometheus.io/path": "/metrics", "prometheus.io/port": "8888", "prometheus.io/scrape": "true", @@ -476,7 +476,7 @@ service: Annotations: nil, }, Data: map[string]string{ - "collector.yaml": "receivers:\n examplereceiver:\n endpoint: \"0.0.0.0:12345\"\nexporters:\n logging:\nservice:\n pipelines:\n metrics:\n receivers: [examplereceiver]\n exporters: [logging]\n", + "collector.yaml": "receivers:\n examplereceiver:\n endpoint: 0.0.0.0:12345\nexporters:\n logging: null\nservice:\n pipelines:\n metrics:\n exporters:\n - logging\n receivers:\n - examplereceiver\n", }, }, &corev1.ServiceAccount{ @@ -646,7 +646,7 @@ service: "app.kubernetes.io/version": "latest", }, Annotations: map[string]string{ - "opentelemetry-operator-config/sha256": "8188c85abd4aa5e9c798874b4f47d37f08d4778933154e3f7d60246510ed9dd2", + "opentelemetry-operator-config/sha256": "6f6f11da374b2c1e42fc78fbe55e2d9bcc2f5998ab63a631b49c478e8c0f6af8", "prometheus.io/path": "/metrics", "prometheus.io/port": "8888", "prometheus.io/scrape": "true", @@ -668,7 +668,7 @@ service: "app.kubernetes.io/version": "latest", }, Annotations: map[string]string{ - "opentelemetry-operator-config/sha256": "8188c85abd4aa5e9c798874b4f47d37f08d4778933154e3f7d60246510ed9dd2", + "opentelemetry-operator-config/sha256": "6f6f11da374b2c1e42fc78fbe55e2d9bcc2f5998ab63a631b49c478e8c0f6af8", "prometheus.io/path": "/metrics", "prometheus.io/port": "8888", "prometheus.io/scrape": "true", @@ -753,7 +753,7 @@ service: Annotations: nil, }, Data: map[string]string{ - "collector.yaml": "receivers:\n examplereceiver:\n endpoint: \"0.0.0.0:12345\"\nexporters:\n logging:\nservice:\n pipelines:\n metrics:\n receivers: [examplereceiver]\n exporters: [logging]\n", + "collector.yaml": "receivers:\n examplereceiver:\n endpoint: 0.0.0.0:12345\nexporters:\n logging: null\nservice:\n pipelines:\n metrics:\n exporters:\n - logging\n receivers:\n - examplereceiver\n", }, }, &corev1.Service{ @@ -1157,7 +1157,7 @@ service: "app.kubernetes.io/version": "latest", }, Annotations: map[string]string{ - "opentelemetry-operator-config/sha256": "5fe4d7d7faf3247bd7ec88688c9f73618f9ab8e170362bd7203c54e7a2f5cec0", + "opentelemetry-operator-config/sha256": "39cae697770f9d7e183e8fa9ba56043315b62e19c7231537870acfaaabc30a43", "prometheus.io/path": "/metrics", "prometheus.io/port": "8888", "prometheus.io/scrape": "true", @@ -1180,7 +1180,7 @@ service: "app.kubernetes.io/version": "latest", }, Annotations: map[string]string{ - "opentelemetry-operator-config/sha256": "5fe4d7d7faf3247bd7ec88688c9f73618f9ab8e170362bd7203c54e7a2f5cec0", + "opentelemetry-operator-config/sha256": "39cae697770f9d7e183e8fa9ba56043315b62e19c7231537870acfaaabc30a43", "prometheus.io/path": "/metrics", "prometheus.io/port": "8888", "prometheus.io/scrape": "true", @@ -1265,7 +1265,7 @@ service: Annotations: nil, }, Data: map[string]string{ - "collector.yaml": "exporters:\n logging: null\nreceivers:\n prometheus:\n config: {}\n target_allocator:\n collector_id: ${POD_NAME}\n endpoint: http://test-targetallocator:80\n interval: 30s\nservice:\n pipelines:\n metrics:\n exporters:\n - logging\n receivers:\n - prometheus\n", + "collector.yaml": "exporters:\n logging: null\nreceivers:\n prometheus:\n config: {}\n target_allocator:\n collector_id: ${POD_NAME}\n endpoint: http://test-targetallocator:80\n interval: 30s\nservice:\n pipelines:\n metrics:\n exporters:\n - logging\n receivers:\n - prometheus\n", }, }, &corev1.ServiceAccount{ @@ -1556,7 +1556,7 @@ prometheus_cr: "app.kubernetes.io/version": "latest", }, Annotations: map[string]string{ - "opentelemetry-operator-config/sha256": "5fe4d7d7faf3247bd7ec88688c9f73618f9ab8e170362bd7203c54e7a2f5cec0", + "opentelemetry-operator-config/sha256": "39cae697770f9d7e183e8fa9ba56043315b62e19c7231537870acfaaabc30a43", "prometheus.io/path": "/metrics", "prometheus.io/port": "8888", "prometheus.io/scrape": "true", @@ -1579,7 +1579,7 @@ prometheus_cr: "app.kubernetes.io/version": "latest", }, Annotations: map[string]string{ - "opentelemetry-operator-config/sha256": "5fe4d7d7faf3247bd7ec88688c9f73618f9ab8e170362bd7203c54e7a2f5cec0", + "opentelemetry-operator-config/sha256": "39cae697770f9d7e183e8fa9ba56043315b62e19c7231537870acfaaabc30a43", "prometheus.io/path": "/metrics", "prometheus.io/port": "8888", "prometheus.io/scrape": "true", @@ -1664,7 +1664,7 @@ prometheus_cr: Annotations: nil, }, Data: map[string]string{ - "collector.yaml": "exporters:\n logging: null\nreceivers:\n prometheus:\n config: {}\n target_allocator:\n collector_id: ${POD_NAME}\n endpoint: http://test-targetallocator:80\n interval: 30s\nservice:\n pipelines:\n metrics:\n exporters:\n - logging\n receivers:\n - prometheus\n", + "collector.yaml": "exporters:\n logging: null\nreceivers:\n prometheus:\n config: {}\n target_allocator:\n collector_id: ${POD_NAME}\n endpoint: http://test-targetallocator:80\n interval: 30s\nservice:\n pipelines:\n metrics:\n exporters:\n - logging\n receivers:\n - prometheus\n", }, }, &corev1.ServiceAccount{ diff --git a/internal/api/convert/v1alpha.go b/internal/api/convert/v1alpha.go new file mode 100644 index 0000000000..1a6ed18313 --- /dev/null +++ b/internal/api/convert/v1alpha.go @@ -0,0 +1,150 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package convert + +import ( + "errors" + + "gopkg.in/yaml.v3" + + "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1" + "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha2" +) + +func V1Alpha1to2(in v1alpha1.OpenTelemetryCollector) (v1alpha2.OpenTelemetryCollector, error) { + copy := in.DeepCopy() + out := v1alpha2.OpenTelemetryCollector{ + TypeMeta: copy.TypeMeta, + ObjectMeta: copy.ObjectMeta, + } + + cfg := &v1alpha2.Config{} + if err := yaml.Unmarshal([]byte(in.Spec.Config), cfg); err != nil { + return v1alpha2.OpenTelemetryCollector{}, errors.New("could not convert config json to v1alpha2.Config") + } + out.Spec.Config = *cfg + + out.Spec.OpenTelemetryCommonFields.ManagementState = v1alpha2.ManagementStateType(copy.Spec.ManagementState) + out.Spec.OpenTelemetryCommonFields.Resources = copy.Spec.Resources + out.Spec.OpenTelemetryCommonFields.NodeSelector = copy.Spec.NodeSelector + out.Spec.OpenTelemetryCommonFields.Args = copy.Spec.NodeSelector + out.Spec.OpenTelemetryCommonFields.Replicas = copy.Spec.Replicas + + if copy.Spec.Autoscaler != nil { + metrics := make([]v1alpha2.MetricSpec, len(copy.Spec.Autoscaler.Metrics)) + for i, m := range copy.Spec.Autoscaler.Metrics { + metrics[i] = v1alpha2.MetricSpec{ + Type: m.Type, + Pods: m.Pods, + } + } + out.Spec.OpenTelemetryCommonFields.Autoscaler = &v1alpha2.AutoscalerSpec{ + MinReplicas: copy.Spec.Autoscaler.MinReplicas, + MaxReplicas: copy.Spec.Autoscaler.MaxReplicas, + Behavior: copy.Spec.Autoscaler.Behavior, + Metrics: metrics, + TargetCPUUtilization: copy.Spec.Autoscaler.TargetCPUUtilization, + TargetMemoryUtilization: copy.Spec.Autoscaler.TargetMemoryUtilization, + } + } + + if copy.Spec.PodDisruptionBudget != nil { + out.Spec.OpenTelemetryCommonFields.PodDisruptionBudget = &v1alpha2.PodDisruptionBudgetSpec{ + MinAvailable: copy.Spec.PodDisruptionBudget.MinAvailable, + MaxUnavailable: copy.Spec.PodDisruptionBudget.MaxUnavailable, + } + } + if copy.Spec.SecurityContext != nil { + out.Spec.OpenTelemetryCommonFields.SecurityContext = copy.Spec.SecurityContext + } + if copy.Spec.PodSecurityContext != nil { + out.Spec.OpenTelemetryCommonFields.PodSecurityContext = copy.Spec.PodSecurityContext + } + out.Spec.OpenTelemetryCommonFields.PodAnnotations = copy.Spec.PodAnnotations + out.Spec.OpenTelemetryCommonFields.ServiceAccount = copy.Spec.ServiceAccount + out.Spec.OpenTelemetryCommonFields.Image = copy.Spec.Image + out.Spec.OpenTelemetryCommonFields.ImagePullPolicy = copy.Spec.ImagePullPolicy + out.Spec.OpenTelemetryCommonFields.VolumeMounts = copy.Spec.VolumeMounts + out.Spec.OpenTelemetryCommonFields.Ports = copy.Spec.Ports + out.Spec.OpenTelemetryCommonFields.Env = copy.Spec.Env + out.Spec.OpenTelemetryCommonFields.EnvFrom = copy.Spec.EnvFrom + out.Spec.OpenTelemetryCommonFields.VolumeClaimTemplates = copy.Spec.VolumeClaimTemplates + out.Spec.OpenTelemetryCommonFields.Tolerations = copy.Spec.Tolerations + out.Spec.OpenTelemetryCommonFields.Volumes = copy.Spec.Volumes + out.Spec.OpenTelemetryCommonFields.Affinity = copy.Spec.Affinity + out.Spec.OpenTelemetryCommonFields.Lifecycle = copy.Spec.Lifecycle + out.Spec.OpenTelemetryCommonFields.TerminationGracePeriodSeconds = copy.Spec.TerminationGracePeriodSeconds + out.Spec.OpenTelemetryCommonFields.TopologySpreadConstraints = copy.Spec.TopologySpreadConstraints + out.Spec.OpenTelemetryCommonFields.HostNetwork = copy.Spec.HostNetwork + out.Spec.OpenTelemetryCommonFields.ShareProcessNamespace = copy.Spec.ShareProcessNamespace + out.Spec.OpenTelemetryCommonFields.PriorityClassName = copy.Spec.PriorityClassName + out.Spec.OpenTelemetryCommonFields.InitContainers = copy.Spec.InitContainers + out.Spec.OpenTelemetryCommonFields.AdditionalContainers = copy.Spec.AdditionalContainers + + out.Spec.TargetAllocator.Replicas = copy.Spec.TargetAllocator.Replicas + out.Spec.TargetAllocator.NodeSelector = copy.Spec.TargetAllocator.NodeSelector + out.Spec.TargetAllocator.Resources = copy.Spec.TargetAllocator.Resources + out.Spec.TargetAllocator.AllocationStrategy = copy.Spec.TargetAllocator.AllocationStrategy + out.Spec.TargetAllocator.FilterStrategy = copy.Spec.TargetAllocator.FilterStrategy + out.Spec.TargetAllocator.ServiceAccount = copy.Spec.TargetAllocator.ServiceAccount + out.Spec.TargetAllocator.Image = copy.Spec.TargetAllocator.Image + out.Spec.TargetAllocator.Enabled = copy.Spec.TargetAllocator.Enabled + out.Spec.TargetAllocator.Affinity = copy.Spec.TargetAllocator.Affinity + out.Spec.TargetAllocator.PrometheusCR.Enabled = copy.Spec.TargetAllocator.PrometheusCR.Enabled + out.Spec.TargetAllocator.PrometheusCR.ScrapeInterval = copy.Spec.TargetAllocator.PrometheusCR.ScrapeInterval + out.Spec.TargetAllocator.PrometheusCR.PodMonitorSelector = copy.Spec.TargetAllocator.PrometheusCR.PodMonitorSelector + out.Spec.TargetAllocator.PrometheusCR.ServiceMonitorSelector = copy.Spec.TargetAllocator.PrometheusCR.ServiceMonitorSelector + out.Spec.TargetAllocator.SecurityContext = copy.Spec.TargetAllocator.SecurityContext + out.Spec.TargetAllocator.PodSecurityContext = copy.Spec.TargetAllocator.PodSecurityContext + out.Spec.TargetAllocator.TopologySpreadConstraints = copy.Spec.TargetAllocator.TopologySpreadConstraints + out.Spec.TargetAllocator.Tolerations = copy.Spec.TargetAllocator.Tolerations + out.Spec.TargetAllocator.Env = copy.Spec.TargetAllocator.Env + out.Spec.TargetAllocator.Observability = v1alpha1.ObservabilitySpec{ + Metrics: v1alpha1.MetricsConfigSpec{ + EnableMetrics: copy.Spec.TargetAllocator.Observability.Metrics.EnableMetrics, + }, + } + out.Spec.TargetAllocator.PodDisruptionBudget = copy.Spec.TargetAllocator.PodDisruptionBudget + + out.Spec.Mode = v1alpha2.Mode(copy.Spec.Mode) + out.Spec.UpgradeStrategy = v1alpha2.UpgradeStrategy(copy.Spec.UpgradeStrategy) + out.Spec.Ingress.Type = v1alpha2.IngressType(copy.Spec.Ingress.Type) + out.Spec.Ingress.RuleType = v1alpha2.IngressRuleType(copy.Spec.Ingress.RuleType) + out.Spec.Ingress.Hostname = copy.Spec.Ingress.Hostname + out.Spec.Ingress.Annotations = copy.Spec.Ingress.Annotations + out.Spec.Ingress.TLS = copy.Spec.Ingress.TLS + out.Spec.Ingress.IngressClassName = copy.Spec.Ingress.IngressClassName + out.Spec.Ingress.Route.Termination = v1alpha2.TLSRouteTerminationType(copy.Spec.Ingress.Route.Termination) + + if copy.Spec.LivenessProbe != nil { + out.Spec.LivenessProbe = &v1alpha2.Probe{ + InitialDelaySeconds: copy.Spec.LivenessProbe.InitialDelaySeconds, + TimeoutSeconds: copy.Spec.LivenessProbe.TimeoutSeconds, + PeriodSeconds: copy.Spec.LivenessProbe.PeriodSeconds, + SuccessThreshold: copy.Spec.LivenessProbe.SuccessThreshold, + FailureThreshold: copy.Spec.LivenessProbe.FailureThreshold, + TerminationGracePeriodSeconds: copy.Spec.LivenessProbe.TerminationGracePeriodSeconds, + } + } + + out.Spec.Observability.Metrics.EnableMetrics = copy.Spec.Observability.Metrics.EnableMetrics + + out.Spec.ConfigMaps = copy.Spec.ConfigMaps + out.Spec.DaemonSetUpdateStrategy = copy.Spec.UpdateStrategy + out.Spec.DeploymentUpdateStrategy.Type = copy.Spec.DeploymentUpdateStrategy.Type + out.Spec.DeploymentUpdateStrategy.RollingUpdate = copy.Spec.DeploymentUpdateStrategy.RollingUpdate + + return out, nil +} diff --git a/internal/api/convert/v1alpha_test.go b/internal/api/convert/v1alpha_test.go new file mode 100644 index 0000000000..8d3bac8297 --- /dev/null +++ b/internal/api/convert/v1alpha_test.go @@ -0,0 +1,71 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package convert + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "gopkg.in/yaml.v3" + + "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1" +) + +func Test_V1Alpha1to2(t *testing.T) { + t.Run("valid config", func(t *testing.T) { + config := `--- +receivers: + otlp: + protocols: + grpc: +processors: + resourcedetection: + detectors: [kubernetes] +exporters: + otlp: + endpoint: "otlp:4317" +service: + pipelines: + traces: + receivers: [otlp] + processors: [resourcedetection] + exporters: [otlp] +` + cfgV1 := v1alpha1.OpenTelemetryCollector{ + Spec: v1alpha1.OpenTelemetryCollectorSpec{ + Config: config, + }, + } + + cfgV2, err := V1Alpha1to2(cfgV1) + assert.Nil(t, err) + assert.NotNil(t, cfgV2) + + yamlCfg, err := yaml.Marshal(&cfgV2.Spec.Config) + assert.Nil(t, err) + assert.YAMLEq(t, config, string(yamlCfg)) + }) + t.Run("invalid config", func(t *testing.T) { + config := `!!!` + cfgV1 := v1alpha1.OpenTelemetryCollector{ + Spec: v1alpha1.OpenTelemetryCollectorSpec{ + Config: config, + }, + } + + _, err := V1Alpha1to2(cfgV1) + assert.ErrorContains(t, err, "could not convert config json to v1alpha2.Config") + }) +} diff --git a/internal/manifests/collector/annotations.go b/internal/manifests/collector/annotations.go index e3f39c773c..32201ea412 100644 --- a/internal/manifests/collector/annotations.go +++ b/internal/manifests/collector/annotations.go @@ -16,13 +16,14 @@ package collector import ( "crypto/sha256" + "encoding/json" "fmt" - "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1" + "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha2" ) // Annotations return the annotations for OpenTelemetryCollector pod. -func Annotations(instance v1alpha1.OpenTelemetryCollector) map[string]string { +func Annotations(instance v1alpha2.OpenTelemetryCollector) (map[string]string, error) { // new map every time, so that we don't touch the instance's annotations annotations := map[string]string{} @@ -40,14 +41,20 @@ func Annotations(instance v1alpha1.OpenTelemetryCollector) map[string]string { annotations[k] = v } } + + hash, err := getConfigMapSHA(instance.Spec.Config) + if err != nil { + return nil, err + } + // make sure sha256 for configMap is always calculated - annotations["opentelemetry-operator-config/sha256"] = getConfigMapSHA(instance.Spec.Config) + annotations["opentelemetry-operator-config/sha256"] = hash - return annotations + return annotations, nil } // PodAnnotations return the spec annotations for OpenTelemetryCollector pod. -func PodAnnotations(instance v1alpha1.OpenTelemetryCollector) map[string]string { +func PodAnnotations(instance v1alpha2.OpenTelemetryCollector) (map[string]string, error) { // new map every time, so that we don't touch the instance's annotations podAnnotations := map[string]string{} @@ -56,20 +63,32 @@ func PodAnnotations(instance v1alpha1.OpenTelemetryCollector) map[string]string podAnnotations[k] = v } + annotations, err := Annotations(instance) + if err != nil { + return nil, err + } // propagating annotations from metadata.annotations - for kMeta, vMeta := range Annotations(instance) { + for kMeta, vMeta := range annotations { if _, found := podAnnotations[kMeta]; !found { podAnnotations[kMeta] = vMeta } } + hash, err := getConfigMapSHA(instance.Spec.Config) + if err != nil { + return nil, err + } // make sure sha256 for configMap is always calculated - podAnnotations["opentelemetry-operator-config/sha256"] = getConfigMapSHA(instance.Spec.Config) + podAnnotations["opentelemetry-operator-config/sha256"] = hash - return podAnnotations + return podAnnotations, nil } -func getConfigMapSHA(config string) string { - h := sha256.Sum256([]byte(config)) - return fmt.Sprintf("%x", h) +func getConfigMapSHA(config v1alpha2.Config) (string, error) { + b, err := json.Marshal(&config) + if err != nil { + return "", err + } + h := sha256.Sum256(b) + return fmt.Sprintf("%x", h), nil } diff --git a/internal/manifests/collector/annotations_test.go b/internal/manifests/collector/annotations_test.go index ddac166ff2..9119bbda0a 100644 --- a/internal/manifests/collector/annotations_test.go +++ b/internal/manifests/collector/annotations_test.go @@ -18,48 +18,58 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1" + "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha2" ) func TestDefaultAnnotations(t *testing.T) { // prepare - otelcol := v1alpha1.OpenTelemetryCollector{ + otelcol := v1alpha2.OpenTelemetryCollector{ ObjectMeta: metav1.ObjectMeta{ Name: "my-instance", Namespace: "my-ns", }, - Spec: v1alpha1.OpenTelemetryCollectorSpec{ - Config: "test", + Spec: v1alpha2.OpenTelemetryCollectorSpec{ + Config: v1alpha2.Config{ + Service: v1alpha2.Service{ + Extensions: func() *[]string { + res := []string{"test"} + return &res + }(), + }, + }, }, } // test - annotations := Annotations(otelcol) - podAnnotations := PodAnnotations(otelcol) + annotations, err := Annotations(otelcol) + require.NoError(t, err) + podAnnotations, err := PodAnnotations(otelcol) + require.NoError(t, err) //verify assert.Equal(t, "true", annotations["prometheus.io/scrape"]) assert.Equal(t, "8888", annotations["prometheus.io/port"]) assert.Equal(t, "/metrics", annotations["prometheus.io/path"]) - assert.Equal(t, "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", annotations["opentelemetry-operator-config/sha256"]) + assert.Equal(t, "5b3b62aa5e0a3c7250084c2b49190e30b72fc2ad352ffbaa699224e1aa900834", annotations["opentelemetry-operator-config/sha256"]) //verify propagation from metadata.annotations to spec.template.spec.metadata.annotations assert.Equal(t, "true", podAnnotations["prometheus.io/scrape"]) assert.Equal(t, "8888", podAnnotations["prometheus.io/port"]) assert.Equal(t, "/metrics", podAnnotations["prometheus.io/path"]) - assert.Equal(t, "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", podAnnotations["opentelemetry-operator-config/sha256"]) + assert.Equal(t, "5b3b62aa5e0a3c7250084c2b49190e30b72fc2ad352ffbaa699224e1aa900834", podAnnotations["opentelemetry-operator-config/sha256"]) } func TestNonDefaultPodAnnotation(t *testing.T) { // prepare - otelcol := v1alpha1.OpenTelemetryCollector{ + otelcol := v1alpha2.OpenTelemetryCollector{ ObjectMeta: metav1.ObjectMeta{ Name: "my-instance", Namespace: "my-ns", }, - Spec: v1alpha1.OpenTelemetryCollectorSpec{ - Config: "test", + Spec: v1alpha2.OpenTelemetryCollectorSpec{ Observability: v1alpha1.ObservabilitySpec{ Metrics: v1alpha1.MetricsConfigSpec{ DisablePrometheusAnnotations: true, @@ -69,24 +79,26 @@ func TestNonDefaultPodAnnotation(t *testing.T) { } // test - annotations := Annotations(otelcol) - podAnnotations := PodAnnotations(otelcol) + annotations, err := Annotations(otelcol) + require.NoError(t, err) + podAnnotations, err := PodAnnotations(otelcol) + require.NoError(t, err) //verify assert.NotContains(t, annotations, "prometheus.io/scrape", "Prometheus scrape annotation should not exist") assert.NotContains(t, annotations, "prometheus.io/port", "Prometheus port annotation should not exist") assert.NotContains(t, annotations, "prometheus.io/path", "Prometheus path annotation should not exist") - assert.Equal(t, "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", annotations["opentelemetry-operator-config/sha256"]) + assert.Equal(t, "fbcdae6a02b2115cd5ca4f34298202ab041d1dfe62edebfaadb48b1ee178231d", annotations["opentelemetry-operator-config/sha256"]) //verify propagation from metadata.annotations to spec.template.spec.metadata.annotations assert.NotContains(t, podAnnotations, "prometheus.io/scrape", "Prometheus scrape annotation should not exist in pod annotations") assert.NotContains(t, podAnnotations, "prometheus.io/port", "Prometheus port annotation should not exist in pod annotations") assert.NotContains(t, podAnnotations, "prometheus.io/path", "Prometheus path annotation should not exist in pod annotations") - assert.Equal(t, "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", podAnnotations["opentelemetry-operator-config/sha256"]) + assert.Equal(t, "fbcdae6a02b2115cd5ca4f34298202ab041d1dfe62edebfaadb48b1ee178231d", podAnnotations["opentelemetry-operator-config/sha256"]) } func TestUserAnnotations(t *testing.T) { // prepare - otelcol := v1alpha1.OpenTelemetryCollector{ + otelcol := v1alpha2.OpenTelemetryCollector{ ObjectMeta: metav1.ObjectMeta{ Name: "my-instance", Namespace: "my-ns", @@ -96,37 +108,50 @@ func TestUserAnnotations(t *testing.T) { "opentelemetry-operator-config/sha256": "shouldBeOverwritten", }, }, - Spec: v1alpha1.OpenTelemetryCollectorSpec{ - Config: "test", + Spec: v1alpha2.OpenTelemetryCollectorSpec{ + Config: v1alpha2.Config{ + Service: v1alpha2.Service{ + Extensions: func() *[]string { + res := []string{"test2"} + return &res + }(), + }, + }, }, } // test - annotations := Annotations(otelcol) - podAnnotations := PodAnnotations(otelcol) + annotations, err := Annotations(otelcol) + require.NoError(t, err) + podAnnotations, err := PodAnnotations(otelcol) + require.NoError(t, err) //verify assert.Equal(t, "false", annotations["prometheus.io/scrape"]) assert.Equal(t, "1234", annotations["prometheus.io/port"]) assert.Equal(t, "/test", annotations["prometheus.io/path"]) - assert.Equal(t, "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", annotations["opentelemetry-operator-config/sha256"]) - assert.Equal(t, "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", podAnnotations["opentelemetry-operator-config/sha256"]) + assert.Equal(t, "29cb15a4b87f8c6284e7c3377f6b6c5c74519f5aee8ca39a90b3cf3ca2043c4d", annotations["opentelemetry-operator-config/sha256"]) + assert.Equal(t, "29cb15a4b87f8c6284e7c3377f6b6c5c74519f5aee8ca39a90b3cf3ca2043c4d", podAnnotations["opentelemetry-operator-config/sha256"]) } func TestAnnotationsPropagateDown(t *testing.T) { // prepare - otelcol := v1alpha1.OpenTelemetryCollector{ + otelcol := v1alpha2.OpenTelemetryCollector{ ObjectMeta: metav1.ObjectMeta{ Annotations: map[string]string{"myapp": "mycomponent"}, }, - Spec: v1alpha1.OpenTelemetryCollectorSpec{ - PodAnnotations: map[string]string{"pod_annotation": "pod_annotation_value"}, + Spec: v1alpha2.OpenTelemetryCollectorSpec{ + OpenTelemetryCommonFields: v1alpha2.OpenTelemetryCommonFields{ + PodAnnotations: map[string]string{"pod_annotation": "pod_annotation_value"}, + }, }, } // test - annotations := Annotations(otelcol) - podAnnotations := PodAnnotations(otelcol) + annotations, err := Annotations(otelcol) + require.NoError(t, err) + podAnnotations, err := PodAnnotations(otelcol) + require.NoError(t, err) // verify assert.Len(t, annotations, 5) diff --git a/internal/manifests/collector/collector.go b/internal/manifests/collector/collector.go index a4236d03b6..37a006c087 100644 --- a/internal/manifests/collector/collector.go +++ b/internal/manifests/collector/collector.go @@ -32,20 +32,20 @@ func Build(params manifests.Params) ([]client.Object, error) { var manifestFactories []manifests.K8sManifestFactory switch params.OtelCol.Spec.Mode { case v1alpha1.ModeDeployment: - manifestFactories = append(manifestFactories, manifests.FactoryWithoutError(Deployment)) - manifestFactories = append(manifestFactories, manifests.FactoryWithoutError(PodDisruptionBudget)) + manifestFactories = append(manifestFactories, manifests.Factory(Deployment)) + manifestFactories = append(manifestFactories, manifests.Factory(PodDisruptionBudget)) case v1alpha1.ModeStatefulSet: - manifestFactories = append(manifestFactories, manifests.FactoryWithoutError(StatefulSet)) - manifestFactories = append(manifestFactories, manifests.FactoryWithoutError(PodDisruptionBudget)) + manifestFactories = append(manifestFactories, manifests.Factory(StatefulSet)) + manifestFactories = append(manifestFactories, manifests.Factory(PodDisruptionBudget)) case v1alpha1.ModeDaemonSet: - manifestFactories = append(manifestFactories, manifests.FactoryWithoutError(DaemonSet)) + manifestFactories = append(manifestFactories, manifests.Factory(DaemonSet)) case v1alpha1.ModeSidecar: params.Log.V(5).Info("not building sidecar...") } manifestFactories = append(manifestFactories, []manifests.K8sManifestFactory{ manifests.Factory(ConfigMap), - manifests.FactoryWithoutError(HorizontalPodAutoscaler), - manifests.FactoryWithoutError(ServiceAccount), + manifests.Factory(HorizontalPodAutoscaler), + manifests.Factory(ServiceAccount), manifests.Factory(Service), manifests.Factory(HeadlessService), manifests.Factory(MonitoringService), @@ -62,8 +62,8 @@ func Build(params manifests.Params) ([]client.Object, error) { if params.Config.CreateRBACPermissions() { manifestFactories = append(manifestFactories, - manifests.FactoryWithoutError(ClusterRole), - manifests.FactoryWithoutError(ClusterRoleBinding), + manifests.Factory(ClusterRole), + manifests.Factory(ClusterRoleBinding), ) } diff --git a/internal/manifests/collector/config_replace.go b/internal/manifests/collector/config_replace.go index c6cc58ad40..79c636b483 100644 --- a/internal/manifests/collector/config_replace.go +++ b/internal/manifests/collector/config_replace.go @@ -19,9 +19,9 @@ import ( promconfig "github.com/prometheus/prometheus/config" _ "github.com/prometheus/prometheus/discovery/install" // Package install has the side-effect of registering all builtin. - "gopkg.in/yaml.v2" + "gopkg.in/yaml.v3" - "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1" + "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha2" "github.com/open-telemetry/opentelemetry-operator/internal/manifests/collector/adapters" ta "github.com/open-telemetry/opentelemetry-operator/internal/manifests/targetallocator/adapters" "github.com/open-telemetry/opentelemetry-operator/internal/naming" @@ -42,18 +42,22 @@ type Config struct { TargetAllocConfig *targetAllocator `yaml:"target_allocator,omitempty"` } -func ReplaceConfig(instance v1alpha1.OpenTelemetryCollector) (string, error) { +func ReplaceConfig(instance v1alpha2.OpenTelemetryCollector) (string, error) { + cfgStr, err := instance.Spec.Config.Yaml() + if err != nil { + return "", err + } // Check if TargetAllocator is enabled, if not, return the original config if !instance.Spec.TargetAllocator.Enabled { - return instance.Spec.Config, nil + return cfgStr, nil } - config, err := adapters.ConfigFromString(instance.Spec.Config) + config, err := adapters.ConfigFromString(cfgStr) if err != nil { return "", err } - promCfgMap, getCfgPromErr := ta.ConfigToPromConfig(instance.Spec.Config) + promCfgMap, getCfgPromErr := ta.ConfigToPromConfig(cfgStr) if getCfgPromErr != nil { return "", getCfgPromErr } @@ -78,7 +82,6 @@ func ReplaceConfig(instance v1alpha1.OpenTelemetryCollector) (string, error) { if updCfgMarshalErr != nil { return "", updCfgMarshalErr } - return string(out), nil } @@ -89,6 +92,7 @@ func ReplaceConfig(instance v1alpha1.OpenTelemetryCollector) (string, error) { return "", err } + // To avoid issues caused by Prometheus validation logic, which fails regex validation when it encounters // type coercion checks are handled in the ConfigToPromConfig method above config["receivers"].(map[interface{}]interface{})["prometheus"] = updPromCfgMap diff --git a/internal/manifests/collector/config_replace_test.go b/internal/manifests/collector/config_replace_test.go index c7ab767505..76fb3af32f 100644 --- a/internal/manifests/collector/config_replace_test.go +++ b/internal/manifests/collector/config_replace_test.go @@ -24,6 +24,7 @@ import ( colfeaturegate "go.opentelemetry.io/collector/featuregate" "gopkg.in/yaml.v2" + "github.com/open-telemetry/opentelemetry-operator/internal/api/convert" ta "github.com/open-telemetry/opentelemetry-operator/internal/manifests/targetallocator/adapters" "github.com/open-telemetry/opentelemetry-operator/pkg/featuregate" ) @@ -31,6 +32,8 @@ import ( func TestPrometheusParser(t *testing.T) { param, err := newParams("test/test-img", "testdata/http_sd_config_test.yaml") assert.NoError(t, err) + otelCol, err := convert.V1Alpha1to2(param.OtelCol) + assert.NoError(t, err) t.Run("should update config with http_sd_config", func(t *testing.T) { err := colfeaturegate.GlobalRegistry().Set(featuregate.EnableTargetAllocatorRewrite.ID(), false) @@ -38,7 +41,7 @@ func TestPrometheusParser(t *testing.T) { t.Cleanup(func() { _ = colfeaturegate.GlobalRegistry().Set(featuregate.EnableTargetAllocatorRewrite.ID(), true) }) - actualConfig, err := ReplaceConfig(param.OtelCol) + actualConfig, err := ReplaceConfig(otelCol) assert.NoError(t, err) // prepare @@ -71,8 +74,8 @@ func TestPrometheusParser(t *testing.T) { t.Run("should update config with targetAllocator block if block not present", func(t *testing.T) { // Set up the test scenario - param.OtelCol.Spec.TargetAllocator.Enabled = true - actualConfig, err := ReplaceConfig(param.OtelCol) + otelCol.Spec.TargetAllocator.Enabled = true + actualConfig, err := ReplaceConfig(otelCol) assert.NoError(t, err) // Verify the expected changes in the config @@ -96,9 +99,12 @@ func TestPrometheusParser(t *testing.T) { // Set up the test scenario paramTa, err := newParams("test/test-img", "testdata/http_sd_config_ta_test.yaml") require.NoError(t, err) + otelColTa, err := convert.V1Alpha1to2(paramTa.OtelCol) + assert.NoError(t, err) + paramTa.OtelCol.Spec.TargetAllocator.Enabled = true - actualConfig, err := ReplaceConfig(paramTa.OtelCol) + actualConfig, err := ReplaceConfig(otelColTa) assert.NoError(t, err) // Verify the expected changes in the config @@ -119,8 +125,9 @@ func TestPrometheusParser(t *testing.T) { }) t.Run("should not update config with http_sd_config", func(t *testing.T) { - param.OtelCol.Spec.TargetAllocator.Enabled = false - actualConfig, err := ReplaceConfig(param.OtelCol) + otelCol.Spec.TargetAllocator.Enabled = false + + actualConfig, err := ReplaceConfig(otelCol) assert.NoError(t, err) // prepare @@ -156,17 +163,19 @@ func TestPrometheusParser(t *testing.T) { func TestReplaceConfig(t *testing.T) { param, err := newParams("test/test-img", "testdata/relabel_config_original.yaml") assert.NoError(t, err) + otelCol, err := convert.V1Alpha1to2(param.OtelCol) + assert.NoError(t, err) t.Run("should not modify config when TargetAllocator is disabled", func(t *testing.T) { - param.OtelCol.Spec.TargetAllocator.Enabled = false + otelCol.Spec.TargetAllocator.Enabled = false expectedConfigBytes, err := os.ReadFile("testdata/relabel_config_original.yaml") assert.NoError(t, err) expectedConfig := string(expectedConfigBytes) - actualConfig, err := ReplaceConfig(param.OtelCol) + actualConfig, err := ReplaceConfig(otelCol) assert.NoError(t, err) - assert.Equal(t, expectedConfig, actualConfig) + assert.YAMLEq(t, expectedConfig, actualConfig) }) t.Run("should rewrite scrape configs with SD config when TargetAllocator is enabled and feature flag is not set", func(t *testing.T) { @@ -176,28 +185,28 @@ func TestReplaceConfig(t *testing.T) { _ = colfeaturegate.GlobalRegistry().Set(featuregate.EnableTargetAllocatorRewrite.ID(), true) }) - param.OtelCol.Spec.TargetAllocator.Enabled = true + otelCol.Spec.TargetAllocator.Enabled = true expectedConfigBytes, err := os.ReadFile("testdata/relabel_config_expected_with_sd_config.yaml") assert.NoError(t, err) expectedConfig := string(expectedConfigBytes) - actualConfig, err := ReplaceConfig(param.OtelCol) + actualConfig, err := ReplaceConfig(otelCol) assert.NoError(t, err) - assert.Equal(t, expectedConfig, actualConfig) + assert.YAMLEq(t, expectedConfig, actualConfig) }) t.Run("should remove scrape configs if TargetAllocator is enabled and feature flag is set", func(t *testing.T) { - param.OtelCol.Spec.TargetAllocator.Enabled = true + otelCol.Spec.TargetAllocator.Enabled = true expectedConfigBytes, err := os.ReadFile("testdata/config_expected_targetallocator.yaml") assert.NoError(t, err) expectedConfig := string(expectedConfigBytes) - actualConfig, err := ReplaceConfig(param.OtelCol) + actualConfig, err := ReplaceConfig(otelCol) assert.NoError(t, err) - assert.Equal(t, expectedConfig, actualConfig) + assert.YAMLEq(t, expectedConfig, actualConfig) }) } diff --git a/internal/manifests/collector/configmap.go b/internal/manifests/collector/configmap.go index 58ee4c1312..6a84c49d53 100644 --- a/internal/manifests/collector/configmap.go +++ b/internal/manifests/collector/configmap.go @@ -18,16 +18,21 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "github.com/open-telemetry/opentelemetry-operator/internal/api/convert" "github.com/open-telemetry/opentelemetry-operator/internal/manifests" "github.com/open-telemetry/opentelemetry-operator/internal/manifests/manifestutils" "github.com/open-telemetry/opentelemetry-operator/internal/naming" ) func ConfigMap(params manifests.Params) (*corev1.ConfigMap, error) { - name := naming.ConfigMap(params.OtelCol.Name) - labels := manifestutils.Labels(params.OtelCol.ObjectMeta, name, params.OtelCol.Spec.Image, ComponentOpenTelemetryCollector, []string{}) + otelCol, err := convert.V1Alpha1to2(params.OtelCol) + if err != nil { + return nil, err + } + name := naming.ConfigMap(otelCol.Name) + labels := manifestutils.Labels(otelCol.ObjectMeta, name, otelCol.Spec.Image, ComponentOpenTelemetryCollector, []string{}) - replacedConf, err := ReplaceConfig(params.OtelCol) + replacedConf, err := ReplaceConfig(otelCol) if err != nil { params.Log.V(2).Info("failed to update prometheus config to use sharded targets: ", "err", err) return nil, err @@ -36,9 +41,9 @@ func ConfigMap(params manifests.Params) (*corev1.ConfigMap, error) { return &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Name: name, - Namespace: params.OtelCol.Namespace, + Namespace: otelCol.Namespace, Labels: labels, - Annotations: params.OtelCol.Annotations, + Annotations: otelCol.Annotations, }, Data: map[string]string{ "collector.yaml": replacedConf, diff --git a/internal/manifests/collector/configmap_test.go b/internal/manifests/collector/configmap_test.go index 9d60763eef..525a5e80be 100644 --- a/internal/manifests/collector/configmap_test.go +++ b/internal/manifests/collector/configmap_test.go @@ -38,8 +38,7 @@ func TestDesiredConfigMap(t *testing.T) { expectedLables["app.kubernetes.io/version"] = "0.47.0" expectedData := map[string]string{ - "collector.yaml": `processors: -receivers: + "collector.yaml": `receivers: jaeger: protocols: grpc: @@ -68,8 +67,10 @@ service: assert.NoError(t, err) assert.Equal(t, "test-collector", actual.Name) assert.Equal(t, expectedLables, actual.Labels) - assert.Equal(t, expectedData, actual.Data) - + assert.Equal(t, len(expectedData), len(actual.Data)) + for k, expected := range expectedData { + assert.YAMLEq(t, expected, actual.Data[k]) + } }) t.Run("should return expected collector config map with http_sd_config if rewrite flag disabled", func(t *testing.T) { @@ -83,8 +84,7 @@ service: expectedData := map[string]string{ "collector.yaml": `exporters: - debug: null -processors: null + debug: receivers: jaeger: protocols: @@ -115,7 +115,10 @@ service: assert.NoError(t, err) assert.Equal(t, "test-collector", actual.GetName()) assert.Equal(t, expectedLables, actual.GetLabels()) - assert.Equal(t, expectedData, actual.Data) + assert.Equal(t, len(expectedData), len(actual.Data)) + for k, expected := range expectedData { + assert.YAMLEq(t, expected, actual.Data[k]) + } }) @@ -132,8 +135,7 @@ service: expectedData := map[string]string{ "collector.yaml": `exporters: - debug: null -processors: null + debug: receivers: prometheus: config: @@ -166,7 +168,10 @@ service: assert.NoError(t, err) assert.Equal(t, "test-collector", actual.Name) assert.Equal(t, expectedLables, actual.Labels) - assert.Equal(t, expectedData, actual.Data) + assert.Equal(t, len(expectedData), len(actual.Data)) + for k, expected := range expectedData { + assert.YAMLEq(t, expected, actual.Data[k]) + } // Reset the value expectedLables["app.kubernetes.io/version"] = "0.47.0" @@ -180,8 +185,7 @@ service: expectedData := map[string]string{ "collector.yaml": `exporters: - debug: null -processors: null + debug: receivers: prometheus: config: {} @@ -208,7 +212,10 @@ service: assert.NoError(t, err) assert.Equal(t, "test-collector", actual.Name) assert.Equal(t, expectedLables, actual.Labels) - assert.Equal(t, expectedData, actual.Data) + assert.Equal(t, len(expectedData), len(actual.Data)) + for k, expected := range expectedData { + assert.YAMLEq(t, expected, actual.Data[k]) + } // Reset the value expectedLables["app.kubernetes.io/version"] = "0.47.0" diff --git a/internal/manifests/collector/container.go b/internal/manifests/collector/container.go index e347d0ce56..00f6e2ee2b 100644 --- a/internal/manifests/collector/container.go +++ b/internal/manifests/collector/container.go @@ -25,7 +25,7 @@ import ( corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/util/validation" - "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1" + "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha2" "github.com/open-telemetry/opentelemetry-operator/internal/config" "github.com/open-telemetry/opentelemetry-operator/internal/manifests/collector/adapters" "github.com/open-telemetry/opentelemetry-operator/internal/naming" @@ -36,14 +36,20 @@ import ( const maxPortLen = 15 // Container builds a container for the given collector. -func Container(cfg config.Config, logger logr.Logger, otelcol v1alpha1.OpenTelemetryCollector, addConfig bool) corev1.Container { +func Container(cfg config.Config, logger logr.Logger, otelcol v1alpha2.OpenTelemetryCollector, addConfig bool) corev1.Container { image := otelcol.Spec.Image if len(image) == 0 { image = cfg.CollectorImage() } + configYaml, err := otelcol.Spec.Config.Yaml() + if err != nil { + logger.Error(err, "could not convert json to yaml") + return corev1.Container{} + } + // build container ports from service ports - ports, err := getConfigContainerPorts(logger, otelcol.Spec.Config) + ports, err := getConfigContainerPorts(logger, configYaml) if err != nil { logger.Error(err, "container ports config") } @@ -133,7 +139,7 @@ func Container(cfg config.Config, logger logr.Logger, otelcol v1alpha1.OpenTelem } var livenessProbe *corev1.Probe - if configFromString, err := adapters.ConfigFromString(otelcol.Spec.Config); err == nil { + if configFromString, err := adapters.ConfigFromString(configYaml); err == nil { if probe, err := getLivenessProbe(configFromString, otelcol.Spec.LivenessProbe); err == nil { livenessProbe = probe } else if errors.Is(err, adapters.ErrNoServiceExtensions) { @@ -220,7 +226,7 @@ func portMapToList(portMap map[string]corev1.ContainerPort) []corev1.ContainerPo return ports } -func getLivenessProbe(config map[interface{}]interface{}, probeConfig *v1alpha1.Probe) (*corev1.Probe, error) { +func getLivenessProbe(config map[interface{}]interface{}, probeConfig *v1alpha2.Probe) (*corev1.Probe, error) { probe, err := adapters.ConfigToContainerProbe(config) if err != nil { return nil, err diff --git a/internal/manifests/collector/container_test.go b/internal/manifests/collector/container_test.go index 5857798f2c..6536d81f2b 100644 --- a/internal/manifests/collector/container_test.go +++ b/internal/manifests/collector/container_test.go @@ -20,11 +20,13 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "gopkg.in/yaml.v3" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" logf "sigs.k8s.io/controller-runtime/pkg/log" "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1" + "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha2" "github.com/open-telemetry/opentelemetry-operator/internal/config" . "github.com/open-telemetry/opentelemetry-operator/internal/manifests/collector" ) @@ -40,28 +42,29 @@ var metricContainerPort = corev1.ContainerPort{ func TestContainerNewDefault(t *testing.T) { // prepare var defaultConfig = `receivers: - otlp: - protocols: - http: - grpc: - exporters: - debug: - service: - pipelines: - metrics: - receivers: [otlp] - exporters: [debug]` - - otelcol := v1alpha1.OpenTelemetryCollector{ - Spec: v1alpha1.OpenTelemetryCollectorSpec{ - Ports: []corev1.ServicePort{ - { - Name: "metrics", - Port: 8888, - Protocol: corev1.ProtocolTCP, + otlp: + protocols: + http: + grpc: + exporters: + debug: + service: + pipelines: + metrics: + receivers: [otlp] + exporters: [debug]` + otelcol := v1alpha2.OpenTelemetryCollector{ + Spec: v1alpha2.OpenTelemetryCollectorSpec{ + OpenTelemetryCommonFields: v1alpha2.OpenTelemetryCommonFields{ + Ports: []corev1.ServicePort{ + { + Name: "metrics", + Port: 8888, + Protocol: corev1.ProtocolTCP, + }, }, }, - Config: defaultConfig, + Config: mustUnmarshalToConfig(t, defaultConfig), }, } cfg := config.New(config.WithCollectorImage("default-image")) @@ -76,9 +79,11 @@ func TestContainerNewDefault(t *testing.T) { func TestContainerWithImageOverridden(t *testing.T) { // prepare - otelcol := v1alpha1.OpenTelemetryCollector{ - Spec: v1alpha1.OpenTelemetryCollectorSpec{ - Image: "overridden-image", + otelcol := v1alpha2.OpenTelemetryCollector{ + Spec: v1alpha2.OpenTelemetryCollectorSpec{ + OpenTelemetryCommonFields: v1alpha2.OpenTelemetryCommonFields{ + Image: "overridden-image", + }, }, } cfg := config.New(config.WithCollectorImage("default-image")) @@ -108,12 +113,6 @@ service: specPorts []corev1.ServicePort expectedPorts []corev1.ContainerPort }{ - { - description: "bad spec config", - specConfig: "🦄", - specPorts: nil, - expectedPorts: []corev1.ContainerPort{}, - }, { description: "couldn't build ports from spec config", specConfig: "", @@ -220,11 +219,11 @@ service: specConfig: `exporters: prometheus: endpoint: "0.0.0.0:9090" - debug: + debug: service: pipelines: metrics: - receivers: [otlp] + receivers: [otlp] exporters: [prometheus, debug] `, specPorts: []corev1.ServicePort{ @@ -257,7 +256,7 @@ service: endpoint: "0.0.0.0:9090" prometheus/dev: endpoint: "0.0.0.0:9091" - debug: + debug: service: pipelines: metrics: @@ -306,18 +305,19 @@ service: }, { description: "multiple prometheus exporters and prometheus RW exporter", - specConfig: `exporters: - prometheus/prod: - endpoint: "0.0.0.0:9090" - prometheus/dev: - endpoint: "0.0.0.0:9091" - prometheusremotewrite/prometheus: - endpoint: http://prometheus-server.monitoring/api/v1/write - debug: + specConfig: `--- +exporters: + prometheus/prod: + endpoint: "0.0.0.0:9090" + prometheus/dev: + endpoint: "0.0.0.0:9091" + prometheusremotewrite/prometheus: + endpoint: "http://prometheus-server.monitoring/api/v1/write" + debug: service: - pipelines: - metrics: - exporters: [prometheus/prod, prometheus/dev, prometheusremotewrite/prometheus, debug]`, + pipelines: + metrics: + exporters: [prometheus/prod, prometheus/dev, prometheusremotewrite/prometheus, debug]`, specPorts: []corev1.ServicePort{ { Name: "metrics", @@ -350,10 +350,12 @@ service: for _, testCase := range tests { t.Run(testCase.description, func(t *testing.T) { // prepare - otelcol := v1alpha1.OpenTelemetryCollector{ - Spec: v1alpha1.OpenTelemetryCollectorSpec{ - Config: testCase.specConfig, - Ports: testCase.specPorts, + otelcol := v1alpha2.OpenTelemetryCollector{ + Spec: v1alpha2.OpenTelemetryCollectorSpec{ + Config: mustUnmarshalToConfig(t, testCase.specConfig), + OpenTelemetryCommonFields: v1alpha2.OpenTelemetryCommonFields{ + Ports: testCase.specPorts, + }, }, } @@ -369,11 +371,13 @@ service: func TestContainerConfigFlagIsIgnored(t *testing.T) { // prepare - otelcol := v1alpha1.OpenTelemetryCollector{ - Spec: v1alpha1.OpenTelemetryCollectorSpec{ - Args: map[string]string{ - "key": "value", - "config": "/some-custom-file.yaml", + otelcol := v1alpha2.OpenTelemetryCollector{ + Spec: v1alpha2.OpenTelemetryCollectorSpec{ + OpenTelemetryCommonFields: v1alpha2.OpenTelemetryCommonFields{ + Args: map[string]string{ + "key": "value", + "config": "/some-custom-file.yaml", + }, }, }, } @@ -390,11 +394,13 @@ func TestContainerConfigFlagIsIgnored(t *testing.T) { func TestContainerCustomVolumes(t *testing.T) { // prepare - otelcol := v1alpha1.OpenTelemetryCollector{ - Spec: v1alpha1.OpenTelemetryCollectorSpec{ - VolumeMounts: []corev1.VolumeMount{{ - Name: "custom-volume-mount", - }}, + otelcol := v1alpha2.OpenTelemetryCollector{ + Spec: v1alpha2.OpenTelemetryCollectorSpec{ + OpenTelemetryCommonFields: v1alpha2.OpenTelemetryCommonFields{ + VolumeMounts: []corev1.VolumeMount{{ + Name: "custom-volume-mount", + }}, + }, }, } cfg := config.New() @@ -409,8 +415,8 @@ func TestContainerCustomVolumes(t *testing.T) { func TestContainerCustomConfigMapsVolumes(t *testing.T) { // prepare - otelcol := v1alpha1.OpenTelemetryCollector{ - Spec: v1alpha1.OpenTelemetryCollectorSpec{ + otelcol := v1alpha2.OpenTelemetryCollector{ + Spec: v1alpha2.OpenTelemetryCollectorSpec{ ConfigMaps: []v1alpha1.ConfigMapsSpec{{ Name: "test", MountPath: "/", @@ -435,7 +441,7 @@ func TestContainerCustomConfigMapsVolumes(t *testing.T) { func TestContainerCustomSecurityContext(t *testing.T) { // default config without security context - c1 := Container(config.New(), logger, v1alpha1.OpenTelemetryCollector{Spec: v1alpha1.OpenTelemetryCollectorSpec{}}, true) + c1 := Container(config.New(), logger, v1alpha2.OpenTelemetryCollector{Spec: v1alpha2.OpenTelemetryCollectorSpec{}}, true) // verify assert.Nil(t, c1.SecurityContext) @@ -445,11 +451,14 @@ func TestContainerCustomSecurityContext(t *testing.T) { uid := int64(1234) // test - c2 := Container(config.New(), logger, v1alpha1.OpenTelemetryCollector{ - Spec: v1alpha1.OpenTelemetryCollectorSpec{ - SecurityContext: &corev1.SecurityContext{ - Privileged: &isPrivileged, - RunAsUser: &uid, + c2 := Container(config.New(), logger, v1alpha2.OpenTelemetryCollector{ + Spec: v1alpha2.OpenTelemetryCollectorSpec{ + OpenTelemetryCommonFields: v1alpha2.OpenTelemetryCommonFields{ + + SecurityContext: &corev1.SecurityContext{ + Privileged: &isPrivileged, + RunAsUser: &uid, + }, }, }, }, true) @@ -461,12 +470,14 @@ func TestContainerCustomSecurityContext(t *testing.T) { } func TestContainerEnvVarsOverridden(t *testing.T) { - otelcol := v1alpha1.OpenTelemetryCollector{ - Spec: v1alpha1.OpenTelemetryCollectorSpec{ - Env: []corev1.EnvVar{ - { - Name: "foo", - Value: "bar", + otelcol := v1alpha2.OpenTelemetryCollector{ + Spec: v1alpha2.OpenTelemetryCollectorSpec{ + OpenTelemetryCommonFields: v1alpha2.OpenTelemetryCommonFields{ + Env: []corev1.EnvVar{ + { + Name: "foo", + Value: "bar", + }, }, }, }, @@ -484,8 +495,8 @@ func TestContainerEnvVarsOverridden(t *testing.T) { } func TestContainerDefaultEnvVars(t *testing.T) { - otelcol := v1alpha1.OpenTelemetryCollector{ - Spec: v1alpha1.OpenTelemetryCollectorSpec{}, + otelcol := v1alpha2.OpenTelemetryCollector{ + Spec: v1alpha2.OpenTelemetryCollectorSpec{}, } cfg := config.New() @@ -502,8 +513,8 @@ func TestContainerProxyEnvVars(t *testing.T) { err := os.Setenv("NO_PROXY", "localhost") require.NoError(t, err) defer os.Unsetenv("NO_PROXY") - otelcol := v1alpha1.OpenTelemetryCollector{ - Spec: v1alpha1.OpenTelemetryCollectorSpec{}, + otelcol := v1alpha2.OpenTelemetryCollector{ + Spec: v1alpha2.OpenTelemetryCollectorSpec{}, } cfg := config.New() @@ -519,16 +530,18 @@ func TestContainerProxyEnvVars(t *testing.T) { } func TestContainerResourceRequirements(t *testing.T) { - otelcol := v1alpha1.OpenTelemetryCollector{ - Spec: v1alpha1.OpenTelemetryCollectorSpec{ - Resources: corev1.ResourceRequirements{ - Limits: corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("100m"), - corev1.ResourceMemory: resource.MustParse("128M"), - }, - Requests: corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("200m"), - corev1.ResourceMemory: resource.MustParse("256M"), + otelcol := v1alpha2.OpenTelemetryCollector{ + Spec: v1alpha2.OpenTelemetryCollectorSpec{ + OpenTelemetryCommonFields: v1alpha2.OpenTelemetryCommonFields{ + Resources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("100m"), + corev1.ResourceMemory: resource.MustParse("128M"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("200m"), + corev1.ResourceMemory: resource.MustParse("256M"), + }, }, }, }, @@ -547,8 +560,8 @@ func TestContainerResourceRequirements(t *testing.T) { } func TestContainerDefaultResourceRequirements(t *testing.T) { - otelcol := v1alpha1.OpenTelemetryCollector{ - Spec: v1alpha1.OpenTelemetryCollectorSpec{}, + otelcol := v1alpha2.OpenTelemetryCollector{ + Spec: v1alpha2.OpenTelemetryCollectorSpec{}, } cfg := config.New() @@ -562,11 +575,13 @@ func TestContainerDefaultResourceRequirements(t *testing.T) { func TestContainerArgs(t *testing.T) { // prepare - otelcol := v1alpha1.OpenTelemetryCollector{ - Spec: v1alpha1.OpenTelemetryCollectorSpec{ - Args: map[string]string{ - "metrics-level": "detailed", - "log-level": "debug", + otelcol := v1alpha2.OpenTelemetryCollector{ + Spec: v1alpha2.OpenTelemetryCollectorSpec{ + OpenTelemetryCommonFields: v1alpha2.OpenTelemetryCommonFields{ + Args: map[string]string{ + "metrics-level": "detailed", + "log-level": "debug", + }, }, }, } @@ -582,11 +597,13 @@ func TestContainerArgs(t *testing.T) { func TestContainerOrderedArgs(t *testing.T) { // prepare a scenario where the debug level and a feature gate has been enabled - otelcol := v1alpha1.OpenTelemetryCollector{ - Spec: v1alpha1.OpenTelemetryCollectorSpec{ - Args: map[string]string{ - "log-level": "debug", - "feature-gates": "+random-feature", + otelcol := v1alpha2.OpenTelemetryCollector{ + Spec: v1alpha2.OpenTelemetryCollectorSpec{ + OpenTelemetryCommonFields: v1alpha2.OpenTelemetryCommonFields{ + Args: map[string]string{ + "log-level": "debug", + "feature-gates": "+random-feature", + }, }, }, } @@ -604,9 +621,11 @@ func TestContainerOrderedArgs(t *testing.T) { func TestContainerImagePullPolicy(t *testing.T) { // prepare - otelcol := v1alpha1.OpenTelemetryCollector{ - Spec: v1alpha1.OpenTelemetryCollectorSpec{ - ImagePullPolicy: corev1.PullIfNotPresent, + otelcol := v1alpha2.OpenTelemetryCollector{ + Spec: v1alpha2.OpenTelemetryCollectorSpec{ + OpenTelemetryCommonFields: v1alpha2.OpenTelemetryCommonFields{ + ImagePullPolicy: corev1.PullIfNotPresent, + }, }, } cfg := config.New() @@ -634,11 +653,13 @@ func TestContainerEnvFrom(t *testing.T) { }, }, } - otelcol := v1alpha1.OpenTelemetryCollector{ - Spec: v1alpha1.OpenTelemetryCollectorSpec{ - EnvFrom: []corev1.EnvFromSource{ - envFrom1, - envFrom2, + otelcol := v1alpha2.OpenTelemetryCollector{ + Spec: v1alpha2.OpenTelemetryCollectorSpec{ + OpenTelemetryCommonFields: v1alpha2.OpenTelemetryCommonFields{ + EnvFrom: []corev1.EnvFromSource{ + envFrom1, + envFrom2, + }, }, }, } @@ -660,13 +681,13 @@ func TestContainerProbe(t *testing.T) { successThreshold := int32(13) failureThreshold := int32(14) terminationGracePeriodSeconds := int64(15) - otelcol := v1alpha1.OpenTelemetryCollector{ - Spec: v1alpha1.OpenTelemetryCollectorSpec{ - Config: `extensions: + otelcol := v1alpha2.OpenTelemetryCollector{ + Spec: v1alpha2.OpenTelemetryCollectorSpec{ + Config: mustUnmarshalToConfig(t, `extensions: health_check: service: - extensions: [health_check]`, - LivenessProbe: &v1alpha1.Probe{ + extensions: [health_check]`), + LivenessProbe: &v1alpha2.Probe{ InitialDelaySeconds: &initialDelaySeconds, TimeoutSeconds: &timeoutSeconds, PeriodSeconds: &periodSeconds, @@ -697,13 +718,13 @@ service: func TestContainerProbeEmptyConfig(t *testing.T) { // prepare - otelcol := v1alpha1.OpenTelemetryCollector{ - Spec: v1alpha1.OpenTelemetryCollectorSpec{ - Config: `extensions: + otelcol := v1alpha2.OpenTelemetryCollector{ + Spec: v1alpha2.OpenTelemetryCollectorSpec{ + Config: mustUnmarshalToConfig(t, `extensions: health_check: service: - extensions: [health_check]`, - LivenessProbe: &v1alpha1.Probe{}, + extensions: [health_check]`), + LivenessProbe: &v1alpha2.Probe{}, }, } cfg := config.New() @@ -719,13 +740,12 @@ service: func TestContainerProbeNoConfig(t *testing.T) { // prepare - - otelcol := v1alpha1.OpenTelemetryCollector{ - Spec: v1alpha1.OpenTelemetryCollectorSpec{ - Config: `extensions: + otelcol := v1alpha2.OpenTelemetryCollector{ + Spec: v1alpha2.OpenTelemetryCollectorSpec{ + Config: mustUnmarshalToConfig(t, `extensions: health_check: service: - extensions: [health_check]`, + extensions: [health_check]`), }, } cfg := config.New() @@ -741,14 +761,16 @@ service: func TestContainerLifecycle(t *testing.T) { // prepare - otelcol := v1alpha1.OpenTelemetryCollector{ - Spec: v1alpha1.OpenTelemetryCollectorSpec{ - Lifecycle: &corev1.Lifecycle{ - PostStart: &corev1.LifecycleHandler{ - Exec: &corev1.ExecAction{Command: []string{"sh", "sleep 100"}}, - }, - PreStop: &corev1.LifecycleHandler{ - Exec: &corev1.ExecAction{Command: []string{"sh", "sleep 300"}}, + otelcol := v1alpha2.OpenTelemetryCollector{ + Spec: v1alpha2.OpenTelemetryCollectorSpec{ + OpenTelemetryCommonFields: v1alpha2.OpenTelemetryCommonFields{ + Lifecycle: &corev1.Lifecycle{ + PostStart: &corev1.LifecycleHandler{ + Exec: &corev1.ExecAction{Command: []string{"sh", "sleep 100"}}, + }, + PreStop: &corev1.LifecycleHandler{ + Exec: &corev1.ExecAction{Command: []string{"sh", "sleep 300"}}, + }, }, }, }, @@ -770,3 +792,11 @@ func TestContainerLifecycle(t *testing.T) { // verify assert.Equal(t, expectedLifecycleHooks, *c.Lifecycle) } + +func mustUnmarshalToConfig(t *testing.T, config string) v1alpha2.Config { + cfg := v1alpha2.Config{} + if err := yaml.Unmarshal([]byte(config), &cfg); err != nil { + t.Fatal(err) + } + return cfg +} diff --git a/internal/manifests/collector/daemonset.go b/internal/manifests/collector/daemonset.go index e92a265b32..0f79c80d6a 100644 --- a/internal/manifests/collector/daemonset.go +++ b/internal/manifests/collector/daemonset.go @@ -19,28 +19,40 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "github.com/open-telemetry/opentelemetry-operator/internal/api/convert" "github.com/open-telemetry/opentelemetry-operator/internal/manifests" "github.com/open-telemetry/opentelemetry-operator/internal/manifests/manifestutils" "github.com/open-telemetry/opentelemetry-operator/internal/naming" ) // DaemonSet builds the deployment for the given instance. -func DaemonSet(params manifests.Params) *appsv1.DaemonSet { - name := naming.Collector(params.OtelCol.Name) - labels := manifestutils.Labels(params.OtelCol.ObjectMeta, name, params.OtelCol.Spec.Image, ComponentOpenTelemetryCollector, params.Config.LabelsFilter()) +func DaemonSet(params manifests.Params) (*appsv1.DaemonSet, error) { + otelCol, err := convert.V1Alpha1to2(params.OtelCol) + if err != nil { + return nil, err + } + name := naming.Collector(otelCol.Name) + labels := manifestutils.Labels(otelCol.ObjectMeta, name, otelCol.Spec.Image, ComponentOpenTelemetryCollector, params.Config.LabelsFilter()) + + annotations, err := Annotations(otelCol) + if err != nil { + return nil, err + } + podAnnotations, err := PodAnnotations(otelCol) + if err != nil { + return nil, err + } - annotations := Annotations(params.OtelCol) - podAnnotations := PodAnnotations(params.OtelCol) return &appsv1.DaemonSet{ ObjectMeta: metav1.ObjectMeta{ - Name: naming.Collector(params.OtelCol.Name), - Namespace: params.OtelCol.Namespace, + Name: naming.Collector(otelCol.Name), + Namespace: otelCol.Namespace, Labels: labels, Annotations: annotations, }, Spec: appsv1.DaemonSetSpec{ Selector: &metav1.LabelSelector{ - MatchLabels: manifestutils.SelectorLabels(params.OtelCol.ObjectMeta, ComponentOpenTelemetryCollector), + MatchLabels: manifestutils.SelectorLabels(otelCol.ObjectMeta, ComponentOpenTelemetryCollector), }, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ @@ -48,15 +60,15 @@ func DaemonSet(params manifests.Params) *appsv1.DaemonSet { Annotations: podAnnotations, }, Spec: corev1.PodSpec{ - ServiceAccountName: ServiceAccountName(params.OtelCol), + ServiceAccountName: ServiceAccountName(otelCol), InitContainers: params.OtelCol.Spec.InitContainers, - Containers: append(params.OtelCol.Spec.AdditionalContainers, Container(params.Config, params.Log, params.OtelCol, true)), - Volumes: Volumes(params.Config, params.OtelCol), - Tolerations: params.OtelCol.Spec.Tolerations, - NodeSelector: params.OtelCol.Spec.NodeSelector, - HostNetwork: params.OtelCol.Spec.HostNetwork, - ShareProcessNamespace: ¶ms.OtelCol.Spec.ShareProcessNamespace, - DNSPolicy: getDNSPolicy(params.OtelCol), + Containers: append(params.OtelCol.Spec.AdditionalContainers, Container(params.Config, params.Log, otelCol, true)), + Volumes: Volumes(params.Config, otelCol), + Tolerations: otelCol.Spec.Tolerations, + NodeSelector: otelCol.Spec.NodeSelector, + HostNetwork: otelCol.Spec.HostNetwork, + ShareProcessNamespace: &otelCol.Spec.ShareProcessNamespace, + DNSPolicy: getDNSPolicy(otelCol), SecurityContext: params.OtelCol.Spec.PodSecurityContext, PriorityClassName: params.OtelCol.Spec.PriorityClassName, Affinity: params.OtelCol.Spec.Affinity, @@ -64,5 +76,5 @@ func DaemonSet(params manifests.Params) *appsv1.DaemonSet { }, UpdateStrategy: params.OtelCol.Spec.UpdateStrategy, }, - } + }, nil } diff --git a/internal/manifests/collector/daemonset_test.go b/internal/manifests/collector/daemonset_test.go index 5caa9b6418..53acfb0b79 100644 --- a/internal/manifests/collector/daemonset_test.go +++ b/internal/manifests/collector/daemonset_test.go @@ -18,6 +18,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" appsv1 "k8s.io/api/apps/v1" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -46,7 +47,8 @@ func TestDaemonSetNewDefault(t *testing.T) { } // test - d := DaemonSet(params) + d, err := DaemonSet(params) + require.NoError(t, err) // verify assert.Equal(t, "my-instance-collector", d.Name) @@ -60,7 +62,7 @@ func TestDaemonSetNewDefault(t *testing.T) { // verify sha256 podAnnotation expectedAnnotations := map[string]string{ - "opentelemetry-operator-config/sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "opentelemetry-operator-config/sha256": "fbcdae6a02b2115cd5ca4f34298202ab041d1dfe62edebfaadb48b1ee178231d", "prometheus.io/path": "/metrics", "prometheus.io/port": "8888", "prometheus.io/scrape": "true", @@ -104,7 +106,8 @@ func TestDaemonsetHostNetwork(t *testing.T) { Log: logger, } // test - d1 := DaemonSet(params1) + d1, err := DaemonSet(params1) + require.NoError(t, err) assert.False(t, d1.Spec.Template.Spec.HostNetwork) assert.Equal(t, d1.Spec.Template.Spec.DNSPolicy, v1.DNSClusterFirst) @@ -122,7 +125,8 @@ func TestDaemonsetHostNetwork(t *testing.T) { }, Log: logger, } - d2 := DaemonSet(params2) + d2, err := DaemonSet(params2) + require.NoError(t, err) assert.True(t, d2.Spec.Template.Spec.HostNetwork) assert.Equal(t, d2.Spec.Template.Spec.DNSPolicy, v1.DNSClusterFirstWithHostNet) } @@ -147,14 +151,15 @@ func TestDaemonsetPodAnnotations(t *testing.T) { } // test - ds := DaemonSet(params) + ds, err := DaemonSet(params) + require.NoError(t, err) // Add sha256 podAnnotation - testPodAnnotationValues["opentelemetry-operator-config/sha256"] = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + testPodAnnotationValues["opentelemetry-operator-config/sha256"] = "fbcdae6a02b2115cd5ca4f34298202ab041d1dfe62edebfaadb48b1ee178231d" expectedAnnotations := map[string]string{ "annotation-key": "annotation-value", - "opentelemetry-operator-config/sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "opentelemetry-operator-config/sha256": "fbcdae6a02b2115cd5ca4f34298202ab041d1dfe62edebfaadb48b1ee178231d", "prometheus.io/path": "/metrics", "prometheus.io/port": "8888", "prometheus.io/scrape": "true", @@ -192,7 +197,8 @@ func TestDaemonstPodSecurityContext(t *testing.T) { Log: logger, } - d := DaemonSet(params) + d, err := DaemonSet(params) + require.NoError(t, err) assert.Equal(t, &runAsNonRoot, d.Spec.Template.Spec.SecurityContext.RunAsNonRoot) assert.Equal(t, &runAsUser, d.Spec.Template.Spec.SecurityContext.RunAsUser) @@ -221,7 +227,8 @@ func TestDaemonsetFilterLabels(t *testing.T) { Log: logger, } - d := DaemonSet(params) + d, err := DaemonSet(params) + require.NoError(t, err) assert.Len(t, d.ObjectMeta.Labels, 6) for k := range excludedLabels { @@ -245,7 +252,8 @@ func TestDaemonSetNodeSelector(t *testing.T) { Log: logger, } - d1 := DaemonSet(params1) + d1, err := DaemonSet(params1) + require.NoError(t, err) assert.Empty(t, d1.Spec.Template.Spec.NodeSelector) @@ -270,7 +278,8 @@ func TestDaemonSetNodeSelector(t *testing.T) { Log: logger, } - d2 := DaemonSet(params2) + d2, err := DaemonSet(params2) + require.NoError(t, err) assert.Equal(t, d2.Spec.Template.Spec.NodeSelector, map[string]string{"node-key": "node-value"}) } @@ -289,7 +298,8 @@ func TestDaemonSetPriorityClassName(t *testing.T) { Log: logger, } - d1 := DaemonSet(params1) + d1, err := DaemonSet(params1) + require.NoError(t, err) assert.Empty(t, d1.Spec.Template.Spec.PriorityClassName) priorityClassName := "test-class" @@ -311,7 +321,8 @@ func TestDaemonSetPriorityClassName(t *testing.T) { Log: logger, } - d2 := DaemonSet(params2) + d2, err := DaemonSet(params2) + require.NoError(t, err) assert.Equal(t, priorityClassName, d2.Spec.Template.Spec.PriorityClassName) } @@ -330,7 +341,8 @@ func TestDaemonSetAffinity(t *testing.T) { Log: logger, } - d1 := DaemonSet(params1) + d1, err := DaemonSet(params1) + require.NoError(t, err) assert.Nil(t, d1.Spec.Template.Spec.Affinity) otelcol2 := v1alpha1.OpenTelemetryCollector{ @@ -350,7 +362,8 @@ func TestDaemonSetAffinity(t *testing.T) { Log: logger, } - d2 := DaemonSet(params2) + d2, err := DaemonSet(params2) + require.NoError(t, err) assert.NotNil(t, d2.Spec.Template.Spec.Affinity) assert.Equal(t, *testAffinityValue, *d2.Spec.Template.Spec.Affinity) } @@ -379,7 +392,8 @@ func TestDaemonSetInitContainer(t *testing.T) { } // test - d := DaemonSet(params) + d, err := DaemonSet(params) + require.NoError(t, err) assert.Equal(t, "my-instance-collector", d.Name) assert.Equal(t, "my-instance-collector", d.Labels["app.kubernetes.io/name"]) assert.Equal(t, "true", d.Annotations["prometheus.io/scrape"]) @@ -412,7 +426,8 @@ func TestDaemonSetAdditionalContainer(t *testing.T) { } // test - d := DaemonSet(params) + d, err := DaemonSet(params) + require.NoError(t, err) assert.Equal(t, "my-instance-collector", d.Name) assert.Equal(t, "my-instance-collector", d.Labels["app.kubernetes.io/name"]) assert.Equal(t, "true", d.Annotations["prometheus.io/scrape"]) @@ -448,7 +463,8 @@ func TestDaemonSetDefaultUpdateStrategy(t *testing.T) { } // test - d := DaemonSet(params) + d, err := DaemonSet(params) + require.NoError(t, err) assert.Equal(t, "my-instance-collector", d.Name) assert.Equal(t, "my-instance-collector", d.Labels["app.kubernetes.io/name"]) assert.Equal(t, appsv1.DaemonSetUpdateStrategyType("RollingUpdate"), d.Spec.UpdateStrategy.Type) @@ -482,7 +498,8 @@ func TestDaemonSetOnDeleteUpdateStrategy(t *testing.T) { } // test - d := DaemonSet(params) + d, err := DaemonSet(params) + require.NoError(t, err) assert.Equal(t, "my-instance-collector", d.Name) assert.Equal(t, "my-instance-collector", d.Labels["app.kubernetes.io/name"]) assert.Equal(t, appsv1.DaemonSetUpdateStrategyType("OnDelete"), d.Spec.UpdateStrategy.Type) @@ -502,7 +519,8 @@ func TestDaemonsetShareProcessNamespace(t *testing.T) { Log: logger, } // test - d1 := DaemonSet(params1) + d1, err := DaemonSet(params1) + require.NoError(t, err) assert.False(t, *d1.Spec.Template.Spec.ShareProcessNamespace) // verify custom @@ -518,6 +536,7 @@ func TestDaemonsetShareProcessNamespace(t *testing.T) { }, Log: logger, } - d2 := DaemonSet(params2) + d2, err := DaemonSet(params2) + require.NoError(t, err) assert.True(t, *d2.Spec.Template.Spec.ShareProcessNamespace) } diff --git a/internal/manifests/collector/deployment.go b/internal/manifests/collector/deployment.go index 5bc2dd964f..a960d3ec11 100644 --- a/internal/manifests/collector/deployment.go +++ b/internal/manifests/collector/deployment.go @@ -19,54 +19,66 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "github.com/open-telemetry/opentelemetry-operator/internal/api/convert" "github.com/open-telemetry/opentelemetry-operator/internal/manifests" "github.com/open-telemetry/opentelemetry-operator/internal/manifests/manifestutils" "github.com/open-telemetry/opentelemetry-operator/internal/naming" ) // Deployment builds the deployment for the given instance. -func Deployment(params manifests.Params) *appsv1.Deployment { - name := naming.Collector(params.OtelCol.Name) - labels := manifestutils.Labels(params.OtelCol.ObjectMeta, name, params.OtelCol.Spec.Image, ComponentOpenTelemetryCollector, params.Config.LabelsFilter()) +func Deployment(params manifests.Params) (*appsv1.Deployment, error) { + otelCol, err := convert.V1Alpha1to2(params.OtelCol) + if err != nil { + return nil, err + } + name := naming.Collector(otelCol.Name) + labels := manifestutils.Labels(otelCol.ObjectMeta, name, otelCol.Spec.Image, ComponentOpenTelemetryCollector, params.Config.LabelsFilter()) - annotations := Annotations(params.OtelCol) - podAnnotations := PodAnnotations(params.OtelCol) + annotations, err := Annotations(otelCol) + if err != nil { + return nil, err + } + + podAnnotations, err := PodAnnotations(otelCol) + if err != nil { + return nil, err + } return &appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ Name: name, - Namespace: params.OtelCol.Namespace, + Namespace: otelCol.Namespace, Labels: labels, Annotations: annotations, }, Spec: appsv1.DeploymentSpec{ - Replicas: params.OtelCol.Spec.Replicas, + Replicas: otelCol.Spec.Replicas, Selector: &metav1.LabelSelector{ - MatchLabels: manifestutils.SelectorLabels(params.OtelCol.ObjectMeta, ComponentOpenTelemetryCollector), + MatchLabels: manifestutils.SelectorLabels(otelCol.ObjectMeta, ComponentOpenTelemetryCollector), }, - Strategy: params.OtelCol.Spec.DeploymentUpdateStrategy, + Strategy: otelCol.Spec.DeploymentUpdateStrategy, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ Labels: labels, Annotations: podAnnotations, }, Spec: corev1.PodSpec{ - ServiceAccountName: ServiceAccountName(params.OtelCol), - InitContainers: params.OtelCol.Spec.InitContainers, - Containers: append(params.OtelCol.Spec.AdditionalContainers, Container(params.Config, params.Log, params.OtelCol, true)), - Volumes: Volumes(params.Config, params.OtelCol), - DNSPolicy: getDNSPolicy(params.OtelCol), - HostNetwork: params.OtelCol.Spec.HostNetwork, - ShareProcessNamespace: ¶ms.OtelCol.Spec.ShareProcessNamespace, - Tolerations: params.OtelCol.Spec.Tolerations, - NodeSelector: params.OtelCol.Spec.NodeSelector, - SecurityContext: params.OtelCol.Spec.PodSecurityContext, - PriorityClassName: params.OtelCol.Spec.PriorityClassName, - Affinity: params.OtelCol.Spec.Affinity, - TerminationGracePeriodSeconds: params.OtelCol.Spec.TerminationGracePeriodSeconds, - TopologySpreadConstraints: params.OtelCol.Spec.TopologySpreadConstraints, + ServiceAccountName: ServiceAccountName(otelCol), + InitContainers: otelCol.Spec.InitContainers, + Containers: append(otelCol.Spec.AdditionalContainers, Container(params.Config, params.Log, otelCol, true)), + Volumes: Volumes(params.Config, otelCol), + DNSPolicy: getDNSPolicy(otelCol), + HostNetwork: otelCol.Spec.HostNetwork, + ShareProcessNamespace: &otelCol.Spec.ShareProcessNamespace, + Tolerations: otelCol.Spec.Tolerations, + NodeSelector: otelCol.Spec.NodeSelector, + SecurityContext: otelCol.Spec.PodSecurityContext, + PriorityClassName: otelCol.Spec.PriorityClassName, + Affinity: otelCol.Spec.Affinity, + TerminationGracePeriodSeconds: otelCol.Spec.TerminationGracePeriodSeconds, + TopologySpreadConstraints: otelCol.Spec.TopologySpreadConstraints, }, }, }, - } + }, nil } diff --git a/internal/manifests/collector/deployment_test.go b/internal/manifests/collector/deployment_test.go index 2edfa03b14..c254fbcda8 100644 --- a/internal/manifests/collector/deployment_test.go +++ b/internal/manifests/collector/deployment_test.go @@ -18,6 +18,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" appsv1 "k8s.io/api/apps/v1" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -88,7 +89,8 @@ func TestDeploymentNewDefault(t *testing.T) { } // test - d := Deployment(params) + d, err := Deployment(params) + require.NoError(t, err) // verify assert.Equal(t, "my-instance-collector", d.Name) @@ -102,7 +104,7 @@ func TestDeploymentNewDefault(t *testing.T) { // verify sha256 podAnnotation expectedAnnotations := map[string]string{ - "opentelemetry-operator-config/sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "opentelemetry-operator-config/sha256": "fbcdae6a02b2115cd5ca4f34298202ab041d1dfe62edebfaadb48b1ee178231d", "prometheus.io/path": "/metrics", "prometheus.io/port": "8888", "prometheus.io/scrape": "true", @@ -153,14 +155,15 @@ func TestDeploymentPodAnnotations(t *testing.T) { } // test - d := Deployment(params) + d, err := Deployment(params) + require.NoError(t, err) // Add sha256 podAnnotation - testPodAnnotationValues["opentelemetry-operator-config/sha256"] = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + testPodAnnotationValues["opentelemetry-operator-config/sha256"] = "fbcdae6a02b2115cd5ca4f34298202ab041d1dfe62edebfaadb48b1ee178231d" expectedPodAnnotationValues := map[string]string{ "annotation-key": "annotation-value", - "opentelemetry-operator-config/sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "opentelemetry-operator-config/sha256": "fbcdae6a02b2115cd5ca4f34298202ab041d1dfe62edebfaadb48b1ee178231d", "prometheus.io/path": "/metrics", "prometheus.io/port": "8888", "prometheus.io/scrape": "true", @@ -198,7 +201,8 @@ func TestDeploymenttPodSecurityContext(t *testing.T) { Log: logger, } - d := Deployment(params) + d, err := Deployment(params) + require.NoError(t, err) assert.Equal(t, &runAsNonRoot, d.Spec.Template.Spec.SecurityContext.RunAsNonRoot) assert.Equal(t, &runAsUser, d.Spec.Template.Spec.SecurityContext.RunAsUser) @@ -229,7 +233,8 @@ func TestDeploymentUpdateStrategy(t *testing.T) { Log: logger, } - d := Deployment(params) + d, err := Deployment(params) + require.NoError(t, err) assert.Equal(t, "RollingUpdate", string(d.Spec.Strategy.Type)) assert.Equal(t, 1, d.Spec.Strategy.RollingUpdate.MaxSurge.IntValue()) @@ -252,7 +257,8 @@ func TestDeploymentHostNetwork(t *testing.T) { Log: logger, } - d1 := Deployment(params1) + d1, err := Deployment(params1) + require.NoError(t, err) assert.Equal(t, d1.Spec.Template.Spec.HostNetwork, false) assert.Equal(t, d1.Spec.Template.Spec.DNSPolicy, v1.DNSClusterFirst) @@ -275,7 +281,8 @@ func TestDeploymentHostNetwork(t *testing.T) { Log: logger, } - d2 := Deployment(params2) + d2, err := Deployment(params2) + require.NoError(t, err) assert.Equal(t, d2.Spec.Template.Spec.HostNetwork, true) assert.Equal(t, d2.Spec.Template.Spec.DNSPolicy, v1.DNSClusterFirstWithHostNet) } @@ -302,7 +309,8 @@ func TestDeploymentFilterLabels(t *testing.T) { Log: logger, } - d := Deployment(params) + d, err := Deployment(params) + require.NoError(t, err) assert.Len(t, d.ObjectMeta.Labels, 6) for k := range excludedLabels { @@ -326,7 +334,8 @@ func TestDeploymentNodeSelector(t *testing.T) { Log: logger, } - d1 := Deployment(params1) + d1, err := Deployment(params1) + require.NoError(t, err) assert.Empty(t, d1.Spec.Template.Spec.NodeSelector) @@ -351,7 +360,8 @@ func TestDeploymentNodeSelector(t *testing.T) { Log: logger, } - d2 := Deployment(params2) + d2, err := Deployment(params2) + require.NoError(t, err) assert.Equal(t, d2.Spec.Template.Spec.NodeSelector, map[string]string{"node-key": "node-value"}) } @@ -370,7 +380,8 @@ func TestDeploymentPriorityClassName(t *testing.T) { Log: logger, } - d1 := Deployment(params1) + d1, err := Deployment(params1) + require.NoError(t, err) assert.Empty(t, d1.Spec.Template.Spec.PriorityClassName) priorityClassName := "test-class" @@ -392,7 +403,8 @@ func TestDeploymentPriorityClassName(t *testing.T) { Log: logger, } - d2 := Deployment(params2) + d2, err := Deployment(params2) + require.NoError(t, err) assert.Equal(t, priorityClassName, d2.Spec.Template.Spec.PriorityClassName) } @@ -411,7 +423,8 @@ func TestDeploymentAffinity(t *testing.T) { Log: logger, } - d1 := Deployment(params1) + d1, err := Deployment(params1) + require.NoError(t, err) assert.Nil(t, d1.Spec.Template.Spec.Affinity) otelcol2 := v1alpha1.OpenTelemetryCollector{ @@ -431,7 +444,8 @@ func TestDeploymentAffinity(t *testing.T) { Log: logger, } - d2 := Deployment(params2) + d2, err := Deployment(params2) + require.NoError(t, err) assert.NotNil(t, d2.Spec.Template.Spec.Affinity) assert.Equal(t, *testAffinityValue, *d2.Spec.Template.Spec.Affinity) } @@ -451,7 +465,8 @@ func TestDeploymentTerminationGracePeriodSeconds(t *testing.T) { Log: logger, } - d1 := Deployment(params1) + d1, err := Deployment(params1) + require.NoError(t, err) assert.Nil(t, d1.Spec.Template.Spec.TerminationGracePeriodSeconds) gracePeriodSec := int64(60) @@ -473,7 +488,8 @@ func TestDeploymentTerminationGracePeriodSeconds(t *testing.T) { Log: logger, } - d2 := Deployment(params2) + d2, err := Deployment(params2) + require.NoError(t, err) assert.NotNil(t, d2.Spec.Template.Spec.TerminationGracePeriodSeconds) assert.Equal(t, gracePeriodSec, *d2.Spec.Template.Spec.TerminationGracePeriodSeconds) } @@ -502,7 +518,8 @@ func TestDeploymentSetInitContainer(t *testing.T) { } // test - d := Deployment(params) + d, err := Deployment(params) + require.NoError(t, err) assert.Equal(t, "my-instance-collector", d.Name) assert.Equal(t, "my-instance-collector", d.Labels["app.kubernetes.io/name"]) assert.Equal(t, "true", d.Annotations["prometheus.io/scrape"]) @@ -526,7 +543,8 @@ func TestDeploymentTopologySpreadConstraints(t *testing.T) { OtelCol: otelcol1, Log: logger, } - d1 := Deployment(params1) + d1, err := Deployment(params1) + require.NoError(t, err) assert.Equal(t, "my-instance-collector", d1.Name) assert.Empty(t, d1.Spec.Template.Spec.TopologySpreadConstraints) @@ -547,7 +565,8 @@ func TestDeploymentTopologySpreadConstraints(t *testing.T) { OtelCol: otelcol2, Log: logger, } - d2 := Deployment(params2) + d2, err := Deployment(params2) + require.NoError(t, err) assert.Equal(t, "my-instance-topologyspreadconstraint-collector", d2.Name) assert.NotNil(t, d2.Spec.Template.Spec.TopologySpreadConstraints) assert.NotEmpty(t, d2.Spec.Template.Spec.TopologySpreadConstraints) @@ -578,7 +597,8 @@ func TestDeploymentAdditionalContainers(t *testing.T) { } // test - d := Deployment(params) + d, err := Deployment(params) + require.NoError(t, err) assert.Equal(t, "my-instance-collector", d.Name) assert.Equal(t, "my-instance-collector", d.Labels["app.kubernetes.io/name"]) assert.Equal(t, "true", d.Annotations["prometheus.io/scrape"]) @@ -604,7 +624,8 @@ func TestDeploymentShareProcessNamespace(t *testing.T) { Log: logger, } - d1 := Deployment(params1) + d1, err := Deployment(params1) + require.NoError(t, err) assert.False(t, *d1.Spec.Template.Spec.ShareProcessNamespace) // Test hostNetwork=true @@ -625,6 +646,7 @@ func TestDeploymentShareProcessNamespace(t *testing.T) { Log: logger, } - d2 := Deployment(params2) + d2, err := Deployment(params2) + require.NoError(t, err) assert.True(t, *d2.Spec.Template.Spec.ShareProcessNamespace) } diff --git a/internal/manifests/collector/horizontalpodautoscaler.go b/internal/manifests/collector/horizontalpodautoscaler.go index 0a4bdefccd..9b176ebc18 100644 --- a/internal/manifests/collector/horizontalpodautoscaler.go +++ b/internal/manifests/collector/horizontalpodautoscaler.go @@ -21,66 +21,75 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1" + "github.com/open-telemetry/opentelemetry-operator/internal/api/convert" "github.com/open-telemetry/opentelemetry-operator/internal/manifests" "github.com/open-telemetry/opentelemetry-operator/internal/manifests/manifestutils" "github.com/open-telemetry/opentelemetry-operator/internal/naming" ) -func HorizontalPodAutoscaler(params manifests.Params) client.Object { - name := naming.Collector(params.OtelCol.Name) - labels := manifestutils.Labels(params.OtelCol.ObjectMeta, name, params.OtelCol.Spec.Image, ComponentOpenTelemetryCollector, params.Config.LabelsFilter()) - annotations := Annotations(params.OtelCol) +func HorizontalPodAutoscaler(params manifests.Params) (client.Object, error) { + otelCol, err := convert.V1Alpha1to2(params.OtelCol) + if err != nil { + return nil, err + } + name := naming.Collector(otelCol.Name) + labels := manifestutils.Labels(otelCol.ObjectMeta, name, otelCol.Spec.Image, ComponentOpenTelemetryCollector, params.Config.LabelsFilter()) + annotations, err := Annotations(otelCol) + if err != nil { + return nil, err + } + var result client.Object objectMeta := metav1.ObjectMeta{ - Name: naming.HorizontalPodAutoscaler(params.OtelCol.Name), - Namespace: params.OtelCol.Namespace, + Name: naming.HorizontalPodAutoscaler(otelCol.Name), + Namespace: otelCol.Namespace, Labels: labels, Annotations: annotations, } // defaulting webhook should always set this, but if unset then return nil. - if params.OtelCol.Spec.Autoscaler == nil { + if otelCol.Spec.Autoscaler == nil { params.Log.Info("hpa field is unset in Spec, skipping autoscaler creation") - return nil + return nil, nil } - if params.OtelCol.Spec.Autoscaler.MaxReplicas == nil { - params.OtelCol.Spec.Autoscaler.MaxReplicas = params.OtelCol.Spec.MaxReplicas + if otelCol.Spec.OpenTelemetryCommonFields.Autoscaler.MaxReplicas == nil { + otelCol.Spec.OpenTelemetryCommonFields.Autoscaler.MaxReplicas = params.OtelCol.Spec.MaxReplicas } - if params.OtelCol.Spec.Autoscaler.MinReplicas == nil { + if otelCol.Spec.OpenTelemetryCommonFields.Autoscaler.MinReplicas == nil { if params.OtelCol.Spec.MinReplicas != nil { - params.OtelCol.Spec.Autoscaler.MinReplicas = params.OtelCol.Spec.MinReplicas + otelCol.Spec.OpenTelemetryCommonFields.Autoscaler.MinReplicas = params.OtelCol.Spec.MinReplicas } else { - params.OtelCol.Spec.Autoscaler.MinReplicas = params.OtelCol.Spec.Replicas + otelCol.Spec.OpenTelemetryCommonFields.Autoscaler.MinReplicas = params.OtelCol.Spec.Replicas } } metrics := []autoscalingv2.MetricSpec{} - if params.OtelCol.Spec.Autoscaler.TargetMemoryUtilization != nil { + if otelCol.Spec.Autoscaler.TargetMemoryUtilization != nil { memoryTarget := autoscalingv2.MetricSpec{ Type: autoscalingv2.ResourceMetricSourceType, Resource: &autoscalingv2.ResourceMetricSource{ Name: corev1.ResourceMemory, Target: autoscalingv2.MetricTarget{ Type: autoscalingv2.UtilizationMetricType, - AverageUtilization: params.OtelCol.Spec.Autoscaler.TargetMemoryUtilization, + AverageUtilization: otelCol.Spec.Autoscaler.TargetMemoryUtilization, }, }, } metrics = append(metrics, memoryTarget) } - if params.OtelCol.Spec.Autoscaler.TargetCPUUtilization != nil { + if otelCol.Spec.Autoscaler.TargetCPUUtilization != nil { cpuTarget := autoscalingv2.MetricSpec{ Type: autoscalingv2.ResourceMetricSourceType, Resource: &autoscalingv2.ResourceMetricSource{ Name: corev1.ResourceCPU, Target: autoscalingv2.MetricTarget{ Type: autoscalingv2.UtilizationMetricType, - AverageUtilization: params.OtelCol.Spec.Autoscaler.TargetCPUUtilization, + AverageUtilization: otelCol.Spec.Autoscaler.TargetCPUUtilization, }, }, } @@ -93,19 +102,24 @@ func HorizontalPodAutoscaler(params manifests.Params) client.Object { ScaleTargetRef: autoscalingv2.CrossVersionObjectReference{ APIVersion: v1alpha1.GroupVersion.String(), Kind: "OpenTelemetryCollector", - Name: naming.OpenTelemetryCollector(params.OtelCol.Name), + Name: naming.OpenTelemetryCollector(otelCol.Name), }, - MinReplicas: params.OtelCol.Spec.Autoscaler.MinReplicas, - MaxReplicas: *params.OtelCol.Spec.Autoscaler.MaxReplicas, - Metrics: metrics, + MinReplicas: otelCol.Spec.OpenTelemetryCommonFields.Autoscaler.MinReplicas, + MaxReplicas: func(max *int32) int32 { + if max == nil { + return 0 + } + return *max + }(otelCol.Spec.OpenTelemetryCommonFields.Autoscaler.MaxReplicas), + Metrics: metrics, }, } - if params.OtelCol.Spec.Autoscaler.Behavior != nil { - autoscaler.Spec.Behavior = params.OtelCol.Spec.Autoscaler.Behavior + if otelCol.Spec.Autoscaler.Behavior != nil { + autoscaler.Spec.Behavior = otelCol.Spec.Autoscaler.Behavior } // convert from v1alpha1.MetricSpec into a autoscalingv2.MetricSpec. - for _, metric := range params.OtelCol.Spec.Autoscaler.Metrics { + for _, metric := range otelCol.Spec.Autoscaler.Metrics { if metric.Type == autoscalingv2.PodsMetricSourceType { v2metric := autoscalingv2.MetricSpec{ Type: metric.Type, @@ -116,5 +130,5 @@ func HorizontalPodAutoscaler(params manifests.Params) client.Object { } result = &autoscaler - return result + return result, nil } diff --git a/internal/manifests/collector/horizontalpodautoscaler_test.go b/internal/manifests/collector/horizontalpodautoscaler_test.go index 8e92360687..62ac2eb460 100644 --- a/internal/manifests/collector/horizontalpodautoscaler_test.go +++ b/internal/manifests/collector/horizontalpodautoscaler_test.go @@ -18,11 +18,13 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" autoscalingv2 "k8s.io/api/autoscaling/v2" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1" + "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha2" "github.com/open-telemetry/opentelemetry-operator/internal/config" "github.com/open-telemetry/opentelemetry-operator/internal/manifests" . "github.com/open-telemetry/opentelemetry-operator/internal/manifests/collector" @@ -40,17 +42,19 @@ func TestHPA(t *testing.T) { var cpuUtilization int32 = 66 var memoryUtilization int32 = 77 - otelcols := []v1alpha1.OpenTelemetryCollector{ + otelcols := []v1alpha2.OpenTelemetryCollector{ { ObjectMeta: metav1.ObjectMeta{ Name: "my-instance", }, - Spec: v1alpha1.OpenTelemetryCollectorSpec{ - Autoscaler: &v1alpha1.AutoscalerSpec{ - MinReplicas: &minReplicas, - MaxReplicas: &maxReplicas, - TargetCPUUtilization: &cpuUtilization, - TargetMemoryUtilization: &memoryUtilization, + Spec: v1alpha2.OpenTelemetryCollectorSpec{ + OpenTelemetryCommonFields: v1alpha2.OpenTelemetryCommonFields{ + Autoscaler: &v1alpha2.AutoscalerSpec{ + MinReplicas: &minReplicas, + MaxReplicas: &maxReplicas, + TargetCPUUtilization: &cpuUtilization, + TargetMemoryUtilization: &memoryUtilization, + }, }, }, }, @@ -58,12 +62,14 @@ func TestHPA(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "my-instance", }, - Spec: v1alpha1.OpenTelemetryCollectorSpec{ - MinReplicas: &minReplicas, - MaxReplicas: &maxReplicas, - Autoscaler: &v1alpha1.AutoscalerSpec{ - TargetCPUUtilization: &cpuUtilization, - TargetMemoryUtilization: &memoryUtilization, + Spec: v1alpha2.OpenTelemetryCollectorSpec{ + OpenTelemetryCommonFields: v1alpha2.OpenTelemetryCommonFields{ + Autoscaler: &v1alpha2.AutoscalerSpec{ + MinReplicas: &minReplicas, + MaxReplicas: &maxReplicas, + TargetCPUUtilization: &cpuUtilization, + TargetMemoryUtilization: &memoryUtilization, + }, }, }, }, @@ -74,19 +80,30 @@ func TestHPA(t *testing.T) { t.Run(test.name, func(t *testing.T) { configuration := config.New() params := manifests.Params{ - Config: configuration, - OtelCol: otelcol, - Log: logger, + Config: configuration, + OtelCol: v1alpha1.OpenTelemetryCollector{ + ObjectMeta: otelcol.ObjectMeta, + Spec: v1alpha1.OpenTelemetryCollectorSpec{ + MinReplicas: otelcol.Spec.OpenTelemetryCommonFields.Autoscaler.MinReplicas, + MaxReplicas: otelcol.Spec.OpenTelemetryCommonFields.Autoscaler.MaxReplicas, + Autoscaler: &v1alpha1.AutoscalerSpec{ + TargetCPUUtilization: otelcol.Spec.OpenTelemetryCommonFields.Autoscaler.TargetCPUUtilization, + TargetMemoryUtilization: otelcol.Spec.OpenTelemetryCommonFields.Autoscaler.TargetMemoryUtilization, + }, + }, + }, + Log: logger, } - raw := HorizontalPodAutoscaler(params) + raw, err := HorizontalPodAutoscaler(params) + require.NoError(t, err) hpa := raw.(*autoscalingv2.HorizontalPodAutoscaler) // verify assert.Equal(t, "my-instance-collector", hpa.Name) assert.Equal(t, "my-instance-collector", hpa.Labels["app.kubernetes.io/name"]) - assert.Equal(t, int32(3), *hpa.Spec.MinReplicas) - assert.Equal(t, int32(5), hpa.Spec.MaxReplicas) + assert.Equal(t, &minReplicas, hpa.Spec.MinReplicas) + assert.Equal(t, maxReplicas, hpa.Spec.MaxReplicas) assert.Equal(t, 2, len(hpa.Spec.Metrics)) for _, metric := range hpa.Spec.Metrics { diff --git a/internal/manifests/collector/ingress.go b/internal/manifests/collector/ingress.go index 4bb692ff90..8875949c95 100644 --- a/internal/manifests/collector/ingress.go +++ b/internal/manifests/collector/ingress.go @@ -22,18 +22,23 @@ import ( networkingv1 "k8s.io/api/networking/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1" + "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha2" + "github.com/open-telemetry/opentelemetry-operator/internal/api/convert" "github.com/open-telemetry/opentelemetry-operator/internal/manifests" "github.com/open-telemetry/opentelemetry-operator/internal/manifests/collector/adapters" "github.com/open-telemetry/opentelemetry-operator/internal/naming" ) func Ingress(params manifests.Params) (*networkingv1.Ingress, error) { - if params.OtelCol.Spec.Ingress.Type != v1alpha1.IngressTypeNginx { + otelCol, err := convert.V1Alpha1to2(params.OtelCol) + if err != nil { + return nil, err + } + if otelCol.Spec.Ingress.Type != v1alpha2.IngressTypeNginx { return nil, nil } - ports, err := servicePortsFromCfg(params.Log, params.OtelCol) + ports, err := servicePortsFromCfg(params.Log, otelCol) // if we have no ports, we don't need a ingress entry if len(ports) == 0 || err != nil { @@ -46,28 +51,28 @@ func Ingress(params manifests.Params) (*networkingv1.Ingress, error) { } var rules []networkingv1.IngressRule - switch params.OtelCol.Spec.Ingress.RuleType { - case v1alpha1.IngressRuleTypePath, "": - rules = []networkingv1.IngressRule{createPathIngressRules(params.OtelCol.Name, params.OtelCol.Spec.Ingress.Hostname, ports)} - case v1alpha1.IngressRuleTypeSubdomain: - rules = createSubdomainIngressRules(params.OtelCol.Name, params.OtelCol.Spec.Ingress.Hostname, ports) + switch otelCol.Spec.Ingress.RuleType { + case v1alpha2.IngressRuleTypePath, "": + rules = []networkingv1.IngressRule{createPathIngressRules(otelCol.Name, otelCol.Spec.Ingress.Hostname, ports)} + case v1alpha2.IngressRuleTypeSubdomain: + rules = createSubdomainIngressRules(otelCol.Name, otelCol.Spec.Ingress.Hostname, ports) } return &networkingv1.Ingress{ ObjectMeta: metav1.ObjectMeta{ - Name: naming.Ingress(params.OtelCol.Name), - Namespace: params.OtelCol.Namespace, - Annotations: params.OtelCol.Spec.Ingress.Annotations, + Name: naming.Ingress(otelCol.Name), + Namespace: otelCol.Namespace, + Annotations: otelCol.Spec.Ingress.Annotations, Labels: map[string]string{ - "app.kubernetes.io/name": naming.Ingress(params.OtelCol.Name), - "app.kubernetes.io/instance": fmt.Sprintf("%s.%s", params.OtelCol.Namespace, params.OtelCol.Name), + "app.kubernetes.io/name": naming.Ingress(otelCol.Name), + "app.kubernetes.io/instance": fmt.Sprintf("%s.%s", otelCol.Namespace, otelCol.Name), "app.kubernetes.io/managed-by": "opentelemetry-operator", }, }, Spec: networkingv1.IngressSpec{ - TLS: params.OtelCol.Spec.Ingress.TLS, + TLS: otelCol.Spec.Ingress.TLS, Rules: rules, - IngressClassName: params.OtelCol.Spec.Ingress.IngressClassName, + IngressClassName: otelCol.Spec.Ingress.IngressClassName, }, }, nil } @@ -136,8 +141,12 @@ func createSubdomainIngressRules(otelcol string, hostname string, ports []corev1 return rules } -func servicePortsFromCfg(logger logr.Logger, otelcol v1alpha1.OpenTelemetryCollector) ([]corev1.ServicePort, error) { - configFromString, err := adapters.ConfigFromString(otelcol.Spec.Config) +func servicePortsFromCfg(logger logr.Logger, otelcol v1alpha2.OpenTelemetryCollector) ([]corev1.ServicePort, error) { + out, err := otelcol.Spec.Config.Yaml() + if err != nil { + return nil, err + } + configFromString, err := adapters.ConfigFromString(out) if err != nil { logger.Error(err, "couldn't extract the configuration from the context") return nil, err diff --git a/internal/manifests/collector/ingress_test.go b/internal/manifests/collector/ingress_test.go index 40a3fa4ddc..8fb2103720 100644 --- a/internal/manifests/collector/ingress_test.go +++ b/internal/manifests/collector/ingress_test.go @@ -23,10 +23,12 @@ import ( networkingv1 "k8s.io/api/networking/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "github.com/open-telemetry/opentelemetry-operator/internal/api/convert" "github.com/open-telemetry/opentelemetry-operator/internal/manifests" "github.com/open-telemetry/opentelemetry-operator/internal/naming" "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1" + "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha2" "github.com/open-telemetry/opentelemetry-operator/internal/config" ) @@ -68,7 +70,7 @@ func TestDesiredIngresses(t *testing.T) { actual, err := Ingress(params) fmt.Printf("error1: %+v", err) assert.Nil(t, actual) - assert.ErrorContains(t, err, "couldn't parse the opentelemetry-collector configuration") + assert.ErrorContains(t, err, "could not convert config json to v1alpha2.Config") }) t.Run("should return nil unable to parse receiver ports", func(t *testing.T) { @@ -77,7 +79,9 @@ func TestDesiredIngresses(t *testing.T) { Log: logger, OtelCol: v1alpha1.OpenTelemetryCollector{ Spec: v1alpha1.OpenTelemetryCollectorSpec{ - Config: "---", + Config: `exporters: + nothing: +`, Ingress: v1alpha1.Ingress{ Type: v1alpha1.IngressTypeNginx, }, @@ -86,9 +90,8 @@ func TestDesiredIngresses(t *testing.T) { } actual, err := Ingress(params) - fmt.Printf("error2: %+v", err) assert.Nil(t, actual) - assert.ErrorContains(t, err, "no receivers available as part of the configuration") + assert.NoError(t, err) }) t.Run("path per port", func(t *testing.T) { @@ -103,9 +106,12 @@ func TestDesiredIngresses(t *testing.T) { t.Fatal(err) } - params.OtelCol.Namespace = ns - params.OtelCol.Spec.Ingress = v1alpha1.Ingress{ - Type: v1alpha1.IngressTypeNginx, + otelCol, err := convert.V1Alpha1to2(params.OtelCol) + assert.Nil(t, err) + + otelCol.Namespace = ns + otelCol.Spec.Ingress = v1alpha2.Ingress{ + Type: v1alpha2.IngressTypeNginx, Hostname: hostname, Annotations: map[string]string{"some.key": "some.value"}, IngressClassName: &ingressClassName, @@ -118,12 +124,12 @@ func TestDesiredIngresses(t *testing.T) { assert.NotEqual(t, &networkingv1.Ingress{ ObjectMeta: metav1.ObjectMeta{ - Name: naming.Ingress(params.OtelCol.Name), + Name: naming.Ingress(otelCol.Name), Namespace: ns, - Annotations: params.OtelCol.Spec.Ingress.Annotations, + Annotations: otelCol.Spec.Ingress.Annotations, Labels: map[string]string{ - "app.kubernetes.io/name": naming.Ingress(params.OtelCol.Name), - "app.kubernetes.io/instance": fmt.Sprintf("%s.%s", params.OtelCol.Namespace, params.OtelCol.Name), + "app.kubernetes.io/name": naming.Ingress(otelCol.Name), + "app.kubernetes.io/instance": fmt.Sprintf("%s.%s", otelCol.Namespace, otelCol.Name), "app.kubernetes.io/managed-by": "opentelemetry-operator", }, }, @@ -191,10 +197,13 @@ func TestDesiredIngresses(t *testing.T) { t.Fatal(err) } - params.OtelCol.Namespace = ns - params.OtelCol.Spec.Ingress = v1alpha1.Ingress{ - Type: v1alpha1.IngressTypeNginx, - RuleType: v1alpha1.IngressRuleTypeSubdomain, + otelCol, err := convert.V1Alpha1to2(params.OtelCol) + assert.Nil(t, err) + + otelCol.Namespace = ns + otelCol.Spec.Ingress = v1alpha2.Ingress{ + Type: v1alpha2.IngressTypeNginx, + RuleType: v1alpha2.IngressRuleTypeSubdomain, Hostname: hostname, Annotations: map[string]string{"some.key": "some.value"}, IngressClassName: &ingressClassName, @@ -207,12 +216,12 @@ func TestDesiredIngresses(t *testing.T) { assert.NotEqual(t, &networkingv1.Ingress{ ObjectMeta: metav1.ObjectMeta{ - Name: naming.Ingress(params.OtelCol.Name), + Name: naming.Ingress(otelCol.Name), Namespace: ns, - Annotations: params.OtelCol.Spec.Ingress.Annotations, + Annotations: otelCol.Spec.Ingress.Annotations, Labels: map[string]string{ - "app.kubernetes.io/name": naming.Ingress(params.OtelCol.Name), - "app.kubernetes.io/instance": fmt.Sprintf("%s.%s", params.OtelCol.Namespace, params.OtelCol.Name), + "app.kubernetes.io/name": naming.Ingress(otelCol.Name), + "app.kubernetes.io/instance": fmt.Sprintf("%s.%s", otelCol.Namespace, otelCol.Name), "app.kubernetes.io/managed-by": "opentelemetry-operator", }, }, diff --git a/internal/manifests/collector/poddisruptionbudget.go b/internal/manifests/collector/poddisruptionbudget.go index 096cd1f6c2..be2a20e52c 100644 --- a/internal/manifests/collector/poddisruptionbudget.go +++ b/internal/manifests/collector/poddisruptionbudget.go @@ -18,25 +18,33 @@ import ( policyV1 "k8s.io/api/policy/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "github.com/open-telemetry/opentelemetry-operator/internal/api/convert" "github.com/open-telemetry/opentelemetry-operator/internal/manifests" "github.com/open-telemetry/opentelemetry-operator/internal/manifests/manifestutils" "github.com/open-telemetry/opentelemetry-operator/internal/naming" ) -func PodDisruptionBudget(params manifests.Params) *policyV1.PodDisruptionBudget { +func PodDisruptionBudget(params manifests.Params) (*policyV1.PodDisruptionBudget, error) { + otelCol, err := convert.V1Alpha1to2(params.OtelCol) + if err != nil { + return nil, err + } // defaulting webhook should always set this, but if unset then return nil. - if params.OtelCol.Spec.PodDisruptionBudget == nil { + if otelCol.Spec.PodDisruptionBudget == nil { params.Log.Info("pdb field is unset in Spec, skipping podDisruptionBudget creation") - return nil + return nil, nil } - name := naming.Collector(params.OtelCol.Name) - labels := manifestutils.Labels(params.OtelCol.ObjectMeta, name, params.OtelCol.Spec.Image, ComponentOpenTelemetryCollector, params.Config.LabelsFilter()) - annotations := Annotations(params.OtelCol) + name := naming.Collector(otelCol.Name) + labels := manifestutils.Labels(otelCol.ObjectMeta, name, otelCol.Spec.Image, ComponentOpenTelemetryCollector, params.Config.LabelsFilter()) + annotations, err := Annotations(otelCol) + if err != nil { + return nil, err + } objectMeta := metav1.ObjectMeta{ - Name: naming.PodDisruptionBudget(params.OtelCol.Name), - Namespace: params.OtelCol.Namespace, + Name: naming.PodDisruptionBudget(otelCol.Name), + Namespace: otelCol.Namespace, Labels: labels, Annotations: annotations, } @@ -44,11 +52,11 @@ func PodDisruptionBudget(params manifests.Params) *policyV1.PodDisruptionBudget return &policyV1.PodDisruptionBudget{ ObjectMeta: objectMeta, Spec: policyV1.PodDisruptionBudgetSpec{ - MinAvailable: params.OtelCol.Spec.PodDisruptionBudget.MinAvailable, - MaxUnavailable: params.OtelCol.Spec.PodDisruptionBudget.MaxUnavailable, + MinAvailable: otelCol.Spec.PodDisruptionBudget.MinAvailable, + MaxUnavailable: otelCol.Spec.PodDisruptionBudget.MaxUnavailable, Selector: &metav1.LabelSelector{ MatchLabels: objectMeta.Labels, }, }, - } + }, nil } diff --git a/internal/manifests/collector/poddisruptionbudget_test.go b/internal/manifests/collector/poddisruptionbudget_test.go index de296aa67f..9adbcd515d 100644 --- a/internal/manifests/collector/poddisruptionbudget_test.go +++ b/internal/manifests/collector/poddisruptionbudget_test.go @@ -18,6 +18,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" @@ -80,11 +81,12 @@ func TestPDB(t *testing.T) { MaxUnavailable: test.MaxUnavailable, } configuration := config.New() - pdb := PodDisruptionBudget(manifests.Params{ + pdb, err := PodDisruptionBudget(manifests.Params{ Log: logger, Config: configuration, OtelCol: otelcol, }) + require.NoError(t, err) // verify assert.Equal(t, "my-instance-collector", pdb.Name) diff --git a/internal/manifests/collector/rbac.go b/internal/manifests/collector/rbac.go index f64cc0c194..f1746f9cd3 100644 --- a/internal/manifests/collector/rbac.go +++ b/internal/manifests/collector/rbac.go @@ -18,22 +18,33 @@ import ( rbacv1 "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "github.com/open-telemetry/opentelemetry-operator/internal/api/convert" "github.com/open-telemetry/opentelemetry-operator/internal/manifests" "github.com/open-telemetry/opentelemetry-operator/internal/manifests/collector/adapters" "github.com/open-telemetry/opentelemetry-operator/internal/manifests/manifestutils" "github.com/open-telemetry/opentelemetry-operator/internal/naming" ) -func ClusterRole(params manifests.Params) *rbacv1.ClusterRole { - configFromString, err := adapters.ConfigFromString(params.OtelCol.Spec.Config) +func ClusterRole(params manifests.Params) (*rbacv1.ClusterRole, error) { + otelCol, err := convert.V1Alpha1to2(params.OtelCol) + if err != nil { + return nil, err + } + + confStr, err := otelCol.Spec.Config.Yaml() + if err != nil { + return nil, err + } + + configFromString, err := adapters.ConfigFromString(confStr) if err != nil { params.Log.Error(err, "couldn't extract the configuration from the context") - return nil + return nil, nil } rules := adapters.ConfigToRBAC(params.Log, configFromString) if len(rules) == 0 { - return nil + return nil, nil } name := naming.ClusterRole(params.OtelCol.Name, params.OtelCol.Namespace) @@ -46,41 +57,49 @@ func ClusterRole(params manifests.Params) *rbacv1.ClusterRole { Labels: labels, }, Rules: rules, - } + }, nil } -func ClusterRoleBinding(params manifests.Params) *rbacv1.ClusterRoleBinding { - configFromString, err := adapters.ConfigFromString(params.OtelCol.Spec.Config) +func ClusterRoleBinding(params manifests.Params) (*rbacv1.ClusterRoleBinding, error) { + otelCol, err := convert.V1Alpha1to2(params.OtelCol) + if err != nil { + return nil, err + } + confStr, err := otelCol.Spec.Config.Yaml() + if err != nil { + return nil, err + } + configFromString, err := adapters.ConfigFromString(confStr) if err != nil { params.Log.Error(err, "couldn't extract the configuration from the context") - return nil + return nil, nil } rules := adapters.ConfigToRBAC(params.Log, configFromString) if len(rules) == 0 { - return nil + return nil, nil } - name := naming.ClusterRoleBinding(params.OtelCol.Name) - labels := manifestutils.Labels(params.OtelCol.ObjectMeta, name, params.OtelCol.Spec.Image, ComponentOpenTelemetryCollector, params.Config.LabelsFilter()) + name := naming.ClusterRoleBinding(otelCol.Name) + labels := manifestutils.Labels(otelCol.ObjectMeta, name, otelCol.Spec.Image, ComponentOpenTelemetryCollector, params.Config.LabelsFilter()) return &rbacv1.ClusterRoleBinding{ ObjectMeta: metav1.ObjectMeta{ Name: name, - Annotations: params.OtelCol.Annotations, + Annotations: otelCol.Annotations, Labels: labels, }, Subjects: []rbacv1.Subject{ { Kind: "ServiceAccount", - Name: ServiceAccountName(params.OtelCol), - Namespace: params.OtelCol.Namespace, + Name: ServiceAccountName(otelCol), + Namespace: otelCol.Namespace, }, }, RoleRef: rbacv1.RoleRef{ Kind: "ClusterRole", - Name: naming.ClusterRole(params.OtelCol.Name, params.OtelCol.Namespace), + Name: naming.ClusterRole(otelCol.Name, otelCol.Namespace), APIGroup: "rbac.authorization.k8s.io", }, - } + }, nil } diff --git a/internal/manifests/collector/rbac_test.go b/internal/manifests/collector/rbac_test.go index 9184222ea5..249558ee62 100644 --- a/internal/manifests/collector/rbac_test.go +++ b/internal/manifests/collector/rbac_test.go @@ -18,6 +18,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" rbacv1 "k8s.io/api/rbac/v1" ) @@ -27,7 +28,8 @@ func TestDesiredClusterRoles(t *testing.T) { params, err := newParams("", "testdata/prometheus-exporter.yaml") assert.NoError(t, err, "No") - cr := ClusterRole(params) + cr, err := ClusterRole(params) + require.NoError(t, err) assert.Nil(t, cr) tests := []struct { @@ -63,7 +65,8 @@ func TestDesiredClusterRoles(t *testing.T) { params, err := newParams("", test.configPath) assert.NoError(t, err, test.desc) - cr := ClusterRole(params) + cr, err := ClusterRole(params) + require.NoError(t, err) assert.Equal(t, test.expectedRules, cr.Rules, test.desc) } } @@ -74,13 +77,15 @@ func TestDesiredClusterRolBinding(t *testing.T) { params, err := newParams("", "testdata/prometheus-exporter.yaml") assert.NoError(t, err) - crb := ClusterRoleBinding(params) + crb, err := ClusterRoleBinding(params) + require.NoError(t, err) assert.Nil(t, crb) // Create ClusterRoleBinding params, err = newParams("", "testdata/rbac_resourcedetectionprocessor_k8s.yaml") assert.NoError(t, err) - crb = ClusterRoleBinding(params) + crb, err = ClusterRoleBinding(params) + require.NoError(t, err) assert.NotNil(t, crb) } diff --git a/internal/manifests/collector/route.go b/internal/manifests/collector/route.go index 43901e59bc..494a0b73e4 100644 --- a/internal/manifests/collector/route.go +++ b/internal/manifests/collector/route.go @@ -21,44 +21,49 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" - "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1" + "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha2" + "github.com/open-telemetry/opentelemetry-operator/internal/api/convert" "github.com/open-telemetry/opentelemetry-operator/internal/autodetect/openshift" "github.com/open-telemetry/opentelemetry-operator/internal/manifests" "github.com/open-telemetry/opentelemetry-operator/internal/naming" ) func Routes(params manifests.Params) ([]*routev1.Route, error) { - if params.OtelCol.Spec.Ingress.Type != v1alpha1.IngressTypeRoute || params.Config.OpenShiftRoutesAvailability() != openshift.RoutesAvailable { + otelCol, err := convert.V1Alpha1to2(params.OtelCol) + if err != nil { + return nil, err + } + if otelCol.Spec.Ingress.Type != v1alpha2.IngressTypeRoute || params.Config.OpenShiftRoutesAvailability() != openshift.RoutesAvailable { return nil, nil } - if params.OtelCol.Spec.Mode == v1alpha1.ModeSidecar { + if otelCol.Spec.Mode == v1alpha2.ModeSidecar { params.Log.V(3).Info("ingress settings are not supported in sidecar mode") return nil, nil } var tlsCfg *routev1.TLSConfig - switch params.OtelCol.Spec.Ingress.Route.Termination { - case v1alpha1.TLSRouteTerminationTypeInsecure: + switch otelCol.Spec.Ingress.Route.Termination { + case v1alpha2.TLSRouteTerminationTypeInsecure: // NOTE: insecure, no tls cfg. - case v1alpha1.TLSRouteTerminationTypeEdge: + case v1alpha2.TLSRouteTerminationTypeEdge: tlsCfg = &routev1.TLSConfig{Termination: routev1.TLSTerminationEdge} - case v1alpha1.TLSRouteTerminationTypePassthrough: + case v1alpha2.TLSRouteTerminationTypePassthrough: tlsCfg = &routev1.TLSConfig{Termination: routev1.TLSTerminationPassthrough} - case v1alpha1.TLSRouteTerminationTypeReencrypt: + case v1alpha2.TLSRouteTerminationTypeReencrypt: tlsCfg = &routev1.TLSConfig{Termination: routev1.TLSTerminationReencrypt} default: // NOTE: if unsupported, end here. return nil, nil } - ports, err := servicePortsFromCfg(params.Log, params.OtelCol) + ports, err := servicePortsFromCfg(params.Log, otelCol) // if we have no ports, we don't need a ingress entry if len(ports) == 0 || err != nil { params.Log.V(1).Info( "the instance's configuration didn't yield any ports to open, skipping ingress", - "instance.name", params.OtelCol.Name, - "instance.namespace", params.OtelCol.Namespace, + "instance.name", otelCol.Name, + "instance.namespace", otelCol.Namespace, ) return nil, err } @@ -67,18 +72,18 @@ func Routes(params manifests.Params) ([]*routev1.Route, error) { for i, p := range ports { portName := naming.PortName(p.Name, p.Port) host := "" - if params.OtelCol.Spec.Ingress.Hostname != "" { + if otelCol.Spec.Ingress.Hostname != "" { host = fmt.Sprintf("%s.%s", portName, params.OtelCol.Spec.Ingress.Hostname) } routes[i] = &routev1.Route{ ObjectMeta: metav1.ObjectMeta{ Name: naming.Route(params.OtelCol.Name, p.Name), - Namespace: params.OtelCol.Namespace, - Annotations: params.OtelCol.Spec.Ingress.Annotations, + Namespace: otelCol.Namespace, + Annotations: otelCol.Spec.Ingress.Annotations, Labels: map[string]string{ - "app.kubernetes.io/name": naming.Route(params.OtelCol.Name, p.Name), - "app.kubernetes.io/instance": fmt.Sprintf("%s.%s", params.OtelCol.Namespace, params.OtelCol.Name), + "app.kubernetes.io/name": naming.Route(otelCol.Name, p.Name), + "app.kubernetes.io/instance": fmt.Sprintf("%s.%s", otelCol.Namespace, otelCol.Name), "app.kubernetes.io/managed-by": "opentelemetry-operator", "app.kubernetes.io/component": "opentelemetry-collector", }, diff --git a/internal/manifests/collector/route_test.go b/internal/manifests/collector/route_test.go index 12104a125c..374b4a0dee 100644 --- a/internal/manifests/collector/route_test.go +++ b/internal/manifests/collector/route_test.go @@ -69,7 +69,7 @@ func TestDesiredRoutes(t *testing.T) { actual, err := Routes(params) assert.Nil(t, actual) - assert.ErrorContains(t, err, "couldn't parse the opentelemetry-collector configuration") + assert.ErrorContains(t, err, "could not convert config json to v1alpha2.Config") }) t.Run("should return nil unable to parse receiver ports", func(t *testing.T) { @@ -91,7 +91,7 @@ func TestDesiredRoutes(t *testing.T) { actual, err := Routes(params) assert.Nil(t, actual) - assert.ErrorContains(t, err, "no receivers available as part of the configuration") + assert.NoError(t, err) }) t.Run("should return nil unable to do something else", func(t *testing.T) { diff --git a/internal/manifests/collector/service.go b/internal/manifests/collector/service.go index 5b23888fbe..b2b4035ac1 100644 --- a/internal/manifests/collector/service.go +++ b/internal/manifests/collector/service.go @@ -22,7 +22,8 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1" + "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha2" + "github.com/open-telemetry/opentelemetry-operator/internal/api/convert" "github.com/open-telemetry/opentelemetry-operator/internal/manifests" "github.com/open-telemetry/opentelemetry-operator/internal/manifests/collector/adapters" "github.com/open-telemetry/opentelemetry-operator/internal/manifests/manifestutils" @@ -41,7 +42,12 @@ func HeadlessService(params manifests.Params) (*corev1.Service, error) { return h, err } - h.Name = naming.HeadlessService(params.OtelCol.Name) + otelCol, err := convert.V1Alpha1to2(params.OtelCol) + if err != nil { + return nil, err + } + + h.Name = naming.HeadlessService(otelCol.Name) h.Labels[headlessLabel] = headlessExists // copy to avoid modifying params.OtelCol.Annotations @@ -58,10 +64,20 @@ func HeadlessService(params manifests.Params) (*corev1.Service, error) { } func MonitoringService(params manifests.Params) (*corev1.Service, error) { - name := naming.MonitoringService(params.OtelCol.Name) - labels := manifestutils.Labels(params.OtelCol.ObjectMeta, name, params.OtelCol.Spec.Image, ComponentOpenTelemetryCollector, []string{}) + otelCol, err := convert.V1Alpha1to2(params.OtelCol) + if err != nil { + return nil, err + } + + name := naming.MonitoringService(otelCol.Name) + labels := manifestutils.Labels(otelCol.ObjectMeta, name, otelCol.Spec.Image, ComponentOpenTelemetryCollector, []string{}) - c, err := adapters.ConfigFromString(params.OtelCol.Spec.Config) + out, err := otelCol.Spec.Config.Yaml() + if err != nil { + return nil, err + } + + c, err := adapters.ConfigFromString(out) if err != nil { params.Log.Error(err, "couldn't extract the configuration") return nil, err @@ -75,12 +91,12 @@ func MonitoringService(params manifests.Params) (*corev1.Service, error) { return &corev1.Service{ ObjectMeta: metav1.ObjectMeta{ Name: name, - Namespace: params.OtelCol.Namespace, + Namespace: otelCol.Namespace, Labels: labels, - Annotations: params.OtelCol.Annotations, + Annotations: otelCol.Annotations, }, Spec: corev1.ServiceSpec{ - Selector: manifestutils.SelectorLabels(params.OtelCol.ObjectMeta, ComponentOpenTelemetryCollector), + Selector: manifestutils.SelectorLabels(otelCol.ObjectMeta, ComponentOpenTelemetryCollector), ClusterIP: "", Ports: []corev1.ServicePort{{ Name: "monitoring", @@ -91,10 +107,19 @@ func MonitoringService(params manifests.Params) (*corev1.Service, error) { } func Service(params manifests.Params) (*corev1.Service, error) { - name := naming.Service(params.OtelCol.Name) - labels := manifestutils.Labels(params.OtelCol.ObjectMeta, name, params.OtelCol.Spec.Image, ComponentOpenTelemetryCollector, []string{}) + otelCol, err := convert.V1Alpha1to2(params.OtelCol) + if err != nil { + return nil, err + } + name := naming.Service(otelCol.Name) + labels := manifestutils.Labels(otelCol.ObjectMeta, name, otelCol.Spec.Image, ComponentOpenTelemetryCollector, []string{}) + + out, err := otelCol.Spec.Config.Yaml() + if err != nil { + return nil, err + } - configFromString, err := adapters.ConfigFromString(params.OtelCol.Spec.Config) + configFromString, err := adapters.ConfigFromString(out) if err != nil { params.Log.Error(err, "couldn't extract the configuration from the context") return nil, err @@ -109,12 +134,12 @@ func Service(params manifests.Params) (*corev1.Service, error) { // OpenShift uses HA proxy that uses appProtocol for its configuration. for i := range ports { h2c := "h2c" - if params.OtelCol.Spec.Ingress.Type == v1alpha1.IngressTypeRoute && ports[i].AppProtocol != nil && strings.EqualFold(*ports[i].AppProtocol, "grpc") { + if otelCol.Spec.Ingress.Type == v1alpha2.IngressTypeRoute && ports[i].AppProtocol != nil && strings.EqualFold(*ports[i].AppProtocol, "grpc") { ports[i].AppProtocol = &h2c } } - if len(params.OtelCol.Spec.Ports) > 0 { + if len(otelCol.Spec.Ports) > 0 { // we should add all the ports from the CR // there are two cases where problems might occur: // 1) when the port number is already being used by a receiver @@ -122,7 +147,7 @@ func Service(params manifests.Params) (*corev1.Service, error) { // // in the first case, we remove the port we inferred from the list // in the second case, we rename our inferred port to something like "port-%d" - portNumbers, portNames := extractPortNumbersAndNames(params.OtelCol.Spec.Ports) + portNumbers, portNames := extractPortNumbersAndNames(otelCol.Spec.Ports) var resultingInferredPorts []corev1.ServicePort for _, inferred := range ports { if filtered := filterPort(params.Log, inferred, portNumbers, portNames); filtered != nil { @@ -130,31 +155,31 @@ func Service(params manifests.Params) (*corev1.Service, error) { } } - ports = append(params.OtelCol.Spec.Ports, resultingInferredPorts...) + ports = append(otelCol.Spec.Ports, resultingInferredPorts...) } // if we have no ports, we don't need a service if len(ports) == 0 { - params.Log.V(1).Info("the instance's configuration didn't yield any ports to open, skipping service", "instance.name", params.OtelCol.Name, "instance.namespace", params.OtelCol.Namespace) + params.Log.V(1).Info("the instance's configuration didn't yield any ports to open, skipping service", "instance.name", otelCol.Name, "instance.namespace", otelCol.Namespace) return nil, err } trafficPolicy := corev1.ServiceInternalTrafficPolicyCluster - if params.OtelCol.Spec.Mode == v1alpha1.ModeDaemonSet { + if otelCol.Spec.Mode == v1alpha2.ModeDaemonSet { trafficPolicy = corev1.ServiceInternalTrafficPolicyLocal } return &corev1.Service{ ObjectMeta: metav1.ObjectMeta{ - Name: naming.Service(params.OtelCol.Name), - Namespace: params.OtelCol.Namespace, + Name: naming.Service(otelCol.Name), + Namespace: otelCol.Namespace, Labels: labels, - Annotations: params.OtelCol.Annotations, + Annotations: otelCol.Annotations, }, Spec: corev1.ServiceSpec{ InternalTrafficPolicy: &trafficPolicy, - Selector: manifestutils.SelectorLabels(params.OtelCol.ObjectMeta, ComponentOpenTelemetryCollector), + Selector: manifestutils.SelectorLabels(otelCol.ObjectMeta, ComponentOpenTelemetryCollector), ClusterIP: "", Ports: ports, }, diff --git a/internal/manifests/collector/service_test.go b/internal/manifests/collector/service_test.go index 37bd668e83..fcc6e5b8d7 100644 --- a/internal/manifests/collector/service_test.go +++ b/internal/manifests/collector/service_test.go @@ -108,9 +108,8 @@ func TestDesiredService(t *testing.T) { } actual, err := Service(params) - assert.ErrorContains(t, err, "no enabled receivers available as part of the configuration") assert.Nil(t, actual) - + assert.NoError(t, err) }) t.Run("should return service with port mentioned in OtelCol.Spec.Ports and inferred ports", func(t *testing.T) { @@ -181,7 +180,7 @@ func TestDesiredService(t *testing.T) { } actual, err := Service(params) - assert.ErrorContains(t, err, "couldn't parse the opentelemetry-collector configuration") + assert.ErrorContains(t, err, "could not convert config json to v1alpha2.Config") assert.Nil(t, actual) }) diff --git a/internal/manifests/collector/serviceaccount.go b/internal/manifests/collector/serviceaccount.go index a3648a593a..3c1d48688c 100644 --- a/internal/manifests/collector/serviceaccount.go +++ b/internal/manifests/collector/serviceaccount.go @@ -18,14 +18,15 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1" + "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha2" + "github.com/open-telemetry/opentelemetry-operator/internal/api/convert" "github.com/open-telemetry/opentelemetry-operator/internal/manifests" "github.com/open-telemetry/opentelemetry-operator/internal/manifests/manifestutils" "github.com/open-telemetry/opentelemetry-operator/internal/naming" ) // ServiceAccountName returns the name of the existing or self-provisioned service account to use for the given instance. -func ServiceAccountName(instance v1alpha1.OpenTelemetryCollector) string { +func ServiceAccountName(instance v1alpha2.OpenTelemetryCollector) string { if len(instance.Spec.ServiceAccount) == 0 { return naming.ServiceAccount(instance.Name) } @@ -34,19 +35,24 @@ func ServiceAccountName(instance v1alpha1.OpenTelemetryCollector) string { } // ServiceAccount returns the service account for the given instance. -func ServiceAccount(params manifests.Params) *corev1.ServiceAccount { - if params.OtelCol.Spec.ServiceAccount != "" { - return nil +func ServiceAccount(params manifests.Params) (*corev1.ServiceAccount, error) { + otelCol, err := convert.V1Alpha1to2(params.OtelCol) + if err != nil { + return nil, err } - name := naming.ServiceAccount(params.OtelCol.Name) - labels := manifestutils.Labels(params.OtelCol.ObjectMeta, name, params.OtelCol.Spec.Image, ComponentOpenTelemetryCollector, []string{}) + if otelCol.Spec.ServiceAccount != "" { + return nil, nil + } + + name := naming.ServiceAccount(otelCol.Name) + labels := manifestutils.Labels(otelCol.ObjectMeta, name, otelCol.Spec.Image, ComponentOpenTelemetryCollector, []string{}) return &corev1.ServiceAccount{ ObjectMeta: metav1.ObjectMeta{ Name: name, - Namespace: params.OtelCol.Namespace, + Namespace: otelCol.Namespace, Labels: labels, - Annotations: params.OtelCol.Annotations, + Annotations: otelCol.Annotations, }, - } + }, nil } diff --git a/internal/manifests/collector/serviceaccount_test.go b/internal/manifests/collector/serviceaccount_test.go index 6d9abafe2f..7a66caf2f8 100644 --- a/internal/manifests/collector/serviceaccount_test.go +++ b/internal/manifests/collector/serviceaccount_test.go @@ -20,13 +20,13 @@ import ( "github.com/stretchr/testify/assert" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1" + "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha2" . "github.com/open-telemetry/opentelemetry-operator/internal/manifests/collector" ) func TestServiceAccountNewDefault(t *testing.T) { // prepare - otelcol := v1alpha1.OpenTelemetryCollector{ + otelcol := v1alpha2.OpenTelemetryCollector{ ObjectMeta: metav1.ObjectMeta{ Name: "my-instance", }, @@ -41,12 +41,14 @@ func TestServiceAccountNewDefault(t *testing.T) { func TestServiceAccountOverride(t *testing.T) { // prepare - otelcol := v1alpha1.OpenTelemetryCollector{ + otelcol := v1alpha2.OpenTelemetryCollector{ ObjectMeta: metav1.ObjectMeta{ Name: "my-instance", }, - Spec: v1alpha1.OpenTelemetryCollectorSpec{ - ServiceAccount: "my-special-sa", + Spec: v1alpha2.OpenTelemetryCollectorSpec{ + OpenTelemetryCommonFields: v1alpha2.OpenTelemetryCommonFields{ + ServiceAccount: "my-special-sa", + }, }, } diff --git a/internal/manifests/collector/statefulset.go b/internal/manifests/collector/statefulset.go index c1a03fce52..f257a35431 100644 --- a/internal/manifests/collector/statefulset.go +++ b/internal/manifests/collector/statefulset.go @@ -19,30 +19,42 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "github.com/open-telemetry/opentelemetry-operator/internal/api/convert" "github.com/open-telemetry/opentelemetry-operator/internal/manifests" "github.com/open-telemetry/opentelemetry-operator/internal/manifests/manifestutils" "github.com/open-telemetry/opentelemetry-operator/internal/naming" ) // StatefulSet builds the statefulset for the given instance. -func StatefulSet(params manifests.Params) *appsv1.StatefulSet { - name := naming.Collector(params.OtelCol.Name) - labels := manifestutils.Labels(params.OtelCol.ObjectMeta, name, params.OtelCol.Spec.Image, ComponentOpenTelemetryCollector, params.Config.LabelsFilter()) +func StatefulSet(params manifests.Params) (*appsv1.StatefulSet, error) { + otelCol, err := convert.V1Alpha1to2(params.OtelCol) + if err != nil { + return nil, err + } + name := naming.Collector(otelCol.Name) + labels := manifestutils.Labels(otelCol.ObjectMeta, name, otelCol.Spec.Image, ComponentOpenTelemetryCollector, params.Config.LabelsFilter()) - annotations := Annotations(params.OtelCol) - podAnnotations := PodAnnotations(params.OtelCol) + annotations, err := Annotations(otelCol) + if err != nil { + return nil, err + } + + podAnnotations, err := PodAnnotations(otelCol) + if err != nil { + return nil, err + } return &appsv1.StatefulSet{ ObjectMeta: metav1.ObjectMeta{ Name: name, - Namespace: params.OtelCol.Namespace, + Namespace: otelCol.Namespace, Labels: labels, Annotations: annotations, }, Spec: appsv1.StatefulSetSpec{ - ServiceName: naming.Service(params.OtelCol.Name), + ServiceName: naming.Service(otelCol.Name), Selector: &metav1.LabelSelector{ - MatchLabels: manifestutils.SelectorLabels(params.OtelCol.ObjectMeta, ComponentOpenTelemetryCollector), + MatchLabels: manifestutils.SelectorLabels(otelCol.ObjectMeta, ComponentOpenTelemetryCollector), }, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ @@ -50,24 +62,24 @@ func StatefulSet(params manifests.Params) *appsv1.StatefulSet { Annotations: podAnnotations, }, Spec: corev1.PodSpec{ - ServiceAccountName: ServiceAccountName(params.OtelCol), - InitContainers: params.OtelCol.Spec.InitContainers, - Containers: append(params.OtelCol.Spec.AdditionalContainers, Container(params.Config, params.Log, params.OtelCol, true)), - Volumes: Volumes(params.Config, params.OtelCol), - DNSPolicy: getDNSPolicy(params.OtelCol), - HostNetwork: params.OtelCol.Spec.HostNetwork, - ShareProcessNamespace: ¶ms.OtelCol.Spec.ShareProcessNamespace, - Tolerations: params.OtelCol.Spec.Tolerations, - NodeSelector: params.OtelCol.Spec.NodeSelector, - SecurityContext: params.OtelCol.Spec.PodSecurityContext, - PriorityClassName: params.OtelCol.Spec.PriorityClassName, - Affinity: params.OtelCol.Spec.Affinity, - TopologySpreadConstraints: params.OtelCol.Spec.TopologySpreadConstraints, + ServiceAccountName: ServiceAccountName(otelCol), + InitContainers: otelCol.Spec.InitContainers, + Containers: append(otelCol.Spec.AdditionalContainers, Container(params.Config, params.Log, otelCol, true)), + Volumes: Volumes(params.Config, otelCol), + DNSPolicy: getDNSPolicy(otelCol), + HostNetwork: otelCol.Spec.HostNetwork, + ShareProcessNamespace: &otelCol.Spec.ShareProcessNamespace, + Tolerations: otelCol.Spec.Tolerations, + NodeSelector: otelCol.Spec.NodeSelector, + SecurityContext: otelCol.Spec.PodSecurityContext, + PriorityClassName: otelCol.Spec.PriorityClassName, + Affinity: otelCol.Spec.Affinity, + TopologySpreadConstraints: otelCol.Spec.TopologySpreadConstraints, }, }, - Replicas: params.OtelCol.Spec.Replicas, + Replicas: otelCol.Spec.Replicas, PodManagementPolicy: "Parallel", - VolumeClaimTemplates: VolumeClaimTemplates(params.OtelCol), + VolumeClaimTemplates: VolumeClaimTemplates(otelCol), }, - } + }, nil } diff --git a/internal/manifests/collector/statefulset_test.go b/internal/manifests/collector/statefulset_test.go index ed7a386854..b726785333 100644 --- a/internal/manifests/collector/statefulset_test.go +++ b/internal/manifests/collector/statefulset_test.go @@ -18,6 +18,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1" @@ -51,7 +52,8 @@ func TestStatefulSetNewDefault(t *testing.T) { } // test - ss := StatefulSet(params) + ss, err := StatefulSet(params) + require.NoError(t, err) // verify assert.Equal(t, "my-instance-collector", ss.Name) @@ -65,7 +67,7 @@ func TestStatefulSetNewDefault(t *testing.T) { // verify sha256 podAnnotation expectedAnnotations := map[string]string{ - "opentelemetry-operator-config/sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "opentelemetry-operator-config/sha256": "fbcdae6a02b2115cd5ca4f34298202ab041d1dfe62edebfaadb48b1ee178231d", "prometheus.io/path": "/metrics", "prometheus.io/port": "8888", "prometheus.io/scrape": "true", @@ -123,7 +125,8 @@ func TestStatefulSetReplicas(t *testing.T) { } // test - ss := StatefulSet(params) + ss, err := StatefulSet(params) + require.NoError(t, err) // assert correct number of replicas assert.Equal(t, int32(3), *ss.Spec.Replicas) @@ -159,7 +162,8 @@ func TestStatefulSetVolumeClaimTemplates(t *testing.T) { } // test - ss := StatefulSet(params) + ss, err := StatefulSet(params) + require.NoError(t, err) // assert correct pvc name assert.Equal(t, "added-volume", ss.Spec.VolumeClaimTemplates[0].Name) @@ -191,14 +195,15 @@ func TestStatefulSetPodAnnotations(t *testing.T) { } // test - ss := StatefulSet(params) + ss, err := StatefulSet(params) + require.NoError(t, err) // Add sha256 podAnnotation - testPodAnnotationValues["opentelemetry-operator-config/sha256"] = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + testPodAnnotationValues["opentelemetry-operator-config/sha256"] = "fbcdae6a02b2115cd5ca4f34298202ab041d1dfe62edebfaadb48b1ee178231d" expectedAnnotations := map[string]string{ "annotation-key": "annotation-value", - "opentelemetry-operator-config/sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "opentelemetry-operator-config/sha256": "fbcdae6a02b2115cd5ca4f34298202ab041d1dfe62edebfaadb48b1ee178231d", "prometheus.io/path": "/metrics", "prometheus.io/port": "8888", "prometheus.io/scrape": "true", @@ -234,7 +239,8 @@ func TestStatefulSetPodSecurityContext(t *testing.T) { Log: logger, } - d := StatefulSet(params) + d, err := StatefulSet(params) + require.NoError(t, err) assert.Equal(t, &runAsNonRoot, d.Spec.Template.Spec.SecurityContext.RunAsNonRoot) assert.Equal(t, &runAsUser, d.Spec.Template.Spec.SecurityContext.RunAsUser) @@ -257,7 +263,8 @@ func TestStatefulSetHostNetwork(t *testing.T) { Log: logger, } - d1 := StatefulSet(params1) + d1, err := StatefulSet(params1) + require.NoError(t, err) assert.Equal(t, d1.Spec.Template.Spec.HostNetwork, false) assert.Equal(t, d1.Spec.Template.Spec.DNSPolicy, v1.DNSClusterFirst) @@ -280,7 +287,8 @@ func TestStatefulSetHostNetwork(t *testing.T) { Log: logger, } - d2 := StatefulSet(params2) + d2, err := StatefulSet(params2) + require.NoError(t, err) assert.Equal(t, d2.Spec.Template.Spec.HostNetwork, true) assert.Equal(t, d2.Spec.Template.Spec.DNSPolicy, v1.DNSClusterFirstWithHostNet) } @@ -307,7 +315,8 @@ func TestStatefulSetFilterLabels(t *testing.T) { Log: logger, } - d := StatefulSet(params) + d, err := StatefulSet(params) + require.NoError(t, err) assert.Len(t, d.ObjectMeta.Labels, 6) for k := range excludedLabels { @@ -331,7 +340,8 @@ func TestStatefulSetNodeSelector(t *testing.T) { Log: logger, } - d1 := StatefulSet(params1) + d1, err := StatefulSet(params1) + require.NoError(t, err) assert.Empty(t, d1.Spec.Template.Spec.NodeSelector) @@ -356,7 +366,8 @@ func TestStatefulSetNodeSelector(t *testing.T) { Log: logger, } - d2 := StatefulSet(params2) + d2, err := StatefulSet(params2) + require.NoError(t, err) assert.Equal(t, d2.Spec.Template.Spec.NodeSelector, map[string]string{"node-key": "node-value"}) } @@ -375,7 +386,8 @@ func TestStatefulSetPriorityClassName(t *testing.T) { Log: logger, } - sts1 := StatefulSet(params1) + sts1, err := StatefulSet(params1) + require.NoError(t, err) assert.Empty(t, sts1.Spec.Template.Spec.PriorityClassName) priorityClassName := "test-class" @@ -397,7 +409,8 @@ func TestStatefulSetPriorityClassName(t *testing.T) { Log: logger, } - sts2 := StatefulSet(params2) + sts2, err := StatefulSet(params2) + require.NoError(t, err) assert.Equal(t, priorityClassName, sts2.Spec.Template.Spec.PriorityClassName) } @@ -416,7 +429,8 @@ func TestStatefulSetAffinity(t *testing.T) { Log: logger, } - sts1 := Deployment(params1) + sts1, err := Deployment(params1) + require.NoError(t, err) assert.Nil(t, sts1.Spec.Template.Spec.Affinity) otelcol2 := v1alpha1.OpenTelemetryCollector{ @@ -436,7 +450,8 @@ func TestStatefulSetAffinity(t *testing.T) { Log: logger, } - sts2 := StatefulSet(params2) + sts2, err := StatefulSet(params2) + require.NoError(t, err) assert.NotNil(t, sts2.Spec.Template.Spec.Affinity) assert.Equal(t, *testAffinityValue, *sts2.Spec.Template.Spec.Affinity) } @@ -465,7 +480,8 @@ func TestStatefulSetInitContainer(t *testing.T) { } // test - s := StatefulSet(params) + s, err := StatefulSet(params) + require.NoError(t, err) assert.Equal(t, "my-instance-collector", s.Name) assert.Equal(t, "my-instance-collector", s.Labels["app.kubernetes.io/name"]) assert.Equal(t, "true", s.Annotations["prometheus.io/scrape"]) @@ -489,7 +505,8 @@ func TestStatefulSetTopologySpreadConstraints(t *testing.T) { Config: cfg, Log: logger, } - s1 := StatefulSet(params1) + s1, err := StatefulSet(params1) + require.NoError(t, err) assert.Equal(t, "my-instance-collector", s1.Name) assert.Empty(t, s1.Spec.Template.Spec.TopologySpreadConstraints) @@ -511,7 +528,8 @@ func TestStatefulSetTopologySpreadConstraints(t *testing.T) { Log: logger, } - s2 := StatefulSet(params2) + s2, err := StatefulSet(params2) + require.NoError(t, err) assert.Equal(t, "my-instance-topologyspreadconstraint-collector", s2.Name) assert.NotNil(t, s2.Spec.Template.Spec.TopologySpreadConstraints) assert.NotEmpty(t, s2.Spec.Template.Spec.TopologySpreadConstraints) @@ -542,7 +560,8 @@ func TestStatefulSetAdditionalContainers(t *testing.T) { } // test - s := StatefulSet(params) + s, err := StatefulSet(params) + require.NoError(t, err) assert.Equal(t, "my-instance-collector", s.Name) assert.Equal(t, "my-instance-collector", s.Labels["app.kubernetes.io/name"]) assert.Equal(t, "true", s.Annotations["prometheus.io/scrape"]) @@ -568,7 +587,8 @@ func TestStatefulSetShareProcessNamespace(t *testing.T) { Log: logger, } - d1 := StatefulSet(params1) + d1, err := StatefulSet(params1) + require.NoError(t, err) assert.False(t, *d1.Spec.Template.Spec.ShareProcessNamespace) // Test shareProcessNamespace=true @@ -589,6 +609,7 @@ func TestStatefulSetShareProcessNamespace(t *testing.T) { Log: logger, } - d2 := StatefulSet(params2) + d2, err := StatefulSet(params2) + require.NoError(t, err) assert.True(t, *d2.Spec.Template.Spec.ShareProcessNamespace) } diff --git a/internal/manifests/collector/testdata/config_expected_targetallocator.yaml b/internal/manifests/collector/testdata/config_expected_targetallocator.yaml index 8708b63155..5ac9467e9d 100644 --- a/internal/manifests/collector/testdata/config_expected_targetallocator.yaml +++ b/internal/manifests/collector/testdata/config_expected_targetallocator.yaml @@ -1,6 +1,5 @@ -debug: null -exporters: null -processors: null +exporters: + debug: receivers: prometheus: config: diff --git a/internal/manifests/collector/testdata/relabel_config_expected_with_sd_config.yaml b/internal/manifests/collector/testdata/relabel_config_expected_with_sd_config.yaml index 507feb8028..d58e5f0834 100644 --- a/internal/manifests/collector/testdata/relabel_config_expected_with_sd_config.yaml +++ b/internal/manifests/collector/testdata/relabel_config_expected_with_sd_config.yaml @@ -1,6 +1,5 @@ -debug: null -exporters: null -processors: null +exporters: + debug: receivers: prometheus: config: diff --git a/internal/manifests/collector/testdata/relabel_config_original.yaml b/internal/manifests/collector/testdata/relabel_config_original.yaml index 673b4ba4af..58f365072b 100644 --- a/internal/manifests/collector/testdata/relabel_config_original.yaml +++ b/internal/manifests/collector/testdata/relabel_config_original.yaml @@ -1,6 +1,5 @@ exporters: -debug: -processors: + debug: receivers: prometheus: config: diff --git a/internal/manifests/collector/utils.go b/internal/manifests/collector/utils.go index 36d6833455..250e7dbcbd 100644 --- a/internal/manifests/collector/utils.go +++ b/internal/manifests/collector/utils.go @@ -17,10 +17,10 @@ package collector import ( corev1 "k8s.io/api/core/v1" - "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1" + "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha2" ) -func getDNSPolicy(otelcol v1alpha1.OpenTelemetryCollector) corev1.DNSPolicy { +func getDNSPolicy(otelcol v1alpha2.OpenTelemetryCollector) corev1.DNSPolicy { dnsPolicy := corev1.DNSClusterFirst if otelcol.Spec.HostNetwork { dnsPolicy = corev1.DNSClusterFirstWithHostNet diff --git a/internal/manifests/collector/volume.go b/internal/manifests/collector/volume.go index 6b014eba80..634694c2a0 100644 --- a/internal/manifests/collector/volume.go +++ b/internal/manifests/collector/volume.go @@ -18,13 +18,13 @@ package collector import ( corev1 "k8s.io/api/core/v1" - "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1" + "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha2" "github.com/open-telemetry/opentelemetry-operator/internal/config" "github.com/open-telemetry/opentelemetry-operator/internal/naming" ) // Volumes builds the volumes for the given instance, including the config map volume. -func Volumes(cfg config.Config, otelcol v1alpha1.OpenTelemetryCollector) []corev1.Volume { +func Volumes(cfg config.Config, otelcol v1alpha2.OpenTelemetryCollector) []corev1.Volume { volumes := []corev1.Volume{{ Name: naming.ConfigMapVolume(), VolumeSource: corev1.VolumeSource{ diff --git a/internal/manifests/collector/volume_test.go b/internal/manifests/collector/volume_test.go index 6232b39c4b..9f355320d2 100644 --- a/internal/manifests/collector/volume_test.go +++ b/internal/manifests/collector/volume_test.go @@ -21,6 +21,7 @@ import ( corev1 "k8s.io/api/core/v1" "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1" + "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha2" "github.com/open-telemetry/opentelemetry-operator/internal/config" . "github.com/open-telemetry/opentelemetry-operator/internal/manifests/collector" "github.com/open-telemetry/opentelemetry-operator/internal/naming" @@ -28,7 +29,7 @@ import ( func TestVolumeNewDefault(t *testing.T) { // prepare - otelcol := v1alpha1.OpenTelemetryCollector{} + otelcol := v1alpha2.OpenTelemetryCollector{} cfg := config.New() // test @@ -43,11 +44,13 @@ func TestVolumeNewDefault(t *testing.T) { func TestVolumeAllowsMoreToBeAdded(t *testing.T) { // prepare - otelcol := v1alpha1.OpenTelemetryCollector{ - Spec: v1alpha1.OpenTelemetryCollectorSpec{ - Volumes: []corev1.Volume{{ - Name: "my-volume", - }}, + otelcol := v1alpha2.OpenTelemetryCollector{ + Spec: v1alpha2.OpenTelemetryCollectorSpec{ + OpenTelemetryCommonFields: v1alpha2.OpenTelemetryCommonFields{ + Volumes: []corev1.Volume{{ + Name: "my-volume", + }}, + }, }, } cfg := config.New() @@ -64,8 +67,8 @@ func TestVolumeAllowsMoreToBeAdded(t *testing.T) { func TestVolumeWithMoreConfigMaps(t *testing.T) { // prepare - otelcol := v1alpha1.OpenTelemetryCollector{ - Spec: v1alpha1.OpenTelemetryCollectorSpec{ + otelcol := v1alpha2.OpenTelemetryCollector{ + Spec: v1alpha2.OpenTelemetryCollectorSpec{ ConfigMaps: []v1alpha1.ConfigMapsSpec{{ Name: "configmap-test", MountPath: "/", diff --git a/internal/manifests/collector/volumeclaim.go b/internal/manifests/collector/volumeclaim.go index c641a38317..cd076cbcd1 100644 --- a/internal/manifests/collector/volumeclaim.go +++ b/internal/manifests/collector/volumeclaim.go @@ -18,12 +18,12 @@ package collector import ( corev1 "k8s.io/api/core/v1" - "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1" + "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha2" ) // VolumeClaimTemplates builds the volumeClaimTemplates for the given instance, // including the config map volume mount. -func VolumeClaimTemplates(otelcol v1alpha1.OpenTelemetryCollector) []corev1.PersistentVolumeClaim { +func VolumeClaimTemplates(otelcol v1alpha2.OpenTelemetryCollector) []corev1.PersistentVolumeClaim { if otelcol.Spec.Mode != "statefulset" { return []corev1.PersistentVolumeClaim{} } diff --git a/internal/manifests/collector/volumeclaim_test.go b/internal/manifests/collector/volumeclaim_test.go index 70db04abb9..f848c98867 100644 --- a/internal/manifests/collector/volumeclaim_test.go +++ b/internal/manifests/collector/volumeclaim_test.go @@ -22,26 +22,28 @@ import ( "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1" + "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha2" . "github.com/open-telemetry/opentelemetry-operator/internal/manifests/collector" ) func TestVolumeClaimAllowsUserToAdd(t *testing.T) { // prepare - otelcol := v1alpha1.OpenTelemetryCollector{ - Spec: v1alpha1.OpenTelemetryCollectorSpec{ + otelcol := v1alpha2.OpenTelemetryCollector{ + Spec: v1alpha2.OpenTelemetryCollectorSpec{ Mode: "statefulset", - VolumeClaimTemplates: []corev1.PersistentVolumeClaim{{ - ObjectMeta: metav1.ObjectMeta{ - Name: "added-volume", - }, - Spec: corev1.PersistentVolumeClaimSpec{ - AccessModes: []corev1.PersistentVolumeAccessMode{"ReadWriteOnce"}, - Resources: corev1.VolumeResourceRequirements{ - Requests: corev1.ResourceList{"storage": resource.MustParse("1Gi")}, + OpenTelemetryCommonFields: v1alpha2.OpenTelemetryCommonFields{ + VolumeClaimTemplates: []corev1.PersistentVolumeClaim{{ + ObjectMeta: metav1.ObjectMeta{ + Name: "added-volume", }, - }, - }}, + Spec: corev1.PersistentVolumeClaimSpec{ + AccessModes: []corev1.PersistentVolumeAccessMode{"ReadWriteOnce"}, + Resources: corev1.VolumeResourceRequirements{ + Requests: corev1.ResourceList{"storage": resource.MustParse("1Gi")}, + }, + }, + }}, + }, }, } @@ -63,20 +65,22 @@ func TestVolumeClaimAllowsUserToAdd(t *testing.T) { func TestVolumeClaimChecksForStatefulset(t *testing.T) { // prepare - otelcol := v1alpha1.OpenTelemetryCollector{ - Spec: v1alpha1.OpenTelemetryCollectorSpec{ + otelcol := v1alpha2.OpenTelemetryCollector{ + Spec: v1alpha2.OpenTelemetryCollectorSpec{ Mode: "daemonset", - VolumeClaimTemplates: []corev1.PersistentVolumeClaim{{ - ObjectMeta: metav1.ObjectMeta{ - Name: "added-volume", - }, - Spec: corev1.PersistentVolumeClaimSpec{ - AccessModes: []corev1.PersistentVolumeAccessMode{"ReadWriteOnce"}, - Resources: corev1.VolumeResourceRequirements{ - Requests: corev1.ResourceList{"storage": resource.MustParse("1Gi")}, + OpenTelemetryCommonFields: v1alpha2.OpenTelemetryCommonFields{ + VolumeClaimTemplates: []corev1.PersistentVolumeClaim{{ + ObjectMeta: metav1.ObjectMeta{ + Name: "added-volume", + }, + Spec: corev1.PersistentVolumeClaimSpec{ + AccessModes: []corev1.PersistentVolumeAccessMode{"ReadWriteOnce"}, + Resources: corev1.VolumeResourceRequirements{ + Requests: corev1.ResourceList{"storage": resource.MustParse("1Gi")}, + }, }, - }, - }}, + }}, + }, }, } diff --git a/pkg/sidecar/pod.go b/pkg/sidecar/pod.go index 6c119fc59c..faae733236 100644 --- a/pkg/sidecar/pod.go +++ b/pkg/sidecar/pod.go @@ -21,7 +21,7 @@ import ( "github.com/go-logr/logr" corev1 "k8s.io/api/core/v1" - "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1" + "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha2" "github.com/open-telemetry/opentelemetry-operator/internal/config" "github.com/open-telemetry/opentelemetry-operator/internal/manifests/collector" "github.com/open-telemetry/opentelemetry-operator/internal/naming" @@ -33,7 +33,7 @@ const ( ) // add a new sidecar container to the given pod, based on the given OpenTelemetryCollector. -func add(cfg config.Config, logger logr.Logger, otelcol v1alpha1.OpenTelemetryCollector, pod corev1.Pod, attributes []corev1.EnvVar) (corev1.Pod, error) { +func add(cfg config.Config, logger logr.Logger, otelcol v1alpha2.OpenTelemetryCollector, pod corev1.Pod, attributes []corev1.EnvVar) (corev1.Pod, error) { otelColCfg, err := collector.ReplaceConfig(otelcol) if err != nil { return pod, err diff --git a/pkg/sidecar/pod_test.go b/pkg/sidecar/pod_test.go index a6d6070f78..d030d370ae 100644 --- a/pkg/sidecar/pod_test.go +++ b/pkg/sidecar/pod_test.go @@ -24,6 +24,8 @@ import ( logf "sigs.k8s.io/controller-runtime/pkg/log" "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1" + "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha2" + "github.com/open-telemetry/opentelemetry-operator/internal/api/convert" "github.com/open-telemetry/opentelemetry-operator/internal/config" "github.com/open-telemetry/opentelemetry-operator/internal/naming" ) @@ -46,31 +48,36 @@ func TestAddSidecarWhenNoSidecarExists(t *testing.T) { Volumes: []corev1.Volume{{}}, }, } - otelcol := v1alpha1.OpenTelemetryCollector{ - ObjectMeta: metav1.ObjectMeta{ - Name: "otelcol-sample-with-a-name-that-is-longer-than-sixty-three-characters", - Namespace: "some-app", - }, - Spec: v1alpha1.OpenTelemetryCollectorSpec{ - Ports: []corev1.ServicePort{ - { - Name: "metrics", - Port: 8888, - Protocol: corev1.ProtocolTCP, - }, + otelcol, err := convert.V1Alpha1to2( + v1alpha1.OpenTelemetryCollector{ + ObjectMeta: metav1.ObjectMeta{ + Name: "otelcol-sample-with-a-name-that-is-longer-than-sixty-three-characters", + Namespace: "some-app", }, - InitContainers: []corev1.Container{ - { - Name: "test", + Spec: v1alpha1.OpenTelemetryCollectorSpec{ + Ports: []corev1.ServicePort{ + { + Name: "metrics", + Port: 8888, + Protocol: corev1.ProtocolTCP, + }, }, - }, - Config: ` + InitContainers: []corev1.Container{ + { + Name: "test", + }, + }, + Config: ` receivers: exporters: processors: `, + }, }, - } + ) + require.NoError(t, err) + otelcolYaml, err := otelcol.Spec.Config.Yaml() + require.NoError(t, err) cfg := config.New(config.WithCollectorImage("some-default-image")) // test @@ -98,7 +105,7 @@ processors: }, { Name: "OTEL_CONFIG", - Value: otelcol.Spec.Config, + Value: string(otelcolYaml), }, }, Ports: []corev1.ContainerPort{ @@ -123,7 +130,7 @@ func TestAddSidecarWhenOneExistsAlready(t *testing.T) { }, }, } - otelcol := v1alpha1.OpenTelemetryCollector{} + otelcol := v1alpha2.OpenTelemetryCollector{} cfg := config.New(config.WithCollectorImage("some-default-image")) // test @@ -212,7 +219,7 @@ func TestAddSidecarWithAditionalEnv(t *testing.T) { }, }, } - otelcol := v1alpha1.OpenTelemetryCollector{ + otelcol := v1alpha2.OpenTelemetryCollector{ ObjectMeta: metav1.ObjectMeta{ Name: "otelcol-sample", Namespace: "some-app", diff --git a/pkg/sidecar/podmutator.go b/pkg/sidecar/podmutator.go index a7a0737b53..d142d90353 100644 --- a/pkg/sidecar/podmutator.go +++ b/pkg/sidecar/podmutator.go @@ -27,6 +27,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1" + "github.com/open-telemetry/opentelemetry-operator/internal/api/convert" "github.com/open-telemetry/opentelemetry-operator/internal/config" "github.com/open-telemetry/opentelemetry-operator/internal/webhook/podmutation" ) @@ -97,7 +98,11 @@ func (p *sidecarPodMutator) Mutate(ctx context.Context, ns corev1.Namespace, pod // we should add the sidecar. logger.V(1).Info("injecting sidecar into pod", "otelcol-namespace", otelcol.Namespace, "otelcol-name", otelcol.Name) - return add(p.config, p.logger, otelcol, pod, attributes) + otc, err := convert.V1Alpha1to2(otelcol) + if err != nil { + return corev1.Pod{}, err + } + return add(p.config, p.logger, otc, pod, attributes) } func (p *sidecarPodMutator) getCollectorInstance(ctx context.Context, ns corev1.Namespace, ann string) (v1alpha1.OpenTelemetryCollector, error) { diff --git a/tests/e2e/managed-reconcile/02-assert.yaml b/tests/e2e/managed-reconcile/02-assert.yaml index f1fe0ee158..0a6a83b1a3 100644 --- a/tests/e2e/managed-reconcile/02-assert.yaml +++ b/tests/e2e/managed-reconcile/02-assert.yaml @@ -58,16 +58,15 @@ data: receivers: otlp: protocols: - grpc: - http: - processors: - + grpc: null + http: null exporters: - debug: - + debug: null service: pipelines: traces: - receivers: [otlp] + exporters: + - debug processors: [] - exporters: [debug] + receivers: + - otlp diff --git a/tests/e2e/smoke-targetallocator/00-assert.yaml b/tests/e2e/smoke-targetallocator/00-assert.yaml index f46af1dd15..12d69b49ea 100644 --- a/tests/e2e/smoke-targetallocator/00-assert.yaml +++ b/tests/e2e/smoke-targetallocator/00-assert.yaml @@ -27,26 +27,25 @@ metadata: data: collector.yaml: | exporters: - debug: null - processors: null + debug: null receivers: - jaeger: - protocols: - grpc: null - prometheus: - config: {} - target_allocator: - collector_id: ${POD_NAME} - endpoint: http://stateful-targetallocator:80 - interval: 30s + jaeger: + protocols: + grpc: null + prometheus: + config: {} + target_allocator: + collector_id: ${POD_NAME} + endpoint: http://stateful-targetallocator:80 + interval: 30s service: - pipelines: - traces: - exporters: - - debug - processors: [] - receivers: - - jaeger + pipelines: + traces: + exporters: + - debug + processors: [] + receivers: + - jaeger --- # Print TA pod logs if test fails apiVersion: kuttl.dev/v1beta1 diff --git a/tests/e2e/targetallocator-prometheuscr/00-assert.yaml b/tests/e2e/targetallocator-prometheuscr/00-assert.yaml index cd45341931..98b57419d4 100644 --- a/tests/e2e/targetallocator-prometheuscr/00-assert.yaml +++ b/tests/e2e/targetallocator-prometheuscr/00-assert.yaml @@ -27,24 +27,23 @@ metadata: data: collector.yaml: | exporters: - prometheus: - endpoint: 0.0.0.0:9090 - processors: null + prometheus: + endpoint: 0.0.0.0:9090 receivers: - prometheus: - config: {} - target_allocator: - collector_id: ${POD_NAME} - endpoint: http://prometheus-cr-targetallocator:80 - interval: 30s + prometheus: + config: {} + target_allocator: + collector_id: ${POD_NAME} + endpoint: http://prometheus-cr-targetallocator:80 + interval: 30s service: - pipelines: - metrics: - exporters: - - prometheus - processors: [] - receivers: - - prometheus + pipelines: + metrics: + exporters: + - prometheus + processors: [] + receivers: + - prometheus --- # Print TA pod logs if test fails apiVersion: kuttl.dev/v1beta1