Skip to content

Commit 644fcf2

Browse files
committed
Delete webhooks when SriovOperatorConfig is deleted
When a user deletes the default SriovOperatorConfig resource and tries to recreate it afterwards, the operator webhooks returns the error: ``` Error from server (InternalError): error when creating "/tmp/opconfig.yml": Internal error occurred: failed calling webhook "operator-webhook.sriovnetwork.openshift.io": failed to call webhook: Post "https://operator-webhook-service.openshift-sriov-network-operator.svc:443/validating-custom-resource?timeout=10s": service "operator-webhook-service" not found ``` as the webhook configuration is still present, while the Service and the DaemonSet has been deleted. Delete all the webhook configurations when the user deletes the default SriovOperatorConfig Signed-off-by: Andrea Panattoni <[email protected]>
1 parent 60c6404 commit 644fcf2

File tree

2 files changed

+83
-10
lines changed

2 files changed

+83
-10
lines changed

controllers/sriovoperatorconfig_controller.go

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package controllers
1818

1919
import (
2020
"context"
21+
"errors"
2122
"fmt"
2223
"os"
2324
"sort"
@@ -28,6 +29,7 @@ import (
2829
apierrors "k8s.io/apimachinery/pkg/api/errors"
2930
uns "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
3031
"k8s.io/apimachinery/pkg/runtime"
32+
"k8s.io/apimachinery/pkg/runtime/schema"
3133
"k8s.io/apimachinery/pkg/types"
3234
kscheme "k8s.io/client-go/kubernetes/scheme"
3335
ctrl "sigs.k8s.io/controller-runtime"
@@ -81,7 +83,9 @@ func (r *SriovOperatorConfigReconciler) Reconcile(ctx context.Context, req ctrl.
8183
if err != nil {
8284
if apierrors.IsNotFound(err) {
8385
logger.Info("default SriovOperatorConfig object not found. waiting for creation.")
84-
return reconcile.Result{}, nil
86+
87+
err := r.deleteAllWebhooks(ctx)
88+
return reconcile.Result{}, err
8589
}
8690
// Error reading the object - requeue the request.
8791
logger.Error(err, "Failed to get default SriovOperatorConfig object")
@@ -457,3 +461,29 @@ func (r SriovOperatorConfigReconciler) setLabelInsideObject(ctx context.Context,
457461

458462
return nil
459463
}
464+
465+
func (r SriovOperatorConfigReconciler) deleteAllWebhooks(ctx context.Context) error {
466+
var err error
467+
obj := &uns.Unstructured{}
468+
obj.SetGroupVersionKind(schema.GroupVersionKind{Group: "admissionregistration.k8s.io", Kind: "MutatingWebhookConfiguration", Version: "v1"})
469+
obj.SetName(consts.OperatorWebHookName)
470+
err = errors.Join(
471+
err, r.deleteWebhookObject(ctx, obj),
472+
)
473+
474+
obj = &uns.Unstructured{}
475+
obj.SetGroupVersionKind(schema.GroupVersionKind{Group: "admissionregistration.k8s.io", Kind: "ValidatingWebhookConfiguration", Version: "v1"})
476+
obj.SetName(consts.OperatorWebHookName)
477+
err = errors.Join(
478+
err, r.deleteWebhookObject(ctx, obj),
479+
)
480+
481+
obj = &uns.Unstructured{}
482+
obj.SetGroupVersionKind(schema.GroupVersionKind{Group: "admissionregistration.k8s.io", Kind: "MutatingWebhookConfiguration", Version: "v1"})
483+
obj.SetName(consts.InjectorWebHookName)
484+
err = errors.Join(
485+
err, r.deleteWebhookObject(ctx, obj),
486+
)
487+
488+
return err
489+
}

controllers/sriovoperatorconfig_controller_test.go

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"os"
77
"strings"
88
"sync"
9+
"time"
910

1011
admv1 "k8s.io/api/admissionregistration/v1"
1112
appsv1 "k8s.io/api/apps/v1"
@@ -38,15 +39,7 @@ var _ = Describe("SriovOperatorConfig controller", Ordered, func() {
3839

3940
BeforeAll(func() {
4041
By("Create SriovOperatorConfig controller k8s objs")
41-
config := &sriovnetworkv1.SriovOperatorConfig{}
42-
config.SetNamespace(testNamespace)
43-
config.SetName(consts.DefaultConfigName)
44-
config.Spec = sriovnetworkv1.SriovOperatorConfigSpec{
45-
EnableInjector: true,
46-
EnableOperatorWebhook: true,
47-
ConfigDaemonNodeSelector: map[string]string{},
48-
LogLevel: 2,
49-
}
42+
config := makeDefaultSriovOpConfig()
5043
Expect(k8sClient.Create(context.Background(), config)).Should(Succeed())
5144
DeferCleanup(func() {
5245
err := k8sClient.Delete(context.Background(), config)
@@ -224,6 +217,29 @@ var _ = Describe("SriovOperatorConfig controller", Ordered, func() {
224217
Expect(err).NotTo(HaveOccurred())
225218
})
226219

220+
// Namespaced resources are deleted via the `.ObjectMeta.OwnerReference` field. That logic can't be tested here because testenv doesn't have built-in controllers
221+
// (See https://book.kubebuilder.io/reference/envtest#testing-considerations). Since Service and DaemonSet are deleted when default/SriovOperatorConfig is no longer
222+
// present, it's important that webhook configurations are deleted as well.
223+
It("should delete the webhooks when SriovOperatorConfig/default is deleted", func() {
224+
DeferCleanup(k8sClient.Create, context.Background(), makeDefaultSriovOpConfig())
225+
226+
err := k8sClient.Delete(context.Background(), &sriovnetworkv1.SriovOperatorConfig{
227+
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: "default"},
228+
})
229+
Expect(err).NotTo(HaveOccurred())
230+
231+
assertResourceDoesNotExist(
232+
schema.GroupVersionKind{Group: "admissionregistration.k8s.io", Kind: "MutatingWebhookConfiguration", Version: "v1"},
233+
client.ObjectKey{Name: "sriov-operator-webhook-config"})
234+
assertResourceDoesNotExist(
235+
schema.GroupVersionKind{Group: "admissionregistration.k8s.io", Kind: "ValidatingWebhookConfiguration", Version: "v1"},
236+
client.ObjectKey{Name: "sriov-operator-webhook-config"})
237+
238+
assertResourceDoesNotExist(
239+
schema.GroupVersionKind{Group: "admissionregistration.k8s.io", Kind: "MutatingWebhookConfiguration", Version: "v1"},
240+
client.ObjectKey{Name: "network-resources-injector-config"})
241+
})
242+
227243
It("should be able to update the node selector of sriov-network-config-daemon", func() {
228244
By("specify the configDaemonNodeSelector")
229245
nodeSelector := map[string]string{"node-role.kubernetes.io/worker": ""}
@@ -517,13 +533,40 @@ var _ = Describe("SriovOperatorConfig controller", Ordered, func() {
517533
})
518534
})
519535

536+
func makeDefaultSriovOpConfig() *sriovnetworkv1.SriovOperatorConfig {
537+
config := &sriovnetworkv1.SriovOperatorConfig{}
538+
config.SetNamespace(testNamespace)
539+
config.SetName(consts.DefaultConfigName)
540+
config.Spec = sriovnetworkv1.SriovOperatorConfigSpec{
541+
EnableInjector: true,
542+
EnableOperatorWebhook: true,
543+
ConfigDaemonNodeSelector: map[string]string{},
544+
LogLevel: 2,
545+
}
546+
return config
547+
}
548+
520549
func assertResourceExists(gvk schema.GroupVersionKind, key client.ObjectKey) {
521550
u := &unstructured.Unstructured{}
522551
u.SetGroupVersionKind(gvk)
523552
err := k8sClient.Get(context.Background(), key, u)
524553
Expect(err).NotTo(HaveOccurred())
525554
}
526555

556+
func assertResourceDoesNotExist(gvk schema.GroupVersionKind, key client.ObjectKey) {
557+
Eventually(func(g Gomega) {
558+
u := &unstructured.Unstructured{}
559+
u.SetGroupVersionKind(gvk)
560+
err := k8sClient.Get(context.Background(), key, u)
561+
g.Expect(err).To(HaveOccurred())
562+
g.Expect(errors.IsNotFound(err)).To(BeTrue())
563+
}).
564+
WithOffset(1).
565+
WithPolling(100*time.Millisecond).
566+
WithTimeout(2*time.Second).
567+
Should(Succeed(), "Resource type[%s] name[%s] still present in the cluster", gvk.String(), key.String())
568+
}
569+
527570
func updateConfigDaemonNodeSelector(newValue map[string]string) func() {
528571
config := &sriovnetworkv1.SriovOperatorConfig{}
529572
err := k8sClient.Get(context.Background(), types.NamespacedName{Namespace: testNamespace, Name: "default"}, config)

0 commit comments

Comments
 (0)