Skip to content

Commit

Permalink
PTEUDO-1990: add dbroleclaim webhook
Browse files Browse the repository at this point in the history
  • Loading branch information
bfabricio committed Nov 29, 2024
1 parent dd3fcea commit 0dd6c49
Show file tree
Hide file tree
Showing 7 changed files with 204 additions and 8 deletions.
3 changes: 3 additions & 0 deletions PROJECT
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ resources:
kind: DbRoleClaim
path: github.com/infobloxopen/db-controller/api/v1
version: v1
webhooks:
validation: true
webhookVersion: v1
- api:
crdVersion: v1
namespaced: true
Expand Down
5 changes: 5 additions & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,11 @@ func main() {
os.Exit(1)
}

if err = webhookpersistancev1.SetupDbRoleClaimWebhookWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create webhook", "webhook", "DbRoleClaim")
os.Exit(1)
}

// +kubebuilder:scaffold:builder

if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
Expand Down
19 changes: 19 additions & 0 deletions config/webhook/manifests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,22 @@ webhooks:
resources:
- databaseclaims
sideEffects: None
- admissionReviewVersions:
- v1
clientConfig:
service:
name: webhook-service
namespace: system
path: /validate-persistance-atlas-infoblox-com-v1-dbroleclaim
failurePolicy: Fail
name: vdbroleclaim-v1.kb.io
rules:
- apiGroups:
- persistance.atlas.infoblox.com
apiVersions:
- v1
operations:
- DELETE
resources:
- dbroleclaims
sideEffects: None
18 changes: 10 additions & 8 deletions internal/webhook/v1/databaseclaim_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,6 @@ import (
persistancev1 "github.com/infobloxopen/db-controller/api/v1"
)

// nolint:unused
// log is for logging in this package.
var databaseclaimlog = logf.Log.WithName("databaseclaim-resource")

const deletionOverrideLabel = "persistance.atlas.infoblox.com/allow-deletion"

// SetupDatabaseClaimWebhookWithManager registers the webhook for DatabaseClaim in the manager.
Expand All @@ -48,27 +44,33 @@ type DatabaseClaimCustomValidator struct{}

var _ webhook.CustomValidator = &DatabaseClaimCustomValidator{}

// ValidateCreate implements webhook.CustomValidator so a webhook will be registered for the type DatabaseClaim.
func (v *DatabaseClaimCustomValidator) ValidateCreate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
return nil, nil
}

// ValidateUpdate implements webhook.CustomValidator so a webhook will be registered for the type DatabaseClaim.
func (v *DatabaseClaimCustomValidator) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (admission.Warnings, error) {
return nil, nil
}

// ValidateDelete implements webhook.CustomValidator so a webhook will be registered for the type DatabaseClaim.
func (v *DatabaseClaimCustomValidator) ValidateDelete(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
log := logf.FromContext(ctx).WithName("databaseclaim-webhook")

req, err := admission.RequestFromContext(ctx)
if err != nil {
log.Error(err, "Unable to retrieve AdmissionRequest from context")
}
log.Info("Deletion request details", "username", req.UserInfo.Username, "groups", req.UserInfo.Groups, "uid", req.UserInfo.UID)

claim, ok := obj.(*persistancev1.DatabaseClaim)
if !ok {
return nil, fmt.Errorf("expected a DatabaseClaim object but got %T", obj)
}

databaseclaimlog.Info("Validation for DatabaseClaim upon deletion", "name", claim.Name)
log.Info("Validation for DatabaseClaim upon deletion", "name", claim.Name)

if value, exists := claim.GetLabels()[deletionOverrideLabel]; exists && value == "true" {
databaseclaimlog.Info("Deletion override label found; allowing deletion", "name", claim.Name)
log.Info("Deletion override label found; allowing deletion", "name", claim.Name)
return nil, nil
}

Expand Down
76 changes: 76 additions & 0 deletions internal/webhook/v1/dbroleclaim_webhook.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
Copyright 2024.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package v1

import (
"context"
"fmt"

"k8s.io/apimachinery/pkg/runtime"
ctrl "sigs.k8s.io/controller-runtime"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/webhook"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"

persistancev1 "github.com/infobloxopen/db-controller/api/v1"
)

// SetupDbRoleClaimWebhookWithManager registers the webhook for DbRoleClaim in the manager.
func SetupDbRoleClaimWebhookWithManager(mgr ctrl.Manager) error {
return ctrl.NewWebhookManagedBy(mgr).For(&persistancev1.DbRoleClaim{}).
WithValidator(&DbRoleClaimCustomValidator{}).
Complete()
}

// +kubebuilder:webhook:path=/validate-persistance-atlas-infoblox-com-v1-dbroleclaim,mutating=false,failurePolicy=fail,sideEffects=None,groups=persistance.atlas.infoblox.com,resources=dbroleclaims,verbs=delete,versions=v1,name=vdbroleclaim-v1.kb.io,admissionReviewVersions=v1

type DbRoleClaimCustomValidator struct{}

var _ webhook.CustomValidator = &DbRoleClaimCustomValidator{}

func (v *DbRoleClaimCustomValidator) ValidateCreate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
return nil, nil
}

