Skip to content

Commit ed59213

Browse files
author
Israel Blancas
authored
Merge branch 'main' into 3432
2 parents 6acd9b6 + 7e6b3cf commit ed59213

File tree

16 files changed

+461
-36
lines changed

16 files changed

+461
-36
lines changed

.chloggen/3429.yaml

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
2+
change_type: enhancement
3+
4+
# The name of the component, or a single word describing the area of concern, (e.g. collector, target allocator, auto-instrumentation, opamp, github action)
5+
component: collector
6+
7+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
8+
note: Create RBAC rules for the k8sobjects receiver automatically.
9+
10+
# One or more tracking issues related to the change
11+
issues: [3429]
12+
13+
# (Optional) One or more lines of additional information to render under the primary note.
14+
# These lines will be padded with 2 spaces and then inserted directly into the document.
15+
# Use pipe (|) for multiline entries.
16+
subtext:

.chloggen/3446.yaml

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
2+
change_type: 'bug_fix'
3+
4+
# The name of the component, or a single word describing the area of concern, (e.g. collector, target allocator, auto-instrumentation, opamp, github action)
5+
component: operator
6+
7+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
8+
note: Operator pod crashed if the Service Monitor for the operator metrics was created before by another operator pod.
9+
10+
# One or more tracking issues related to the change
11+
issues: [3446]
12+
13+
# (Optional) One or more lines of additional information to render under the primary note.
14+
# These lines will be padded with 2 spaces and then inserted directly into the document.
15+
# Use pipe (|) for multiline entries.
16+
subtext: |
17+
Operator fails when the pod is restarted and the Service Monitor for operator metrics was already created by another operator pod.
18+
To fix this, the operator now sets the owner reference on the Service Monitor to itself and checks if the Service Monitor already exists.
19+

autoinstrumentation/java/version.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2.9.0
1+
2.10.0

internal/components/receivers/helpers.go

