Skip to content

Commit 21c394e

Browse files
authored
chore: extract otelBaseController (#1565)
1 parent edf340b commit 21c394e

File tree

5 files changed

+87
-62
lines changed

5 files changed

+87
-62
lines changed

cmd/reconciler-manager/main.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -165,16 +165,15 @@ func main() {
165165

166166
otel := controllers.NewOtelReconciler(mgr.GetClient(),
167167
textlogger.NewLogger(textlogger.NewConfig()).WithName("controllers").WithName("Otel"),
168-
mgr.GetScheme(), otelCredentialProvider)
168+
otelCredentialProvider)
169169
if err := otel.Register(mgr); err != nil {
170170
setupLog.Error(err, "failed to register controller", "controller", "Otel")
171171
os.Exit(1)
172172
}
173173
setupLog.Info("Otel controller registration successful")
174174

175175
otelSA := controllers.NewOtelSAReconciler(*clusterName, mgr.GetClient(),
176-
textlogger.NewLogger(textlogger.NewConfig()).WithName("controllers").WithName(controllers.OtelSALoggerName),
177-
mgr.GetScheme())
176+
textlogger.NewLogger(textlogger.NewConfig()).WithName("controllers").WithName(controllers.OtelSALoggerName))
178177
if err := otelSA.Register(mgr); err != nil {
179178
setupLog.Error(err, "failed to register controller", "controller", "OtelSA")
180179
os.Exit(1)
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Copyright 2025 Google LLC
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 controllers
16+
17+
import (
18+
"context"
19+
20+
appsv1 "k8s.io/api/apps/v1"
21+
"k8s.io/apimachinery/pkg/api/equality"
22+
"kpt.dev/configsync/pkg/api/configsync"
23+
"kpt.dev/configsync/pkg/core"
24+
"kpt.dev/configsync/pkg/status"
25+
"sigs.k8s.io/controller-runtime/pkg/client"
26+
)
27+
28+
// otelBaseController implements common functionality for otel controllers.
29+
type otelBaseController struct {
30+
loggingController
31+
32+
client client.Client
33+
}
34+
35+
// updateDeploymentAnnotation updates the otel deployment's spec.template.annotation.
36+
// This triggers the deployment to restart in the event of an annotation update.
37+
func (r *otelBaseController) updateDeploymentAnnotation(ctx context.Context, annotationKey, annotationValue string) error {
38+
key := otelCollectorDeploymentRef()
39+
dep := &appsv1.Deployment{}
40+
dep.Name = key.Name
41+
dep.Namespace = key.Namespace
42+
43+
if err := r.client.Get(ctx, key, dep); err != nil {
44+
return status.APIServerErrorf(err, "failed to get Deployment: %s", key)
45+
}
46+
47+
existing := dep.DeepCopy()
48+
core.SetAnnotation(&dep.Spec.Template, annotationKey, annotationValue)
49+
50+
// Avoid unnecessary API writes, if possible.
51+
if equality.Semantic.DeepEqual(existing, dep) {
52+
return nil
53+
}
54+
55+
r.logger(ctx).V(3).Info("Patching object",
56+
logFieldObjectRef, key.String(),
57+
logFieldObjectKind, "Deployment",
58+
annotationKey, annotationValue)
59+
patch := client.MergeFrom(existing)
60+
err := r.client.Patch(ctx, dep, patch, client.FieldOwner(configsync.FieldManager))
61+
if err != nil {
62+
return status.APIServerErrorf(err, "failed to patch Deployment: %s", key)
63+
}
64+
r.logger(ctx).Info("Patching object successful",
65+
logFieldObjectRef, key.String(),
66+
logFieldObjectKind, "Deployment",
67+
annotationKey, annotationValue)
68+
return nil
69+
}

pkg/reconcilermanager/controllers/otel_controller.go

Lines changed: 8 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,10 @@ import (
1919
"fmt"
2020

2121
"github.com/go-logr/logr"
22-
appsv1 "k8s.io/api/apps/v1"
2322
corev1 "k8s.io/api/core/v1"
24-
"k8s.io/apimachinery/pkg/api/equality"
2523
apierrors "k8s.io/apimachinery/pkg/api/errors"
26-
"k8s.io/apimachinery/pkg/runtime"
2724
"kpt.dev/configsync/pkg/api/configmanagement"
28-
"kpt.dev/configsync/pkg/api/configsync"
2925
"kpt.dev/configsync/pkg/auth"
30-
"kpt.dev/configsync/pkg/core"
3126
"kpt.dev/configsync/pkg/metadata"
3227
"kpt.dev/configsync/pkg/metrics"
3328
"kpt.dev/configsync/pkg/status"
@@ -44,21 +39,20 @@ var _ reconcile.Reconciler = &OtelReconciler{}
4439

4540
// OtelReconciler reconciles OpenTelemetry ConfigMaps.
4641
type OtelReconciler struct {
47-
loggingController
42+
otelBaseController
4843

49-
client client.Client
50-
scheme *runtime.Scheme
5144
credentialProvider auth.CredentialProvider
5245
}
5346

5447
// NewOtelReconciler returns a new OtelReconciler.
55-
func NewOtelReconciler(client client.Client, log logr.Logger, scheme *runtime.Scheme, credentialProvider auth.CredentialProvider) *OtelReconciler {
48+
func NewOtelReconciler(client client.Client, log logr.Logger, credentialProvider auth.CredentialProvider) *OtelReconciler {
5649
return &OtelReconciler{
57-
loggingController: loggingController{
58-
log: log,
50+
otelBaseController: otelBaseController{
51+
loggingController: loggingController{
52+
log: log,
53+
},
54+
client: client,
5955
},
60-
client: client,
61-
scheme: scheme,
6256
credentialProvider: credentialProvider,
6357
}
6458
}
@@ -79,17 +73,12 @@ func (r *OtelReconciler) Reconcile(ctx context.Context, req reconcile.Request) (
7973
return controllerruntime.Result{}, nil
8074
}
8175
base16Hash := fmt.Sprintf("%x", configMapDataHash)
82-
err = updateDeploymentAnnotation(ctx, r.client, metadata.ConfigMapAnnotationKey, base16Hash)
83-
if err != nil {
76+
if err := r.updateDeploymentAnnotation(ctx, metadata.ConfigMapAnnotationKey, base16Hash); err != nil {
8477
r.logger(ctx).Error(err, "Failed to update Deployment",
8578
logFieldObjectRef, otelCollectorDeploymentRef(),
8679
logFieldObjectKind, "Deployment")
8780
return controllerruntime.Result{}, err
8881
}
89-
r.logger(ctx).Info("Deployment annotation patch successful",
90-
logFieldObjectRef, otelCollectorDeploymentRef(),
91-
logFieldObjectKind, "Deployment",
92-
metadata.ConfigMapAnnotationKey, base16Hash)
9382
return controllerruntime.Result{}, nil
9483
}
9584

@@ -172,30 +161,6 @@ func (r *OtelReconciler) configureGooglecloudConfigMap(ctx context.Context) ([]b
172161
return nil, nil
173162
}
174163

175-
// updateDeploymentAnnotation updates the otel deployment's spec.template.annotation.
176-
// This triggers the deployment to restart in the event of an annotation update.
177-
func updateDeploymentAnnotation(ctx context.Context, c client.Client, annotationKey, annotationValue string) error {
178-
key := otelCollectorDeploymentRef()
179-
dep := &appsv1.Deployment{}
180-
dep.Name = key.Name
181-
dep.Namespace = key.Namespace
182-
183-
if err := c.Get(ctx, key, dep); err != nil {
184-
return status.APIServerError(err, "failed to get otel Deployment")
185-
}
186-
187-
existing := dep.DeepCopy()
188-
patch := client.MergeFrom(existing)
189-
190-
core.SetAnnotation(&dep.Spec.Template, annotationKey, annotationValue)
191-
192-
if equality.Semantic.DeepEqual(existing, dep) {
193-
return nil
194-
}
195-
196-
return c.Patch(ctx, dep, patch, client.FieldOwner(configsync.FieldManager))
197-
}
198-
199164
// Register otel controller with reconciler-manager.
200165
func (r *OtelReconciler) Register(mgr controllerruntime.Manager) error {
201166
// Process create / update events for resources in the `config-management-monitoring` namespace.

pkg/reconcilermanager/controllers/otel_controller_test.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,6 @@ func setupOtelReconciler(t *testing.T, credentialprovider auth.CredentialProvide
6767
testReconciler := NewOtelReconciler(
6868
fakeClient,
6969
controllerruntime.Log.WithName("controllers").WithName("Otel"),
70-
fakeClient.Scheme(),
7170
credentialprovider,
7271
)
7372
return fakeClient, testReconciler
@@ -302,7 +301,6 @@ func setupOtelSAReconciler(t *testing.T, objs ...client.Object) (*syncerFake.Cli
302301
testReconciler := NewOtelSAReconciler("",
303302
fakeClient,
304303
controllerruntime.Log.WithName("controllers").WithName(OtelSALoggerName),
305-
fakeClient.Scheme(),
306304
)
307305
return fakeClient, testReconciler
308306
}

pkg/reconcilermanager/controllers/otel_sa_controller.go

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import (
2020
"github.com/go-logr/logr"
2121
corev1 "k8s.io/api/core/v1"
2222
apierrors "k8s.io/apimachinery/pkg/api/errors"
23-
"k8s.io/apimachinery/pkg/runtime"
2423
"kpt.dev/configsync/pkg/api/configmanagement"
2524
"kpt.dev/configsync/pkg/status"
2625
controllerruntime "sigs.k8s.io/controller-runtime"
@@ -41,25 +40,24 @@ const (
4140

4241
// OtelSAReconciler reconciles the default service account under the config-management-monitoring namespace.
4342
type OtelSAReconciler struct {
44-
loggingController
43+
otelBaseController
4544

4645
clusterName string
47-
client client.Client
48-
scheme *runtime.Scheme
4946
}
5047

5148
// NewOtelSAReconciler returns a new OtelSAReconciler.
52-
func NewOtelSAReconciler(clusterName string, client client.Client, log logr.Logger, scheme *runtime.Scheme) *OtelSAReconciler {
49+
func NewOtelSAReconciler(clusterName string, client client.Client, log logr.Logger) *OtelSAReconciler {
5350
if clusterName == "" {
5451
clusterName = "unknown_cluster"
5552
}
5653
return &OtelSAReconciler{
57-
loggingController: loggingController{
58-
log: log,
54+
otelBaseController: otelBaseController{
55+
loggingController: loggingController{
56+
log: log,
57+
},
58+
client: client,
5959
},
6060
clusterName: clusterName,
61-
client: client,
62-
scheme: scheme,
6361
}
6462
}
6563

@@ -88,16 +86,12 @@ func (r *OtelSAReconciler) Reconcile(ctx context.Context, req reconcile.Request)
8886
// and Cloud Monarch on a GKE cluster with Workload Identity eanbled.
8987
// On a cluster without Workload Identity, the annotation does not have any effects.
9088
// Therefore, we don't check whether the cluster has Workload Identity enabled before updating the Deployment annotation.
91-
if err := updateDeploymentAnnotation(ctx, r.client, GCPSAAnnotationKey, v); err != nil {
89+
if err := r.updateDeploymentAnnotation(ctx, GCPSAAnnotationKey, v); err != nil {
9290
r.logger(ctx).Error(err, "Failed to update Deployment",
9391
logFieldObjectRef, otelCollectorDeploymentRef(),
9492
logFieldObjectKind, "Deployment")
9593
return controllerruntime.Result{}, err
9694
}
97-
r.logger(ctx).Info("Deployment annotation patch successful",
98-
logFieldObjectRef, otelCollectorDeploymentRef(),
99-
logFieldObjectKind, "Deployment",
100-
GCPSAAnnotationKey, v)
10195
return controllerruntime.Result{}, nil
10296
}
10397

0 commit comments

Comments
 (0)