From 1dc43eb8f5f18f83f5ec005e50a13441026d5764 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20=C5=9Awi=C4=85tek?= Date: Thu, 7 Mar 2024 12:53:11 +0000 Subject: [PATCH] Add Observability field to Target Allocator CRD (#2732) --- apis/v1beta1/targetallocator_types.go | 6 + apis/v1beta1/zz_generated.deepcopy.go | 1 + .../manifests/collector/targetallocator.go | 6 +- .../collector/targetallocator_test.go | 217 ++++++++++++++++++ 4 files changed, 228 insertions(+), 2 deletions(-) diff --git a/apis/v1beta1/targetallocator_types.go b/apis/v1beta1/targetallocator_types.go index 7185a75576..5b4063a3f0 100644 --- a/apis/v1beta1/targetallocator_types.go +++ b/apis/v1beta1/targetallocator_types.go @@ -82,6 +82,12 @@ type TargetAllocatorSpec struct { // PrometheusCR defines the configuration for the retrieval of PrometheusOperator CRDs ( servicemonitor.monitoring.coreos.com/v1 and podmonitor.monitoring.coreos.com/v1 ). // +optional PrometheusCR TargetAllocatorPrometheusCR `json:"prometheusCR,omitempty"` + // ObservabilitySpec defines how telemetry data gets handled. + // + // +optional + // +kubebuilder:validation:Optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Observability" + Observability ObservabilitySpec `json:"observability,omitempty"` } // TargetAllocatorPrometheusCR configures Prometheus CustomResource handling in the Target Allocator. diff --git a/apis/v1beta1/zz_generated.deepcopy.go b/apis/v1beta1/zz_generated.deepcopy.go index d87eedf789..23eb1000f7 100644 --- a/apis/v1beta1/zz_generated.deepcopy.go +++ b/apis/v1beta1/zz_generated.deepcopy.go @@ -762,6 +762,7 @@ func (in *TargetAllocatorSpec) DeepCopyInto(out *TargetAllocatorSpec) { } } in.PrometheusCR.DeepCopyInto(&out.PrometheusCR) + out.Observability = in.Observability } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TargetAllocatorSpec. diff --git a/internal/manifests/collector/targetallocator.go b/internal/manifests/collector/targetallocator.go index 9abd34b81d..4083d4c3f7 100644 --- a/internal/manifests/collector/targetallocator.go +++ b/internal/manifests/collector/targetallocator.go @@ -57,20 +57,22 @@ func TargetAllocator(params manifests.Params) (*v1beta1.TargetAllocator, error) NodeSelector: taSpec.NodeSelector, Resources: taSpec.Resources, ServiceAccount: taSpec.ServiceAccount, - SecurityContext: taSpec.SecurityContext, - PodSecurityContext: taSpec.PodSecurityContext, Image: taSpec.Image, Affinity: taSpec.Affinity, + SecurityContext: taSpec.SecurityContext, + PodSecurityContext: taSpec.PodSecurityContext, TopologySpreadConstraints: taSpec.TopologySpreadConstraints, Tolerations: taSpec.Tolerations, Env: taSpec.Env, PodAnnotations: params.OtelCol.Spec.PodAnnotations, + PodDisruptionBudget: taSpec.PodDisruptionBudget, }, CollectorSelector: collectorSelector, AllocationStrategy: taSpec.AllocationStrategy, FilterStrategy: taSpec.FilterStrategy, ScrapeConfigs: scrapeConfigs, PrometheusCR: taSpec.PrometheusCR, + Observability: taSpec.Observability, }, }, nil } diff --git a/internal/manifests/collector/targetallocator_test.go b/internal/manifests/collector/targetallocator_test.go index 0d60b84a74..c73a3240bb 100644 --- a/internal/manifests/collector/targetallocator_test.go +++ b/internal/manifests/collector/targetallocator_test.go @@ -17,10 +17,14 @@ package collector import ( "fmt" "testing" + "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" "github.com/open-telemetry/opentelemetry-operator/internal/manifests" @@ -38,6 +42,11 @@ func TestTargetAllocator(t *testing.T) { "label_key": "label_value", }, } + replicas := int32(2) + runAsNonRoot := true + privileged := true + runAsUser := int64(1337) + runasGroup := int64(1338) otelcolConfig := v1beta1.Config{ Receivers: v1beta1.AnyConfig{ Object: map[string]interface{}{ @@ -88,6 +97,214 @@ func TestTargetAllocator(t *testing.T) { }, }, }, + { + name: "full", + input: v1beta1.OpenTelemetryCollector{ + ObjectMeta: objectMetadata, + Spec: v1beta1.OpenTelemetryCollectorSpec{ + TargetAllocator: v1beta1.TargetAllocatorEmbedded{ + Replicas: &replicas, + NodeSelector: map[string]string{"key": "value"}, + Resources: v1.ResourceRequirements{ + Limits: v1.ResourceList{ + v1.ResourceCPU: resource.MustParse("500m"), + v1.ResourceMemory: resource.MustParse("128Mi"), + }, + Requests: v1.ResourceList{ + v1.ResourceCPU: resource.MustParse("500m"), + v1.ResourceMemory: resource.MustParse("128Mi"), + }, + }, + AllocationStrategy: v1beta1.TargetAllocatorAllocationStrategyConsistentHashing, + FilterStrategy: "relabel-config", + ServiceAccount: "serviceAccountName", + Image: "custom_image", + Enabled: true, + Affinity: &v1.Affinity{ + NodeAffinity: &v1.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &v1.NodeSelector{ + NodeSelectorTerms: []v1.NodeSelectorTerm{ + { + MatchExpressions: []v1.NodeSelectorRequirement{ + { + Key: "node", + Operator: v1.NodeSelectorOpIn, + Values: []string{"test-node"}, + }, + }, + }, + }, + }, + }, + }, + PrometheusCR: v1beta1.TargetAllocatorPrometheusCR{ + Enabled: true, + ScrapeInterval: &metav1.Duration{Duration: time.Second}, + PodMonitorSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"podmonitorkey": "podmonitorvalue"}, + }, + ServiceMonitorSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"servicemonitorkey": "servicemonitorkey"}, + }, + }, + PodSecurityContext: &v1.PodSecurityContext{ + RunAsNonRoot: &runAsNonRoot, + RunAsUser: &runAsUser, + RunAsGroup: &runasGroup, + }, + SecurityContext: &v1.SecurityContext{ + RunAsUser: &runAsUser, + Privileged: &privileged, + }, + TopologySpreadConstraints: []v1.TopologySpreadConstraint{ + { + MaxSkew: 1, + TopologyKey: "kubernetes.io/hostname", + WhenUnsatisfiable: "DoNotSchedule", + LabelSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "foo": "bar", + }, + }, + }, + }, + Tolerations: []v1.Toleration{ + { + Key: "hii", + Value: "greeting", + Effect: "NoSchedule", + }, + }, + Env: []v1.EnvVar{ + { + Name: "POD_NAME", + ValueFrom: &v1.EnvVarSource{ + FieldRef: &v1.ObjectFieldSelector{ + FieldPath: "metadata.name", + }, + }, + }, + }, + Observability: v1beta1.ObservabilitySpec{ + Metrics: v1beta1.MetricsConfigSpec{ + EnableMetrics: true, + }, + }, + PodDisruptionBudget: &v1beta1.PodDisruptionBudgetSpec{ + MaxUnavailable: &intstr.IntOrString{ + Type: intstr.Int, + IntVal: 1, + }, + }, + }, + Config: otelcolConfig, + }, + }, + want: &v1beta1.TargetAllocator{ + ObjectMeta: objectMetadata, + Spec: v1beta1.TargetAllocatorSpec{ + OpenTelemetryCommonFields: v1beta1.OpenTelemetryCommonFields{ + Replicas: &replicas, + NodeSelector: map[string]string{"key": "value"}, + Resources: v1.ResourceRequirements{ + Limits: v1.ResourceList{ + v1.ResourceCPU: resource.MustParse("500m"), + v1.ResourceMemory: resource.MustParse("128Mi"), + }, + Requests: v1.ResourceList{ + v1.ResourceCPU: resource.MustParse("500m"), + v1.ResourceMemory: resource.MustParse("128Mi"), + }, + }, + ServiceAccount: "serviceAccountName", + Image: "custom_image", + Affinity: &v1.Affinity{ + NodeAffinity: &v1.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &v1.NodeSelector{ + NodeSelectorTerms: []v1.NodeSelectorTerm{ + { + MatchExpressions: []v1.NodeSelectorRequirement{ + { + Key: "node", + Operator: v1.NodeSelectorOpIn, + Values: []string{"test-node"}, + }, + }, + }, + }, + }, + }, + }, + PodSecurityContext: &v1.PodSecurityContext{ + RunAsNonRoot: &runAsNonRoot, + RunAsUser: &runAsUser, + RunAsGroup: &runasGroup, + }, + SecurityContext: &v1.SecurityContext{ + RunAsUser: &runAsUser, + Privileged: &privileged, + }, + TopologySpreadConstraints: []v1.TopologySpreadConstraint{ + { + MaxSkew: 1, + TopologyKey: "kubernetes.io/hostname", + WhenUnsatisfiable: "DoNotSchedule", + LabelSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "foo": "bar", + }, + }, + }, + }, + Tolerations: []v1.Toleration{ + { + Key: "hii", + Value: "greeting", + Effect: "NoSchedule", + }, + }, + Env: []v1.EnvVar{ + { + Name: "POD_NAME", + ValueFrom: &v1.EnvVarSource{ + FieldRef: &v1.ObjectFieldSelector{ + FieldPath: "metadata.name", + }, + }, + }, + }, + + PodDisruptionBudget: &v1beta1.PodDisruptionBudgetSpec{ + MaxUnavailable: &intstr.IntOrString{ + Type: intstr.Int, + IntVal: 1, + }, + }, + }, + CollectorSelector: metav1.LabelSelector{ + MatchLabels: manifestutils.SelectorLabels(objectMetadata, ComponentOpenTelemetryCollector), + }, + AllocationStrategy: v1beta1.TargetAllocatorAllocationStrategyConsistentHashing, + FilterStrategy: v1beta1.TargetAllocatorFilterStrategyRelabelConfig, + PrometheusCR: v1beta1.TargetAllocatorPrometheusCR{ + Enabled: true, + ScrapeInterval: &metav1.Duration{Duration: time.Second}, + PodMonitorSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"podmonitorkey": "podmonitorvalue"}, + }, + ServiceMonitorSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"servicemonitorkey": "servicemonitorkey"}, + }, + }, + ScrapeConfigs: []v1beta1.AnyConfig{}, + Observability: v1beta1.ObservabilitySpec{ + Metrics: v1beta1.MetricsConfigSpec{ + EnableMetrics: true, + }, + }, + }, + }, + }, } for _, testCase := range testCases {