From 9e513aadb4519d4055494662c1db686000f8bc73 Mon Sep 17 00:00:00 2001 From: Adam Cattermole Date: Mon, 22 Jun 2026 14:15:09 +0100 Subject: [PATCH 1/2] Cleanup orphaned WasmPlugin objects Signed-off-by: Adam Cattermole --- .../kuadrant-operator.clusterserviceversion.yaml | 8 +++++++- charts/kuadrant-operator/templates/manifests.yaml | 6 ++++++ config/rbac/role.yaml | 6 ++++++ internal/controller/istio_extension_reconciler.go | 8 ++++++++ 4 files changed, 27 insertions(+), 1 deletion(-) diff --git a/bundle/manifests/kuadrant-operator.clusterserviceversion.yaml b/bundle/manifests/kuadrant-operator.clusterserviceversion.yaml index ef3f0fd31..386870408 100644 --- a/bundle/manifests/kuadrant-operator.clusterserviceversion.yaml +++ b/bundle/manifests/kuadrant-operator.clusterserviceversion.yaml @@ -225,7 +225,7 @@ metadata: categories: Integration & Delivery console.openshift.io/plugins: '["kuadrant-console-plugin"]' containerImage: quay.io/kuadrant/kuadrant-operator:latest - createdAt: "2026-05-25T14:07:27Z" + createdAt: "2026-06-22T15:16:38Z" description: A Kubernetes Operator to manage the lifecycle of the Kuadrant system operators.operatorframework.io/builder: operator-sdk-v1.33.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v4 @@ -502,6 +502,12 @@ spec: - patch - update - watch + - apiGroups: + - extensions.istio.io + resources: + - wasmplugins + verbs: + - delete - apiGroups: - extensions.kuadrant.io resources: diff --git a/charts/kuadrant-operator/templates/manifests.yaml b/charts/kuadrant-operator/templates/manifests.yaml index f827076a2..cd4e7d6be 100644 --- a/charts/kuadrant-operator/templates/manifests.yaml +++ b/charts/kuadrant-operator/templates/manifests.yaml @@ -14346,6 +14346,12 @@ rules: - patch - update - watch +- apiGroups: + - extensions.istio.io + resources: + - wasmplugins + verbs: + - delete - apiGroups: - extensions.kuadrant.io resources: diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 993979629..385e376d9 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -112,6 +112,12 @@ rules: - patch - update - watch +- apiGroups: + - extensions.istio.io + resources: + - wasmplugins + verbs: + - delete - apiGroups: - extensions.kuadrant.io resources: diff --git a/internal/controller/istio_extension_reconciler.go b/internal/controller/istio_extension_reconciler.go index bcd72b478..4dd2efd31 100644 --- a/internal/controller/istio_extension_reconciler.go +++ b/internal/controller/istio_extension_reconciler.go @@ -16,6 +16,7 @@ import ( istioapinetworkingv1alpha3 "istio.io/api/networking/v1alpha3" istiov1beta1 "istio.io/api/type/v1beta1" istioclientgonetworkingv1alpha3 "istio.io/client-go/pkg/apis/networking/v1alpha3" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" k8stypes "k8s.io/apimachinery/pkg/types" @@ -35,6 +36,7 @@ import ( "github.com/kuadrant/kuadrant-operator/internal/wasm" ) +//+kubebuilder:rbac:groups=extensions.istio.io,resources=wasmplugins,verbs=delete //+kubebuilder:rbac:groups=networking.istio.io,resources=envoyfilters,verbs=get;list;watch;create;update;patch;delete // IstioExtensionReconciler reconciles Istio EnvoyFilter custom resources for wasm plugin injection @@ -131,6 +133,12 @@ func (r *IstioExtensionReconciler) Reconcile(ctx context.Context, _ []controller continue } + // Clean up old WasmPlugin for this specific gateway - temporary to be removed + wasmPluginName := wasm.ExtensionName(gateway.GetName()) + if err := r.client.Resource(kuadrantistio.WasmPluginsResource).Namespace(gateway.GetNamespace()).Delete(ctx, wasmPluginName, metav1.DeleteOptions{}); err != nil && !apierrors.IsNotFound(err) { + logger.Error(err, "failed to delete old wasmplugin", "gateway", gatewayKey.String(), "wasmplugin", wasmPluginName) + } + existingEnvoyFilter := existingEnvoyFilterObj.(*controller.RuntimeObject).Object.(*istioclientgonetworkingv1alpha3.EnvoyFilter) // delete From ed89ee94c75c45c7a8c7be9a9aae4a885b88d677 Mon Sep 17 00:00:00 2001 From: Adam Cattermole Date: Wed, 24 Jun 2026 14:05:42 +0100 Subject: [PATCH 2/2] Handle error cases Signed-off-by: Adam Cattermole --- internal/controller/istio_extension_reconciler.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/internal/controller/istio_extension_reconciler.go b/internal/controller/istio_extension_reconciler.go index 4dd2efd31..d91475593 100644 --- a/internal/controller/istio_extension_reconciler.go +++ b/internal/controller/istio_extension_reconciler.go @@ -97,6 +97,7 @@ func (r *IstioExtensionReconciler) Reconcile(ctx context.Context, _ []controller } modifiedGateways := make([]string, 0, len(gateways)) + var reconcileErr error for _, gateway := range gateways { gatewayKey := k8stypes.NamespacedName{Name: gateway.GetName(), Namespace: gateway.GetNamespace()} @@ -124,11 +125,12 @@ func (r *IstioExtensionReconciler) Reconcile(ctx context.Context, _ []controller desiredEnvoyFilterUnstructured, err := controller.Destruct(desiredEnvoyFilter) if err != nil { logger.Error(err, "failed to destruct envoyfilter object", "gateway", gatewayKey.String(), "envoyfilter", desiredEnvoyFilter) + reconcileErr = errors.Join(reconcileErr, fmt.Errorf("failed to destruct envoyfilter %s/%s: %w", gateway.GetNamespace(), desiredEnvoyFilter.GetName(), err)) continue } if _, err = resource.Create(ctx, desiredEnvoyFilterUnstructured, metav1.CreateOptions{}); err != nil { logger.Error(err, "failed to create envoyfilter object", "gateway", gatewayKey.String(), "envoyfilter", desiredEnvoyFilterUnstructured.Object) - // TODO: handle error + reconcileErr = errors.Join(reconcileErr, fmt.Errorf("failed to create envoyfilter %s/%s: %w", gateway.GetNamespace(), desiredEnvoyFilter.GetName(), err)) } continue } @@ -136,7 +138,8 @@ func (r *IstioExtensionReconciler) Reconcile(ctx context.Context, _ []controller // Clean up old WasmPlugin for this specific gateway - temporary to be removed wasmPluginName := wasm.ExtensionName(gateway.GetName()) if err := r.client.Resource(kuadrantistio.WasmPluginsResource).Namespace(gateway.GetNamespace()).Delete(ctx, wasmPluginName, metav1.DeleteOptions{}); err != nil && !apierrors.IsNotFound(err) { - logger.Error(err, "failed to delete old wasmplugin", "gateway", gatewayKey.String(), "wasmplugin", wasmPluginName) + logger.Error(err, "failed to delete wasmplugin", "gateway", gatewayKey.String(), "wasmplugin", wasmPluginName) + reconcileErr = errors.Join(reconcileErr, fmt.Errorf("failed to delete wasmplugin %s/%s: %w", gateway.GetNamespace(), wasmPluginName, err)) } existingEnvoyFilter := existingEnvoyFilterObj.(*controller.RuntimeObject).Object.(*istioclientgonetworkingv1alpha3.EnvoyFilter) @@ -145,7 +148,7 @@ func (r *IstioExtensionReconciler) Reconcile(ctx context.Context, _ []controller if utils.IsObjectTaggedToDelete(desiredEnvoyFilter) && !utils.IsObjectTaggedToDelete(existingEnvoyFilter) { if err := resource.Delete(ctx, existingEnvoyFilter.GetName(), metav1.DeleteOptions{}); err != nil { logger.Error(err, "failed to delete envoyfilter object", "gateway", gatewayKey.String(), "envoyfilter", fmt.Sprintf("%s/%s", existingEnvoyFilter.GetNamespace(), existingEnvoyFilter.GetName())) - // TODO: handle error + reconcileErr = errors.Join(reconcileErr, fmt.Errorf("failed to delete envoyfilter %s/%s: %w", existingEnvoyFilter.GetNamespace(), existingEnvoyFilter.GetName(), err)) } continue } @@ -167,13 +170,13 @@ func (r *IstioExtensionReconciler) Reconcile(ctx context.Context, _ []controller } if _, err = resource.Update(ctx, existingEnvoyFilterUnstructured, metav1.UpdateOptions{}); err != nil { logger.Error(err, "failed to update envoyfilter object", "gateway", gatewayKey.String(), "envoyfilter", existingEnvoyFilterUnstructured.Object) - // TODO: handle error + reconcileErr = errors.Join(reconcileErr, fmt.Errorf("failed to update envoyfilter %s/%s: %w", existingEnvoyFilter.GetNamespace(), existingEnvoyFilter.GetName(), err)) } } state.Store(StateIstioExtensionsModified, modifiedGateways) - return nil + return reconcileErr } func (r *IstioExtensionReconciler) reconcileUpstreamClusters(ctx context.Context, topology *machinery.Topology, gateways []*machinery.Gateway) {