Skip to content

Commit 893f9f6

Browse files
committed
Generate TargetAllocator CR from Collector CR
1 parent c10fe8a commit 893f9f6

File tree

8 files changed

+390
-21
lines changed

8 files changed

+390
-21
lines changed

apis/v1alpha2/targetallocator_types.go

+51-2
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,17 @@
1717
package v1alpha2
1818

1919
import (
20+
"encoding/json"
21+
2022
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2123
)
2224

2325
// TargetAllocatorSpec defines the desired state of TargetAllocator.
2426
type TargetAllocatorSpec struct {
2527
// Common defines fields that are common to all OpenTelemetry CRD workloads.
2628
OpenTelemetryCommonFields `json:",inline"`
29+
// CollectorSelector is the selector for Collector Pods the target allocator will allocate targets to.
30+
CollectorSelector metav1.LabelSelector `json:"collectorSelector,omitempty"`
2731
// AllocationStrategy determines which strategy the target allocator should use for allocation.
2832
// The current options are least-weighted and consistent-hashing. The default option is consistent-hashing
2933
// +optional
@@ -35,8 +39,13 @@ type TargetAllocatorSpec struct {
3539
// +optional
3640
// +kubebuilder:default:=relabel-config
3741
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.
42+
// ScrapeConfigs define static Prometheus scrape configurations for the target allocator.
43+
// To use dynamic configurations from ServiceMonitors and PodMonitors, see the PrometheusCR section.
44+
// For the exact format, see https://prometheus.io/docs/prometheus/latest/configuration/configuration/#scrape_config.
45+
// +optional
46+
// +listType=atomic
47+
ScrapeConfigs []ScrapeConfig `json:"scrapeConfigs,omitempty"`
48+
// PrometheusCR defines the configuration for the retrieval of PrometheusOperator CRDs ( servicemonitor.monitoring.coreos.com/v1 and podmonitor.monitoring.coreos.com/v1 ).
4049
// +optional
4150
PrometheusCR TargetAllocatorPrometheusCR `json:"prometheusCR,omitempty"`
4251
}
@@ -82,6 +91,46 @@ type TargetAllocatorStatus struct {
8291
Messages []string `json:"messages,omitempty"`
8392
}
8493

94+
// ScrapeConfig is a Prometheus scrape config definition.
95+
type ScrapeConfig map[string]interface{}
96+
97+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
98+
func (in *ScrapeConfig) DeepCopyInto(out *ScrapeConfig) {
99+
*out = make(map[string]interface{}, len(*in))
100+
for key, val := range *in {
101+
(*out)[key] = val
102+
}
103+
}
104+
105+
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ScrapeConfig.
106+
func (in *ScrapeConfig) DeepCopy() *ScrapeConfig {
107+
if in == nil {
108+
return nil
109+
}
110+
out := new(ScrapeConfig)
111+
in.DeepCopyInto(out)
112+
return out
113+
}
114+
115+
var _ json.Marshaler = &ScrapeConfig{}
116+
var _ json.Unmarshaler = &ScrapeConfig{}
117+
118+
// UnmarshalJSON implements an alternative parser for this field.
119+
func (c *ScrapeConfig) UnmarshalJSON(b []byte) error {
120+
if err := json.Unmarshal(b, c); err != nil {
121+
return err
122+
}
123+
return nil
124+
}
125+
126+
// MarshalJSON specifies how to convert this object into JSON.
127+
func (c *ScrapeConfig) MarshalJSON() ([]byte, error) {
128+
if c == nil {
129+
return []byte("{}"), nil
130+
}
131+
return json.Marshal(c)
132+
}
133+
85134
//+kubebuilder:object:root=true
86135
//+kubebuilder:subresource:status
87136

apis/v1alpha2/zz_generated.deepcopy.go

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

config/manager/kustomization.yaml

+13
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,15 @@
11
resources:
22
- manager.yaml
3+
apiVersion: kustomize.config.k8s.io/v1beta1
4+
kind: Kustomization
5+
images:
6+
- name: controller
7+
newName: ghcr.io/open-telemetry/opentelemetry-operator/opentelemetry-operator
8+
newTag: 0.93.0-12-g4f0b94f
9+
patches:
10+
- patch: '[{"op":"add","path":"/spec/template/spec/containers/0/args/-","value":"--target-allocator-image=ghcr.io/open-telemetry/opentelemetry-operator/target-allocator:v0.93.0-12-g4f0b94f"}]'
11+
target:
12+
kind: Deployment
13+
- patch: '[{"op":"add","path":"/spec/template/spec/containers/0/args/-","value":"--operator-opamp-bridge-image=ghcr.io/open-telemetry/opentelemetry-operator/operator-opamp-bridge:v0.93.0-12-g4f0b94f"}]'
14+
target:
15+
kind: Deployment

controllers/opentelemetrycollector_controller.go

+13-2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import (
3535
"github.com/open-telemetry/opentelemetry-operator/internal/api/convert"
3636
"github.com/open-telemetry/opentelemetry-operator/internal/config"
3737
"github.com/open-telemetry/opentelemetry-operator/internal/manifests"
38+
"github.com/open-telemetry/opentelemetry-operator/internal/manifests/collector"
3839
collectorStatus "github.com/open-telemetry/opentelemetry-operator/internal/status/collector"
3940
"github.com/open-telemetry/opentelemetry-operator/pkg/featuregate"
4041
)
@@ -62,14 +63,24 @@ func (r *OpenTelemetryCollectorReconciler) getParams(instance v1alpha1.OpenTelem
6263
if err != nil {
6364
return manifests.Params{}, err
6465
}
65-
return manifests.Params{
66+
params := manifests.Params{
6667
Config: r.config,
6768
Client: r.Client,
6869
OtelCol: otelCol,
6970
Log: r.log,
7071
Scheme: r.scheme,
7172
Recorder: r.recorder,
72-
}, nil
73+
}
74+
75+
// generate the target allocator CR from the collector CR
76+
targetAllocator, err := collector.TargetAllocator(params)
77+
if err != nil {
78+
return params, err
79+
}
80+
if targetAllocator != nil {
81+
params.TargetAllocator = *targetAllocator
82+
}
83+
return params, nil
7384
}
7485

7586
// 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/v1alpha2"
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) (*v1alpha2.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 &v1alpha2.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: v1alpha2.TargetAllocatorSpec{
55+
OpenTelemetryCommonFields: v1alpha2.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) ([]v1alpha2.ScrapeConfig, 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+
v1alpha2scrapeConfigs := make([]v1alpha2.ScrapeConfig, len(scrapeConfigs))
92+
93+
for i, config := range scrapeConfigs {
94+
v1alpha2scrapeConfigs[i] = config
95+
}
96+
97+
return v1alpha2scrapeConfigs, nil
98+
}

0 commit comments

Comments
 (0)