Skip to content

Commit

Permalink
Add validation webhook for users.rabbitmq.com
Browse files Browse the repository at this point in the history
  • Loading branch information
ChunyiLyu committed Mar 19, 2021
1 parent b15855d commit db1ffb2
Show file tree
Hide file tree
Showing 9 changed files with 125 additions and 2 deletions.
8 changes: 8 additions & 0 deletions api/v1alpha1/user_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ package v1alpha1
import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
)

// UserSpec defines the desired state of User.
Expand Down Expand Up @@ -74,6 +75,13 @@ type UserList struct {
Items []User `json:"items"`
}

func (u *User) GroupResource() schema.GroupResource {
return schema.GroupResource{
Group: u.GroupVersionKind().Group,
Resource: u.GroupVersionKind().Kind,
}
}

func init() {
SchemeBuilder.Register(&User{}, &UserList{})
}
45 changes: 45 additions & 0 deletions api/v1alpha1/user_webhook.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package v1alpha1

import (
"fmt"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/validation/field"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/webhook"
)

func (u *User) SetupWebhookWithManager(mgr ctrl.Manager) error {
return ctrl.NewWebhookManagedBy(mgr).
For(u).
Complete()
}

// +kubebuilder:webhook:verbs=create;update,path=/validate-rabbitmq-com-v1alpha1-user,mutating=false,failurePolicy=fail,groups=rabbitmq.com,resources=users,versions=v1alpha1,name=vuser.kb.io,sideEffects=none,admissionReviewVersions=v1

var _ webhook.Validator = &User{}

// no validation on create
func (u *User) ValidateCreate() error {
return nil
}

// returns error type 'forbidden' for updates on rabbitmqClusterReference
// user.spec.tags can be updated
func (u *User) ValidateUpdate(old runtime.Object) error {
oldUser, ok := old.(*User)
if !ok {
return apierrors.NewBadRequest(fmt.Sprintf("expected a user but got a %T", old))
}

if u.Spec.RabbitmqClusterReference != oldUser.Spec.RabbitmqClusterReference {
return apierrors.NewForbidden(u.GroupResource(), u.Name,
field.Forbidden(field.NewPath("spec", "rabbitmqClusterReference"), "update on rabbitmqClusterReference is forbidden"))
}
return nil
}

// no validation on delete
func (u *User) ValidateDelete() error {
return nil
}
38 changes: 38 additions & 0 deletions api/v1alpha1/user_webhook_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package v1alpha1

import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

var _ = Describe("user webhook", func() {
var user = User{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
},
Spec: UserSpec{
Tags: []UserTag{"policymaker"},
RabbitmqClusterReference: RabbitmqClusterReference{
Name: "a-cluster",
Namespace: "default",
},
},
}

It("does not allow updates on RabbitmqClusterReference", func() {
new := user.DeepCopy()
new.Spec.RabbitmqClusterReference = RabbitmqClusterReference{
Name: "new-cluster",
Namespace: "default",
}
Expect(apierrors.IsForbidden(new.ValidateUpdate(&user))).To(BeTrue())
})

It("allows update on tags", func() {
new := user.DeepCopy()
new.Spec.Tags = []UserTag{"monitoring"}
Expect(new.ValidateUpdate(&user)).To(Succeed())
})
})
2 changes: 2 additions & 0 deletions config/crd/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@ patchesStrategicMerge:
- patches/webhook_in_exchanges.yaml
- patches/webhook_in_vhosts.yaml
- patches/webhook_in_policies.yaml
- patches/webhook_in_users.yaml
# +kubebuilder:scaffold:crdkustomizewebhookpatch

- patches/cainjection_in_bindings.yaml
- patches/cainjection_in_queues.yaml
- patches/cainjection_in_exchanges.yaml
- patches/cainjection_in_vhosts.yaml
- patches/cainjection_in_policies.yaml
- patches/cainjection_in_users.yaml
# +kubebuilder:scaffold:crdkustomizecainjectionpatch

configurations:
Expand Down
2 changes: 1 addition & 1 deletion config/crd/patches/cainjection_in_users.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# The following patch adds a directive for certmanager to inject CA into the CRD
# CRD conversion requires k8s 1.13 or later.
apiVersion: apiextensions.k8s.io/v1beta1
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
Expand Down
2 changes: 1 addition & 1 deletion config/crd/patches/webhook_in_users.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# The following patch enables conversion webhook for CRD
# CRD conversion requires k8s 1.13 or later.
apiVersion: apiextensions.k8s.io/v1beta1
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: users.rabbitmq.com
Expand Down
20 changes: 20 additions & 0 deletions config/webhook/manifests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,26 @@ webhooks:
resources:
- queues
sideEffects: None
- admissionReviewVersions:
- v1
clientConfig:
service:
name: webhook-service
namespace: system
path: /validate-rabbitmq-com-v1alpha1-user
failurePolicy: Fail
name: vuser.kb.io
rules:
- apiGroups:
- rabbitmq.com
apiVersions:
- v1alpha1
operations:
- CREATE
- UPDATE
resources:
- users
sideEffects: None
- admissionReviewVersions:
- v1
clientConfig:
Expand Down
4 changes: 4 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,10 @@ func main() {
log.Error(err, "unable to create webhook", "webhook", "Policy")
os.Exit(1)
}
if err = (&topologyv1alpha1.User{}).SetupWebhookWithManager(mgr); err != nil {
log.Error(err, "unable to create webhook", "webhook", "User")
os.Exit(1)
}
// +kubebuilder:scaffold:builder

log.Info("starting manager")
Expand Down
6 changes: 6 additions & 0 deletions system_tests/user_system_tests.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,12 @@ var _ = Describe("Users", func() {
By("setting status.observedGeneration")
Expect(updatedUser.Status.ObservedGeneration).To(Equal(updatedUser.GetGeneration()))

By("not allowing updates on certain fields")
updateTest := topologyv1alpha1.User{}
Expect(k8sClient.Get(ctx, types.NamespacedName{Name: user.Name, Namespace: user.Namespace}, &updateTest)).To(Succeed())
updateTest.Spec.RabbitmqClusterReference = topologyv1alpha1.RabbitmqClusterReference{Name: "a-new-cluster", Namespace: "default"}
Expect(k8sClient.Update(ctx, &updateTest).Error()).To(ContainSubstring("spec.rabbitmqClusterReference: Forbidden: update on rabbitmqClusterReference is forbidden"))

By("deleting user")
Expect(k8sClient.Delete(ctx, user)).To(Succeed())
Eventually(func() error {
Expand Down

0 comments on commit db1ffb2

Please sign in to comment.