Skip to content

Commit 73db075

Browse files
author
Jan Fajerski
committed
chore: migrate to controller-runtime client.Apply over client.Patch
Signed-off-by: Jan Fajerski <jan@fajerski.name>
1 parent ce88b7d commit 73db075

2 files changed

Lines changed: 47 additions & 24 deletions

File tree

pkg/controllers/observability/reconcilers_test.go

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,7 @@ func TestGetReconcilers(t *testing.T) {
3737
mockClient: func() *MockClient {
3838
mockClient := &MockClient{}
3939
mockClient.On("Get", context.Background(), mock.Anything, mock.IsType(&olmv1alpha1.Subscription{}), mock.Anything).Return(nil)
40-
mockClient.On("Patch", context.Background(), mock.IsType(&corev1.Namespace{}), mock.Anything, mock.Anything).Return(nil)
41-
mockClient.On("Patch", context.Background(), mock.IsType(&otelv1beta1.OpenTelemetryCollector{}), mock.Anything, mock.Anything).Return(nil)
42-
mockClient.On("Patch", context.Background(), mock.IsType(&rbacv1.ClusterRole{}), mock.Anything, mock.Anything).Return(nil)
43-
mockClient.On("Patch", context.Background(), mock.IsType(&rbacv1.ClusterRoleBinding{}), mock.Anything, mock.Anything).Return(nil)
44-
mockClient.On("Patch", context.Background(), mock.IsType(&tempov1alpha1.TempoStack{}), mock.Anything, mock.Anything).Return(nil)
45-
mockClient.On("Patch", context.Background(), mock.IsType(&corev1.Secret{}), mock.Anything, mock.Anything).Return(nil)
46-
mockClient.On("Patch", context.Background(), mock.IsType(&uiv1alpha1.UIPlugin{}), mock.Anything, mock.Anything).Return(nil)
40+
mockClient.On("Apply", context.Background(), mock.Anything, mock.Anything).Return(nil)
4741
return mockClient
4842
},
4943
instance: &obsv1alpha1.ObservabilityInstaller{
@@ -70,14 +64,7 @@ func TestGetReconcilers(t *testing.T) {
7064
mockClient.On("Get", context.Background(), mock.Anything, mock.IsType(&olmv1alpha1.Subscription{}), mock.Anything).Return(nil)
7165
mockClient.On("Get", context.Background(), mock.Anything, mock.IsType(&corev1.Secret{}), mock.Anything).Return(nil)
7266
mockClient.On("Get", context.Background(), mock.Anything, mock.IsType(&corev1.ConfigMap{}), mock.Anything).Return(nil)
73-
mockClient.On("Patch", context.Background(), mock.IsType(&corev1.Namespace{}), mock.Anything, mock.Anything).Return(nil)
74-
mockClient.On("Patch", context.Background(), mock.IsType(&otelv1beta1.OpenTelemetryCollector{}), mock.Anything, mock.Anything).Return(nil)
75-
mockClient.On("Patch", context.Background(), mock.IsType(&rbacv1.ClusterRole{}), mock.Anything, mock.Anything).Return(nil)
76-
mockClient.On("Patch", context.Background(), mock.IsType(&rbacv1.ClusterRoleBinding{}), mock.Anything, mock.Anything).Return(nil)
77-
mockClient.On("Patch", context.Background(), mock.IsType(&tempov1alpha1.TempoStack{}), mock.Anything, mock.Anything).Return(nil)
78-
mockClient.On("Patch", context.Background(), mock.IsType(&corev1.Secret{}), mock.Anything, mock.Anything).Return(nil)
79-
mockClient.On("Patch", context.Background(), mock.IsType(&corev1.ConfigMap{}), mock.Anything, mock.Anything).Return(nil)
80-
mockClient.On("Patch", context.Background(), mock.IsType(&uiv1alpha1.UIPlugin{}), mock.Anything, mock.Anything).Return(nil)
67+
mockClient.On("Apply", context.Background(), mock.Anything, mock.Anything).Return(nil)
8168
return mockClient
8269
},
8370
instance: &obsv1alpha1.ObservabilityInstaller{
@@ -184,13 +171,7 @@ func TestGetReconcilers(t *testing.T) {
184171
name: "tracing capability enabled, subscription already installed",
185172
mockClient: func() *MockClient {
186173
mockClient := &MockClient{}
187-
mockClient.On("Patch", context.Background(), mock.IsType(&corev1.Namespace{}), mock.Anything, mock.Anything).Return(nil)
188-
mockClient.On("Patch", context.Background(), mock.IsType(&otelv1beta1.OpenTelemetryCollector{}), mock.Anything, mock.Anything).Return(nil)
189-
mockClient.On("Patch", context.Background(), mock.IsType(&rbacv1.ClusterRole{}), mock.Anything, mock.Anything).Return(nil)
190-
mockClient.On("Patch", context.Background(), mock.IsType(&rbacv1.ClusterRoleBinding{}), mock.Anything, mock.Anything).Return(nil)
191-
mockClient.On("Patch", context.Background(), mock.IsType(&tempov1alpha1.TempoStack{}), mock.Anything, mock.Anything).Return(nil)
192-
mockClient.On("Patch", context.Background(), mock.IsType(&corev1.Secret{}), mock.Anything, mock.Anything).Return(nil)
193-
mockClient.On("Patch", context.Background(), mock.IsType(&uiv1alpha1.UIPlugin{}), mock.Anything, mock.Anything).Return(nil)
174+
mockClient.On("Apply", context.Background(), mock.Anything, mock.Anything).Return(nil)
194175
return mockClient
195176
},
196177
instance: &obsv1alpha1.ObservabilityInstaller{

pkg/reconciler/reconciler.go

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package reconciler
22

33
import (
44
"context"
5+
"encoding/json"
56
"fmt"
67

78
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -48,8 +49,8 @@ func (r Updater) Reconcile(ctx context.Context, c client.Client, scheme *runtime
4849
}
4950
}
5051

51-
if err := c.Patch(ctx, r.resource, client.Apply, client.ForceOwnership, client.FieldOwner("observability-operator")); err != nil {
52-
return fmt.Errorf("%s/%s (%s): updater failed to patch: %w",
52+
if err := c.Apply(ctx, &clientObjectApplyConfig{obj: r.resource}, client.ForceOwnership, client.FieldOwner("observability-operator")); err != nil {
53+
return fmt.Errorf("%s/%s (%s): updater failed to apply: %w",
5354
r.resource.GetNamespace(), r.resource.GetName(),
5455
r.resource.GetObjectKind().GroupVersionKind().String(), err)
5556
}
@@ -123,3 +124,44 @@ func NewOptionalUnmanagedUpdater(r client.Object, c metav1.Object, cond bool) Re
123124
}
124125
return NewDeleter(r)
125126
}
127+
128+
// clientObjectApplyConfig wraps a client.Object so it satisfies runtime.ApplyConfiguration,
129+
// allowing Updater to use client.Client.Apply() instead of the deprecated
130+
// client.Client.Patch(..., client.Apply, ...) path.
131+
//
132+
// The object is held as a plain field (not embedded) so the wrapper does NOT
133+
// satisfy runtime.Object. Without this, the typed client's type-switch would
134+
// hit the runtime.Object branch and try to look up *clientObjectApplyConfig
135+
// in the scheme, causing "no kind is registered" errors at runtime.
136+
//
137+
// Serialisation is identical to the old applyPatch path: apply.NewRequest
138+
// calls json.Marshal on this wrapper, which delegates to the underlying object.
139+
type clientObjectApplyConfig struct {
140+
obj client.Object
141+
}
142+
143+
func (a *clientObjectApplyConfig) IsApplyConfiguration() {}
144+
145+
func (a *clientObjectApplyConfig) GetName() *string {
146+
n := a.obj.GetName()
147+
return &n
148+
}
149+
150+
func (a *clientObjectApplyConfig) GetNamespace() *string {
151+
ns := a.obj.GetNamespace()
152+
return &ns
153+
}
154+
155+
func (a *clientObjectApplyConfig) GetKind() *string {
156+
k := a.obj.GetObjectKind().GroupVersionKind().Kind
157+
return &k
158+
}
159+
160+
func (a *clientObjectApplyConfig) GetAPIVersion() *string {
161+
av := a.obj.GetObjectKind().GroupVersionKind().GroupVersion().String()
162+
return &av
163+
}
164+
165+
func (a *clientObjectApplyConfig) MarshalJSON() ([]byte, error) {
166+
return json.Marshal(a.obj)
167+
}

0 commit comments

Comments
 (0)