Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 3 additions & 22 deletions pkg/controllers/observability/reconcilers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,7 @@ func TestGetReconcilers(t *testing.T) {
mockClient: func() *MockClient {
mockClient := &MockClient{}
mockClient.On("Get", context.Background(), mock.Anything, mock.IsType(&olmv1alpha1.Subscription{}), mock.Anything).Return(nil)
mockClient.On("Patch", context.Background(), mock.IsType(&corev1.Namespace{}), mock.Anything, mock.Anything).Return(nil)
mockClient.On("Patch", context.Background(), mock.IsType(&otelv1beta1.OpenTelemetryCollector{}), mock.Anything, mock.Anything).Return(nil)
mockClient.On("Patch", context.Background(), mock.IsType(&rbacv1.ClusterRole{}), mock.Anything, mock.Anything).Return(nil)
mockClient.On("Patch", context.Background(), mock.IsType(&rbacv1.ClusterRoleBinding{}), mock.Anything, mock.Anything).Return(nil)
mockClient.On("Patch", context.Background(), mock.IsType(&tempov1alpha1.TempoStack{}), mock.Anything, mock.Anything).Return(nil)
mockClient.On("Patch", context.Background(), mock.IsType(&corev1.Secret{}), mock.Anything, mock.Anything).Return(nil)
mockClient.On("Patch", context.Background(), mock.IsType(&uiv1alpha1.UIPlugin{}), mock.Anything, mock.Anything).Return(nil)
mockClient.On("Apply", context.Background(), mock.Anything, mock.Anything).Return(nil)
return mockClient
},
instance: &obsv1alpha1.ObservabilityInstaller{
Expand All @@ -70,14 +64,7 @@ func TestGetReconcilers(t *testing.T) {
mockClient.On("Get", context.Background(), mock.Anything, mock.IsType(&olmv1alpha1.Subscription{}), mock.Anything).Return(nil)
mockClient.On("Get", context.Background(), mock.Anything, mock.IsType(&corev1.Secret{}), mock.Anything).Return(nil)
mockClient.On("Get", context.Background(), mock.Anything, mock.IsType(&corev1.ConfigMap{}), mock.Anything).Return(nil)
mockClient.On("Patch", context.Background(), mock.IsType(&corev1.Namespace{}), mock.Anything, mock.Anything).Return(nil)
mockClient.On("Patch", context.Background(), mock.IsType(&otelv1beta1.OpenTelemetryCollector{}), mock.Anything, mock.Anything).Return(nil)
mockClient.On("Patch", context.Background(), mock.IsType(&rbacv1.ClusterRole{}), mock.Anything, mock.Anything).Return(nil)
mockClient.On("Patch", context.Background(), mock.IsType(&rbacv1.ClusterRoleBinding{}), mock.Anything, mock.Anything).Return(nil)
mockClient.On("Patch", context.Background(), mock.IsType(&tempov1alpha1.TempoStack{}), mock.Anything, mock.Anything).Return(nil)
mockClient.On("Patch", context.Background(), mock.IsType(&corev1.Secret{}), mock.Anything, mock.Anything).Return(nil)
mockClient.On("Patch", context.Background(), mock.IsType(&corev1.ConfigMap{}), mock.Anything, mock.Anything).Return(nil)
mockClient.On("Patch", context.Background(), mock.IsType(&uiv1alpha1.UIPlugin{}), mock.Anything, mock.Anything).Return(nil)
mockClient.On("Apply", context.Background(), mock.Anything, mock.Anything).Return(nil)
return mockClient
},
instance: &obsv1alpha1.ObservabilityInstaller{
Expand Down Expand Up @@ -184,13 +171,7 @@ func TestGetReconcilers(t *testing.T) {
name: "tracing capability enabled, subscription already installed",
mockClient: func() *MockClient {
mockClient := &MockClient{}
mockClient.On("Patch", context.Background(), mock.IsType(&corev1.Namespace{}), mock.Anything, mock.Anything).Return(nil)
mockClient.On("Patch", context.Background(), mock.IsType(&otelv1beta1.OpenTelemetryCollector{}), mock.Anything, mock.Anything).Return(nil)
mockClient.On("Patch", context.Background(), mock.IsType(&rbacv1.ClusterRole{}), mock.Anything, mock.Anything).Return(nil)
mockClient.On("Patch", context.Background(), mock.IsType(&rbacv1.ClusterRoleBinding{}), mock.Anything, mock.Anything).Return(nil)
mockClient.On("Patch", context.Background(), mock.IsType(&tempov1alpha1.TempoStack{}), mock.Anything, mock.Anything).Return(nil)
mockClient.On("Patch", context.Background(), mock.IsType(&corev1.Secret{}), mock.Anything, mock.Anything).Return(nil)
mockClient.On("Patch", context.Background(), mock.IsType(&uiv1alpha1.UIPlugin{}), mock.Anything, mock.Anything).Return(nil)
mockClient.On("Apply", context.Background(), mock.Anything, mock.Anything).Return(nil)
return mockClient
},
instance: &obsv1alpha1.ObservabilityInstaller{
Expand Down
46 changes: 44 additions & 2 deletions pkg/reconciler/reconciler.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package reconciler

import (
"context"
"encoding/json"
"fmt"

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

if err := c.Patch(ctx, r.resource, client.Apply, client.ForceOwnership, client.FieldOwner("observability-operator")); err != nil {
return fmt.Errorf("%s/%s (%s): updater failed to patch: %w",
if err := c.Apply(ctx, &clientObjectApplyConfig{obj: r.resource}, client.ForceOwnership, client.FieldOwner("observability-operator")); err != nil {
return fmt.Errorf("%s/%s (%s): updater failed to apply: %w",
r.resource.GetNamespace(), r.resource.GetName(),
r.resource.GetObjectKind().GroupVersionKind().String(), err)
}
Expand Down Expand Up @@ -123,3 +124,44 @@ func NewOptionalUnmanagedUpdater(r client.Object, c metav1.Object, cond bool) Re
}
return NewDeleter(r)
}

// clientObjectApplyConfig wraps a client.Object so it satisfies runtime.ApplyConfiguration,
// allowing Updater to use client.Client.Apply() instead of the deprecated
// client.Client.Patch(..., client.Apply, ...) path.
//
// The object is held as a plain field (not embedded) so the wrapper does NOT
// satisfy runtime.Object. Without this, the typed client's type-switch would
// hit the runtime.Object branch and try to look up *clientObjectApplyConfig
// in the scheme, causing "no kind is registered" errors at runtime.
//
// Serialisation is identical to the old applyPatch path: apply.NewRequest
// calls json.Marshal on this wrapper, which delegates to the underlying object.
type clientObjectApplyConfig struct {
obj client.Object
}

func (a *clientObjectApplyConfig) IsApplyConfiguration() {}

func (a *clientObjectApplyConfig) GetName() *string {
n := a.obj.GetName()
return &n
}

func (a *clientObjectApplyConfig) GetNamespace() *string {
ns := a.obj.GetNamespace()
return &ns
}

func (a *clientObjectApplyConfig) GetKind() *string {
k := a.obj.GetObjectKind().GroupVersionKind().Kind
return &k
}

func (a *clientObjectApplyConfig) GetAPIVersion() *string {
av := a.obj.GetObjectKind().GroupVersionKind().GroupVersion().String()
return &av
}

func (a *clientObjectApplyConfig) MarshalJSON() ([]byte, error) {
return json.Marshal(a.obj)
}
Loading