From c9508fe58aadc551090935356f27e49aa3604414 Mon Sep 17 00:00:00 2001 From: Pavol Loffay Date: Tue, 5 Mar 2024 19:25:52 +0100 Subject: [PATCH] Add conversion go APIs (#2711) * Add conversion go APIs Signed-off-by: Pavol Loffay * Fix Signed-off-by: Pavol Loffay * Fix Signed-off-by: Pavol Loffay * Fix Signed-off-by: Pavol Loffay --------- Signed-off-by: Pavol Loffay --- apis/v1alpha1/convert.go | 43 ++++++++++- apis/v1alpha1/convert_test.go | 74 ++++++++++++++++++- apis/v1beta1/opentelemetrycollector_types.go | 2 + .../opentelemetrycollector_controller.go | 4 +- pkg/sidecar/pod_test.go | 42 ++++++----- pkg/sidecar/podmutator.go | 4 +- 6 files changed, 142 insertions(+), 27 deletions(-) diff --git a/apis/v1alpha1/convert.go b/apis/v1alpha1/convert.go index 792e891e30..9f7e01fb78 100644 --- a/apis/v1alpha1/convert.go +++ b/apis/v1alpha1/convert.go @@ -16,15 +16,53 @@ package v1alpha1 import ( "errors" + "fmt" "gopkg.in/yaml.v3" appsv1 "k8s.io/api/apps/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/conversion" "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" ) -func Tov1beta1(in OpenTelemetryCollector) (v1beta1.OpenTelemetryCollector, error) { +var _ conversion.Convertible = &OpenTelemetryCollector{} + +func (src *OpenTelemetryCollector) ConvertTo(dstRaw conversion.Hub) error { + switch t := dstRaw.(type) { + case *v1beta1.OpenTelemetryCollector: + dst := dstRaw.(*v1beta1.OpenTelemetryCollector) + convertedSrc, err := tov1beta1(*src) + if err != nil { + return fmt.Errorf("failed to convert to v1beta1: %w", err) + } + dst.ObjectMeta = convertedSrc.ObjectMeta + dst.Spec = convertedSrc.Spec + dst.Status = convertedSrc.Status + default: + return fmt.Errorf("unsupported type %v", t) + } + return nil +} + +func (dst *OpenTelemetryCollector) ConvertFrom(srcRaw conversion.Hub) error { + switch t := srcRaw.(type) { + case *v1beta1.OpenTelemetryCollector: + src := srcRaw.(*v1beta1.OpenTelemetryCollector) + srcConverted, err := tov1alpha1(*src) + if err != nil { + return fmt.Errorf("failed to convert to v1alpha1: %w", err) + } + dst.ObjectMeta = srcConverted.ObjectMeta + dst.Spec = srcConverted.Spec + dst.Status = srcConverted.Status + default: + return fmt.Errorf("unsupported type %v", t) + } + return nil +} + +func tov1beta1(in OpenTelemetryCollector) (v1beta1.OpenTelemetryCollector, error) { copy := in.DeepCopy() cfg := &v1beta1.Config{} if err := yaml.Unmarshal([]byte(copy.Spec.Config), cfg); err != nil { @@ -120,6 +158,7 @@ func tov1beta1TA(in OpenTelemetryTargetAllocator) v1beta1.TargetAllocatorEmbedde PrometheusCR: v1beta1.TargetAllocatorPrometheusCR{ Enabled: in.PrometheusCR.Enabled, ScrapeInterval: in.PrometheusCR.ScrapeInterval, + // prometheus_cr.pod_monitor_selector shouldn't be nil when selector is empty PodMonitorSelector: &metav1.LabelSelector{ MatchLabels: in.PrometheusCR.PodMonitorSelector, }, @@ -236,7 +275,7 @@ func tov1alpha1(in v1beta1.OpenTelemetryCollector) (*OpenTelemetryCollector, err SecurityContext: copy.Spec.SecurityContext, PodSecurityContext: copy.Spec.PodSecurityContext, PodAnnotations: copy.Spec.PodAnnotations, - TargetAllocator: tov1alpha1TA(in.Spec.TargetAllocator), + TargetAllocator: tov1alpha1TA(copy.Spec.TargetAllocator), Mode: Mode(copy.Spec.Mode), ServiceAccount: copy.Spec.ServiceAccount, Image: copy.Spec.Image, diff --git a/apis/v1alpha1/convert_test.go b/apis/v1alpha1/convert_test.go index ad248d278b..f7952702ce 100644 --- a/apis/v1alpha1/convert_test.go +++ b/apis/v1alpha1/convert_test.go @@ -62,7 +62,7 @@ func Test_tov1beta1_config(t *testing.T) { }, } - cfgV2, err := Tov1beta1(cfgV1) + cfgV2, err := tov1beta1(cfgV1) assert.Nil(t, err) assert.NotNil(t, cfgV2) assert.Equal(t, cfgV1.Spec.Args, cfgV2.Spec.Args) @@ -79,7 +79,7 @@ func Test_tov1beta1_config(t *testing.T) { }, } - _, err := Tov1beta1(cfgV1) + _, err := tov1beta1(cfgV1) assert.ErrorContains(t, err, "could not convert config json to v1beta1.Config") }) } @@ -310,7 +310,7 @@ func Test_tov1beta1AndBack(t *testing.T) { }, } - colbeta1, err := Tov1beta1(*colalpha1) + colbeta1, err := tov1beta1(*colalpha1) require.NoError(t, err) colalpha1Converted, err := tov1alpha1(colbeta1) require.NoError(t, err) @@ -421,3 +421,71 @@ func createTA() OpenTelemetryTargetAllocator { }, } } + +func TestConvertTo(t *testing.T) { + col := OpenTelemetryCollector{ + ObjectMeta: metav1.ObjectMeta{ + Name: "otel", + }, + Spec: OpenTelemetryCollectorSpec{ + ServiceAccount: "otelcol", + }, + Status: OpenTelemetryCollectorStatus{ + Image: "otel/col", + }, + } + colbeta1 := v1beta1.OpenTelemetryCollector{} + err := col.ConvertTo(&colbeta1) + require.NoError(t, err) + assert.Equal(t, v1beta1.OpenTelemetryCollector{ + ObjectMeta: metav1.ObjectMeta{ + Name: "otel", + }, + Spec: v1beta1.OpenTelemetryCollectorSpec{ + OpenTelemetryCommonFields: v1beta1.OpenTelemetryCommonFields{ + ServiceAccount: "otelcol", + }, + TargetAllocator: v1beta1.TargetAllocatorEmbedded{ + PrometheusCR: v1beta1.TargetAllocatorPrometheusCR{ + PodMonitorSelector: &metav1.LabelSelector{}, + ServiceMonitorSelector: &metav1.LabelSelector{}, + }, + }, + }, + Status: v1beta1.OpenTelemetryCollectorStatus{ + Image: "otel/col", + }, + }, colbeta1) +} + +func TestConvertFrom(t *testing.T) { + colbeta1 := v1beta1.OpenTelemetryCollector{ + ObjectMeta: metav1.ObjectMeta{ + Name: "otel", + }, + Spec: v1beta1.OpenTelemetryCollectorSpec{ + OpenTelemetryCommonFields: v1beta1.OpenTelemetryCommonFields{ + ServiceAccount: "otelcol", + }, + }, + Status: v1beta1.OpenTelemetryCollectorStatus{ + Image: "otel/col", + }, + } + col := OpenTelemetryCollector{} + err := col.ConvertFrom(&colbeta1) + require.NoError(t, err) + // set config to empty. The v1beta1 marshals config with empty receivers, exporters.. + col.Spec.Config = "" + assert.Equal(t, OpenTelemetryCollector{ + ObjectMeta: metav1.ObjectMeta{ + Name: "otel", + }, + Spec: OpenTelemetryCollectorSpec{ + ServiceAccount: "otelcol", + }, + Status: OpenTelemetryCollectorStatus{ + Image: "otel/col", + }, + }, col) +} diff --git a/apis/v1beta1/opentelemetrycollector_types.go b/apis/v1beta1/opentelemetrycollector_types.go index 246bdbb0d5..6982cabab9 100644 --- a/apis/v1beta1/opentelemetrycollector_types.go +++ b/apis/v1beta1/opentelemetrycollector_types.go @@ -334,6 +334,8 @@ type OpenTelemetryCollector struct { Status OpenTelemetryCollectorStatus `json:"status,omitempty"` } +func (*OpenTelemetryCollector) Hub() {} + //+kubebuilder:object:root=true // OpenTelemetryCollectorList contains a list of OpenTelemetryCollector. diff --git a/controllers/opentelemetrycollector_controller.go b/controllers/opentelemetrycollector_controller.go index 8ce028ff7e..309da9aa91 100644 --- a/controllers/opentelemetrycollector_controller.go +++ b/controllers/opentelemetrycollector_controller.go @@ -37,6 +37,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1" + "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" "github.com/open-telemetry/opentelemetry-operator/internal/autodetect/openshift" "github.com/open-telemetry/opentelemetry-operator/internal/config" "github.com/open-telemetry/opentelemetry-operator/internal/manifests" @@ -130,7 +131,8 @@ func (r *OpenTelemetryCollectorReconciler) findOtelOwnedObjects(ctx context.Cont } func (r *OpenTelemetryCollectorReconciler) getParams(instance v1alpha1.OpenTelemetryCollector) (manifests.Params, error) { - otelCol, err := v1alpha1.Tov1beta1(instance) + otelCol := v1beta1.OpenTelemetryCollector{} + err := instance.ConvertTo(&otelCol) if err != nil { return manifests.Params{}, err } diff --git a/pkg/sidecar/pod_test.go b/pkg/sidecar/pod_test.go index 044437309b..a15548c62d 100644 --- a/pkg/sidecar/pod_test.go +++ b/pkg/sidecar/pod_test.go @@ -47,33 +47,35 @@ func TestAddSidecarWhenNoSidecarExists(t *testing.T) { Volumes: []corev1.Volume{{}}, }, } - otelcol, err := v1alpha1.Tov1beta1( - 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, - }, + + v1alpha1Col := 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, }, - InitContainers: []corev1.Container{ - { - Name: "test", - }, + }, + InitContainers: []corev1.Container{ + { + Name: "test", }, - Config: ` + }, + Config: ` receivers: exporters: processors: `, - }, }, - ) + } + + otelcol := v1beta1.OpenTelemetryCollector{} + err := v1alpha1Col.ConvertTo(&otelcol) require.NoError(t, err) otelcolYaml, err := otelcol.Spec.Config.Yaml() require.NoError(t, err) diff --git a/pkg/sidecar/podmutator.go b/pkg/sidecar/podmutator.go index b489aec7f8..635c668463 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/apis/v1beta1" "github.com/open-telemetry/opentelemetry-operator/internal/config" "github.com/open-telemetry/opentelemetry-operator/internal/webhook/podmutation" ) @@ -97,7 +98,8 @@ 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) - otc, err := v1alpha1.Tov1beta1(otelcol) + otc := v1beta1.OpenTelemetryCollector{} + err = otelcol.ConvertTo(&otc) if err != nil { return corev1.Pod{}, err }