Skip to content

Commit

Permalink
Fixes #605 - Filter out unneeded labels
Browse files Browse the repository at this point in the history
  • Loading branch information
ekarlso committed Dec 6, 2021
1 parent e0a5a5a commit 36b5dd9
Show file tree
Hide file tree
Showing 15 changed files with 153 additions and 13 deletions.
7 changes: 7 additions & 0 deletions internal/config/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ type Config struct {
targetAllocatorConfigMapEntry string
platform platform.Platform
autoInstrumentationJavaImage string
labelsFilter []string
}

// New constructs a new configuration based on the given options.
Expand Down Expand Up @@ -78,6 +79,7 @@ func New(opts ...Option) Config {
onChange: o.onChange,
platform: o.platform,
autoInstrumentationJavaImage: o.autoInstrumentationjavaImage,
labelsFilter: o.labelsFilter,
}
}

Expand Down Expand Up @@ -173,3 +175,8 @@ func (c *Config) Platform() platform.Platform {
func (c *Config) AutoInstrumentationJavaImage() string {
return c.autoInstrumentationJavaImage
}

// Returns the filters converted to regex strings used to filter out unwanted labels from propagations.
func (c *Config) LabelsFilter() []string {
return c.labelsFilter
}
28 changes: 28 additions & 0 deletions internal/config/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
package config

import (
"regexp"
"strings"
"time"

"github.com/go-logr/logr"
Expand All @@ -39,6 +41,7 @@ type options struct {
onChange []func() error
platform platform.Platform
version version.Version
labelsFilter []string
}

func WithAutoDetect(a autodetect.AutoDetect) Option {
Expand Down Expand Up @@ -101,3 +104,28 @@ func WithAutoInstrumentationJavaImage(s string) Option {
o.autoInstrumentationjavaImage = s
}
}

func WithLabelFilters(labelFilters []string) Option {
return func(o *options) {

filters := []string{}
for _, pattern := range labelFilters {
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.labelsFilter = filters
}
}
4 changes: 4 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ func main() {
collectorImage string
targetAllocatorImage string
autoInstrumentationJava string
labelsFilter []string
)
pflag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.")
flag.StringVar(&probeAddr, "health-probe-addr", ":8081", "The address the probe endpoint binds to.")
Expand All @@ -85,6 +86,7 @@ func main() {
pflag.StringVar(&collectorImage, "collector-image", fmt.Sprintf("otel/opentelemetry-collector:%s", v.OpenTelemetryCollector), "The default OpenTelemetry collector image. This image is used when no image is specified in the CustomResource.")
pflag.StringVar(&targetAllocatorImage, "target-allocator-image", fmt.Sprintf("quay.io/opentelemetry/target-allocator:%s", v.TargetAllocator), "The default OpenTelemetry target allocator image. This image is used when no image is specified in the CustomResource.")
pflag.StringVar(&autoInstrumentationJava, "auto-instrumentation-java-image", fmt.Sprintf("ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-java:%s", v.JavaAutoInstrumentation), "The default OpenTelemetry Java instrumentation image. This image is used when no image is specified in the CustomResource.")
pflag.StringArray("labels", labelsFilter, "Labels to filter away from propagating onto depoys")

logger := zap.New(zap.UseFlagOptions(&opts))
ctrl.SetLogger(logger)
Expand All @@ -98,6 +100,7 @@ func main() {
"go-version", v.Go,
"go-arch", runtime.GOARCH,
"go-os", runtime.GOOS,
"laebls-filter", labelsFilter,
)

restConfig := ctrl.GetConfigOrDie()
Expand All @@ -116,6 +119,7 @@ func main() {
config.WithTargetAllocatorImage(targetAllocatorImage),
config.WithAutoInstrumentationJavaImage(autoInstrumentationJava),
config.WithAutoDetect(ad),
config.WithLabelFilters(labelsFilter),
)

pflag.CommandLine.AddFlagSet(cfg.FlagSet())
Expand Down
2 changes: 1 addition & 1 deletion pkg/collector/daemonset.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import (

// DaemonSet builds the deployment for the given instance.
func DaemonSet(cfg config.Config, logger logr.Logger, otelcol v1alpha1.OpenTelemetryCollector) appsv1.DaemonSet {
labels := Labels(otelcol)
labels := Labels(otelcol, cfg.LabelsFilter())
labels["app.kubernetes.io/name"] = naming.Collector(otelcol)

annotations := Annotations(otelcol)
Expand Down
24 changes: 24 additions & 0 deletions pkg/collector/daemonset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,27 @@ func TestDaemonstPodSecurityContext(t *testing.T) {
assert.Equal(t, &runAsUser, d.Spec.Template.Spec.SecurityContext.RunAsUser)
assert.Equal(t, &runasGroup, d.Spec.Template.Spec.SecurityContext.RunAsGroup)
}

func TestDaemonsetFilterLabels(t *testing.T) {
excludedLabels := map[string]string{
"foo": "1",
"app.foo.bar": "1",
}

otelcol := v1alpha1.OpenTelemetryCollector{
ObjectMeta: metav1.ObjectMeta{
Name: "my-instance",
Labels: excludedLabels,
},
Spec: v1alpha1.OpenTelemetryCollectorSpec{},
}

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

d := DaemonSet(cfg, logger, otelcol)

assert.Len(t, d.ObjectMeta.Labels, 5)
for k := range excludedLabels {
assert.NotContains(t, d.ObjectMeta.Labels, k)
}
}
2 changes: 1 addition & 1 deletion pkg/collector/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import (

// Deployment builds the deployment for the given instance.
func Deployment(cfg config.Config, logger logr.Logger, otelcol v1alpha1.OpenTelemetryCollector) appsv1.Deployment {
labels := Labels(otelcol)
labels := Labels(otelcol, cfg.LabelsFilter())
labels["app.kubernetes.io/name"] = naming.Collector(otelcol)

annotations := Annotations(otelcol)
Expand Down
24 changes: 24 additions & 0 deletions pkg/collector/deployment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,27 @@ func TestDeploymenttPodSecurityContext(t *testing.T) {
assert.Equal(t, &runAsUser, d.Spec.Template.Spec.SecurityContext.RunAsUser)
assert.Equal(t, &runasGroup, d.Spec.Template.Spec.SecurityContext.RunAsGroup)
}

func TestDeploymentFilterLabels(t *testing.T) {
excludedLabels := map[string]string{
"foo": "1",
"app.foo.bar": "1",
}

otelcol := v1alpha1.OpenTelemetryCollector{
ObjectMeta: metav1.ObjectMeta{
Name: "my-instance",
Labels: excludedLabels,
},
Spec: v1alpha1.OpenTelemetryCollectorSpec{},
}

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

d := Deployment(cfg, logger, otelcol)

assert.Len(t, d.ObjectMeta.Labels, 5)
for k := range excludedLabels {
assert.NotContains(t, d.ObjectMeta.Labels, k)
}
}
16 changes: 14 additions & 2 deletions pkg/collector/labels.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,29 @@ package collector

import (
"fmt"
"regexp"

"github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1"
)

func isFilteredLabel(label string, filterLabels []string) bool {
for _, pattern := range filterLabels {
match, _ := regexp.MatchString(pattern, label)
return match
}

return false
}

// Labels return the common labels to all objects that are part of a managed OpenTelemetryCollector.
func Labels(instance v1alpha1.OpenTelemetryCollector) map[string]string {
func Labels(instance v1alpha1.OpenTelemetryCollector, filterLabels []string) map[string]string {
// new map every time, so that we don't touch the instance's label
base := map[string]string{}
if nil != instance.Labels {
for k, v := range instance.Labels {
base[k] = v
if !isFilteredLabel(k, filterLabels) {
base[k] = v
}
}
}

Expand Down
21 changes: 19 additions & 2 deletions pkg/collector/labels_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func TestLabelsCommonSet(t *testing.T) {
}

// test
labels := Labels(otelcol)
labels := Labels(otelcol, []string{})
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"])
Expand All @@ -50,9 +50,26 @@ func TestLabelsPropagateDown(t *testing.T) {
}

// test
labels := Labels(otelcol)
labels := Labels(otelcol, []string{})

// verify
assert.Len(t, labels, 5)
assert.Equal(t, "mycomponent", labels["myapp"])
}

func TestLabelsFilter(t *testing.T) {
otelcol := v1alpha1.OpenTelemetryCollector{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{"test.bar.io": "foo", "test.foo.io": "bar"},
},
}

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

t.Log(labels)
// verify
assert.Len(t, labels, 5)
assert.NotContains(t, labels, "test.bar.io")
assert.Equal(t, "bar", labels["test.foo.io"])
}
2 changes: 1 addition & 1 deletion pkg/collector/reconcile/configmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func ConfigMaps(ctx context.Context, params Params) error {

func desiredConfigMap(_ context.Context, params Params) corev1.ConfigMap {
name := naming.ConfigMap(params.Instance)
labels := collector.Labels(params.Instance)
labels := collector.Labels(params.Instance, []string{})
labels["app.kubernetes.io/name"] = name
config, err := ReplaceConfig(params)
if err != nil {
Expand Down
6 changes: 3 additions & 3 deletions pkg/collector/reconcile/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func Services(ctx context.Context, params Params) error {
}

func desiredService(ctx context.Context, params Params) *corev1.Service {
labels := collector.Labels(params.Instance)
labels := collector.Labels(params.Instance, []string{})
labels["app.kubernetes.io/name"] = naming.Service(params.Instance)

// by coincidence, the selector is the same as the label, but note that the selector points to the deployment
Expand Down Expand Up @@ -163,10 +163,10 @@ func headless(ctx context.Context, params Params) *corev1.Service {
}

func monitoringService(ctx context.Context, params Params) *corev1.Service {
labels := collector.Labels(params.Instance)
labels := collector.Labels(params.Instance, []string{})
labels["app.kubernetes.io/name"] = naming.MonitoringService(params.Instance)

selector := collector.Labels(params.Instance)
selector := collector.Labels(params.Instance, []string{})
selector["app.kubernetes.io/name"] = fmt.Sprintf("%s-collector", params.Instance.Name)

return &corev1.Service{
Expand Down
2 changes: 1 addition & 1 deletion pkg/collector/reconcile/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ func TestMonitoringService(t *testing.T) {
}

func service(name string, ports []v1.ServicePort) v1.Service {
labels := collector.Labels(params().Instance)
labels := collector.Labels(params().Instance, []string{})
labels["app.kubernetes.io/name"] = name

selector := labels
Expand Down
2 changes: 1 addition & 1 deletion pkg/collector/serviceaccount.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func ServiceAccountName(instance v1alpha1.OpenTelemetryCollector) string {

//ServiceAccount returns the service account for the given instance.
func ServiceAccount(otelcol v1alpha1.OpenTelemetryCollector) corev1.ServiceAccount {
labels := Labels(otelcol)
labels := Labels(otelcol, []string{})
labels["app.kubernetes.io/name"] = naming.ServiceAccount(otelcol)

return corev1.ServiceAccount{
Expand Down
2 changes: 1 addition & 1 deletion pkg/collector/statefulset.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import (

// StatefulSet builds the statefulset for the given instance.
func StatefulSet(cfg config.Config, logger logr.Logger, otelcol v1alpha1.OpenTelemetryCollector) appsv1.StatefulSet {
labels := Labels(otelcol)
labels := Labels(otelcol, cfg.LabelsFilter())
labels["app.kubernetes.io/name"] = naming.Collector(otelcol)

annotations := Annotations(otelcol)
Expand Down
24 changes: 24 additions & 0 deletions pkg/collector/statefulset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,3 +172,27 @@ func TestStatefulSetPodSecurityContext(t *testing.T) {
assert.Equal(t, &runAsUser, d.Spec.Template.Spec.SecurityContext.RunAsUser)
assert.Equal(t, &runasGroup, d.Spec.Template.Spec.SecurityContext.RunAsGroup)
}

func TestStatefulSetFilterLabels(t *testing.T) {
excludedLabels := map[string]string{
"foo": "1",
"app.foo.bar": "1",
}

otelcol := v1alpha1.OpenTelemetryCollector{
ObjectMeta: metav1.ObjectMeta{
Name: "my-instance",
Labels: excludedLabels,
},
Spec: v1alpha1.OpenTelemetryCollectorSpec{},
}

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

d := StatefulSet(cfg, logger, otelcol)

assert.Len(t, d.ObjectMeta.Labels, 5)
for k := range excludedLabels {
assert.NotContains(t, d.ObjectMeta.Labels, k)
}
}

0 comments on commit 36b5dd9

Please sign in to comment.