+3
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,9 @@ var (
143143
components.NewBuilder[k8seventsConfig]().WithName("k8s_events").
144144
WithRbacGen(generatek8seventsRbacRules).
145145
MustBuild(),
146+
components.NewBuilder[k8sobjectsConfig]().WithName("k8sobjects").
147+
WithRbacGen(generatek8sobjectsRbacRules).
148+
MustBuild(),
146149
NewScraperParser("prometheus"),
147150
NewScraperParser("sshcheck"),
148151
NewScraperParser("cloudfoundry"),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
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 receivers
16+
17+
import (
18+
"github.com/go-logr/logr"
19+
rbacv1 "k8s.io/api/rbac/v1"
20+
)
21+
22+
type k8sobjectsConfig struct {
23+
Objects []k8sObject `yaml:"objects"`
24+
}
25+
26+
type k8sObject struct {
27+
Name string `yaml:"name"`
28+
Mode string `yaml:"mode"`
29+
Group string `yaml:"group,omitempty"`
30+
}
31+
32+
func generatek8sobjectsRbacRules(_ logr.Logger, config k8sobjectsConfig) ([]rbacv1.PolicyRule, error) {
33+
// https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/k8sobjectsreceiver#rbac
34+
prs := []rbacv1.PolicyRule{}
35+
for _, obj := range config.Objects {
36+
permissions := []string{"list"}
37+
if obj.Mode == "pull" && (obj.Name != "events" && obj.Name != "events.k8s.io") {
38+
permissions = append(permissions, "get")
39+
} else if obj.Mode == "watch" {
40+
permissions = append(permissions, "watch")
41+
}
42+
prs = append(prs, rbacv1.PolicyRule{
43+
APIGroups: []string{obj.Group},
44+
Resources: []string{obj.Name},
45+
Verbs: permissions,
46+
})
47+
}
48+
return prs, nil
49+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
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 receivers
16+
17+
import (
18+
"testing"
19+
20+
"github.com/go-logr/logr"
21+
"github.com/stretchr/testify/assert"
22+
rbacv1 "k8s.io/api/rbac/v1"
23+
)
24+
25+
func Test_generatek8sobjectsRbacRules(t *testing.T) {
26+
tests := []struct {
27+
name string
28+
config k8sobjectsConfig
29+
want []rbacv1.PolicyRule
30+
}{
31+
{
32+
name: "basic watch mode",
33+
config: k8sobjectsConfig{
34+
Objects: []k8sObject{
35+
{
36+
Name: "pods",
37+
Mode: "watch",
38+
Group: "v1",
39+
},
40+
},
41+
},
42+
want: []rbacv1.PolicyRule{
43+
{
44+
APIGroups: []string{"v1"},
45+
Resources: []string{"pods"},
46+
Verbs: []string{"list", "watch"},
47+
},
48+
},
49+
},
50+
{
51+
name: "pull mode with events",
52+
config: k8sobjectsConfig{
53+
Objects: []k8sObject{
54+
{
55+
Name: "events",
56+
Mode: "pull",
57+
Group: "v1",
58+
},
59+
},
60+
},
61+
want: []rbacv1.PolicyRule{
62+
{
63+
APIGroups: []string{"v1"},
64+
Resources: []string{"events"},
65+
Verbs: []string{"list"},
66+
},
67+
},
68+
},
69+
{
70+
name: "pull mode with non-events",
71+
config: k8sobjectsConfig{
72+
Objects: []k8sObject{
73+
{
74+
Name: "pods",
75+
Mode: "pull",
76+
Group: "v1",
77+
},
78+
},
79+
},
80+
want: []rbacv1.PolicyRule{
81+
{
82+
APIGroups: []string{"v1"},
83+
Resources: []string{"pods"},
84+
Verbs: []string{"list", "get"},
85+
},
86+
},
87+
},
88+
{
89+
name: "multiple objects",
90+
config: k8sobjectsConfig{
91+
Objects: []k8sObject{
92+
{
93+
Name: "pods",
94+
Mode: "pull",
95+
Group: "v1",
96+
},
97+
{
98+
Name: "events",
99+
Mode: "pull",
100+
Group: "v1",
101+
},
102+
{
103+
Name: "deployments",
104+
Mode: "watch",
105+
Group: "apps/v1",
106+
},
107+
},
108+
},
109+
want: []rbacv1.PolicyRule{
110+
{
111+
APIGroups: []string{"v1"},
112+
Resources: []string{"pods"},
113+
Verbs: []string{"list", "get"},
114+
},
115+
{
116+
APIGroups: []string{"v1"},
117+
Resources: []string{"events"},
118+
Verbs: []string{"list"},
119+
},
120+
{
121+
APIGroups: []string{"apps/v1"},
122+
Resources: []string{"deployments"},
123+
Verbs: []string{"list", "watch"},
124+
},
125+
},
126+
},
127+
}
128+
129+
for _, tt := range tests {
130+
t.Run(tt.name, func(t *testing.T) {
131+
got, err := generatek8sobjectsRbacRules(logr.Logger{}, tt.config)
132+
assert.NoError(t, err)
133+
assert.Equal(t, tt.want, got)
134+
})
135+
}
136+
}

internal/operator-metrics/metrics.go

+67-15
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,11 @@ import (
1919
"fmt"
2020
"os"
2121

22+
"github.com/go-logr/logr"
2223
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
24+
appsv1 "k8s.io/api/apps/v1"
2325
corev1 "k8s.io/api/core/v1"
26+
apierrors "k8s.io/apimachinery/pkg/api/errors"
2427
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2528
"k8s.io/apimachinery/pkg/runtime"
2629
"k8s.io/apimachinery/pkg/util/intstr"
@@ -51,26 +54,85 @@ var _ manager.Runnable = &OperatorMetrics{}
5154

5255
type OperatorMetrics struct {
5356
kubeClient client.Client
57+
log logr.Logger
5458
}
5559

56-
func NewOperatorMetrics(config *rest.Config, scheme *runtime.Scheme) (OperatorMetrics, error) {
60+
func NewOperatorMetrics(config *rest.Config, scheme *runtime.Scheme, log logr.Logger) (OperatorMetrics, error) {
5761
kubeClient, err := client.New(config, client.Options{Scheme: scheme})
5862
if err != nil {
5963
return OperatorMetrics{}, err
6064
}
6165

6266
return OperatorMetrics{
6367
kubeClient: kubeClient,
68+
log: log,
6469
}, nil
6570
}
6671

6772
func (om OperatorMetrics) Start(ctx context.Context) error {
73+
err := om.createOperatorMetricsServiceMonitor(ctx)
74+
if err != nil {
75+
om.log.Error(err, "error creating Service Monitor for operator metrics")
76+
}
77+
78+
return nil
79+
}
80+
81+
func (om OperatorMetrics) NeedLeaderElection() bool {
82+
return true
83+
}
84+
85+
func (om OperatorMetrics) caConfigMapExists() bool {
86+
return om.kubeClient.Get(context.Background(), client.ObjectKey{
87+
Name: caBundleConfigMap,
88+
Namespace: openshiftInClusterMonitoringNamespace,
89+
}, &corev1.ConfigMap{},
90+
) == nil
91+
}
92+
93+
func (om OperatorMetrics) getOwnerReferences(ctx context.Context, namespace string) (metav1.OwnerReference, error) {
94+
var deploymentList appsv1.DeploymentList
95+
96+
listOptions := []client.ListOption{
97+
client.InNamespace(namespace),
98+
client.MatchingLabels(map[string]string{
99+
"app.kubernetes.io/name": "opentelemetry-operator",
100+
"control-plane": "controller-manager",
101+
}),
102+
}
103+
104+
err := om.kubeClient.List(ctx, &deploymentList, listOptions...)
105+
if err != nil {
106+
return metav1.OwnerReference{}, err
107+
}
108+
109+
if len(deploymentList.Items) == 0 {
110+
return metav1.OwnerReference{}, fmt.Errorf("no deployments found with the specified label")
111+
}
112+
deployment := &deploymentList.Items[0]
113+
114+
ownerRef := metav1.OwnerReference{
115+
APIVersion: "apps/v1",
116+
Kind: "Deployment",
117+
Name: deployment.Name,
118+
UID: deployment.UID,
119+
}
120+
121+
return ownerRef, nil
122+
}
123+
124+
func (om OperatorMetrics) createOperatorMetricsServiceMonitor(ctx context.Context) error {
68125
rawNamespace, err := os.ReadFile(namespaceFile)
69126
if err != nil {
70127
return fmt.Errorf("error reading namespace file: %w", err)
71128
}
72129
namespace := string(rawNamespace)
73130

131+
ownerRef, err := om.getOwnerReferences(ctx, namespace)
132+
if err != nil {
133+
return fmt.Errorf("error getting owner references: %w", err)
134+
}
135+
74136
var tlsConfig *monitoringv1.TLSConfig
75137

76138
if om.caConfigMapExists() {
@@ -101,6 +163,7 @@ func (om OperatorMetrics) Start(ctx context.Context) error {
101163
"app.kubernetes.io/part-of": "opentelemetry-operator",
102164
"control-plane": "controller-manager",
103165
},
166+
OwnerReferences: []metav1.OwnerReference{ownerRef},
104167
},
105168
Spec: monitoringv1.ServiceMonitorSpec{
106169
Selector: metav1.LabelSelector{
@@ -123,23 +186,12 @@ func (om OperatorMetrics) Start(ctx context.Context) error {
123186
}
124187

125188
err = om.kubeClient.Create(ctx, &sm)
126-
if err != nil {
127-
return fmt.Errorf("error creating service monitor: %w", err)
189+
// The ServiceMonitor can be already there if this is a restart
190+
if err != nil && !apierrors.IsAlreadyExists(err) {
191+
return err
128192
}
129193

130194
<-ctx.Done()
131195

132196
return om.kubeClient.Delete(ctx, &sm)
133197
}
134-
135-
func (om OperatorMetrics) NeedLeaderElection() bool {
136-
return true
137-
}
138-
139-
func (om OperatorMetrics) caConfigMapExists() bool {
140-
return om.kubeClient.Get(context.Background(), client.ObjectKey{
141-
Name: caBundleConfigMap,
142-
Namespace: openshiftInClusterMonitoringNamespace,
143-
}, &corev1.ConfigMap{},
144-
) == nil
145-
}

0 commit comments

Comments
 (0)