func (v *DbRoleClaimCustomValidator) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (admission.Warnings, error) {
return nil, nil
}

func (v *DbRoleClaimCustomValidator) ValidateDelete(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
log := logf.FromContext(ctx).WithName("dbroleclaim-webhook")

req, err := admission.RequestFromContext(ctx)
if err != nil {
log.Error(err, "Unable to retrieve AdmissionRequest from context")
}
log.Info("Deletion request details", "username", req.UserInfo.Username, "groups", req.UserInfo.Groups, "uid", req.UserInfo.UID)

roleClaim, ok := obj.(*persistancev1.DbRoleClaim)
if !ok {
return nil, fmt.Errorf("expected a DatabaseClaim object but got %T", obj)
}

log.Info("Validation for DatabaseClaim upon deletion", "name", roleClaim.Name)

if value, exists := roleClaim.GetLabels()[deletionOverrideLabel]; exists && value == "true" {
log.Info("Deletion override label found; allowing deletion", "name", roleClaim.Name)
return nil, nil
}

return nil, fmt.Errorf("deletion is denied for DatabaseClaim '%s'; set annotation or label '%s=true' to override",
roleClaim.Name, deletionOverrideLabel)
}
88 changes: 88 additions & 0 deletions internal/webhook/v1/dbroleclaim_webhook_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
Copyright 2024.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package v1

import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

persistancev1 "github.com/infobloxopen/db-controller/api/v1"
)

var _ = Describe("DbRoleClaim Webhook", func() {
var (
obj *persistancev1.DbRoleClaim
oldObj *persistancev1.DbRoleClaim
validator DbRoleClaimCustomValidator
)

BeforeEach(func() {
obj = &persistancev1.DbRoleClaim{}
oldObj = &persistancev1.DbRoleClaim{}
validator = DbRoleClaimCustomValidator{}
Expect(validator).NotTo(BeNil(), "Expected validator to be initialized")
Expect(oldObj).NotTo(BeNil(), "Expected oldObj to be initialized")
Expect(obj).NotTo(BeNil(), "Expected obj to be initialized")
})

Context("When deleting a DatabaseClaim under Validating Webhook", func() {
It("Should allow deletion if the deletion override label is set to true", func() {
By("Setting the deletion override label")
obj.SetLabels(map[string]string{deletionOverrideLabel: "true"})

By("Calling ValidateDelete")
warnings, err := validator.ValidateDelete(ctx, obj)

By("Expecting no errors and no warnings")
Expect(err).NotTo(HaveOccurred())
Expect(warnings).To(BeNil())
})

It("Should deny deletion if the deletion override label is not set", func() {
By("Not setting the deletion override label")
obj.SetLabels(map[string]string{})

By("Calling ValidateDelete")
warnings, err := validator.ValidateDelete(ctx, obj)

By("Expecting an error to occur")
Expect(err).To(HaveOccurred())
Expect(warnings).To(BeNil())

By("Validating the error message")
Expect(err.Error()).To(ContainSubstring("deletion is denied for DatabaseClaim"))
Expect(err.Error()).To(ContainSubstring(deletionOverrideLabel))
})

It("Should deny deletion if the deletion override label is set to false", func() {
By("Setting the deletion override label to false")
obj.SetLabels(map[string]string{deletionOverrideLabel: "false"})

By("Calling ValidateDelete")
warnings, err := validator.ValidateDelete(ctx, obj)

By("Expecting an error to occur")
Expect(err).To(HaveOccurred())
Expect(warnings).To(BeNil())

By("Validating the error message")
Expect(err.Error()).To(ContainSubstring("deletion is denied for DatabaseClaim"))
Expect(err.Error()).To(ContainSubstring(deletionOverrideLabel))
})
})

})
3 changes: 3 additions & 0 deletions internal/webhook/v1/webhook_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@ var _ = BeforeSuite(func() {
err = SetupDatabaseClaimWebhookWithManager(mgr)
Expect(err).NotTo(HaveOccurred())

err = SetupDbRoleClaimWebhookWithManager(mgr)
Expect(err).NotTo(HaveOccurred())

// +kubebuilder:scaffold:webhook

go func() {
Expand Down

0 comments on commit 0dd6c49

Please sign in to comment.