Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Created annotations filter #2692

Merged
merged 15 commits into from
Mar 7, 2024
3 changes: 3 additions & 0 deletions controllers/builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -930,6 +930,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,
Expand Down
33 changes: 25 additions & 8 deletions internal/config/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,11 +162,11 @@ func WithOpenShiftRoutesAvailability(os openshift.RoutesAvailability) Option {
}
}

func WithSetFilters(setFilters []string, setType string) Option {
func WithLabelFilters(labelFilters []string) Option {
return func(o *options) {

filters := []string{}
for _, pattern := range setFilters {
for _, pattern := range labelFilters {
var result strings.Builder

for i, literal := range strings.Split(pattern, "*") {
Expand All @@ -181,12 +181,29 @@ func WithSetFilters(setFilters []string, setType string) Option {
}
filters = append(filters, result.String())
}
switch filterType := setType; filterType {
case "labels":
o.labelsFilter = filters
case "annotations":
o.annotationsFilter = filters
}
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
}
}
4 changes: 2 additions & 2 deletions internal/manifests/collector/daemonset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ func TestDaemonsetFilterLabels(t *testing.T) {
Spec: v1beta1.OpenTelemetryCollectorSpec{},
}

cfg := config.New(config.WithSetFilters([]string{"foo*", "app.*.bar"}, "labels"))
cfg := config.New(config.WithLabelFilters([]string{"foo*", "app.*.bar"}))

params := manifests.Params{
Config: cfg,
Expand Down Expand Up @@ -258,7 +258,7 @@ func TestDaemonsetFilterAnnotations(t *testing.T) {
Spec: v1beta1.OpenTelemetryCollectorSpec{},
}

cfg := config.New(config.WithSetFilters([]string{"foo*", "app.*.bar"}, "annotations"))
cfg := config.New(config.WithAnnotationFilters([]string{"foo*", "app.*.bar"}))

params := manifests.Params{
Config: cfg,
Expand Down
4 changes: 2 additions & 2 deletions internal/manifests/collector/deployment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ func TestDeploymentFilterLabels(t *testing.T) {
Spec: v1beta1.OpenTelemetryCollectorSpec{},
}

cfg := config.New(config.WithSetFilters([]string{"foo*", "app.*.bar"}, "labels"))
cfg := config.New(config.WithLabelFilters([]string{"foo*", "app.*.bar"}))

params := manifests.Params{
Config: cfg,
Expand Down Expand Up @@ -340,7 +340,7 @@ func TestDeploymentFilterAnnotations(t *testing.T) {
Spec: v1beta1.OpenTelemetryCollectorSpec{},
}

cfg := config.New(config.WithSetFilters([]string{"foo*", "app.*.bar"}, "annotations"))
cfg := config.New(config.WithAnnotationFilters([]string{"foo*", "app.*.bar"}))

params := manifests.Params{
Config: cfg,
Expand Down
4 changes: 2 additions & 2 deletions internal/manifests/collector/statefulset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ func TestStatefulSetFilterLabels(t *testing.T) {
Spec: v1beta1.OpenTelemetryCollectorSpec{},
}

cfg := config.New(config.WithSetFilters([]string{"foo*", "app.*.bar"}, "labels"))
cfg := config.New(config.WithLabelFilters([]string{"foo*", "app.*.bar"}))

params := manifests.Params{
OtelCol: otelcol,
Expand Down Expand Up @@ -350,7 +350,7 @@ func TestStatefulSetFilterAnnotations(t *testing.T) {
Spec: v1beta1.OpenTelemetryCollectorSpec{},
}

cfg := config.New(config.WithSetFilters([]string{"foo*", "app.*.bar"}, "annotations"))
cfg := config.New(config.WithAnnotationFilters([]string{"foo*", "app.*.bar"}))

params := manifests.Params{
OtelCol: otelcol,
Expand Down
4 changes: 2 additions & 2 deletions internal/manifests/manifestutils/annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func Annotations(instance v1beta1.OpenTelemetryCollector, filterAnnotations []st
// allow override of prometheus annotations
if nil != instance.ObjectMeta.Annotations {
for k, v := range instance.ObjectMeta.Annotations {
if !isFilteredSet(k, filterAnnotations) {
if !IsFilteredSet(k, filterAnnotations) {
annotations[k] = v
}
}
Expand All @@ -61,7 +61,7 @@ func PodAnnotations(instance v1beta1.OpenTelemetryCollector, filterAnnotations [
podAnnotations := map[string]string{}
if nil != instance.Spec.PodAnnotations {
for k, v := range instance.Spec.PodAnnotations {
if !isFilteredSet(k, filterAnnotations) {
if !IsFilteredSet(k, filterAnnotations) {
podAnnotations[k] = v
}
}
Expand Down
6 changes: 4 additions & 2 deletions internal/manifests/manifestutils/annotations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (

"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"
Expand Down Expand Up @@ -163,7 +164,8 @@ func TestAnnotationsPropagateDown(t *testing.T) {
func TestAnnotationsFilter(t *testing.T) {
otelcol := v1beta1.OpenTelemetryCollector{
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{"test.bar.io": "foo",
Annotations: map[string]string{
"test.bar.io": "foo",
"test.io/port": "1234",
"test.io/path": "/test",
},
Expand All @@ -174,7 +176,7 @@ func TestAnnotationsFilter(t *testing.T) {
}

// This requires the filter to be in regex match form and not the other simpler wildcard one.
annotations, err := Annotations(otelcol, []string{".*.bar.io"})
annotations, err := Annotations(otelcol, []string{".*\\.bar\\.io"})

// verify
require.NoError(t, err)
Expand Down
29 changes: 25 additions & 4 deletions internal/manifests/manifestutils/labels.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,13 @@ 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 isFilteredSet(sourceSet string, filterSet []string) bool {
func IsFilteredSet(sourceSet string, filterSet []string) bool {
for _, pattern := range filterSet {
match, _ := regexp.MatchString(pattern, sourceSet)
return match
Expand All @@ -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 !isFilteredSet(k, filterLabels) {
if !IsFilteredSet(k, filterLabels) {
base[k] = v
}
}
Expand Down Expand Up @@ -81,3 +82,23 @@ func SelectorLabels(instance metav1.ObjectMeta, component string) map[string]str
"app.kubernetes.io/component": component,
}
}

// Labels return the common labels to all TargetAllocator objects that are part of a managed OpenTelemetryCollector.
func TALabels(instance v1beta1.OpenTelemetryCollector, name string, component string) map[string]string {
return Labels(instance.ObjectMeta, name, instance.Spec.TargetAllocator.Image, component, nil)
}

// SelectorLabels return the selector labels for Target Allocator Pods.
func TASelectorLabels(instance v1beta1.OpenTelemetryCollector, 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
}
64 changes: 64 additions & 0 deletions internal/manifests/manifestutils/labels_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -168,3 +173,62 @@ func TestSelectorLabels(t *testing.T) {
// verify
assert.Equal(t, expected, result)
}

func TestLabelsTACommonSet(t *testing.T) {
// prepare
otelcol := v1beta1.OpenTelemetryCollector{
ObjectMeta: metav1.ObjectMeta{
Name: taname,
Namespace: tanamespace,
},
}

// test
labels := TALabels(otelcol, taname, "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, "latest", labels["app.kubernetes.io/version"])
assert.Equal(t, taname, labels["app.kubernetes.io/name"])
}

func TestLabelsTAPropagateDown(t *testing.T) {
// prepare
otelcol := v1beta1.OpenTelemetryCollector{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{
"myapp": "mycomponent",
"app.kubernetes.io/name": "test",
},
},
}

// test
labels := TALabels(otelcol, taname, "opentelemetry-targetallocator")
selectorLabels := TASelectorLabels(otelcol, "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
otelcol := v1beta1.OpenTelemetryCollector{
ObjectMeta: metav1.ObjectMeta{
Name: taname,
Namespace: tanamespace,
},
}

// test
labels := TASelectorLabels(otelcol, "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(otelcol.Name), labels["app.kubernetes.io/name"])
}
61 changes: 61 additions & 0 deletions internal/manifests/opampbridge/annotations.go
Original file line number Diff line number Diff line change
@@ -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 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i wonder if we should also move annotations.go and labels.go to a shared thing in manifestutils?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be honest, I've tried to do that, but I faced an import cycle issue. I believe we could dig into that in the future, moving the annotations to the manifestutils. wdyt?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah that makes sense, want to open an issue about that?

// 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)
}
Loading
Loading