From a394a0e45f22277502a0488a64b79d55ea0ec7a5 Mon Sep 17 00:00:00 2001 From: andrefrco Date: Sun, 24 Aug 2025 23:03:44 -0300 Subject: [PATCH] feat: add TrafficDistribution support for OpenTelemetryCollector and TargetAllocator Services Add TrafficDistribution field to OpenTelemetryCommonFields which is inherited by OpenTelemetryCollector and TargetAllocator. This field allows setting the traffic distribution policy for Kubernetes Services created by these resources. Signed-off-by: andrefrco --- .chloggen/traffic-distribution-field.yaml | 18 ++++++++++++++++ apis/v1alpha1/convert.go | 2 ++ apis/v1alpha1/opentelemetrycollector_types.go | 5 +++++ apis/v1alpha1/zz_generated.deepcopy.go | 5 +++++ apis/v1beta1/common.go | 5 +++++ apis/v1beta1/zz_generated.deepcopy.go | 5 +++++ ...emetry-operator.clusterserviceversion.yaml | 2 +- ...ntelemetry.io_opentelemetrycollectors.yaml | 4 ++++ .../opentelemetry.io_targetallocators.yaml | 2 ++ ...emetry-operator.clusterserviceversion.yaml | 2 +- ...ntelemetry.io_opentelemetrycollectors.yaml | 4 ++++ .../opentelemetry.io_targetallocators.yaml | 2 ++ ...ntelemetry.io_opentelemetrycollectors.yaml | 4 ++++ .../opentelemetry.io_targetallocators.yaml | 2 ++ docs/api/opentelemetrycollectors.md | 18 ++++++++++++++++ docs/api/targetallocators.md | 9 ++++++++ internal/manifests/collector/service.go | 11 ++++++---- internal/manifests/collector/service_test.go | 18 ++++++++++++++++ internal/manifests/targetallocator/service.go | 9 ++++---- tests/e2e/smoke-ports/00-install.yaml | 1 + tests/e2e/smoke-ports/01-install.yaml | 1 + tests/e2e/smoke-ports/chainsaw-test.yaml | 21 +++++++++++++++++++ 22 files changed, 140 insertions(+), 10 deletions(-) create mode 100644 .chloggen/traffic-distribution-field.yaml diff --git a/.chloggen/traffic-distribution-field.yaml b/.chloggen/traffic-distribution-field.yaml new file mode 100644 index 0000000000..a187c21538 --- /dev/null +++ b/.chloggen/traffic-distribution-field.yaml @@ -0,0 +1,18 @@ +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: enhancement + +# The name of the component, or a single word describing the area of concern, (e.g. collector, target allocator, auto-instrumentation, opamp, github action) +component: collector, target allocator + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Add TrafficDistribution support for OpenTelemetryCollector and TargetAllocator Services + +# One or more tracking issues related to the change +issues: [4285] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: | + The TrafficDistribution field is now available in OpenTelemetryCollector and TargetAllocator. + This field allows setting the traffic distribution policy for Kubernetes Services. diff --git a/apis/v1alpha1/convert.go b/apis/v1alpha1/convert.go index d672e0122d..7638996abb 100644 --- a/apis/v1alpha1/convert.go +++ b/apis/v1alpha1/convert.go @@ -115,6 +115,7 @@ func tov1beta1(in OpenTelemetryCollector) v1beta1.OpenTelemetryCollector { PriorityClassName: copy.Spec.PriorityClassName, InitContainers: copy.Spec.InitContainers, AdditionalContainers: copy.Spec.AdditionalContainers, + TrafficDistribution: copy.Spec.TrafficDistribution, }, StatefulSetCommonFields: v1beta1.StatefulSetCommonFields{ VolumeClaimTemplates: copy.Spec.VolumeClaimTemplates, @@ -371,6 +372,7 @@ func tov1alpha1(in v1beta1.OpenTelemetryCollector) (*OpenTelemetryCollector, err ConfigMaps: tov1alpha1ConfigMaps(copy.Spec.ConfigMaps), UpdateStrategy: copy.Spec.DaemonSetUpdateStrategy, DeploymentUpdateStrategy: copy.Spec.DeploymentUpdateStrategy, + TrafficDistribution: copy.Spec.TrafficDistribution, }, }, nil } diff --git a/apis/v1alpha1/opentelemetrycollector_types.go b/apis/v1alpha1/opentelemetrycollector_types.go index 5a466137a8..53ac68c3a0 100644 --- a/apis/v1alpha1/opentelemetrycollector_types.go +++ b/apis/v1alpha1/opentelemetrycollector_types.go @@ -238,6 +238,11 @@ type OpenTelemetryCollectorSpec struct { // If not specified, it will default to "-headless". // +optional ServiceName string `json:"serviceName,omitempty"` + // TrafficDistribution specifies how traffic to this service is routed. + // https://kubernetes.io/docs/concepts/services-networking/service/#traffic-distribution + // This is only applicable to Service resources. + // +optional + TrafficDistribution *string `json:"trafficDistribution,omitempty"` // AdditionalContainers allows injecting additional containers into the Collector's pod definition. // These sidecar containers can be used for authentication proxies, log shipping sidecars, agents for shipping diff --git a/apis/v1alpha1/zz_generated.deepcopy.go b/apis/v1alpha1/zz_generated.deepcopy.go index c03c4d4443..2168d86fe3 100644 --- a/apis/v1alpha1/zz_generated.deepcopy.go +++ b/apis/v1alpha1/zz_generated.deepcopy.go @@ -973,6 +973,11 @@ func (in *OpenTelemetryCollectorSpec) DeepCopyInto(out *OpenTelemetryCollectorSp (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.TrafficDistribution != nil { + in, out := &in.TrafficDistribution, &out.TrafficDistribution + *out = new(string) + **out = **in + } if in.AdditionalContainers != nil { in, out := &in.AdditionalContainers, &out.AdditionalContainers *out = make([]v1.Container, len(*in)) diff --git a/apis/v1beta1/common.go b/apis/v1beta1/common.go index 7ad5546b4e..e606506fec 100644 --- a/apis/v1beta1/common.go +++ b/apis/v1beta1/common.go @@ -224,6 +224,11 @@ type OpenTelemetryCommonFields struct { // +kubebuilder:default:=SingleStack // +optional IpFamilyPolicy *v1.IPFamilyPolicy `json:"ipFamilyPolicy,omitempty"` + // TrafficDistribution specifies how traffic to this service is routed. + // https://kubernetes.io/docs/concepts/services-networking/service/#traffic-distribution + // This is only applicable to Service resources. + // +optional + TrafficDistribution *string `json:"trafficDistribution,omitempty"` } type StatefulSetCommonFields struct { diff --git a/apis/v1beta1/zz_generated.deepcopy.go b/apis/v1beta1/zz_generated.deepcopy.go index f1c340949f..6d588d0a96 100644 --- a/apis/v1beta1/zz_generated.deepcopy.go +++ b/apis/v1beta1/zz_generated.deepcopy.go @@ -490,6 +490,11 @@ func (in *OpenTelemetryCommonFields) DeepCopyInto(out *OpenTelemetryCommonFields *out = new(v1.IPFamilyPolicy) **out = **in } + if in.TrafficDistribution != nil { + in, out := &in.TrafficDistribution, &out.TrafficDistribution + *out = new(string) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenTelemetryCommonFields. diff --git a/bundle/community/manifests/opentelemetry-operator.clusterserviceversion.yaml b/bundle/community/manifests/opentelemetry-operator.clusterserviceversion.yaml index fd896d2fc6..971cdb7555 100644 --- a/bundle/community/manifests/opentelemetry-operator.clusterserviceversion.yaml +++ b/bundle/community/manifests/opentelemetry-operator.clusterserviceversion.yaml @@ -99,7 +99,7 @@ metadata: categories: Logging & Tracing,Monitoring certified: "false" containerImage: ghcr.io/open-telemetry/opentelemetry-operator/opentelemetry-operator - createdAt: "2025-09-03T14:59:23Z" + createdAt: "2025-08-25T02:08:39Z" description: Provides the OpenTelemetry components, including the Collector operators.operatorframework.io/builder: operator-sdk-v1.29.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 diff --git a/bundle/community/manifests/opentelemetry.io_opentelemetrycollectors.yaml b/bundle/community/manifests/opentelemetry.io_opentelemetrycollectors.yaml index b919719c96..41080ab6fc 100644 --- a/bundle/community/manifests/opentelemetry.io_opentelemetrycollectors.yaml +++ b/bundle/community/manifests/opentelemetry.io_opentelemetrycollectors.yaml @@ -3500,6 +3500,8 @@ spec: - whenUnsatisfiable type: object type: array + trafficDistribution: + type: string updateStrategy: properties: rollingUpdate: @@ -8289,6 +8291,8 @@ spec: - whenUnsatisfiable type: object type: array + trafficDistribution: + type: string upgradeStrategy: enum: - automatic diff --git a/bundle/community/manifests/opentelemetry.io_targetallocators.yaml b/bundle/community/manifests/opentelemetry.io_targetallocators.yaml index e67620328f..b94f4044d2 100644 --- a/bundle/community/manifests/opentelemetry.io_targetallocators.yaml +++ b/bundle/community/manifests/opentelemetry.io_targetallocators.yaml @@ -2580,6 +2580,8 @@ spec: - whenUnsatisfiable type: object type: array + trafficDistribution: + type: string volumeMounts: items: properties: diff --git a/bundle/openshift/manifests/opentelemetry-operator.clusterserviceversion.yaml b/bundle/openshift/manifests/opentelemetry-operator.clusterserviceversion.yaml index 0e79ea02cb..9a7f86e344 100644 --- a/bundle/openshift/manifests/opentelemetry-operator.clusterserviceversion.yaml +++ b/bundle/openshift/manifests/opentelemetry-operator.clusterserviceversion.yaml @@ -99,7 +99,7 @@ metadata: categories: Logging & Tracing,Monitoring certified: "false" containerImage: ghcr.io/open-telemetry/opentelemetry-operator/opentelemetry-operator - createdAt: "2025-09-03T14:59:23Z" + createdAt: "2025-08-25T02:08:40Z" description: Provides the OpenTelemetry components, including the Collector operators.operatorframework.io/builder: operator-sdk-v1.29.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 diff --git a/bundle/openshift/manifests/opentelemetry.io_opentelemetrycollectors.yaml b/bundle/openshift/manifests/opentelemetry.io_opentelemetrycollectors.yaml index 6a2dc4028b..6c0da5d8ec 100644 --- a/bundle/openshift/manifests/opentelemetry.io_opentelemetrycollectors.yaml +++ b/bundle/openshift/manifests/opentelemetry.io_opentelemetrycollectors.yaml @@ -3499,6 +3499,8 @@ spec: - whenUnsatisfiable type: object type: array + trafficDistribution: + type: string updateStrategy: properties: rollingUpdate: @@ -8288,6 +8290,8 @@ spec: - whenUnsatisfiable type: object type: array + trafficDistribution: + type: string upgradeStrategy: enum: - automatic diff --git a/bundle/openshift/manifests/opentelemetry.io_targetallocators.yaml b/bundle/openshift/manifests/opentelemetry.io_targetallocators.yaml index e67620328f..b94f4044d2 100644 --- a/bundle/openshift/manifests/opentelemetry.io_targetallocators.yaml +++ b/bundle/openshift/manifests/opentelemetry.io_targetallocators.yaml @@ -2580,6 +2580,8 @@ spec: - whenUnsatisfiable type: object type: array + trafficDistribution: + type: string volumeMounts: items: properties: diff --git a/config/crd/bases/opentelemetry.io_opentelemetrycollectors.yaml b/config/crd/bases/opentelemetry.io_opentelemetrycollectors.yaml index 2b2c226be7..69a4db2bd6 100644 --- a/config/crd/bases/opentelemetry.io_opentelemetrycollectors.yaml +++ b/config/crd/bases/opentelemetry.io_opentelemetrycollectors.yaml @@ -3486,6 +3486,8 @@ spec: - whenUnsatisfiable type: object type: array + trafficDistribution: + type: string updateStrategy: properties: rollingUpdate: @@ -8275,6 +8277,8 @@ spec: - whenUnsatisfiable type: object type: array + trafficDistribution: + type: string upgradeStrategy: enum: - automatic diff --git a/config/crd/bases/opentelemetry.io_targetallocators.yaml b/config/crd/bases/opentelemetry.io_targetallocators.yaml index 30838f47a4..5369894b77 100644 --- a/config/crd/bases/opentelemetry.io_targetallocators.yaml +++ b/config/crd/bases/opentelemetry.io_targetallocators.yaml @@ -2578,6 +2578,8 @@ spec: - whenUnsatisfiable type: object type: array + trafficDistribution: + type: string volumeMounts: items: properties: diff --git a/docs/api/opentelemetrycollectors.md b/docs/api/opentelemetrycollectors.md index 20cb37792c..2b70ef4ab7 100644 --- a/docs/api/opentelemetrycollectors.md +++ b/docs/api/opentelemetrycollectors.md @@ -411,6 +411,15 @@ https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constrain This is only relevant to statefulset, and deployment mode
false + + trafficDistribution + string + + TrafficDistribution specifies how traffic to this service is routed. +https://kubernetes.io/docs/concepts/services-networking/service/#traffic-distribution +This is only applicable to Service resources.
+ + false updateStrategy object @@ -19810,6 +19819,15 @@ https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constrain This only works with the following OpenTelemetryCollector mode's: statefulset, and deployment.
false + + trafficDistribution + string + + TrafficDistribution specifies how traffic to this service is routed. +https://kubernetes.io/docs/concepts/services-networking/service/#traffic-distribution +This is only applicable to Service resources.
+ + false upgradeStrategy enum diff --git a/docs/api/targetallocators.md b/docs/api/targetallocators.md index d109306482..58d567693e 100644 --- a/docs/api/targetallocators.md +++ b/docs/api/targetallocators.md @@ -403,6 +403,15 @@ https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constrain This only works with the following OpenTelemetryCollector mode's: statefulset, and deployment.
false + + trafficDistribution + string + + TrafficDistribution specifies how traffic to this service is routed. +https://kubernetes.io/docs/concepts/services-networking/service/#traffic-distribution +This is only applicable to Service resources.
+ + false volumeMounts []object diff --git a/internal/manifests/collector/service.go b/internal/manifests/collector/service.go index 6e5bcbbd75..ca4efc1ced 100644 --- a/internal/manifests/collector/service.go +++ b/internal/manifests/collector/service.go @@ -91,8 +91,9 @@ func MonitoringService(params manifests.Params) (*corev1.Service, error) { Name: "monitoring", Port: metricsPort, }}, - IPFamilies: params.OtelCol.Spec.IpFamilies, - IPFamilyPolicy: params.OtelCol.Spec.IpFamilyPolicy, + IPFamilies: params.OtelCol.Spec.IpFamilies, + IPFamilyPolicy: params.OtelCol.Spec.IpFamilyPolicy, + TrafficDistribution: params.OtelCol.Spec.TrafficDistribution, }, }, nil } @@ -124,8 +125,9 @@ func ExtensionService(params manifests.Params) (*corev1.Service, error) { Annotations: annotations, }, Spec: corev1.ServiceSpec{ - Ports: ports, - Selector: manifestutils.SelectorLabels(params.OtelCol.ObjectMeta, ComponentOpenTelemetryCollector), + Ports: ports, + Selector: manifestutils.SelectorLabels(params.OtelCol.ObjectMeta, ComponentOpenTelemetryCollector), + TrafficDistribution: params.OtelCol.Spec.TrafficDistribution, }, }, nil } @@ -199,6 +201,7 @@ func Service(params manifests.Params) (*corev1.Service, error) { Ports: ports, IPFamilies: params.OtelCol.Spec.IpFamilies, IPFamilyPolicy: params.OtelCol.Spec.IpFamilyPolicy, + TrafficDistribution: params.OtelCol.Spec.TrafficDistribution, }, }, nil } diff --git a/internal/manifests/collector/service_test.go b/internal/manifests/collector/service_test.go index 73fddb9932..2660d7beb4 100644 --- a/internal/manifests/collector/service_test.go +++ b/internal/manifests/collector/service_test.go @@ -586,3 +586,21 @@ func TestServiceWithIpFamily(t *testing.T) { assert.Equal(t, actual.Spec.IPFamilyPolicy, params.OtelCol.Spec.IpFamilyPolicy) }) } + +func TestServiceWithTrafficDistribution(t *testing.T) { + t.Run("should set TrafficDistribution when specified", func(t *testing.T) { + params := deploymentParams() + trafficDistribution := "PreferClose" + params.OtelCol.Spec.TrafficDistribution = &trafficDistribution + actual, err := Service(params) + assert.NoError(t, err) + assert.Equal(t, &trafficDistribution, actual.Spec.TrafficDistribution) + }) + + t.Run("should not set TrafficDistribution when not specified", func(t *testing.T) { + params := deploymentParams() + actual, err := Service(params) + assert.NoError(t, err) + assert.Nil(t, actual.Spec.TrafficDistribution) + }) +} diff --git a/internal/manifests/targetallocator/service.go b/internal/manifests/targetallocator/service.go index 22404e4bec..e9215bf57f 100644 --- a/internal/manifests/targetallocator/service.go +++ b/internal/manifests/targetallocator/service.go @@ -39,10 +39,11 @@ func Service(params Params) *corev1.Service { Labels: labels, }, Spec: corev1.ServiceSpec{ - Selector: selector, - Ports: ports, - IPFamilies: params.TargetAllocator.Spec.IpFamilies, - IPFamilyPolicy: params.TargetAllocator.Spec.IpFamilyPolicy, + Selector: selector, + Ports: ports, + IPFamilies: params.TargetAllocator.Spec.IpFamilies, + IPFamilyPolicy: params.TargetAllocator.Spec.IpFamilyPolicy, + TrafficDistribution: params.TargetAllocator.Spec.TrafficDistribution, }, } } diff --git a/tests/e2e/smoke-ports/00-install.yaml b/tests/e2e/smoke-ports/00-install.yaml index 66cf042629..d90d30438b 100644 --- a/tests/e2e/smoke-ports/00-install.yaml +++ b/tests/e2e/smoke-ports/00-install.yaml @@ -4,6 +4,7 @@ metadata: name: smoke-ports spec: mode: daemonset + trafficDistribution: PreferClose ports: - appProtocol: grpc name: otlp-grpc diff --git a/tests/e2e/smoke-ports/01-install.yaml b/tests/e2e/smoke-ports/01-install.yaml index fc15363631..f55ee8066e 100644 --- a/tests/e2e/smoke-ports/01-install.yaml +++ b/tests/e2e/smoke-ports/01-install.yaml @@ -4,6 +4,7 @@ metadata: name: smoke-ports spec: mode: daemonset + trafficDistribution: PreferClose ports: - appProtocol: http name: custom-port diff --git a/tests/e2e/smoke-ports/chainsaw-test.yaml b/tests/e2e/smoke-ports/chainsaw-test.yaml index ffd5f5e001..71ce1834c1 100755 --- a/tests/e2e/smoke-ports/chainsaw-test.yaml +++ b/tests/e2e/smoke-ports/chainsaw-test.yaml @@ -5,6 +5,11 @@ metadata: creationTimestamp: null name: smoke-ports spec: + bindings: + - name: version + value: (x_k8s_server_version($config)) + - name: minorVersion + value: (to_number($version.minor)) steps: - name: step-00 try: @@ -12,9 +17,25 @@ spec: file: 00-install.yaml - assert: file: 00-assert.yaml + - script: + content: kubectl get svc smoke-ports-collector -n $NAMESPACE -o jsonpath='{.spec.trafficDistribution}' || echo "" + outputs: + - name: trafficDistribution + value: ($stdout) + - assert: + resource: + (($minorVersion >= `29` && $trafficDistribution == 'PreferClose') || ($minorVersion < `26` && $trafficDistribution == '')): true - name: step-01 try: - apply: file: 01-install.yaml - assert: file: 01-assert.yaml + - script: + content: kubectl get svc smoke-ports-collector -n $NAMESPACE -o jsonpath='{.spec.trafficDistribution}' || echo "" + outputs: + - name: trafficDistribution + value: ($stdout) + - assert: + resource: + (($minorVersion >= `29` && $trafficDistribution == 'PreferClose') || ($minorVersion < `26` && $trafficDistribution == '')): true