Skip to content

Commit 4e53f53

Browse files
authored
Merge branch 'main' into bug/2655
2 parents 4bc4dd3 + 6daa60e commit 4e53f53

File tree

8 files changed

+391
-21
lines changed

8 files changed

+391
-21
lines changed

apis/v1alpha1/convert_test.go

+59
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,65 @@ func Test_tov1beta1AndBack(t *testing.T) {
323323
assert.Equal(t, colalpha1, colalpha1Converted)
324324
}
325325

326+
func Test_tov1beta1AndBack_prometheus_selectors(t *testing.T) {
327+
t.Run("nil-selectors", func(t *testing.T) {
328+
colalpha1 := OpenTelemetryCollector{
329+
Spec: OpenTelemetryCollectorSpec{
330+
TargetAllocator: OpenTelemetryTargetAllocator{
331+
PrometheusCR: OpenTelemetryTargetAllocatorPrometheusCR{
332+
// nil or empty map means select everything
333+
PodMonitorSelector: nil,
334+
ServiceMonitorSelector: nil,
335+
},
336+
},
337+
},
338+
}
339+
340+
colbeta1 := v1beta1.OpenTelemetryCollector{}
341+
err := colalpha1.ConvertTo(&colbeta1)
342+
require.NoError(t, err)
343+
344+
// nil LabelSelector means select nothing
345+
// empty LabelSelector mean select everything
346+
assert.NotNil(t, colbeta1.Spec.TargetAllocator.PrometheusCR.PodMonitorSelector)
347+
assert.NotNil(t, colbeta1.Spec.TargetAllocator.PrometheusCR.ServiceMonitorSelector)
348+
assert.Equal(t, 0, len(colalpha1.Spec.TargetAllocator.PrometheusCR.PodMonitorSelector))
349+
assert.Equal(t, 0, len(colalpha1.Spec.TargetAllocator.PrometheusCR.ServiceMonitorSelector))
350+
351+
err = colalpha1.ConvertFrom(&colbeta1)
352+
require.NoError(t, err)
353+
assert.Nil(t, colalpha1.Spec.TargetAllocator.PrometheusCR.PodMonitorSelector)
354+
assert.Nil(t, colalpha1.Spec.TargetAllocator.PrometheusCR.ServiceMonitorSelector)
355+
})
356+
t.Run("empty-selectors", func(t *testing.T) {
357+
colalpha1 := OpenTelemetryCollector{
358+
Spec: OpenTelemetryCollectorSpec{
359+
TargetAllocator: OpenTelemetryTargetAllocator{
360+
PrometheusCR: OpenTelemetryTargetAllocatorPrometheusCR{
361+
// nil or empty map means select everything
362+
PodMonitorSelector: map[string]string{},
363+
ServiceMonitorSelector: map[string]string{},
364+
},
365+
},
366+
},
367+
}
368+
369+
colbeta1 := v1beta1.OpenTelemetryCollector{}
370+
err := colalpha1.ConvertTo(&colbeta1)
371+
require.NoError(t, err)
372+
373+
// nil LabelSelector means select nothing
374+
// empty LabelSelector mean select everything
375+
assert.NotNil(t, colbeta1.Spec.TargetAllocator.PrometheusCR.PodMonitorSelector)
376+
assert.NotNil(t, colbeta1.Spec.TargetAllocator.PrometheusCR.ServiceMonitorSelector)
377+
378+
err = colalpha1.ConvertFrom(&colbeta1)
379+
require.NoError(t, err)
380+
assert.Equal(t, map[string]string{}, colalpha1.Spec.TargetAllocator.PrometheusCR.PodMonitorSelector)
381+
assert.Equal(t, map[string]string{}, colalpha1.Spec.TargetAllocator.PrometheusCR.ServiceMonitorSelector)
382+
})
383+
}
384+
326385
func createTA() OpenTelemetryTargetAllocator {
327386
replicas := int32(2)
328387
runAsNonRoot := true

apis/v1beta1/targetallocator_types.go

+9-2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import (
2424
type TargetAllocatorSpec struct {
2525
// Common defines fields that are common to all OpenTelemetry CRD workloads.
2626
OpenTelemetryCommonFields `json:",inline"`
27+
// CollectorSelector is the selector for Collector Pods the target allocator will allocate targets to.
28+
CollectorSelector metav1.LabelSelector `json:"collectorSelector,omitempty"`
2729
// AllocationStrategy determines which strategy the target allocator should use for allocation.
2830
// The current options are least-weighted and consistent-hashing. The default option is consistent-hashing
2931
// +optional
@@ -35,8 +37,13 @@ type TargetAllocatorSpec struct {
3537
// +optional
3638
// +kubebuilder:default:=relabel-config
3739
FilterStrategy TargetAllocatorFilterStrategy `json:"filterStrategy,omitempty"`
38-
// ServiceAccount indicates the name of an existing service account to use with this instance. When set,
39-
// the operator will not automatically create a ServiceAccount for the TargetAllocator.
40+
// ScrapeConfigs define static Prometheus scrape configurations for the target allocator.
41+
// To use dynamic configurations from ServiceMonitors and PodMonitors, see the PrometheusCR section.
42+
// For the exact format, see https://prometheus.io/docs/prometheus/latest/configuration/configuration/#scrape_config.
43+
// +optional
44+
// +listType=atomic
45+
ScrapeConfigs []AnyConfig `json:"scrapeConfigs,omitempty"`
46+
// PrometheusCR defines the configuration for the retrieval of PrometheusOperator CRDs ( servicemonitor.monitoring.coreos.com/v1 and podmonitor.monitoring.coreos.com/v1 ).
4047
// +optional
4148
PrometheusCR TargetAllocatorPrometheusCR `json:"prometheusCR,omitempty"`
4249
}

apis/v1beta1/zz_generated.deepcopy.go

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

controllers/opentelemetrycollector_controller.go

+12-2
Original file line numberDiff line numberDiff line change
@@ -136,14 +136,24 @@ func (r *OpenTelemetryCollectorReconciler) getParams(instance v1alpha1.OpenTelem
136136
if err != nil {
137137
return manifests.Params{}, err
138138
}
139-
return manifests.Params{
139+
params := manifests.Params{
140140
Config: r.config,
141141
Client: r.Client,
142142
OtelCol: otelCol,
143143
Log: r.log,
144144
Scheme: r.scheme,
145145
Recorder: r.recorder,
146-
}, nil
146+
}
147+
148+
// generate the target allocator CR from the collector CR
149+
targetAllocator, err := collector.TargetAllocator(params)
150+
if err != nil {
151+
return params, err
152+
}
153+
if targetAllocator != nil {
154+
params.TargetAllocator = *targetAllocator
155+
}
156+
return params, nil
147157
}
148158

149159
// NewReconciler creates a new reconciler for OpenTelemetryCollector objects.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
// Copyright The OpenTelemetry Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package collector
16+
17+
import (
18+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
19+
20+
"github.com/open-telemetry/opentelemetry-operator/apis/v1beta1"
21+
"github.com/open-telemetry/opentelemetry-operator/internal/manifests"
22+
"github.com/open-telemetry/opentelemetry-operator/internal/manifests/manifestutils"
23+
"github.com/open-telemetry/opentelemetry-operator/internal/manifests/targetallocator/adapters"
24+
)
25+
26+
// TargetAllocator builds the TargetAllocator CR for the given instance.
27+
func TargetAllocator(params manifests.Params) (*v1beta1.TargetAllocator, error) {
28+
29+
taSpec := params.OtelCol.Spec.TargetAllocator
30+
if !taSpec.Enabled {
31+
return nil, nil
32+
}
33+
34+
collectorSelector := metav1.LabelSelector{
35+
MatchLabels: manifestutils.SelectorLabels(params.OtelCol.ObjectMeta, ComponentOpenTelemetryCollector),
36+
}
37+
38+
configStr, err := params.OtelCol.Spec.Config.Yaml()
39+
if err != nil {
40+
return nil, err
41+
}
42+
scrapeConfigs, err := getScrapeConfigs(configStr)
43+
if err != nil {
44+
return nil, err
45+
}
46+
47+
return &v1beta1.TargetAllocator{
48+
ObjectMeta: metav1.ObjectMeta{
49+
Name: params.OtelCol.Name,
50+
Namespace: params.OtelCol.Namespace,
51+
Annotations: params.OtelCol.Annotations,
52+
Labels: params.OtelCol.Labels,
53+
},
54+
Spec: v1beta1.TargetAllocatorSpec{
55+
OpenTelemetryCommonFields: v1beta1.OpenTelemetryCommonFields{
56+
Replicas: taSpec.Replicas,
57+
NodeSelector: taSpec.NodeSelector,
58+
Resources: taSpec.Resources,
59+
ServiceAccount: taSpec.ServiceAccount,
60+
SecurityContext: taSpec.SecurityContext,
61+
PodSecurityContext: taSpec.PodSecurityContext,
62+
Image: taSpec.Image,
63+
Affinity: taSpec.Affinity,
64+
TopologySpreadConstraints: taSpec.TopologySpreadConstraints,
65+
Tolerations: taSpec.Tolerations,
66+
Env: taSpec.Env,
67+
PodAnnotations: params.OtelCol.Spec.PodAnnotations,
68+
},
69+
CollectorSelector: collectorSelector,
70+
AllocationStrategy: taSpec.AllocationStrategy,
71+
FilterStrategy: taSpec.FilterStrategy,
72+
ScrapeConfigs: scrapeConfigs,
73+
PrometheusCR: taSpec.PrometheusCR,
74+
},
75+
}, nil
76+
}
77+
78+
func getScrapeConfigs(otelcolConfig string) ([]v1beta1.AnyConfig, error) {
79+
// Collector supports environment variable substitution, but the TA does not.
80+
// TA Scrape Configs should have a single "$", as it does not support env var substitution
81+
prometheusReceiverConfig, err := adapters.UnescapeDollarSignsInPromConfig(otelcolConfig)
82+
if err != nil {
83+
return nil, err
84+
}
85+
86+
scrapeConfigs, err := adapters.GetScrapeConfigsFromPromConfig(prometheusReceiverConfig)
87+
if err != nil {
88+
return nil, err
89+
}
90+
91+
v1beta1scrapeConfigs := make([]v1beta1.AnyConfig, len(scrapeConfigs))
92+
93+
for i, config := range scrapeConfigs {
94+
v1beta1scrapeConfigs[i] = v1beta1.AnyConfig{Object: config}
95+
}
96+
97+
return v1beta1scrapeConfigs, nil
98+
}

0 commit comments

Comments
 (0)