diff --git a/.chloggen/add-ip-families.yaml b/.chloggen/add-ip-families.yaml new file mode 100755 index 0000000000..bd4f68db2f --- /dev/null +++ b/.chloggen/add-ip-families.yaml @@ -0,0 +1,16 @@ +# 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' + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: "Enabling ipFamilies and ipFamilyPolicy to be configured via OpenTelemetryCollector" + +# One or more tracking issues related to the change +issues: [2958] + +# (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: diff --git a/apis/v1alpha1/opampbridge_types.go b/apis/v1alpha1/opampbridge_types.go index e8ee0e52e6..3f6a3dc3a2 100644 --- a/apis/v1alpha1/opampbridge_types.go +++ b/apis/v1alpha1/opampbridge_types.go @@ -107,6 +107,12 @@ type OpAMPBridgeSpec struct { TopologySpreadConstraints []v1.TopologySpreadConstraint `json:"topologySpreadConstraints,omitempty"` // PodDNSConfig defines the DNS parameters of a pod in addition to those generated from DNSPolicy. PodDNSConfig v1.PodDNSConfig `json:"podDnsConfig,omitempty"` + // IPFamily represents the IP Family (IPv4 or IPv6). This type is used + // to express the family of an IP expressed by a type (e.g. service.spec.ipFamilies). + // +optional + IpFamilies []v1.IPFamily `json:"ipFamilies,omitempty"` + // IPFamilyPolicy represents the dual-stack-ness requested or required by a Service + IpFamilyPolicy *v1.IPFamilyPolicy `json:"ipFamilyPolicy,omitempty"` } // OpAMPBridgeStatus defines the observed state of OpAMPBridge. diff --git a/apis/v1alpha1/zz_generated.deepcopy.go b/apis/v1alpha1/zz_generated.deepcopy.go index 086fafcfd2..87092d21f8 100644 --- a/apis/v1alpha1/zz_generated.deepcopy.go +++ b/apis/v1alpha1/zz_generated.deepcopy.go @@ -681,6 +681,16 @@ func (in *OpAMPBridgeSpec) DeepCopyInto(out *OpAMPBridgeSpec) { } } in.PodDNSConfig.DeepCopyInto(&out.PodDNSConfig) + if in.IpFamilies != nil { + in, out := &in.IpFamilies, &out.IpFamilies + *out = make([]v1.IPFamily, len(*in)) + copy(*out, *in) + } + if in.IpFamilyPolicy != nil { + in, out := &in.IpFamilyPolicy, &out.IpFamilyPolicy + *out = new(v1.IPFamilyPolicy) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpAMPBridgeSpec. diff --git a/apis/v1beta1/common.go b/apis/v1beta1/common.go index 374f5a2a82..88c4edcdb4 100644 --- a/apis/v1beta1/common.go +++ b/apis/v1beta1/common.go @@ -226,6 +226,16 @@ type OpenTelemetryCommonFields struct { AdditionalContainers []v1.Container `json:"additionalContainers,omitempty"` // PodDNSConfig defines the DNS parameters of a pod in addition to those generated from DNSPolicy. PodDNSConfig v1.PodDNSConfig `json:"podDnsConfig,omitempty"` + // IPFamily represents the IP Family (IPv4 or IPv6). This type is used + // to express the family of an IP expressed by a type (e.g. service.spec.ipFamilies). + // +kubebuilder:default:={IPv4} + // +optional + // +listType=set + IpFamilies []v1.IPFamily `json:"ipFamilies,omitempty"` + // IPFamilyPolicy represents the dual-stack-ness requested or required by a Service + // +kubebuilder:default:=SingleStack + // +optional + IpFamilyPolicy *v1.IPFamilyPolicy `json:"ipFamilyPolicy,omitempty"` } type StatefulSetCommonFields struct { diff --git a/apis/v1beta1/zz_generated.deepcopy.go b/apis/v1beta1/zz_generated.deepcopy.go index cff0c978e3..d0334a8051 100644 --- a/apis/v1beta1/zz_generated.deepcopy.go +++ b/apis/v1beta1/zz_generated.deepcopy.go @@ -477,6 +477,16 @@ func (in *OpenTelemetryCommonFields) DeepCopyInto(out *OpenTelemetryCommonFields } } in.PodDNSConfig.DeepCopyInto(&out.PodDNSConfig) + if in.IpFamilies != nil { + in, out := &in.IpFamilies, &out.IpFamilies + *out = make([]v1.IPFamily, len(*in)) + copy(*out, *in) + } + if in.IpFamilyPolicy != nil { + in, out := &in.IpFamilyPolicy, &out.IpFamilyPolicy + *out = new(v1.IPFamilyPolicy) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenTelemetryCommonFields. diff --git a/bundle/manifests/opentelemetry.io_opampbridges.yaml b/bundle/manifests/opentelemetry.io_opampbridges.yaml index 6e7a42fd34..f20a9de845 100644 --- a/bundle/manifests/opentelemetry.io_opampbridges.yaml +++ b/bundle/manifests/opentelemetry.io_opampbridges.yaml @@ -592,6 +592,12 @@ spec: type: string imagePullPolicy: type: string + ipFamilies: + items: + type: string + type: array + ipFamilyPolicy: + type: string nodeSelector: additionalProperties: type: string diff --git a/bundle/manifests/opentelemetry.io_opentelemetrycollectors.yaml b/bundle/manifests/opentelemetry.io_opentelemetrycollectors.yaml index af08b8e91c..5812bb589b 100644 --- a/bundle/manifests/opentelemetry.io_opentelemetrycollectors.yaml +++ b/bundle/manifests/opentelemetry.io_opentelemetrycollectors.yaml @@ -6740,6 +6740,16 @@ spec: - name type: object type: array + ipFamilies: + default: + - IPv4 + items: + type: string + type: array + x-kubernetes-list-type: set + ipFamilyPolicy: + default: SingleStack + type: string lifecycle: properties: postStart: diff --git a/config/crd/bases/opentelemetry.io_opampbridges.yaml b/config/crd/bases/opentelemetry.io_opampbridges.yaml index 181f2f2d1c..7e789c115f 100644 --- a/config/crd/bases/opentelemetry.io_opampbridges.yaml +++ b/config/crd/bases/opentelemetry.io_opampbridges.yaml @@ -589,6 +589,12 @@ spec: type: string imagePullPolicy: type: string + ipFamilies: + items: + type: string + type: array + ipFamilyPolicy: + type: string nodeSelector: additionalProperties: type: string diff --git a/config/crd/bases/opentelemetry.io_opentelemetrycollectors.yaml b/config/crd/bases/opentelemetry.io_opentelemetrycollectors.yaml index 445cc211e5..0c609cdab6 100644 --- a/config/crd/bases/opentelemetry.io_opentelemetrycollectors.yaml +++ b/config/crd/bases/opentelemetry.io_opentelemetrycollectors.yaml @@ -6726,6 +6726,16 @@ spec: - name type: object type: array + ipFamilies: + default: + - IPv4 + items: + type: string + type: array + x-kubernetes-list-type: set + ipFamilyPolicy: + default: SingleStack + type: string lifecycle: properties: postStart: diff --git a/config/crd/bases/opentelemetry.io_targetallocators.yaml b/config/crd/bases/opentelemetry.io_targetallocators.yaml index 27e6c74678..085c12b7db 100644 --- a/config/crd/bases/opentelemetry.io_targetallocators.yaml +++ b/config/crd/bases/opentelemetry.io_targetallocators.yaml @@ -1929,6 +1929,16 @@ spec: - name type: object type: array + ipFamilies: + default: + - IPv4 + items: + type: string + type: array + x-kubernetes-list-type: set + ipFamilyPolicy: + default: SingleStack + type: string lifecycle: properties: postStart: diff --git a/docs/api.md b/docs/api.md index ab8e1a0b02..56e40e18f2 100644 --- a/docs/api.md +++ b/docs/api.md @@ -4183,6 +4183,21 @@ typically used to set access tokens or other authorization headers.
ImagePullPolicy indicates the pull policy to be used for retrieving the container image (Always, Never, IfNotPresent)
false + + ipFamilies + []string + + IPFamily represents the IP Family (IPv4 or IPv6). This type is used +to express the family of an IP expressed by a type (e.g. service.spec.ipFamilies).
+ + false + + ipFamilyPolicy + string + + IPFamilyPolicy represents the dual-stack-ness requested or required by a Service
+ + false nodeSelector map[string]string @@ -30936,6 +30951,25 @@ an initContainer will lead to a restart of the Pod. More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/
false + + ipFamilies + []string + + IPFamily represents the IP Family (IPv4 or IPv6). This type is used +to express the family of an IP expressed by a type (e.g. service.spec.ipFamilies).
+
+ Default: [IPv4]
+ + false + + ipFamilyPolicy + string + + IPFamilyPolicy represents the dual-stack-ness requested or required by a Service
+
+ Default: SingleStack
+ + false lifecycle object diff --git a/internal/manifests/collector/service.go b/internal/manifests/collector/service.go index d66e4bfe99..c080349747 100644 --- a/internal/manifests/collector/service.go +++ b/internal/manifests/collector/service.go @@ -98,6 +98,8 @@ func MonitoringService(params manifests.Params) (*corev1.Service, error) { Name: "monitoring", Port: metricsPort, }}, + IPFamilies: params.OtelCol.Spec.IpFamilies, + IPFamilyPolicy: params.OtelCol.Spec.IpFamilyPolicy, }, }, nil } @@ -175,6 +177,8 @@ func Service(params manifests.Params) (*corev1.Service, error) { Selector: manifestutils.SelectorLabels(params.OtelCol.ObjectMeta, ComponentOpenTelemetryCollector), ClusterIP: "", Ports: ports, + IPFamilies: params.OtelCol.Spec.IpFamilies, + IPFamilyPolicy: params.OtelCol.Spec.IpFamilyPolicy, }, }, nil } diff --git a/internal/manifests/collector/service_test.go b/internal/manifests/collector/service_test.go index 2a5cd8d08f..35dc472fdb 100644 --- a/internal/manifests/collector/service_test.go +++ b/internal/manifests/collector/service_test.go @@ -308,3 +308,43 @@ func serviceWithInternalTrafficPolicy(name string, ports []v1beta1.PortsSpec, in }, } } + +func TestServiceWithIpFamily(t *testing.T) { + t.Run("should return IPFamilies for IPV4 and IPV6", func(t *testing.T) { + params := deploymentParams() + params.OtelCol.Spec.IpFamilies = []v1.IPFamily{ + "IPv4", + "IPv6", + } + actual, err := Service(params) + assert.NoError(t, err) + assert.Equal(t, actual.Spec.IPFamilies, []v1.IPFamily{ + "IPv4", + "IPv6", + }) + }) + t.Run("should return IPPolicy SingleStack", func(t *testing.T) { + params := deploymentParams() + baseIpFamily := v1.IPFamilyPolicySingleStack + params.OtelCol.Spec.IpFamilyPolicy = &baseIpFamily + actual, err := Service(params) + assert.NoError(t, err) + assert.Equal(t, actual.Spec.IPFamilyPolicy, params.OtelCol.Spec.IpFamilyPolicy) + }) + t.Run("should return IPPolicy PreferDualStack", func(t *testing.T) { + params := deploymentParams() + baseIpFamily := v1.IPFamilyPolicyPreferDualStack + params.OtelCol.Spec.IpFamilyPolicy = &baseIpFamily + actual, err := Service(params) + assert.NoError(t, err) + assert.Equal(t, actual.Spec.IPFamilyPolicy, params.OtelCol.Spec.IpFamilyPolicy) + }) + t.Run("should return IPPolicy RequireDualStack ", func(t *testing.T) { + params := deploymentParams() + baseIpFamily := v1.IPFamilyPolicyRequireDualStack + params.OtelCol.Spec.IpFamilyPolicy = &baseIpFamily + actual, err := Service(params) + assert.NoError(t, err) + assert.Equal(t, actual.Spec.IPFamilyPolicy, params.OtelCol.Spec.IpFamilyPolicy) + }) +} diff --git a/internal/manifests/opampbridge/service.go b/internal/manifests/opampbridge/service.go index 0c2a7dd9a0..b8faef887e 100644 --- a/internal/manifests/opampbridge/service.go +++ b/internal/manifests/opampbridge/service.go @@ -44,8 +44,10 @@ func Service(params manifests.Params) *corev1.Service { Labels: labels, }, Spec: corev1.ServiceSpec{ - Selector: selector, - Ports: ports, + Selector: selector, + Ports: ports, + IPFamilies: params.OpAMPBridge.Spec.IpFamilies, + IPFamilyPolicy: params.OpAMPBridge.Spec.IpFamilyPolicy, }, } } diff --git a/internal/manifests/targetallocator/service.go b/internal/manifests/targetallocator/service.go index c31cb927d5..9577a43290 100644 --- a/internal/manifests/targetallocator/service.go +++ b/internal/manifests/targetallocator/service.go @@ -41,6 +41,8 @@ func Service(params Params) *corev1.Service { Port: 80, TargetPort: intstr.FromString("http"), }}, + IPFamilies: params.TargetAllocator.Spec.IpFamilies, + IPFamilyPolicy: params.TargetAllocator.Spec.IpFamilyPolicy, }, } } diff --git a/tests/e2e/smoke-ip-families/00-assert.yaml b/tests/e2e/smoke-ip-families/00-assert.yaml new file mode 100644 index 0000000000..65eb0c0e99 --- /dev/null +++ b/tests/e2e/smoke-ip-families/00-assert.yaml @@ -0,0 +1,60 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: simplest-ipfamily-collector +status: + readyReplicas: 1 + +--- + +apiVersion: v1 +kind: Service +metadata: + name: simplest-ipfamily-collector-headless +spec: + ipFamilies: + - IPv4 + ipFamilyPolicy: SingleStack + ports: + - appProtocol: grpc + name: jaeger-grpc + port: 14250 + protocol: TCP + targetPort: 14250 + - appProtocol: grpc + name: otlp-grpc + port: 4317 + protocol: TCP + targetPort: 4317 + - appProtocol: http + name: otlp-http + port: 4318 + protocol: TCP + targetPort: 4318 + +--- + +apiVersion: v1 +kind: Service +metadata: + name: simplest-ipfamily-collector +spec: + ipFamilies: + - IPv4 + ipFamilyPolicy: SingleStack + ports: + - appProtocol: grpc + name: jaeger-grpc + port: 14250 + protocol: TCP + targetPort: 14250 + - appProtocol: grpc + name: otlp-grpc + port: 4317 + protocol: TCP + targetPort: 4317 + - appProtocol: http + name: otlp-http + port: 4318 + protocol: TCP + targetPort: 4318 diff --git a/tests/e2e/smoke-ip-families/00-install.yaml b/tests/e2e/smoke-ip-families/00-install.yaml new file mode 100644 index 0000000000..809d978caa --- /dev/null +++ b/tests/e2e/smoke-ip-families/00-install.yaml @@ -0,0 +1,28 @@ +apiVersion: opentelemetry.io/v1beta1 +kind: OpenTelemetryCollector +metadata: + name: simplest-ipfamily +spec: + ipFamilies: + - IPv4 + ipFamilyPolicy: SingleStack + config: + receivers: + jaeger: + protocols: + grpc: + otlp: + protocols: + grpc: + http: + processors: + + exporters: + debug: + + service: + pipelines: + traces: + receivers: [jaeger, otlp] + processors: [] + exporters: [debug] diff --git a/tests/e2e/smoke-ip-families/01-assert.yaml b/tests/e2e/smoke-ip-families/01-assert.yaml new file mode 100644 index 0000000000..70ab2d3e35 --- /dev/null +++ b/tests/e2e/smoke-ip-families/01-assert.yaml @@ -0,0 +1,62 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: simplest-ippolicy-collector +status: + readyReplicas: 1 + +--- + +apiVersion: v1 +kind: Service +metadata: + name: simplest-ippolicy-collector-headless +spec: + ipFamilies: + - IPv4 + - IPv6 + ipFamilyPolicy: PreferDualStack + ports: + - appProtocol: grpc + name: jaeger-grpc + port: 14250 + protocol: TCP + targetPort: 14250 + - appProtocol: grpc + name: otlp-grpc + port: 4317 + protocol: TCP + targetPort: 4317 + - appProtocol: http + name: otlp-http + port: 4318 + protocol: TCP + targetPort: 4318 + +--- + +apiVersion: v1 +kind: Service +metadata: + name: simplest-ippolicy-collector +spec: + ipFamilies: + - IPv4 + - IPv6 + ipFamilyPolicy: PreferDualStack + ports: + - appProtocol: grpc + name: jaeger-grpc + port: 14250 + protocol: TCP + targetPort: 14250 + - appProtocol: grpc + name: otlp-grpc + port: 4317 + protocol: TCP + targetPort: 4317 + - appProtocol: http + name: otlp-http + port: 4318 + protocol: TCP + targetPort: 4318 diff --git a/tests/e2e/smoke-ip-families/01-install.yaml b/tests/e2e/smoke-ip-families/01-install.yaml new file mode 100644 index 0000000000..9eb7d5e60e --- /dev/null +++ b/tests/e2e/smoke-ip-families/01-install.yaml @@ -0,0 +1,29 @@ +apiVersion: opentelemetry.io/v1beta1 +kind: OpenTelemetryCollector +metadata: + name: simplest-ippolicy +spec: + ipFamilies: + - IPv4 + - IPv6 + ipFamilyPolicy: PreferDualStack + config: + receivers: + jaeger: + protocols: + grpc: + otlp: + protocols: + grpc: + http: + processors: + + exporters: + debug: + + service: + pipelines: + traces: + receivers: [jaeger, otlp] + processors: [] + exporters: [debug] diff --git a/tests/e2e/smoke-ip-families/chainsaw-test.yaml b/tests/e2e/smoke-ip-families/chainsaw-test.yaml new file mode 100755 index 0000000000..c8cf14641c --- /dev/null +++ b/tests/e2e/smoke-ip-families/chainsaw-test.yaml @@ -0,0 +1,20 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/kyverno/chainsaw/main/.schemas/json/test-chainsaw-v1alpha1.json +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + creationTimestamp: null + name: smoke-ip-families-policies +spec: + steps: + - name: step-00 + try: + - apply: + file: 00-install.yaml + - assert: + file: 00-assert.yaml + - name: step-01 + try: + - apply: + file: 01-install.yaml + - assert: + file: 01-assert.yaml