Skip to content

Commit dc952c2

Browse files
committed
Fixes #605 - Filter out unneeded labels
- 10.98.72.0/21
1 parent cd4fa9b commit dc952c2

16 files changed

+157
-14
lines changed

internal/config/main.go

+7
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ type Config struct {
5151
autoInstrumentationJavaImage string
5252
autoInstrumentationNodeJSImage string
5353
autoInstrumentationPythonImage string
54+
labelsFilter []string
5455
}
5556

5657
// New constructs a new configuration based on the given options.
@@ -81,6 +82,7 @@ func New(opts ...Option) Config {
8182
autoInstrumentationJavaImage: o.autoInstrumentationJavaImage,
8283
autoInstrumentationNodeJSImage: o.autoInstrumentationNodeJSImage,
8384
autoInstrumentationPythonImage: o.autoInstrumentationPythonImage,
85+
labelsFilter: o.labelsFilter,
8486
}
8587
}
8688

@@ -174,3 +176,8 @@ func (c *Config) AutoInstrumentationNodeJSImage() string {
174176
func (c *Config) AutoInstrumentationPythonImage() string {
175177
return c.autoInstrumentationPythonImage
176178
}
179+
180+
// Returns the filters converted to regex strings used to filter out unwanted labels from propagations.
181+
func (c *Config) LabelsFilter() []string {
182+
return c.labelsFilter
183+
}

internal/config/options.go

+28
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
package config
1616

1717
import (
18+
"regexp"
19+
"strings"
1820
"time"
1921

2022
"github.com/go-logr/logr"
@@ -41,6 +43,7 @@ type options struct {
4143
onChange []func() error
4244
platform platform.Platform
4345
version version.Version
46+
labelsFilter []string
4447
}
4548

4649
func WithAutoDetect(a autodetect.AutoDetect) Option {
@@ -115,3 +118,28 @@ func WithAutoInstrumentationPythonImage(s string) Option {
115118
o.autoInstrumentationPythonImage = s
116119
}
117120
}
121+
122+
func WithLabelFilters(labelFilters []string) Option {
123+
return func(o *options) {
124+
125+
filters := []string{}
126+
for _, pattern := range labelFilters {
127+
var result strings.Builder
128+
129+
for i, literal := range strings.Split(pattern, "*") {
130+
131+
// Replace * with .*
132+
if i > 0 {
133+
result.WriteString(".*")
134+
}
135+
136+
// Quote any regular expression meta characters in the
137+
// literal text.
138+
result.WriteString(regexp.QuoteMeta(literal))
139+
}
140+
filters = append(filters, result.String())
141+
}
142+
143+
o.labelsFilter = filters
144+
}
145+
}

main.go

+7
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,9 @@ func main() {
8080
autoInstrumentationJava string
8181
autoInstrumentationNodeJS string
8282
autoInstrumentationPython string
83+
labelsFilter []string
8384
)
85+
8486
pflag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.")
8587
flag.StringVar(&probeAddr, "health-probe-addr", ":8081", "The address the probe endpoint binds to.")
8688
pflag.BoolVar(&enableLeaderElection, "enable-leader-election", false,
@@ -91,11 +93,14 @@ func main() {
9193
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.")
9294
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.")
9395
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.")
96+
pflag.StringArrayVar(&labelsFilter, "labels", []string{}, "Labels to filter away from propagating onto deploys")
9497
pflag.Parse()
9598

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

102+
pflag.Parse()
103+
99104
logger.Info("Starting the OpenTelemetry Operator",
100105
"opentelemetry-operator", v.Operator,
101106
"opentelemetry-collector", collectorImage,
@@ -107,6 +112,7 @@ func main() {
107112
"go-version", v.Go,
108113
"go-arch", runtime.GOARCH,
109114
"go-os", runtime.GOOS,
115+
"labels-filter", labelsFilter,
110116
)
111117

112118
restConfig := ctrl.GetConfigOrDie()
@@ -127,6 +133,7 @@ func main() {
127133
config.WithAutoInstrumentationNodeJSImage(autoInstrumentationNodeJS),
128134
config.WithAutoInstrumentationPythonImage(autoInstrumentationPython),
129135
config.WithAutoDetect(ad),
136+
config.WithLabelFilters(labelsFilter),
130137
)
131138

132139
watchNamespace, found := os.LookupEnv("WATCH_NAMESPACE")

pkg/collector/daemonset.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import (
2727

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

3333
annotations := Annotations(otelcol)

pkg/collector/daemonset_test.go

+24
Original file line numberDiff line numberDiff line change
@@ -129,3 +129,27 @@ func TestDaemonstPodSecurityContext(t *testing.T) {
129129
assert.Equal(t, &runAsUser, d.Spec.Template.Spec.SecurityContext.RunAsUser)
130130
assert.Equal(t, &runasGroup, d.Spec.Template.Spec.SecurityContext.RunAsGroup)
131131
}
132+
133+
func TestDaemonsetFilterLabels(t *testing.T) {
134+
excludedLabels := map[string]string{
135+
"foo": "1",
136+
"app.foo.bar": "1",
137+
}
138+
139+
otelcol := v1alpha1.OpenTelemetryCollector{
140+
ObjectMeta: metav1.ObjectMeta{
141+
Name: "my-instance",
142+
Labels: excludedLabels,
143+
},
144+
Spec: v1alpha1.OpenTelemetryCollectorSpec{},
145+
}
146+
147+
cfg := config.New(config.WithLabelFilters([]string{"foo*", "app.*.bar"}))
148+
149+
d := DaemonSet(cfg, logger, otelcol)
150+
151+
assert.Len(t, d.ObjectMeta.Labels, 5)
152+
for k := range excludedLabels {
153+
assert.NotContains(t, d.ObjectMeta.Labels, k)
154+
}
155+
}

pkg/collector/deployment.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import (
2727

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

3333
annotations := Annotations(otelcol)

pkg/collector/deployment_test.go

+24
Original file line numberDiff line numberDiff line change
@@ -151,3 +151,27 @@ func TestDeploymentHostNetwork(t *testing.T) {
151151
assert.Equal(t, d2.Spec.Template.Spec.HostNetwork, true)
152152
assert.Equal(t, d2.Spec.Template.Spec.DNSPolicy, v1.DNSClusterFirstWithHostNet)
153153
}
154+
155+
func TestDeploymentFilterLabels(t *testing.T) {
156+
excludedLabels := map[string]string{
157+
"foo": "1",
158+
"app.foo.bar": "1",
159+
}
160+
161+
otelcol := v1alpha1.OpenTelemetryCollector{
162+
ObjectMeta: metav1.ObjectMeta{
163+
Name: "my-instance",
164+
Labels: excludedLabels,
165+
},
166+
Spec: v1alpha1.OpenTelemetryCollectorSpec{},
167+
}
168+
169+
cfg := config.New(config.WithLabelFilters([]string{"foo*", "app.*.bar"}))
170+
171+
d := Deployment(cfg, logger, otelcol)
172+
173+
assert.Len(t, d.ObjectMeta.Labels, 5)
174+
for k := range excludedLabels {
175+
assert.NotContains(t, d.ObjectMeta.Labels, k)
176+
}
177+
}

pkg/collector/horizontalpodautoscaler.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import (
2727
const defaultCPUTarget int32 = 90
2828

2929
func HorizontalPodAutoscaler(cfg config.Config, logger logr.Logger, otelcol v1alpha1.OpenTelemetryCollector) autoscalingv1.HorizontalPodAutoscaler {
30-
labels := Labels(otelcol)
30+
labels := Labels(otelcol, cfg.LabelsFilter())
3131
labels["app.kubernetes.io/name"] = naming.Collector(otelcol)
3232

3333
annotations := Annotations(otelcol)

pkg/collector/labels.go

+15-2
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,30 @@
1515
package collector
1616

1717
import (
18+
"regexp"
19+
1820
"github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1"
1921
"github.com/open-telemetry/opentelemetry-operator/pkg/naming"
2022
)
2123

24+
func isFilteredLabel(label string, filterLabels []string) bool {
25+
for _, pattern := range filterLabels {
26+
match, _ := regexp.MatchString(pattern, label)
27+
return match
28+
}
29+
30+
return false
31+
}
32+
2233
// Labels return the common labels to all objects that are part of a managed OpenTelemetryCollector.
23-
func Labels(instance v1alpha1.OpenTelemetryCollector) map[string]string {
34+
func Labels(instance v1alpha1.OpenTelemetryCollector, filterLabels []string) map[string]string {
2435
// new map every time, so that we don't touch the instance's label
2536
base := map[string]string{}
2637
if nil != instance.Labels {
2738
for k, v := range instance.Labels {
28-
base[k] = v
39+
if !isFilteredLabel(k, filterLabels) {
40+
base[k] = v
41+
}
2942
}
3043
}
3144

pkg/collector/labels_test.go

+18-2
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ func TestLabelsCommonSet(t *testing.T) {
3434
}
3535

3636
// test
37-
labels := Labels(otelcol)
37+
labels := Labels(otelcol, []string{})
3838
assert.Equal(t, "opentelemetry-operator", labels["app.kubernetes.io/managed-by"])
3939
assert.Equal(t, "my-ns.my-instance", labels["app.kubernetes.io/instance"])
4040
assert.Equal(t, "opentelemetry", labels["app.kubernetes.io/part-of"])
@@ -50,9 +50,25 @@ func TestLabelsPropagateDown(t *testing.T) {
5050
}
5151

5252
// test
53-
labels := Labels(otelcol)
53+
labels := Labels(otelcol, []string{})
5454

5555
// verify
5656
assert.Len(t, labels, 5)
5757
assert.Equal(t, "mycomponent", labels["myapp"])
5858
}
59+
60+
func TestLabelsFilter(t *testing.T) {
61+
otelcol := v1alpha1.OpenTelemetryCollector{
62+
ObjectMeta: metav1.ObjectMeta{
63+
Labels: map[string]string{"test.bar.io": "foo", "test.foo.io": "bar"},
64+
},
65+
}
66+
67+
// This requires the filter to be in regex match form and not the other simpler wildcard one.
68+
labels := Labels(otelcol, []string{".*.bar.io"})
69+
70+
// verify
71+
assert.Len(t, labels, 5)
72+
assert.NotContains(t, labels, "test.bar.io")
73+
assert.Equal(t, "bar", labels["test.foo.io"])
74+
}

pkg/collector/reconcile/configmap.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ func ConfigMaps(ctx context.Context, params Params) error {
6464

6565
func desiredConfigMap(_ context.Context, params Params) corev1.ConfigMap {
6666
name := naming.ConfigMap(params.Instance)
67-
labels := collector.Labels(params.Instance)
67+
labels := collector.Labels(params.Instance, []string{})
6868
labels["app.kubernetes.io/name"] = name
6969
config, err := ReplaceConfig(params)
7070
if err != nil {

pkg/collector/reconcile/service.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ func Services(ctx context.Context, params Params) error {
6868
}
6969

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

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

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

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

172172
return &corev1.Service{

pkg/collector/reconcile/service_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ func TestMonitoringService(t *testing.T) {
213213
}
214214

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

219219
selector := labels

pkg/collector/serviceaccount.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func ServiceAccountName(instance v1alpha1.OpenTelemetryCollector) string {
3333

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

3939
return corev1.ServiceAccount{

pkg/collector/statefulset.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import (
2727

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

3333
annotations := Annotations(otelcol)

pkg/collector/statefulset_test.go

+24
Original file line numberDiff line numberDiff line change
@@ -210,3 +210,27 @@ func TestStatefulSetHostNetwork(t *testing.T) {
210210
assert.Equal(t, d2.Spec.Template.Spec.HostNetwork, true)
211211
assert.Equal(t, d2.Spec.Template.Spec.DNSPolicy, v1.DNSClusterFirstWithHostNet)
212212
}
213+
214+
func TestStatefulSetFilterLabels(t *testing.T) {
215+
excludedLabels := map[string]string{
216+
"foo": "1",
217+
"app.foo.bar": "1",
218+
}
219+
220+
otelcol := v1alpha1.OpenTelemetryCollector{
221+
ObjectMeta: metav1.ObjectMeta{
222+
Name: "my-instance",
223+
Labels: excludedLabels,
224+
},
225+
Spec: v1alpha1.OpenTelemetryCollectorSpec{},
226+
}
227+
228+
cfg := config.New(config.WithLabelFilters([]string{"foo*", "app.*.bar"}))
229+
230+
d := StatefulSet(cfg, logger, otelcol)
231+
232+
assert.Len(t, d.ObjectMeta.Labels, 5)
233+
for k := range excludedLabels {
234+
assert.NotContains(t, d.ObjectMeta.Labels, k)
235+
}
236+
}

0 commit comments

Comments
 (0)