diff --git a/.chloggen/annotations-filter.yaml b/.chloggen/annotations-filter.yaml new file mode 100755 index 0000000000..e7f7a268a3 --- /dev/null +++ b/.chloggen/annotations-filter.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. operator, target allocator, github action) +component: operator + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Created ability to filter out Annotations + +# One or more tracking issues related to the change +issues: [2627] + +# (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/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index ba63f3524f..2f3dbf260e 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -32,11 +32,14 @@ jobs: - e2e-targetallocator - e2e-upgrade - e2e-multi-instrumentation + - e2e-metadata-filters include: - group: e2e-prometheuscr setup: "prepare-e2e-with-featuregates FEATUREGATES=+operator.observability.prometheus" - group: e2e-multi-instrumentation setup: "add-operator-arg OPERATOR_ARG=--enable-multi-instrumentation prepare-e2e" + - group: e2e-metadata-filters + setup: "add-operator-arg OPERATOR_ARG='--annotations-filter=*filter.out --labels=*filter.out' prepare-e2e" steps: - name: Check out code into the Go module directory diff --git a/Makefile b/Makefile index a693f4750f..2a3e503344 100644 --- a/Makefile +++ b/Makefile @@ -240,6 +240,11 @@ e2e-prometheuscr: chainsaw e2e-targetallocator: chainsaw $(CHAINSAW) test --test-dir ./tests/e2e-targetallocator +# end-to-end-test for Annotations/Labels Filters +.PHONY: e2e-metadata-filters +e2e-metadata-filters: chainsaw + $(CHAINSAW) test --test-dir ./tests/e2e-metadata-filters + # end-to-end-test for testing upgrading .PHONY: e2e-upgrade e2e-upgrade: undeploy chainsaw diff --git a/controllers/builder_test.go b/controllers/builder_test.go index 8736adb9ed..c22dd0161a 100644 --- a/controllers/builder_test.go +++ b/controllers/builder_test.go @@ -931,6 +931,9 @@ func TestBuildAll_OpAMPBridge(t *testing.T) { "app.kubernetes.io/part-of": "opentelemetry", "app.kubernetes.io/version": "latest", }, + Annotations: map[string]string{ + "opentelemetry-opampbridge-config/hash": "bd5cfc0df684966e25597a2847d5a3bae2c2b037d8bf10e7ea402ebe4d41c9f0", + }, }, Spec: appsv1.DeploymentSpec{ Replicas: &one, diff --git a/internal/config/main.go b/internal/config/main.go index 7454200ab0..e24e54c863 100644 --- a/internal/config/main.go +++ b/internal/config/main.go @@ -56,6 +56,7 @@ type Config struct { autoInstrumentationJavaImage string openshiftRoutesAvailability openshift.RoutesAvailability labelsFilter []string + annotationsFilter []string } // New constructs a new configuration based on the given options. @@ -95,6 +96,7 @@ func New(opts ...Option) Config { autoInstrumentationApacheHttpdImage: o.autoInstrumentationApacheHttpdImage, autoInstrumentationNginxImage: o.autoInstrumentationNginxImage, labelsFilter: o.labelsFilter, + annotationsFilter: o.annotationsFilter, } } @@ -204,3 +206,8 @@ func (c *Config) AutoInstrumentationNginxImage() string { func (c *Config) LabelsFilter() []string { return c.labelsFilter } + +// AnnotationsFilter Returns the filters converted to regex strings used to filter out unwanted labels from propagations. +func (c *Config) AnnotationsFilter() []string { + return c.annotationsFilter +} diff --git a/internal/config/options.go b/internal/config/options.go index e698c84a5b..bfde188480 100644 --- a/internal/config/options.go +++ b/internal/config/options.go @@ -51,6 +51,7 @@ type options struct { operatorOpAMPBridgeImage string openshiftRoutesAvailability openshift.RoutesAvailability labelsFilter []string + annotationsFilter []string } func WithAutoDetect(a autodetect.AutoDetect) Option { @@ -180,14 +181,35 @@ func WithLabelFilters(labelFilters []string) Option { if i > 0 { result.WriteString(".*") } - // Quote any regular expression meta characters in the // literal text. result.WriteString(regexp.QuoteMeta(literal)) } filters = append(filters, result.String()) } - o.labelsFilter = filters } } + +func WithAnnotationFilters(annotationFilters []string) Option { + return func(o *options) { + + filters := []string{} + for _, pattern := range annotationFilters { + var result strings.Builder + + for i, literal := range strings.Split(pattern, "*") { + + // Replace * with .* + if i > 0 { + result.WriteString(".*") + } + // Quote any regular expression meta characters in the + // literal text. + result.WriteString(regexp.QuoteMeta(literal)) + } + filters = append(filters, result.String()) + } + o.annotationsFilter = filters + } +} diff --git a/internal/manifests/collector/daemonset.go b/internal/manifests/collector/daemonset.go index c257be3397..c006dbd10a 100644 --- a/internal/manifests/collector/daemonset.go +++ b/internal/manifests/collector/daemonset.go @@ -29,11 +29,12 @@ func DaemonSet(params manifests.Params) (*appsv1.DaemonSet, error) { name := naming.Collector(params.OtelCol.Name) labels := manifestutils.Labels(params.OtelCol.ObjectMeta, name, params.OtelCol.Spec.Image, ComponentOpenTelemetryCollector, params.Config.LabelsFilter()) - annotations, err := Annotations(params.OtelCol) + annotations, err := manifestutils.Annotations(params.OtelCol, params.Config.AnnotationsFilter()) if err != nil { return nil, err } - podAnnotations, err := PodAnnotations(params.OtelCol) + + podAnnotations, err := manifestutils.PodAnnotations(params.OtelCol, params.Config.AnnotationsFilter()) if err != nil { return nil, err } diff --git a/internal/manifests/collector/daemonset_test.go b/internal/manifests/collector/daemonset_test.go index 17a326967c..778c3791f6 100644 --- a/internal/manifests/collector/daemonset_test.go +++ b/internal/manifests/collector/daemonset_test.go @@ -244,6 +244,37 @@ func TestDaemonsetFilterLabels(t *testing.T) { } } +func TestDaemonsetFilterAnnotations(t *testing.T) { + excludedAnnotations := map[string]string{ + "foo": "1", + "app.foo.bar": "1", + } + + otelcol := v1beta1.OpenTelemetryCollector{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-instance", + Annotations: excludedAnnotations, + }, + Spec: v1beta1.OpenTelemetryCollectorSpec{}, + } + + cfg := config.New(config.WithAnnotationFilters([]string{"foo*", "app.*.bar"})) + + params := manifests.Params{ + Config: cfg, + OtelCol: otelcol, + Log: logger, + } + + d, err := DaemonSet(params) + require.NoError(t, err) + + assert.Len(t, d.ObjectMeta.Annotations, 4) + for k := range excludedAnnotations { + assert.NotContains(t, d.ObjectMeta.Annotations, k) + } +} + func TestDaemonSetNodeSelector(t *testing.T) { // Test default otelcol1 := v1beta1.OpenTelemetryCollector{ diff --git a/internal/manifests/collector/deployment.go b/internal/manifests/collector/deployment.go index 58e80a2d7e..1cc105114b 100644 --- a/internal/manifests/collector/deployment.go +++ b/internal/manifests/collector/deployment.go @@ -28,13 +28,12 @@ import ( func Deployment(params manifests.Params) (*appsv1.Deployment, error) { name := naming.Collector(params.OtelCol.Name) labels := manifestutils.Labels(params.OtelCol.ObjectMeta, name, params.OtelCol.Spec.Image, ComponentOpenTelemetryCollector, params.Config.LabelsFilter()) - - annotations, err := Annotations(params.OtelCol) + annotations, err := manifestutils.Annotations(params.OtelCol, params.Config.AnnotationsFilter()) if err != nil { return nil, err } - podAnnotations, err := PodAnnotations(params.OtelCol) + podAnnotations, err := manifestutils.PodAnnotations(params.OtelCol, params.Config.AnnotationsFilter()) if err != nil { return nil, err } diff --git a/internal/manifests/collector/deployment_test.go b/internal/manifests/collector/deployment_test.go index 662ef1de62..0523a214b6 100644 --- a/internal/manifests/collector/deployment_test.go +++ b/internal/manifests/collector/deployment_test.go @@ -326,6 +326,37 @@ func TestDeploymentFilterLabels(t *testing.T) { } } +func TestDeploymentFilterAnnotations(t *testing.T) { + excludedAnnotations := map[string]string{ + "foo": "1", + "app.foo.bar": "1", + } + + otelcol := v1beta1.OpenTelemetryCollector{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-instance", + Annotations: excludedAnnotations, + }, + Spec: v1beta1.OpenTelemetryCollectorSpec{}, + } + + cfg := config.New(config.WithAnnotationFilters([]string{"foo*", "app.*.bar"})) + + params := manifests.Params{ + Config: cfg, + OtelCol: otelcol, + Log: logger, + } + + d, err := Deployment(params) + require.NoError(t, err) + + assert.Len(t, d.ObjectMeta.Annotations, 4) + for k := range excludedAnnotations { + assert.NotContains(t, d.ObjectMeta.Annotations, k) + } +} + func TestDeploymentNodeSelector(t *testing.T) { // Test default otelcol1 := v1beta1.OpenTelemetryCollector{ diff --git a/internal/manifests/collector/horizontalpodautoscaler.go b/internal/manifests/collector/horizontalpodautoscaler.go index 758217bd99..28b0b3cc52 100644 --- a/internal/manifests/collector/horizontalpodautoscaler.go +++ b/internal/manifests/collector/horizontalpodautoscaler.go @@ -28,7 +28,7 @@ import ( func HorizontalPodAutoscaler(params manifests.Params) (*autoscalingv2.HorizontalPodAutoscaler, error) { name := naming.Collector(params.OtelCol.Name) labels := manifestutils.Labels(params.OtelCol.ObjectMeta, name, params.OtelCol.Spec.Image, ComponentOpenTelemetryCollector, params.Config.LabelsFilter()) - annotations, err := Annotations(params.OtelCol) + annotations, err := manifestutils.Annotations(params.OtelCol, params.Config.AnnotationsFilter()) if err != nil { return nil, err } diff --git a/internal/manifests/collector/poddisruptionbudget.go b/internal/manifests/collector/poddisruptionbudget.go index 73fe774da0..619fc7a110 100644 --- a/internal/manifests/collector/poddisruptionbudget.go +++ b/internal/manifests/collector/poddisruptionbudget.go @@ -32,7 +32,7 @@ func PodDisruptionBudget(params manifests.Params) (*policyV1.PodDisruptionBudget name := naming.Collector(params.OtelCol.Name) labels := manifestutils.Labels(params.OtelCol.ObjectMeta, name, params.OtelCol.Spec.Image, ComponentOpenTelemetryCollector, params.Config.LabelsFilter()) - annotations, err := Annotations(params.OtelCol) + annotations, err := manifestutils.Annotations(params.OtelCol, params.Config.AnnotationsFilter()) if err != nil { return nil, err } diff --git a/internal/manifests/collector/statefulset.go b/internal/manifests/collector/statefulset.go index 7ac287a8da..bfb3a70964 100644 --- a/internal/manifests/collector/statefulset.go +++ b/internal/manifests/collector/statefulset.go @@ -29,12 +29,12 @@ func StatefulSet(params manifests.Params) (*appsv1.StatefulSet, error) { name := naming.Collector(params.OtelCol.Name) labels := manifestutils.Labels(params.OtelCol.ObjectMeta, name, params.OtelCol.Spec.Image, ComponentOpenTelemetryCollector, params.Config.LabelsFilter()) - annotations, err := Annotations(params.OtelCol) + annotations, err := manifestutils.Annotations(params.OtelCol, params.Config.AnnotationsFilter()) if err != nil { return nil, err } - podAnnotations, err := PodAnnotations(params.OtelCol) + podAnnotations, err := manifestutils.PodAnnotations(params.OtelCol, params.Config.AnnotationsFilter()) if err != nil { return nil, err } diff --git a/internal/manifests/collector/statefulset_test.go b/internal/manifests/collector/statefulset_test.go index 0a9d822f29..5e0af9d110 100644 --- a/internal/manifests/collector/statefulset_test.go +++ b/internal/manifests/collector/statefulset_test.go @@ -336,6 +336,37 @@ func TestStatefulSetFilterLabels(t *testing.T) { } } +func TestStatefulSetFilterAnnotations(t *testing.T) { + excludedAnnotations := map[string]string{ + "foo": "1", + "app.foo.bar": "1", + } + + otelcol := v1beta1.OpenTelemetryCollector{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-instance", + Annotations: excludedAnnotations, + }, + Spec: v1beta1.OpenTelemetryCollectorSpec{}, + } + + cfg := config.New(config.WithAnnotationFilters([]string{"foo*", "app.*.bar"})) + + params := manifests.Params{ + OtelCol: otelcol, + Config: cfg, + Log: logger, + } + + d, err := StatefulSet(params) + require.NoError(t, err) + + assert.Len(t, d.ObjectMeta.Annotations, 4) + for k := range excludedAnnotations { + assert.NotContains(t, d.ObjectMeta.Annotations, k) + } +} + func TestStatefulSetNodeSelector(t *testing.T) { // Test default otelcol1 := v1beta1.OpenTelemetryCollector{ diff --git a/internal/manifests/collector/annotations.go b/internal/manifests/manifestutils/annotations.go similarity index 78% rename from internal/manifests/collector/annotations.go rename to internal/manifests/manifestutils/annotations.go index 5f4c7c41be..06f1baed81 100644 --- a/internal/manifests/collector/annotations.go +++ b/internal/manifests/manifestutils/annotations.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package collector +package manifestutils import ( "crypto/sha256" @@ -23,7 +23,7 @@ import ( ) // Annotations return the annotations for OpenTelemetryCollector pod. -func Annotations(instance v1beta1.OpenTelemetryCollector) (map[string]string, error) { +func Annotations(instance v1beta1.OpenTelemetryCollector, filterAnnotations []string) (map[string]string, error) { // new map every time, so that we don't touch the instance's annotations annotations := map[string]string{} @@ -36,9 +36,11 @@ func Annotations(instance v1beta1.OpenTelemetryCollector) (map[string]string, er } // allow override of prometheus annotations - if nil != instance.Annotations { - for k, v := range instance.Annotations { - annotations[k] = v + if nil != instance.ObjectMeta.Annotations { + for k, v := range instance.ObjectMeta.Annotations { + if !IsFilteredSet(k, filterAnnotations) { + annotations[k] = v + } } } @@ -54,16 +56,18 @@ func Annotations(instance v1beta1.OpenTelemetryCollector) (map[string]string, er } // PodAnnotations return the spec annotations for OpenTelemetryCollector pod. -func PodAnnotations(instance v1beta1.OpenTelemetryCollector) (map[string]string, error) { +func PodAnnotations(instance v1beta1.OpenTelemetryCollector, filterAnnotations []string) (map[string]string, error) { // new map every time, so that we don't touch the instance's annotations podAnnotations := map[string]string{} - - // allow override of pod annotations - for k, v := range instance.Spec.PodAnnotations { - podAnnotations[k] = v + if nil != instance.Spec.PodAnnotations { + for k, v := range instance.Spec.PodAnnotations { + if !IsFilteredSet(k, filterAnnotations) { + podAnnotations[k] = v + } + } } - annotations, err := Annotations(instance) + annotations, err := Annotations(instance, filterAnnotations) if err != nil { return nil, err } diff --git a/internal/manifests/collector/annotations_test.go b/internal/manifests/manifestutils/annotations_test.go similarity index 82% rename from internal/manifests/collector/annotations_test.go rename to internal/manifests/manifestutils/annotations_test.go index d65bb41b27..a09831bbf9 100644 --- a/internal/manifests/collector/annotations_test.go +++ b/internal/manifests/manifestutils/annotations_test.go @@ -12,13 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -package collector +package manifestutils 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/v1beta1" @@ -44,9 +45,9 @@ func TestDefaultAnnotations(t *testing.T) { } // test - annotations, err := Annotations(otelcol) + annotations, err := Annotations(otelcol, []string{}) require.NoError(t, err) - podAnnotations, err := PodAnnotations(otelcol) + podAnnotations, err := PodAnnotations(otelcol, []string{}) require.NoError(t, err) //verify @@ -78,9 +79,9 @@ func TestNonDefaultPodAnnotation(t *testing.T) { } // test - annotations, err := Annotations(otelcol) + annotations, err := Annotations(otelcol, []string{}) require.NoError(t, err) - podAnnotations, err := PodAnnotations(otelcol) + podAnnotations, err := PodAnnotations(otelcol, []string{}) require.NoError(t, err) //verify @@ -120,9 +121,9 @@ func TestUserAnnotations(t *testing.T) { } // test - annotations, err := Annotations(otelcol) + annotations, err := Annotations(otelcol, []string{}) require.NoError(t, err) - podAnnotations, err := PodAnnotations(otelcol) + podAnnotations, err := PodAnnotations(otelcol, []string{}) require.NoError(t, err) //verify @@ -147,9 +148,9 @@ func TestAnnotationsPropagateDown(t *testing.T) { } // test - annotations, err := Annotations(otelcol) + annotations, err := Annotations(otelcol, []string{}) require.NoError(t, err) - podAnnotations, err := PodAnnotations(otelcol) + podAnnotations, err := PodAnnotations(otelcol, []string{}) require.NoError(t, err) // verify @@ -158,3 +159,27 @@ func TestAnnotationsPropagateDown(t *testing.T) { assert.Equal(t, "mycomponent", podAnnotations["myapp"]) assert.Equal(t, "pod_annotation_value", podAnnotations["pod_annotation"]) } + +func TestAnnotationsFilter(t *testing.T) { + otelcol := v1beta1.OpenTelemetryCollector{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + "test.bar.io": "foo", + "test.io/port": "1234", + "test.io/path": "/test", + }, + }, + Spec: v1beta1.OpenTelemetryCollectorSpec{ + Mode: "deployment", + }, + } + + // This requires the filter to be in regex match form and not the other simpler wildcard one. + annotations, err := Annotations(otelcol, []string{".*\\.bar\\.io"}) + + // verify + require.NoError(t, err) + assert.Len(t, annotations, 6) + assert.NotContains(t, annotations, "test.bar.io") + assert.Equal(t, "1234", annotations["test.io/port"]) +} diff --git a/internal/manifests/manifestutils/labels.go b/internal/manifests/manifestutils/labels.go index cfcf3d2430..76fd5a4e58 100644 --- a/internal/manifests/manifestutils/labels.go +++ b/internal/manifests/manifestutils/labels.go @@ -18,14 +18,15 @@ import ( "regexp" "strings" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - + "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" "github.com/open-telemetry/opentelemetry-operator/internal/naming" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -func isFilteredLabel(label string, filterLabels []string) bool { - for _, pattern := range filterLabels { - match, _ := regexp.MatchString(pattern, label) +func IsFilteredSet(sourceSet string, filterSet []string) bool { + for _, pattern := range filterSet { + match, _ := regexp.MatchString(pattern, sourceSet) return match } return false @@ -38,7 +39,7 @@ func Labels(instance metav1.ObjectMeta, name string, image string, component str base := map[string]string{} if nil != instance.Labels { for k, v := range instance.Labels { - if !isFilteredLabel(k, filterLabels) { + if !IsFilteredSet(k, filterLabels) { base[k] = v } } @@ -81,3 +82,18 @@ func SelectorLabels(instance metav1.ObjectMeta, component string) map[string]str "app.kubernetes.io/component": component, } } + +// SelectorLabels return the selector labels for Target Allocator Pods. +func TASelectorLabels(instance v1beta1.TargetAllocator, component string) map[string]string { + selectorLabels := SelectorLabels(instance.ObjectMeta, component) + + // TargetAllocator uses the name label as well for selection + // This is inconsistent with the Collector, but changing is a somewhat painful breaking change + // Don't override the app name if it already exists + if name, ok := instance.ObjectMeta.Labels["app.kubernetes.io/name"]; ok { + selectorLabels["app.kubernetes.io/name"] = name + } else { + selectorLabels["app.kubernetes.io/name"] = naming.TargetAllocator(instance.Name) + } + return selectorLabels +} diff --git a/internal/manifests/manifestutils/labels_test.go b/internal/manifests/manifestutils/labels_test.go index 4a0bd794de..e76e9fc958 100644 --- a/internal/manifests/manifestutils/labels_test.go +++ b/internal/manifests/manifestutils/labels_test.go @@ -21,11 +21,16 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1" + "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" + + "github.com/open-telemetry/opentelemetry-operator/internal/naming" ) const ( collectorName = "my-instance" collectorNamespace = "my-ns" + taname = "my-instance" + tanamespace = "my-ns" ) func TestLabelsCommonSet(t *testing.T) { @@ -156,15 +161,76 @@ func TestSelectorLabels(t *testing.T) { "app.kubernetes.io/component": "opentelemetry-collector", "app.kubernetes.io/instance": "my-namespace.my-opentelemetry-collector", "app.kubernetes.io/managed-by": "opentelemetry-operator", + "app.kubernetes.io/name": "my-opentelemetry-collector-targetallocator", "app.kubernetes.io/part-of": "opentelemetry", } - otelcol := v1alpha1.OpenTelemetryCollector{ + tainstance := v1beta1.TargetAllocator{ ObjectMeta: metav1.ObjectMeta{Name: "my-opentelemetry-collector", Namespace: "my-namespace"}, } // test - result := SelectorLabels(otelcol.ObjectMeta, "opentelemetry-collector") + result := TASelectorLabels(tainstance, "opentelemetry-collector") // verify assert.Equal(t, expected, result) } + +func TestLabelsTACommonSet(t *testing.T) { + // prepare + tainstance := v1beta1.TargetAllocator{ + ObjectMeta: metav1.ObjectMeta{ + Name: taname, + Namespace: tanamespace, + }, + } + + // test + labels := Labels(tainstance.ObjectMeta, taname, tainstance.Spec.Image, "opentelemetry-targetallocator", nil) + assert.Equal(t, "opentelemetry-operator", labels["app.kubernetes.io/managed-by"]) + assert.Equal(t, "my-ns.my-instance", labels["app.kubernetes.io/instance"]) + assert.Equal(t, "opentelemetry", labels["app.kubernetes.io/part-of"]) + assert.Equal(t, "opentelemetry-targetallocator", labels["app.kubernetes.io/component"]) + assert.Equal(t, "latest", labels["app.kubernetes.io/version"]) + assert.Equal(t, taname, labels["app.kubernetes.io/name"]) +} + +func TestLabelsTAPropagateDown(t *testing.T) { + // prepare + tainstance := v1beta1.TargetAllocator{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{ + "myapp": "mycomponent", + "app.kubernetes.io/name": "test", + }, + }, + } + + // test + labels := Labels(tainstance.ObjectMeta, taname, tainstance.Spec.Image, "opentelemetry-targetallocator", nil) + + selectorLabels := TASelectorLabels(tainstance, "opentelemetry-targetallocator") + + // verify + assert.Len(t, labels, 7) + assert.Equal(t, "mycomponent", labels["myapp"]) + assert.Equal(t, "test", labels["app.kubernetes.io/name"]) + assert.Equal(t, "test", selectorLabels["app.kubernetes.io/name"]) +} + +func TestSelectorTALabels(t *testing.T) { + // prepare + tainstance := v1beta1.TargetAllocator{ + ObjectMeta: metav1.ObjectMeta{ + Name: taname, + Namespace: tanamespace, + }, + } + + // test + labels := TASelectorLabels(tainstance, "opentelemetry-targetallocator") + assert.Equal(t, "opentelemetry-operator", labels["app.kubernetes.io/managed-by"]) + assert.Equal(t, "my-ns.my-instance", labels["app.kubernetes.io/instance"]) + assert.Equal(t, "opentelemetry", labels["app.kubernetes.io/part-of"]) + assert.Equal(t, "opentelemetry-targetallocator", labels["app.kubernetes.io/component"]) + assert.Equal(t, naming.TargetAllocator(tainstance.Name), labels["app.kubernetes.io/name"]) +} diff --git a/internal/manifests/opampbridge/annotations.go b/internal/manifests/opampbridge/annotations.go new file mode 100644 index 0000000000..2f29b69eb4 --- /dev/null +++ b/internal/manifests/opampbridge/annotations.go @@ -0,0 +1,61 @@ +// 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 opampbridge + +import ( + "crypto/sha256" + "fmt" + + v1 "k8s.io/api/core/v1" + + "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1" + "github.com/open-telemetry/opentelemetry-operator/internal/manifests/manifestutils" +) + +const configMapHashAnnotationKey = "opentelemetry-opampbridge-config/hash" + +// Annotations returns the annotations for the OPAmpBridge Pod. +func Annotations(instance v1alpha1.OpAMPBridge, configMap *v1.ConfigMap, filterAnnotations []string) map[string]string { + // Make a copy of PodAnnotations to be safe + annotations := make(map[string]string, len(instance.Spec.PodAnnotations)) + for key, value := range instance.Spec.PodAnnotations { + annotations[key] = value + } + if nil != instance.ObjectMeta.Annotations { + for k, v := range instance.ObjectMeta.Annotations { + if !manifestutils.IsFilteredSet(k, filterAnnotations) { + annotations[k] = v + } + } + } + if configMap != nil { + cmHash := getConfigMapSHA(configMap) + if cmHash != "" { + annotations[configMapHashAnnotationKey] = getConfigMapSHA(configMap) + } + } + + return annotations +} + +// getConfigMapSHA returns the hash of the content of the OpAMPBridge ConfigMap. +func getConfigMapSHA(configMap *v1.ConfigMap) string { + configString, ok := configMap.Data[OpAMPBridgeFilename] + if !ok { + return "" + } + h := sha256.Sum256([]byte(configString)) + return fmt.Sprintf("%x", h) +} diff --git a/internal/manifests/opampbridge/annotations_test.go b/internal/manifests/opampbridge/annotations_test.go new file mode 100644 index 0000000000..cc4f030156 --- /dev/null +++ b/internal/manifests/opampbridge/annotations_test.go @@ -0,0 +1,61 @@ +// 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 opampbridge + +import ( + "crypto/sha256" + "fmt" + "testing" + + "github.com/go-logr/logr" + "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/internal/config" + "github.com/open-telemetry/opentelemetry-operator/internal/manifests" +) + +func TestConfigMapHash(t *testing.T) { + cfg := config.New() + excludedAnnotations := map[string]string{ + "foo": "1", + "app.foo.bar": "1", + "opampbridge": "true", + } + opampBridge := v1alpha1.OpAMPBridge{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-instance", + Annotations: excludedAnnotations, + }, + Spec: v1alpha1.OpAMPBridgeSpec{}, + } + params := manifests.Params{ + OpAMPBridge: opampBridge, + Config: cfg, + Log: logr.Discard(), + } + expectedConfigMap, err := ConfigMap(params) + require.NoError(t, err) + expectedConfig := expectedConfigMap.Data[OpAMPBridgeFilename] + require.NotEmpty(t, expectedConfig) + expectedHash := sha256.Sum256([]byte(expectedConfig)) + annotations := Annotations(opampBridge, expectedConfigMap, []string{".*\\.bar\\.io"}) + require.Contains(t, annotations, configMapHashAnnotationKey) + cmHash := annotations[configMapHashAnnotationKey] + assert.Equal(t, fmt.Sprintf("%x", expectedHash), cmHash) +} diff --git a/internal/manifests/opampbridge/configmap.go b/internal/manifests/opampbridge/configmap.go index 9f16ef5a6d..620b6c7c16 100644 --- a/internal/manifests/opampbridge/configmap.go +++ b/internal/manifests/opampbridge/configmap.go @@ -27,6 +27,10 @@ import ( "github.com/open-telemetry/opentelemetry-operator/internal/naming" ) +const ( + OpAMPBridgeFilename = "remoteconfiguration.yaml" +) + func ConfigMap(params manifests.Params) (*corev1.ConfigMap, error) { name := naming.OpAMPBridgeConfigMap(params.OpAMPBridge.Name) version := strings.Split(params.OpAMPBridge.Spec.Image, ":") @@ -69,7 +73,7 @@ func ConfigMap(params manifests.Params) (*corev1.ConfigMap, error) { Annotations: params.OpAMPBridge.Annotations, }, Data: map[string]string{ - "remoteconfiguration.yaml": string(configYAML), + OpAMPBridgeFilename: string(configYAML), }, }, nil } diff --git a/internal/manifests/opampbridge/deployment.go b/internal/manifests/opampbridge/deployment.go index 81c1e908a9..9b146c83eb 100644 --- a/internal/manifests/opampbridge/deployment.go +++ b/internal/manifests/opampbridge/deployment.go @@ -28,13 +28,18 @@ import ( func Deployment(params manifests.Params) *appsv1.Deployment { name := naming.OpAMPBridge(params.OpAMPBridge.Name) labels := manifestutils.Labels(params.OpAMPBridge.ObjectMeta, name, params.OpAMPBridge.Spec.Image, ComponentOpAMPBridge, params.Config.LabelsFilter()) - + configMap, err := ConfigMap(params) + if err != nil { + params.Log.Info("failed to construct OpAMPBridge ConfigMap for annotations") + configMap = nil + } + annotations := Annotations(params.OpAMPBridge, configMap, params.Config.AnnotationsFilter()) return &appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ Name: name, Namespace: params.OpAMPBridge.Namespace, Labels: labels, - Annotations: params.OpAMPBridge.Annotations, + Annotations: annotations, }, Spec: appsv1.DeploymentSpec{ Replicas: params.OpAMPBridge.Spec.Replicas, diff --git a/internal/manifests/opampbridge/deployment_test.go b/internal/manifests/opampbridge/deployment_test.go index 4ec3f07de6..77af7843b0 100644 --- a/internal/manifests/opampbridge/deployment_test.go +++ b/internal/manifests/opampbridge/deployment_test.go @@ -253,6 +253,36 @@ func TestDeploymentFilterLabels(t *testing.T) { } } +func TestDeploymentFilterAnnotations(t *testing.T) { + excludedAnnotations := map[string]string{ + "foo": "1", + "app.foo.bar": "1", + "opampbridge": "true", + } + + opampBridge := v1alpha1.OpAMPBridge{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-instance", + Annotations: excludedAnnotations, + }, + Spec: v1alpha1.OpAMPBridgeSpec{}, + } + + cfg := config.New(config.WithAnnotationFilters([]string{"foo*", "app.*.bar"})) + + params := manifests.Params{ + Config: cfg, + OpAMPBridge: opampBridge, + Log: logger, + } + + d := Deployment(params) + + assert.Len(t, d.ObjectMeta.Annotations, 2) + assert.NotContains(t, d.ObjectMeta.Annotations, "foo") + assert.NotContains(t, d.ObjectMeta.Annotations, "app.foo.bar") +} + func TestDeploymentNodeSelector(t *testing.T) { // Test default opampBridge1 := v1alpha1.OpAMPBridge{ diff --git a/internal/manifests/targetallocator/annotations.go b/internal/manifests/targetallocator/annotations.go index 46ac4e332f..7666bd64ab 100644 --- a/internal/manifests/targetallocator/annotations.go +++ b/internal/manifests/targetallocator/annotations.go @@ -21,18 +21,25 @@ import ( v1 "k8s.io/api/core/v1" "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" + "github.com/open-telemetry/opentelemetry-operator/internal/manifests/manifestutils" ) const configMapHashAnnotationKey = "opentelemetry-targetallocator-config/hash" // Annotations returns the annotations for the TargetAllocator Pod. -func Annotations(instance v1beta1.TargetAllocator, configMap *v1.ConfigMap) map[string]string { +func Annotations(instance v1beta1.TargetAllocator, configMap *v1.ConfigMap, filterAnnotations []string) map[string]string { // Make a copy of PodAnnotations to be safe annotations := make(map[string]string, len(instance.Spec.PodAnnotations)) for key, value := range instance.Spec.PodAnnotations { annotations[key] = value } - + if nil != instance.ObjectMeta.Annotations { + for k, v := range instance.ObjectMeta.Annotations { + if !manifestutils.IsFilteredSet(k, filterAnnotations) { + annotations[k] = v + } + } + } if configMap != nil { cmHash := getConfigMapSHA(configMap) if cmHash != "" { diff --git a/internal/manifests/targetallocator/annotations_test.go b/internal/manifests/targetallocator/annotations_test.go index 022f5e0cb9..5f6c839a1d 100644 --- a/internal/manifests/targetallocator/annotations_test.go +++ b/internal/manifests/targetallocator/annotations_test.go @@ -32,7 +32,7 @@ func TestPodAnnotations(t *testing.T) { instance.Spec.PodAnnotations = map[string]string{ "key": "value", } - annotations := Annotations(instance, nil) + annotations := Annotations(instance, nil, []string{".*\\.bar\\.io"}) assert.Subset(t, annotations, instance.Spec.PodAnnotations) } @@ -51,7 +51,7 @@ func TestConfigMapHash(t *testing.T) { expectedConfig := expectedConfigMap.Data[targetAllocatorFilename] require.NotEmpty(t, expectedConfig) expectedHash := sha256.Sum256([]byte(expectedConfig)) - annotations := Annotations(targetAllocator, expectedConfigMap) + annotations := Annotations(targetAllocator, expectedConfigMap, []string{".*\\.bar\\.io"}) require.Contains(t, annotations, configMapHashAnnotationKey) cmHash := annotations[configMapHashAnnotationKey] assert.Equal(t, fmt.Sprintf("%x", expectedHash), cmHash) @@ -59,6 +59,6 @@ func TestConfigMapHash(t *testing.T) { func TestInvalidConfigNoHash(t *testing.T) { instance := targetAllocatorInstance() - annotations := Annotations(instance, nil) + annotations := Annotations(instance, nil, []string{".*\\.bar\\.io"}) require.NotContains(t, annotations, configMapHashAnnotationKey) } diff --git a/internal/manifests/targetallocator/configmap.go b/internal/manifests/targetallocator/configmap.go index 40dc0c5a34..ebf99459d0 100644 --- a/internal/manifests/targetallocator/configmap.go +++ b/internal/manifests/targetallocator/configmap.go @@ -21,6 +21,7 @@ import ( "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" "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" ) @@ -31,7 +32,7 @@ const ( func ConfigMap(params manifests.Params) (*corev1.ConfigMap, error) { instance := params.TargetAllocator name := naming.TAConfigMap(instance.Name) - labels := Labels(instance, name) + labels := manifestutils.Labels(instance.ObjectMeta, name, params.TargetAllocator.Spec.Image, ComponentOpenTelemetryTargetAllocator, nil) taSpec := instance.Spec taConfig := make(map[interface{}]interface{}) diff --git a/internal/manifests/targetallocator/deployment.go b/internal/manifests/targetallocator/deployment.go index 5136f36c9d..db36d214fb 100644 --- a/internal/manifests/targetallocator/deployment.go +++ b/internal/manifests/targetallocator/deployment.go @@ -20,20 +20,21 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "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, error) { name := naming.TargetAllocator(params.TargetAllocator.Name) - labels := Labels(params.TargetAllocator, name) + labels := manifestutils.Labels(params.TargetAllocator.ObjectMeta, name, params.TargetAllocator.Spec.Image, ComponentOpenTelemetryTargetAllocator, nil) configMap, err := ConfigMap(params) if err != nil { params.Log.Info("failed to construct target allocator config map for annotations") configMap = nil } - annotations := Annotations(params.TargetAllocator, configMap) + annotations := Annotations(params.TargetAllocator, configMap, params.Config.AnnotationsFilter()) return &appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ @@ -44,7 +45,7 @@ func Deployment(params manifests.Params) (*appsv1.Deployment, error) { Spec: appsv1.DeploymentSpec{ Replicas: params.TargetAllocator.Spec.Replicas, Selector: &metav1.LabelSelector{ - MatchLabels: SelectorLabels(params.TargetAllocator), + MatchLabels: manifestutils.TASelectorLabels(params.TargetAllocator, ComponentOpenTelemetryTargetAllocator), }, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ diff --git a/internal/manifests/targetallocator/labels.go b/internal/manifests/targetallocator/labels.go deleted file mode 100644 index c180f9855a..0000000000 --- a/internal/manifests/targetallocator/labels.go +++ /dev/null @@ -1,41 +0,0 @@ -// 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 targetallocator - -import ( - "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" - "github.com/open-telemetry/opentelemetry-operator/internal/manifests/manifestutils" - "github.com/open-telemetry/opentelemetry-operator/internal/naming" -) - -// Labels return the common labels to all TargetAllocator objects that are part of a managed OpenTelemetryCollector. -func Labels(instance v1beta1.TargetAllocator, name string) map[string]string { - return manifestutils.Labels(instance.ObjectMeta, name, instance.Spec.Image, ComponentOpenTelemetryTargetAllocator, nil) -} - -// SelectorLabels return the selector labels for Target Allocator Pods. -func SelectorLabels(instance v1beta1.TargetAllocator) map[string]string { - selectorLabels := manifestutils.SelectorLabels(instance.ObjectMeta, ComponentOpenTelemetryTargetAllocator) - - // TargetAllocator uses the name label as well for selection - // This is inconsistent with the Collector, but changing is a somewhat painful breaking change - // Don't override the app name if it already exists - if name, ok := instance.ObjectMeta.Labels["app.kubernetes.io/name"]; ok { - selectorLabels["app.kubernetes.io/name"] = name - } else { - selectorLabels["app.kubernetes.io/name"] = naming.TargetAllocator(instance.Name) - } - return selectorLabels -} diff --git a/internal/manifests/targetallocator/labels_test.go b/internal/manifests/targetallocator/labels_test.go deleted file mode 100644 index aa7a0556c0..0000000000 --- a/internal/manifests/targetallocator/labels_test.go +++ /dev/null @@ -1,89 +0,0 @@ -// 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 targetallocator - -import ( - "testing" - - "github.com/stretchr/testify/assert" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" - "github.com/open-telemetry/opentelemetry-operator/internal/naming" -) - -const ( - name = "my-instance" - namespace = "my-ns" -) - -func TestLabelsCommonSet(t *testing.T) { - // prepare - allocator := v1beta1.TargetAllocator{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: namespace, - }, - } - - // test - labels := Labels(allocator, name) - assert.Equal(t, "opentelemetry-operator", labels["app.kubernetes.io/managed-by"]) - assert.Equal(t, "my-ns.my-instance", labels["app.kubernetes.io/instance"]) - assert.Equal(t, "opentelemetry", labels["app.kubernetes.io/part-of"]) - assert.Equal(t, "opentelemetry-targetallocator", labels["app.kubernetes.io/component"]) - assert.Equal(t, "latest", labels["app.kubernetes.io/version"]) - assert.Equal(t, name, labels["app.kubernetes.io/name"]) -} - -func TestLabelsPropagateDown(t *testing.T) { - // prepare - allocator := v1beta1.TargetAllocator{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - "myapp": "mycomponent", - "app.kubernetes.io/name": "test", - }, - }, - } - - // test - labels := Labels(allocator, name) - selectorLabels := SelectorLabels(allocator) - - // verify - assert.Len(t, labels, 7) - assert.Equal(t, "mycomponent", labels["myapp"]) - assert.Equal(t, "test", labels["app.kubernetes.io/name"]) - assert.Equal(t, "test", selectorLabels["app.kubernetes.io/name"]) -} - -func TestSelectorLabels(t *testing.T) { - // prepare - otelcol := v1beta1.TargetAllocator{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: namespace, - }, - } - - // test - labels := SelectorLabels(otelcol) - assert.Equal(t, "opentelemetry-operator", labels["app.kubernetes.io/managed-by"]) - assert.Equal(t, "my-ns.my-instance", labels["app.kubernetes.io/instance"]) - assert.Equal(t, "opentelemetry", labels["app.kubernetes.io/part-of"]) - assert.Equal(t, "opentelemetry-targetallocator", labels["app.kubernetes.io/component"]) - assert.Equal(t, naming.TargetAllocator(otelcol.Name), labels["app.kubernetes.io/name"]) -} diff --git a/internal/manifests/targetallocator/poddisruptionbudget.go b/internal/manifests/targetallocator/poddisruptionbudget.go index 5c8ffe41ba..7746975f1b 100644 --- a/internal/manifests/targetallocator/poddisruptionbudget.go +++ b/internal/manifests/targetallocator/poddisruptionbudget.go @@ -19,6 +19,7 @@ import ( "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" "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" policyV1 "k8s.io/api/policy/v1" @@ -41,9 +42,13 @@ func PodDisruptionBudget(params manifests.Params) (*policyV1.PodDisruptionBudget } name := naming.TAPodDisruptionBudget(params.TargetAllocator.Name) - labels := Labels(params.TargetAllocator, name) - - annotations := Annotations(params.TargetAllocator, nil) + labels := manifestutils.Labels(params.TargetAllocator.ObjectMeta, name, params.TargetAllocator.Spec.Image, ComponentOpenTelemetryTargetAllocator, nil) + configMap, err := ConfigMap(params) + if err != nil { + params.Log.Info("failed to construct target allocator config map for annotations") + configMap = nil + } + annotations := Annotations(params.TargetAllocator, configMap, params.Config.AnnotationsFilter()) objectMeta := metav1.ObjectMeta{ Name: name, @@ -58,7 +63,7 @@ func PodDisruptionBudget(params manifests.Params) (*policyV1.PodDisruptionBudget MinAvailable: params.TargetAllocator.Spec.PodDisruptionBudget.MinAvailable, MaxUnavailable: params.TargetAllocator.Spec.PodDisruptionBudget.MaxUnavailable, Selector: &metav1.LabelSelector{ - MatchLabels: SelectorLabels(params.TargetAllocator), + MatchLabels: manifestutils.TASelectorLabels(params.TargetAllocator, ComponentOpenTelemetryTargetAllocator), }, }, }, nil diff --git a/internal/manifests/targetallocator/service.go b/internal/manifests/targetallocator/service.go index e11773ff1a..144213f56d 100644 --- a/internal/manifests/targetallocator/service.go +++ b/internal/manifests/targetallocator/service.go @@ -20,14 +20,14 @@ import ( "k8s.io/apimachinery/pkg/util/intstr" "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 Service(params manifests.Params) *corev1.Service { name := naming.TAService(params.TargetAllocator.Name) - labels := Labels(params.TargetAllocator, name) - - selector := SelectorLabels(params.TargetAllocator) + labels := manifestutils.Labels(params.TargetAllocator.ObjectMeta, name, params.TargetAllocator.Spec.Image, ComponentOpenTelemetryTargetAllocator, nil) + selector := manifestutils.TASelectorLabels(params.TargetAllocator, ComponentOpenTelemetryTargetAllocator) return &corev1.Service{ ObjectMeta: metav1.ObjectMeta{ diff --git a/internal/manifests/targetallocator/serviceaccount.go b/internal/manifests/targetallocator/serviceaccount.go index 916a21ebf9..e38e64b557 100644 --- a/internal/manifests/targetallocator/serviceaccount.go +++ b/internal/manifests/targetallocator/serviceaccount.go @@ -20,6 +20,7 @@ import ( "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" "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" ) @@ -37,9 +38,8 @@ func ServiceAccount(params manifests.Params) *corev1.ServiceAccount { if len(params.TargetAllocator.Spec.ServiceAccount) > 0 { return nil } - name := naming.TargetAllocatorServiceAccount(params.TargetAllocator.Name) - labels := Labels(params.TargetAllocator, name) + labels := manifestutils.Labels(params.TargetAllocator.ObjectMeta, name, params.TargetAllocator.Spec.Image, ComponentOpenTelemetryTargetAllocator, nil) return &corev1.ServiceAccount{ ObjectMeta: metav1.ObjectMeta{ diff --git a/internal/manifests/targetallocator/serviceaccount_test.go b/internal/manifests/targetallocator/serviceaccount_test.go index 6c4c58509e..f8bd532f9e 100644 --- a/internal/manifests/targetallocator/serviceaccount_test.go +++ b/internal/manifests/targetallocator/serviceaccount_test.go @@ -23,6 +23,7 @@ import ( "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" "github.com/open-telemetry/opentelemetry-operator/internal/manifests" + "github.com/open-telemetry/opentelemetry-operator/internal/manifests/manifestutils" ) func TestServiceAccountDefaultName(t *testing.T) { @@ -72,7 +73,7 @@ func TestServiceAccountDefault(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "my-instance-targetallocator", Namespace: params.OtelCol.Namespace, - Labels: Labels(params.TargetAllocator, "my-instance-targetallocator"), + Labels: manifestutils.Labels(params.TargetAllocator.ObjectMeta, "my-instance-targetallocator", params.TargetAllocator.Spec.Image, ComponentOpenTelemetryTargetAllocator, nil), Annotations: params.OtelCol.Annotations, }, } diff --git a/internal/manifests/targetallocator/servicemonitor.go b/internal/manifests/targetallocator/servicemonitor.go index cf4cd4a46e..a22e4b50f2 100644 --- a/internal/manifests/targetallocator/servicemonitor.go +++ b/internal/manifests/targetallocator/servicemonitor.go @@ -19,17 +19,18 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "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" ) // ServiceMonitor returns the service monitor for the given instance. func ServiceMonitor(params manifests.Params) *monitoringv1.ServiceMonitor { - name := naming.TargetAllocator(params.OtelCol.Name) - labels := Labels(params.TargetAllocator, name) + name := naming.TargetAllocator(params.TargetAllocator.Name) + labels := manifestutils.Labels(params.TargetAllocator.ObjectMeta, name, params.TargetAllocator.Spec.Image, ComponentOpenTelemetryTargetAllocator, nil) return &monitoringv1.ServiceMonitor{ ObjectMeta: metav1.ObjectMeta{ - Namespace: params.OtelCol.Namespace, + Namespace: params.TargetAllocator.Namespace, Name: name, Labels: labels, }, @@ -41,10 +42,10 @@ func ServiceMonitor(params manifests.Params) *monitoringv1.ServiceMonitor { }, NamespaceSelector: monitoringv1.NamespaceSelector{ - MatchNames: []string{params.OtelCol.Namespace}, + MatchNames: []string{params.TargetAllocator.Namespace}, }, Selector: metav1.LabelSelector{ - MatchLabels: SelectorLabels(params.TargetAllocator), + MatchLabels: manifestutils.TASelectorLabels(params.TargetAllocator, ComponentOpenTelemetryTargetAllocator), }, }, } diff --git a/internal/manifests/targetallocator/servicemonitor_test.go b/internal/manifests/targetallocator/servicemonitor_test.go index ac5027e5ac..43521bd70a 100644 --- a/internal/manifests/targetallocator/servicemonitor_test.go +++ b/internal/manifests/targetallocator/servicemonitor_test.go @@ -28,30 +28,29 @@ import ( ) func TestDesiredServiceMonitors(t *testing.T) { - otelcol := v1beta1.OpenTelemetryCollector{ + ta := v1beta1.TargetAllocator{ ObjectMeta: metav1.ObjectMeta{ Name: "my-instance", Namespace: "my-namespace", }, - Spec: v1beta1.OpenTelemetryCollectorSpec{ + Spec: v1beta1.TargetAllocatorSpec{ OpenTelemetryCommonFields: v1beta1.OpenTelemetryCommonFields{ Tolerations: testTolerationValues, }, - Mode: v1beta1.ModeStatefulSet, }, } cfg := config.New() params := manifests.Params{ - OtelCol: otelcol, - Config: cfg, - Log: logger, + TargetAllocator: ta, + Config: cfg, + Log: logger, } actual := ServiceMonitor(params) assert.NotNil(t, actual) - assert.Equal(t, fmt.Sprintf("%s-targetallocator", params.OtelCol.Name), actual.Name) - assert.Equal(t, params.OtelCol.Namespace, actual.Namespace) + assert.Equal(t, fmt.Sprintf("%s-targetallocator", params.TargetAllocator.Name), actual.Name) + assert.Equal(t, params.TargetAllocator.Namespace, actual.Namespace) assert.Equal(t, "targetallocation", actual.Spec.Endpoints[0].Port) } diff --git a/main.go b/main.go index 2f0d0d9b61..58ec788e00 100644 --- a/main.go +++ b/main.go @@ -121,6 +121,7 @@ func main() { autoInstrumentationNginx string autoInstrumentationGo string labelsFilter []string + annotationsFilter []string webhookPort int tlsOpt tlsConfig ) @@ -145,7 +146,8 @@ func main() { stringFlagOrEnv(&autoInstrumentationGo, "auto-instrumentation-go-image", "RELATED_IMAGE_AUTO_INSTRUMENTATION_GO", fmt.Sprintf("ghcr.io/open-telemetry/opentelemetry-go-instrumentation/autoinstrumentation-go:%s", v.AutoInstrumentationGo), "The default OpenTelemetry Go instrumentation image. This image is used when no image is specified in the CustomResource.") stringFlagOrEnv(&autoInstrumentationApacheHttpd, "auto-instrumentation-apache-httpd-image", "RELATED_IMAGE_AUTO_INSTRUMENTATION_APACHE_HTTPD", fmt.Sprintf("ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-apache-httpd:%s", v.AutoInstrumentationApacheHttpd), "The default OpenTelemetry Apache HTTPD instrumentation image. This image is used when no image is specified in the CustomResource.") stringFlagOrEnv(&autoInstrumentationNginx, "auto-instrumentation-nginx-image", "RELATED_IMAGE_AUTO_INSTRUMENTATION_NGINX", fmt.Sprintf("ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-apache-httpd:%s", v.AutoInstrumentationNginx), "The default OpenTelemetry Nginx instrumentation image. This image is used when no image is specified in the CustomResource.") - pflag.StringArrayVar(&labelsFilter, "labels", []string{}, "Labels to filter away from propagating onto deploys") + pflag.StringArrayVar(&labelsFilter, "label", []string{}, "Labels to filter away from propagating onto deploys") + pflag.StringArrayVar(&annotationsFilter, "annotations-filter", []string{}, "Annotations to filter away from propagating onto deploys. It should be a string array containing patterns, which are literal strings optionally containing a * wildcard character. Example: --annotations-filter=*filter.out will filter out annotations that looks like: annotation.filter.out: true") pflag.IntVar(&webhookPort, "webhook-port", 9443, "The port the webhook endpoint binds to.") pflag.StringVar(&tlsOpt.minVersion, "tls-min-version", "VersionTLS12", "Minimum TLS version supported. Value must match version names from https://golang.org/pkg/crypto/tls/#pkg-constants.") pflag.StringSliceVar(&tlsOpt.cipherSuites, "tls-cipher-suites", nil, "Comma-separated list of cipher suites for the server. Values are from tls package constants (https://golang.org/pkg/crypto/tls/#pkg-constants). If omitted, the default Go cipher suites will be used") @@ -172,6 +174,7 @@ func main() { "go-arch", runtime.GOARCH, "go-os", runtime.GOOS, "labels-filter", labelsFilter, + "annotations-filter", annotationsFilter, "enable-multi-instrumentation", enableMultiInstrumentation, "enable-apache-httpd-instrumentation", enableApacheHttpdInstrumentation, "enable-dotnet-instrumentation", enableDotNetInstrumentation, @@ -205,6 +208,7 @@ func main() { config.WithAutoInstrumentationNginxImage(autoInstrumentationNginx), config.WithAutoDetect(ad), config.WithLabelFilters(labelsFilter), + config.WithAnnotationFilters(annotationsFilter), ) err = cfg.AutoDetect() if err != nil { diff --git a/tests/e2e-metadata-filters/annotations/00-error.yaml b/tests/e2e-metadata-filters/annotations/00-error.yaml new file mode 100644 index 0000000000..be76e1f6d4 --- /dev/null +++ b/tests/e2e-metadata-filters/annotations/00-error.yaml @@ -0,0 +1,15 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: test-annotations-collector + annotations: + annotation.filter.out: "true" +spec: + updateStrategy: + rollingUpdate: + maxSurge: 0 + maxUnavailable: 1 + type: RollingUpdate +status: + numberMisscheduled: 0 + (desiredNumberScheduled == numberReady): true diff --git a/tests/e2e-metadata-filters/annotations/00-install.yaml b/tests/e2e-metadata-filters/annotations/00-install.yaml new file mode 100644 index 0000000000..66c0353334 --- /dev/null +++ b/tests/e2e-metadata-filters/annotations/00-install.yaml @@ -0,0 +1,24 @@ +apiVersion: opentelemetry.io/v1alpha1 +kind: OpenTelemetryCollector +metadata: + name: test-annotations + annotations: + annotation.filter.out: "true" +spec: + mode: daemonset + config: | + receivers: + jaeger: + protocols: + grpc: + processors: + + exporters: + debug: + + service: + pipelines: + traces: + receivers: [jaeger] + processors: [] + exporters: [debug] diff --git a/tests/e2e-metadata-filters/annotations/01-error.yaml b/tests/e2e-metadata-filters/annotations/01-error.yaml new file mode 100644 index 0000000000..be76e1f6d4 --- /dev/null +++ b/tests/e2e-metadata-filters/annotations/01-error.yaml @@ -0,0 +1,15 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: test-annotations-collector + annotations: + annotation.filter.out: "true" +spec: + updateStrategy: + rollingUpdate: + maxSurge: 0 + maxUnavailable: 1 + type: RollingUpdate +status: + numberMisscheduled: 0 + (desiredNumberScheduled == numberReady): true diff --git a/tests/e2e-metadata-filters/annotations/01-patch.yaml b/tests/e2e-metadata-filters/annotations/01-patch.yaml new file mode 100644 index 0000000000..8b03dbe862 --- /dev/null +++ b/tests/e2e-metadata-filters/annotations/01-patch.yaml @@ -0,0 +1,6 @@ +apiVersion: opentelemetry.io/v1alpha1 +kind: OpenTelemetryCollector +metadata: + name: test-annotations + annotations: + annotation.filter.out: "false" diff --git a/tests/e2e-metadata-filters/annotations/chainsaw-test.yaml b/tests/e2e-metadata-filters/annotations/chainsaw-test.yaml new file mode 100755 index 0000000000..32f6a88ec8 --- /dev/null +++ b/tests/e2e-metadata-filters/annotations/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-pod-annotations +spec: + steps: + - name: step-00 + try: + - apply: + file: 00-install.yaml + - error: + file: 00-error.yaml + - name: step-01 + try: + - patch: + file: 01-patch.yaml + - error: + file: 01-error.yaml diff --git a/tests/e2e-metadata-filters/labels/00-error.yaml b/tests/e2e-metadata-filters/labels/00-error.yaml new file mode 100644 index 0000000000..be76e1f6d4 --- /dev/null +++ b/tests/e2e-metadata-filters/labels/00-error.yaml @@ -0,0 +1,15 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: test-annotations-collector + annotations: + annotation.filter.out: "true" +spec: + updateStrategy: + rollingUpdate: + maxSurge: 0 + maxUnavailable: 1 + type: RollingUpdate +status: + numberMisscheduled: 0 + (desiredNumberScheduled == numberReady): true diff --git a/tests/e2e-metadata-filters/labels/00-install.yaml b/tests/e2e-metadata-filters/labels/00-install.yaml new file mode 100644 index 0000000000..f7728e0c2d --- /dev/null +++ b/tests/e2e-metadata-filters/labels/00-install.yaml @@ -0,0 +1,24 @@ +apiVersion: opentelemetry.io/v1alpha1 +kind: OpenTelemetryCollector +metadata: + name: test-labels + labels: + annotation.filter.out: "true" +spec: + mode: daemonset + config: | + receivers: + jaeger: + protocols: + grpc: + processors: + + exporters: + debug: + + service: + pipelines: + traces: + receivers: [jaeger] + processors: [] + exporters: [debug] diff --git a/tests/e2e-metadata-filters/labels/01-error.yaml b/tests/e2e-metadata-filters/labels/01-error.yaml new file mode 100644 index 0000000000..be76e1f6d4 --- /dev/null +++ b/tests/e2e-metadata-filters/labels/01-error.yaml @@ -0,0 +1,15 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: test-annotations-collector + annotations: + annotation.filter.out: "true" +spec: + updateStrategy: + rollingUpdate: + maxSurge: 0 + maxUnavailable: 1 + type: RollingUpdate +status: + numberMisscheduled: 0 + (desiredNumberScheduled == numberReady): true diff --git a/tests/e2e-metadata-filters/labels/01-patch.yaml b/tests/e2e-metadata-filters/labels/01-patch.yaml new file mode 100644 index 0000000000..0b2206af16 --- /dev/null +++ b/tests/e2e-metadata-filters/labels/01-patch.yaml @@ -0,0 +1,6 @@ +apiVersion: opentelemetry.io/v1alpha1 +kind: OpenTelemetryCollector +metadata: + name: test-labels + labels: + annotation.filter.out: "false" diff --git a/tests/e2e-metadata-filters/labels/chainsaw-test.yaml b/tests/e2e-metadata-filters/labels/chainsaw-test.yaml new file mode 100755 index 0000000000..32f6a88ec8 --- /dev/null +++ b/tests/e2e-metadata-filters/labels/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-pod-annotations +spec: + steps: + - name: step-00 + try: + - apply: + file: 00-install.yaml + - error: + file: 00-error.yaml + - name: step-01 + try: + - patch: + file: 01-patch.yaml + - error: + file: 01-error.yaml