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 Feb 28, 2022
1 parent c256873 commit 9605936
Show file tree
Hide file tree
Showing 15 changed files with 162 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 @@ -51,6 +51,7 @@ type Config struct {
autoInstrumentationJavaImage string
autoInstrumentationNodeJSImage string
autoInstrumentationPythonImage string
labelsFilter []string
}

// New constructs a new configuration based on the given options.
Expand Down Expand Up @@ -81,6 +82,7 @@ func New(opts ...Option) Config {
autoInstrumentationJavaImage: o.autoInstrumentationJavaImage,
autoInstrumentationNodeJSImage: o.autoInstrumentationNodeJSImage,
autoInstrumentationPythonImage: o.autoInstrumentationPythonImage,
labelsFilter: o.labelsFilter,
}
}

Expand Down Expand Up @@ -174,3 +176,8 @@ func (c *Config) AutoInstrumentationNodeJSImage() string {
func (c *Config) AutoInstrumentationPythonImage() string {
return c.autoInstrumentationPythonImage
}

// 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 @@ -41,6 +43,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 @@ -115,3 +118,28 @@ func WithAutoInstrumentationPythonImage(s string) Option {
o.autoInstrumentationPythonImage = 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
}
}
12 changes: 12 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,9 @@ func main() {
autoInstrumentationJava string
autoInstrumentationNodeJS string
autoInstrumentationPython 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.")
pflag.BoolVar(&enableLeaderElection, "enable-leader-election", false,
Expand All @@ -90,11 +92,14 @@ func main() {
pflag.StringVar(&autoInstrumentationJava, "auto-instrumentation-java-image", fmt.Sprintf("ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-java:%s", v.AutoInstrumentationJava), "The default OpenTelemetry Java instrumentation image. This image is used when no image is specified in the CustomResource.")
pflag.StringVar(&autoInstrumentationNodeJS, "auto-instrumentation-nodejs-image", fmt.Sprintf("ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-nodejs:%s", v.AutoInstrumentationNodeJS), "The default OpenTelemetry NodeJS instrumentation image. This image is used when no image is specified in the CustomResource.")
pflag.StringVar(&autoInstrumentationPython, "auto-instrumentation-python-image", fmt.Sprintf("ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-python:%s", v.AutoInstrumentationPython), "The default OpenTelemetry Python 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.Parse()

logger := zap.New(zap.UseFlagOptions(&opts))
ctrl.SetLogger(logger)

pflag.Parse()

logger.Info("Starting the OpenTelemetry Operator",
"opentelemetry-operator", v.Operator,
"opentelemetry-collector", collectorImage,
Expand All @@ -106,6 +111,7 @@ func main() {
"go-version", v.Go,
"go-arch", runtime.GOARCH,
"go-os", runtime.GOOS,
"labels-filter", labelsFilter,
)

restConfig := ctrl.GetConfigOrDie()
Expand All @@ -126,8 +132,14 @@ func main() {
config.WithAutoInstrumentationNodeJSImage(autoInstrumentationNodeJS),
config.WithAutoInstrumentationPythonImage(autoInstrumentationPython),
config.WithAutoDetect(ad),
config.WithLabelFilters(labelsFilter),
)

<<<<<<< HEAD
=======
pflag.CommandLine.AddFlagSet(cfg.FlagSet())

>>>>>>> a8a5e9a (Fixes #605 - Filter out unneeded labels)
watchNamespace, found := os.LookupEnv("WATCH_NAMESPACE")
if found {
setupLog.Info("watching namespace(s)", "namespaces", watchNamespace)
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 @@ -129,3 +129,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 @@ -151,3 +151,27 @@ func TestDeploymentHostNetwork(t *testing.T) {
assert.Equal(t, d2.Spec.Template.Spec.HostNetwork, true)
assert.Equal(t, d2.Spec.Template.Spec.DNSPolicy, v1.DNSClusterFirstWithHostNet)
}

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)
}
}
17 changes: 15 additions & 2 deletions pkg/collector/labels.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,30 @@
package collector

import (
"regexp"

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

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 @@ -213,7 +213,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 @@ -210,3 +210,27 @@ func TestStatefulSetHostNetwork(t *testing.T) {
assert.Equal(t, d2.Spec.Template.Spec.HostNetwork, true)
assert.Equal(t, d2.Spec.Template.Spec.DNSPolicy, v1.DNSClusterFirstWithHostNet)
}

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 9605936

Please sign in to comment.