From b39c02d09622901dbb36df9e83448c1fab05d986 Mon Sep 17 00:00:00 2001 From: Chunyi Lyu Date: Wed, 17 Mar 2021 13:32:14 +0000 Subject: [PATCH 1/7] Bootstrap admission webhook for bindings.rabbitmq.com --- Makefile | 6 +++ api/v1alpha1/binding_webhook.go | 41 +++++++++++++++++++ config/certmanager/certificate.yaml | 8 +--- config/crd/kustomization.yaml | 7 ++++ .../crd/patches/cainjection_in_bindings.yaml | 2 +- config/crd/patches/webhook_in_bindings.yaml | 18 ++++---- config/default/base/kustomization.yaml | 34 +++++++++++++++ .../default/base/manager_webhook_patch.yaml | 23 +++++++++++ .../base/webhookcainjection_patch.yaml | 7 ++++ config/webhook/kustomizeconfig.yaml | 2 - config/webhook/manifests.yaml | 28 +++++++++++++ config/webhook/service.yaml | 3 +- main.go | 6 +++ 13 files changed, 165 insertions(+), 20 deletions(-) create mode 100644 api/v1alpha1/binding_webhook.go create mode 100644 config/default/base/manager_webhook_patch.yaml create mode 100644 config/default/base/webhookcainjection_patch.yaml create mode 100644 config/webhook/manifests.yaml diff --git a/Makefile b/Makefile index 30d792db..79d8e1f8 100644 --- a/Makefile +++ b/Makefile @@ -123,3 +123,9 @@ generate-manifests: mkdir -p releases kustomize build config/installation/ > releases/messaging-topology-operator.yaml +CERT_MANAGER_VERSION ?=v1.2.0 +cert-manager: + kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/$(CERT_MANAGER_VERSION)/cert-manager.yaml + +destroy-cert-manager: + kubectl delete -f https://github.com/jetstack/cert-manager/releases/download/$(CERT_MANAGER_VERSION)/cert-manager.yaml diff --git a/api/v1alpha1/binding_webhook.go b/api/v1alpha1/binding_webhook.go new file mode 100644 index 00000000..2f8add76 --- /dev/null +++ b/api/v1alpha1/binding_webhook.go @@ -0,0 +1,41 @@ +package v1alpha1 + +import ( + "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" +) + +var logger = logf.Log.WithName("binding-webhook") + +func (r *Binding) SetupWebhookWithManager(mgr ctrl.Manager) error { + return ctrl.NewWebhookManagedBy(mgr). + For(r). + Complete() +} + +// +kubebuilder:webhook:verbs=create;update,path=/validate-rabbitmq-com-v1alpha1-binding,mutating=false,failurePolicy=fail,groups=rabbitmq.com,resources=bindings,versions=v1alpha1,name=vbinding.kb.io,sideEffects=none,admissionReviewVersions=v1 + +var _ webhook.Validator = &Binding{} + +// ValidateCreate implements webhook.Validator so a webhook will be registered for the type +func (r *Binding) ValidateCreate() error { + logger.Info("validate create", "name", r.Name) + + return nil +} + +// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type +func (r *Binding) ValidateUpdate(old runtime.Object) error { + logger.Info("validate update", "name", r.Name) + + return nil +} + +// ValidateDelete implements webhook.Validator so a webhook will be registered for the type +func (r *Binding) ValidateDelete() error { + logger.Info("validate delete", "name", r.Name) + + return nil +} diff --git a/config/certmanager/certificate.yaml b/config/certmanager/certificate.yaml index 58db114f..5c103694 100644 --- a/config/certmanager/certificate.yaml +++ b/config/certmanager/certificate.yaml @@ -1,8 +1,4 @@ -# The following manifests contain a self-signed issuer CR and a certificate CR. -# More document can be found at https://docs.cert-manager.io -# WARNING: Targets CertManager 0.11 check https://docs.cert-manager.io/en/latest/tasks/upgrading/index.html for -# breaking changes -apiVersion: cert-manager.io/v1alpha2 +apiVersion: cert-manager.io/v1 kind: Issuer metadata: name: selfsigned-issuer @@ -10,7 +6,7 @@ metadata: spec: selfSigned: {} --- -apiVersion: cert-manager.io/v1alpha2 +apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: serving-cert # this name should match the one appeared in kustomizeconfig.yaml diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index 0ee39489..535d2496 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -10,5 +10,12 @@ resources: - bases/rabbitmq.com_policies.yaml # +kubebuilder:scaffold:crdkustomizeresource +patchesStrategicMerge: +- patches/webhook_in_bindings.yaml +# +kubebuilder:scaffold:crdkustomizewebhookpatch + +- patches/cainjection_in_bindings.yaml +# +kubebuilder:scaffold:crdkustomizecainjectionpatch + configurations: - kustomizeconfig.yaml diff --git a/config/crd/patches/cainjection_in_bindings.yaml b/config/crd/patches/cainjection_in_bindings.yaml index b0bfdccc..686e35bf 100644 --- a/config/crd/patches/cainjection_in_bindings.yaml +++ b/config/crd/patches/cainjection_in_bindings.yaml @@ -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/v1alpha1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: diff --git a/config/crd/patches/webhook_in_bindings.yaml b/config/crd/patches/webhook_in_bindings.yaml index f6c86c65..a9d42c36 100644 --- a/config/crd/patches/webhook_in_bindings.yaml +++ b/config/crd/patches/webhook_in_bindings.yaml @@ -1,17 +1,17 @@ # The following patch enables conversion webhook for CRD # CRD conversion requires k8s 1.13 or later. -apiVersion: apiextensions.k8s.io/v1alpha1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: name: bindings.rabbitmq.com spec: conversion: strategy: Webhook - webhookClientConfig: - # this is "\n" used as a placeholder, otherwise it will be rejected by the apiserver for being blank, - # but we're going to set it later using the cert-manager (or potentially a patch if not using cert-manager) - caBundle: Cg== - service: - namespace: system - name: webhook-service - path: /convert + webhook: + conversionReviewVersions: ["v1", "v1beta1"] + clientConfig: + caBundle: Cg== + service: + namespace: system + name: webhook-service + path: /convert diff --git a/config/default/base/kustomization.yaml b/config/default/base/kustomization.yaml index 0d101b3d..102ca860 100644 --- a/config/default/base/kustomization.yaml +++ b/config/default/base/kustomization.yaml @@ -6,6 +6,40 @@ namespace: rabbitmq-system resources: - ../../crd - ../../manager +- ../../webhook +- ../../certmanager + +patches: +- manager_webhook_patch.yaml +- webhookcainjection_patch.yaml + +vars: +- name: CERTIFICATE_NAMESPACE # namespace of the certificate CR + objref: + kind: Certificate + group: cert-manager.io + version: v1 + name: serving-cert # this name should match the one in certificate.yaml + fieldref: + fieldpath: metadata.namespace +- name: CERTIFICATE_NAME + objref: + kind: Certificate + group: cert-manager.io + version: v1 + name: serving-cert # this name should match the one in certificate.yaml +- name: SERVICE_NAMESPACE # namespace of the service + objref: + kind: Service + version: v1 + name: webhook-service + fieldref: + fieldpath: metadata.namespace +- name: SERVICE_NAME + objref: + kind: Service + version: v1 + name: webhook-service images: - name: controller diff --git a/config/default/base/manager_webhook_patch.yaml b/config/default/base/manager_webhook_patch.yaml new file mode 100644 index 00000000..0465e073 --- /dev/null +++ b/config/default/base/manager_webhook_patch.yaml @@ -0,0 +1,23 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: operator + namespace: system +spec: + template: + spec: + containers: + - name: manager + ports: + - containerPort: 9443 + name: webhook-server + protocol: TCP + volumeMounts: + - mountPath: /tmp/k8s-webhook-server/serving-certs + name: cert + readOnly: true + volumes: + - name: cert + secret: + defaultMode: 420 + secretName: webhook-server-cert diff --git a/config/default/base/webhookcainjection_patch.yaml b/config/default/base/webhookcainjection_patch.yaml new file mode 100644 index 00000000..7cc9d358 --- /dev/null +++ b/config/default/base/webhookcainjection_patch.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + name: validating-webhook-configuration + annotations: + cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) diff --git a/config/webhook/kustomizeconfig.yaml b/config/webhook/kustomizeconfig.yaml index 25e21e3c..3091ac60 100644 --- a/config/webhook/kustomizeconfig.yaml +++ b/config/webhook/kustomizeconfig.yaml @@ -1,5 +1,3 @@ -# the following config is for teaching kustomize where to look at when substituting vars. -# It requires kustomize v2.1.0 or newer to work properly. nameReference: - kind: Service version: v1 diff --git a/config/webhook/manifests.yaml b/config/webhook/manifests.yaml new file mode 100644 index 00000000..40de2130 --- /dev/null +++ b/config/webhook/manifests.yaml @@ -0,0 +1,28 @@ + +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + creationTimestamp: null + name: validating-webhook-configuration +webhooks: +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /validate-rabbitmq-com-v1alpha1-binding + failurePolicy: Fail + name: vbinding.kb.io + rules: + - apiGroups: + - rabbitmq.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - bindings + sideEffects: None diff --git a/config/webhook/service.yaml b/config/webhook/service.yaml index 31e0f829..48414412 100644 --- a/config/webhook/service.yaml +++ b/config/webhook/service.yaml @@ -1,4 +1,3 @@ - apiVersion: v1 kind: Service metadata: @@ -9,4 +8,4 @@ spec: - port: 443 targetPort: 9443 selector: - control-plane: controller-manager + app.kubernetes.io/name: messaging-topology-operator diff --git a/main.go b/main.go index 94379a36..38adbe56 100644 --- a/main.go +++ b/main.go @@ -21,6 +21,7 @@ import ( rabbitmqv1beta1 "github.com/rabbitmq/cluster-operator/api/v1beta1" + rabbitmqcomv1alpha1 "github.com/rabbitmq/messaging-topology-operator/api/v1alpha1" topologyv1alpha1 "github.com/rabbitmq/messaging-topology-operator/api/v1alpha1" "github.com/rabbitmq/messaging-topology-operator/controllers" // +kubebuilder:scaffold:imports @@ -43,6 +44,7 @@ func init() { _ = rabbitmqv1beta1.AddToScheme(scheme) _ = topologyv1alpha1.AddToScheme(scheme) + _ = rabbitmqcomv1alpha1.AddToScheme(scheme) // +kubebuilder:scaffold:scheme } @@ -118,6 +120,10 @@ func main() { log.Error(err, "unable to create controller", "controller", policyControllerName) os.Exit(1) } + if err = (&rabbitmqcomv1alpha1.Binding{}).SetupWebhookWithManager(mgr); err != nil { + log.Error(err, "unable to create webhook", "webhook", "Binding") + os.Exit(1) + } // +kubebuilder:scaffold:builder log.Info("starting manager") From 8aec363520a51131104167875e1fa2c666887e2d Mon Sep 17 00:00:00 2001 From: Chunyi Lyu Date: Wed, 17 Mar 2021 15:17:37 +0000 Subject: [PATCH 2/7] Update validation on bindings to make it immutable --- api/v1alpha1/binding_types.go | 8 ++ api/v1alpha1/binding_webhook.go | 36 ++++--- api/v1alpha1/binding_webhook_test.go | 139 +++++++++++++++++++++++++++ system_tests/binding_system_tests.go | 6 ++ 4 files changed, 175 insertions(+), 14 deletions(-) create mode 100644 api/v1alpha1/binding_webhook_test.go diff --git a/api/v1alpha1/binding_types.go b/api/v1alpha1/binding_types.go index 3d5cdbe2..29c7ba0a 100644 --- a/api/v1alpha1/binding_types.go +++ b/api/v1alpha1/binding_types.go @@ -12,6 +12,7 @@ package v1alpha1 import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" ) // BindingSpec defines the desired state of Binding @@ -66,6 +67,13 @@ type BindingList struct { Items []Binding `json:"items"` } +func (b *Binding) GroupResource() schema.GroupResource { + return schema.GroupResource{ + Group: b.GroupVersionKind().Group, + Resource: b.GroupVersionKind().Kind, + } +} + func init() { SchemeBuilder.Register(&Binding{}, &BindingList{}) } diff --git a/api/v1alpha1/binding_webhook.go b/api/v1alpha1/binding_webhook.go index 2f8add76..f7aac2cc 100644 --- a/api/v1alpha1/binding_webhook.go +++ b/api/v1alpha1/binding_webhook.go @@ -1,7 +1,10 @@ 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" logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/webhook" @@ -9,9 +12,9 @@ import ( var logger = logf.Log.WithName("binding-webhook") -func (r *Binding) SetupWebhookWithManager(mgr ctrl.Manager) error { +func (b *Binding) SetupWebhookWithManager(mgr ctrl.Manager) error { return ctrl.NewWebhookManagedBy(mgr). - For(r). + For(b). Complete() } @@ -19,23 +22,28 @@ func (r *Binding) SetupWebhookWithManager(mgr ctrl.Manager) error { var _ webhook.Validator = &Binding{} -// ValidateCreate implements webhook.Validator so a webhook will be registered for the type -func (r *Binding) ValidateCreate() error { - logger.Info("validate create", "name", r.Name) - +// no validation logic on create +func (b *Binding) ValidateCreate() error { return nil } -// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type -func (r *Binding) ValidateUpdate(old runtime.Object) error { - logger.Info("validate update", "name", r.Name) - +// updates on bindings.rabbitmq.com is forbidden +func (b *Binding) ValidateUpdate(old runtime.Object) error { + oldBinding, ok := old.(*Binding) + if !ok { + return apierrors.NewBadRequest(fmt.Sprintf("expected a binding but got a %T", old)) + } + + if oldBinding.Spec != b.Spec { + return apierrors.NewForbidden( + b.GroupResource(), + b.Name, + field.Forbidden(field.NewPath("spec"), "binding.spec is immutable")) + } return nil } -// ValidateDelete implements webhook.Validator so a webhook will be registered for the type -func (r *Binding) ValidateDelete() error { - logger.Info("validate delete", "name", r.Name) - +// no validation logic on delete +func (b *Binding) ValidateDelete() error { return nil } diff --git a/api/v1alpha1/binding_webhook_test.go b/api/v1alpha1/binding_webhook_test.go new file mode 100644 index 00000000..d739a3c5 --- /dev/null +++ b/api/v1alpha1/binding_webhook_test.go @@ -0,0 +1,139 @@ +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" + "k8s.io/apimachinery/pkg/runtime" +) + +var _ = Describe("Binding webhook", func() { + + var oldBinding = Binding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "update-binding", + }, + Spec: BindingSpec{ + Source: "test", + Destination: "test", + DestinationType: "queue", + RabbitmqClusterReference: RabbitmqClusterReference{ + Name: "some-cluster", + Namespace: "default", + }, + }, + } + + It("does not allow updates on source", func() { + newBinding := Binding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "update-binding", + }, + Spec: BindingSpec{ + Source: "updated-source", + Destination: "test", + DestinationType: "queue", + RabbitmqClusterReference: RabbitmqClusterReference{ + Name: "some-cluster", + Namespace: "default", + }, + }, + } + Expect(apierrors.IsForbidden(newBinding.ValidateUpdate(&oldBinding))).To(BeTrue()) + }) + + It("does not allow updates on destination", func() { + newBinding := Binding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "update-binding", + }, + Spec: BindingSpec{ + Source: "test", + Destination: "updated-des", + DestinationType: "queue", + RabbitmqClusterReference: RabbitmqClusterReference{ + Name: "some-cluster", + Namespace: "default", + }, + }, + } + Expect(apierrors.IsForbidden(newBinding.ValidateUpdate(&oldBinding))).To(BeTrue()) + }) + + It("does not allow updates on destination type", func() { + newBinding := Binding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "update-binding", + }, + Spec: BindingSpec{ + Source: "test", + Destination: "test", + DestinationType: "exchange", + RabbitmqClusterReference: RabbitmqClusterReference{ + Name: "some-cluster", + Namespace: "default", + }, + }, + } + Expect(apierrors.IsForbidden(newBinding.ValidateUpdate(&oldBinding))).To(BeTrue()) + }) + + It("does not allow updates on routing key", func() { + newBinding := Binding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "update-binding", + }, + Spec: BindingSpec{ + Source: "test", + Destination: "test", + DestinationType: "queue", + RoutingKey: "not-allowed", + RabbitmqClusterReference: RabbitmqClusterReference{ + Name: "some-cluster", + Namespace: "default", + }, + }, + } + Expect(apierrors.IsForbidden(newBinding.ValidateUpdate(&oldBinding))).To(BeTrue()) + }) + + It("does not allow updates on binding arguments", func() { + newBinding := Binding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "update-binding", + }, + Spec: BindingSpec{ + Source: "test", + Destination: "test", + DestinationType: "queue", + Arguments: &runtime.RawExtension{ + Raw: []byte(`{"new":"new-value"}`), + }, + RabbitmqClusterReference: RabbitmqClusterReference{ + Name: "some-cluster", + Namespace: "default", + }, + }, + } + Expect(apierrors.IsForbidden(newBinding.ValidateUpdate(&oldBinding))).To(BeTrue()) + }) + + It("does not allow updates on RabbitmqClusterReference", func() { + newBinding := Binding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "update-binding", + }, + Spec: BindingSpec{ + Source: "test", + Destination: "test", + DestinationType: "queue", + RabbitmqClusterReference: RabbitmqClusterReference{ + Name: "new-cluster", + Namespace: "default", + }, + }, + } + Expect(apierrors.IsForbidden(newBinding.ValidateUpdate(&oldBinding))).To(BeTrue()) + }) +}) diff --git a/system_tests/binding_system_tests.go b/system_tests/binding_system_tests.go index b6875f1d..9c203f8f 100644 --- a/system_tests/binding_system_tests.go +++ b/system_tests/binding_system_tests.go @@ -124,5 +124,11 @@ var _ = Describe("Binding", func() { By("setting status.observedGeneration") Expect(updatedBinding.Status.ObservedGeneration).To(Equal(updatedBinding.GetGeneration())) + + By("not allowing updates on binding.spec") + updateBinding := topologyv1alpha1.Binding{} + Expect(k8sClient.Get(ctx, types.NamespacedName{Name: binding.Name, Namespace: binding.Namespace}, &updateBinding)).To(Succeed()) + updatedBinding.Spec.RoutingKey = "new-key" + Expect(k8sClient.Update(ctx, &updatedBinding).Error()).To(ContainSubstring("spec: Forbidden: binding.spec is immutable")) }) }) From 74336755eedc560b3d1a18931f77119601266237 Mon Sep 17 00:00:00 2001 From: Chunyi Lyu Date: Wed, 17 Mar 2021 15:27:04 +0000 Subject: [PATCH 3/7] Include cert manager as an installation requirement --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2d5cce05..c864cf8d 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,9 @@ Kubernetes operator to manage [RabbitMQ](https://www.rabbitmq.com/) messaging to Before deploying Messaging Topology Operator, you need to have: 1. A Running k8s cluster -2. RabbitMQ [Cluster Operator](https://github.com/rabbitmq/cluster-operator) installed in the k8s cluster -3. A [RabbitMQ cluster](https://github.com/rabbitmq/cluster-operator/tree/main/docs/examples) deployed using the Cluster Operator +2. [Cert Manager](https://cert-manager.io/docs/installation/kubernetes/) installed in the k8s cluster +3. RabbitMQ [Cluster Operator](https://github.com/rabbitmq/cluster-operator) installed in the k8s cluster +4. A [RabbitMQ cluster](https://github.com/rabbitmq/cluster-operator/tree/main/docs/examples) deployed using the Cluster Operator If you have `kubectl` configured to access your running k8s cluster, you can then run the following command to install the Messaging Topology Operator: From 9cbea51aa100065f38549348c64482d38083970e Mon Sep 17 00:00:00 2001 From: Chunyi Lyu Date: Wed, 17 Mar 2021 15:41:10 +0000 Subject: [PATCH 4/7] Simplify binding webhook unit test --- api/v1alpha1/binding_webhook_test.go | 108 ++++++--------------------- main.go | 1 - system_tests/utils.go | 2 +- 3 files changed, 22 insertions(+), 89 deletions(-) diff --git a/api/v1alpha1/binding_webhook_test.go b/api/v1alpha1/binding_webhook_test.go index d739a3c5..e4b85f89 100644 --- a/api/v1alpha1/binding_webhook_test.go +++ b/api/v1alpha1/binding_webhook_test.go @@ -15,6 +15,7 @@ var _ = Describe("Binding webhook", func() { Name: "update-binding", }, Spec: BindingSpec{ + Vhost: "/test", Source: "test", Destination: "test", DestinationType: "queue", @@ -25,114 +26,47 @@ var _ = Describe("Binding webhook", func() { }, } + It("does not allow updates on vhost", func() { + newBinding := oldBinding.DeepCopy() + newBinding.Spec.Vhost = "/new-vhost" + Expect(apierrors.IsForbidden(newBinding.ValidateUpdate(&oldBinding))).To(BeTrue()) + }) + It("does not allow updates on source", func() { - newBinding := Binding{ - ObjectMeta: metav1.ObjectMeta{ - Name: "update-binding", - }, - Spec: BindingSpec{ - Source: "updated-source", - Destination: "test", - DestinationType: "queue", - RabbitmqClusterReference: RabbitmqClusterReference{ - Name: "some-cluster", - Namespace: "default", - }, - }, - } + newBinding := oldBinding.DeepCopy() + newBinding.Spec.Source = "updated-source" Expect(apierrors.IsForbidden(newBinding.ValidateUpdate(&oldBinding))).To(BeTrue()) }) It("does not allow updates on destination", func() { - newBinding := Binding{ - ObjectMeta: metav1.ObjectMeta{ - Name: "update-binding", - }, - Spec: BindingSpec{ - Source: "test", - Destination: "updated-des", - DestinationType: "queue", - RabbitmqClusterReference: RabbitmqClusterReference{ - Name: "some-cluster", - Namespace: "default", - }, - }, - } + newBinding := oldBinding.DeepCopy() + newBinding.Spec.Destination = "updated-des" Expect(apierrors.IsForbidden(newBinding.ValidateUpdate(&oldBinding))).To(BeTrue()) }) It("does not allow updates on destination type", func() { - newBinding := Binding{ - ObjectMeta: metav1.ObjectMeta{ - Name: "update-binding", - }, - Spec: BindingSpec{ - Source: "test", - Destination: "test", - DestinationType: "exchange", - RabbitmqClusterReference: RabbitmqClusterReference{ - Name: "some-cluster", - Namespace: "default", - }, - }, - } + newBinding := oldBinding.DeepCopy() + newBinding.Spec.DestinationType = "exchange" Expect(apierrors.IsForbidden(newBinding.ValidateUpdate(&oldBinding))).To(BeTrue()) }) It("does not allow updates on routing key", func() { - newBinding := Binding{ - ObjectMeta: metav1.ObjectMeta{ - Name: "update-binding", - }, - Spec: BindingSpec{ - Source: "test", - Destination: "test", - DestinationType: "queue", - RoutingKey: "not-allowed", - RabbitmqClusterReference: RabbitmqClusterReference{ - Name: "some-cluster", - Namespace: "default", - }, - }, - } + newBinding := oldBinding.DeepCopy() + newBinding.Spec.RoutingKey = "not-allowed" Expect(apierrors.IsForbidden(newBinding.ValidateUpdate(&oldBinding))).To(BeTrue()) }) It("does not allow updates on binding arguments", func() { - newBinding := Binding{ - ObjectMeta: metav1.ObjectMeta{ - Name: "update-binding", - }, - Spec: BindingSpec{ - Source: "test", - Destination: "test", - DestinationType: "queue", - Arguments: &runtime.RawExtension{ - Raw: []byte(`{"new":"new-value"}`), - }, - RabbitmqClusterReference: RabbitmqClusterReference{ - Name: "some-cluster", - Namespace: "default", - }, - }, - } + newBinding := oldBinding.DeepCopy() + newBinding.Spec.Arguments = &runtime.RawExtension{Raw: []byte(`{"new":"new-value"}`)} Expect(apierrors.IsForbidden(newBinding.ValidateUpdate(&oldBinding))).To(BeTrue()) }) It("does not allow updates on RabbitmqClusterReference", func() { - newBinding := Binding{ - ObjectMeta: metav1.ObjectMeta{ - Name: "update-binding", - }, - Spec: BindingSpec{ - Source: "test", - Destination: "test", - DestinationType: "queue", - RabbitmqClusterReference: RabbitmqClusterReference{ - Name: "new-cluster", - Namespace: "default", - }, - }, + newBinding := oldBinding.DeepCopy() + newBinding.Spec.RabbitmqClusterReference = RabbitmqClusterReference{ + Name: "new-cluster", + Namespace: "default", } Expect(apierrors.IsForbidden(newBinding.ValidateUpdate(&oldBinding))).To(BeTrue()) }) diff --git a/main.go b/main.go index 38adbe56..68fad4e2 100644 --- a/main.go +++ b/main.go @@ -44,7 +44,6 @@ func init() { _ = rabbitmqv1beta1.AddToScheme(scheme) _ = topologyv1alpha1.AddToScheme(scheme) - _ = rabbitmqcomv1alpha1.AddToScheme(scheme) // +kubebuilder:scaffold:scheme } diff --git a/system_tests/utils.go b/system_tests/utils.go index 71a8f435..27a5cb89 100644 --- a/system_tests/utils.go +++ b/system_tests/utils.go @@ -16,8 +16,8 @@ import ( rabbitmqv1beta1 "github.com/rabbitmq/cluster-operator/api/v1beta1" "github.com/rabbitmq/messaging-topology-operator/api/v1alpha1" corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" From aec609df53403af68831fe4b390221627c97df86 Mon Sep 17 00:00:00 2001 From: Chunyi Lyu Date: Wed, 17 Mar 2021 15:43:16 +0000 Subject: [PATCH 5/7] Specify cert-manager version --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c864cf8d..aefc6a5f 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Kubernetes operator to manage [RabbitMQ](https://www.rabbitmq.com/) messaging to Before deploying Messaging Topology Operator, you need to have: 1. A Running k8s cluster -2. [Cert Manager](https://cert-manager.io/docs/installation/kubernetes/) installed in the k8s cluster +2. [cert-manager](https://cert-manager.io/docs/installation/kubernetes/) `1.2.0` or above, installed in the k8s cluster 3. RabbitMQ [Cluster Operator](https://github.com/rabbitmq/cluster-operator) installed in the k8s cluster 4. A [RabbitMQ cluster](https://github.com/rabbitmq/cluster-operator/tree/main/docs/examples) deployed using the Cluster Operator From 7f9948b97e8b00691322f332429b707096722b6b Mon Sep 17 00:00:00 2001 From: Chunyi Lyu Date: Wed, 17 Mar 2021 15:54:16 +0000 Subject: [PATCH 6/7] Install cert-manager in PR workflow --- .github/workflows/pr.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 0bd33df2..0761faa4 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -33,6 +33,7 @@ jobs: export PATH="$PATH:$GOPATH/bin" make install-tools kind create cluster --image kindest/node:"$K8S_VERSION" + make cert-manager make cluster-operator DOCKER_REGISTRY_SERVER=local-server OPERATOR_IMAGE=local-operator make deploy-kind make system-tests From 03fb332422173d659a0fbcde472a674749efa509 Mon Sep 17 00:00:00 2001 From: Chunyi Lyu Date: Thu, 18 Mar 2021 10:49:15 +0000 Subject: [PATCH 7/7] Add a note that cert-manager is optional - will add more detailed documentation about how to install without cert-manager as part of: https://github.com/rabbitmq/messaging-topology-operator/issues/73 --- README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index aefc6a5f..7d716e10 100644 --- a/README.md +++ b/README.md @@ -9,9 +9,9 @@ Kubernetes operator to manage [RabbitMQ](https://www.rabbitmq.com/) messaging to Before deploying Messaging Topology Operator, you need to have: 1. A Running k8s cluster -2. [cert-manager](https://cert-manager.io/docs/installation/kubernetes/) `1.2.0` or above, installed in the k8s cluster -3. RabbitMQ [Cluster Operator](https://github.com/rabbitmq/cluster-operator) installed in the k8s cluster -4. A [RabbitMQ cluster](https://github.com/rabbitmq/cluster-operator/tree/main/docs/examples) deployed using the Cluster Operator +2. RabbitMQ [Cluster Operator](https://github.com/rabbitmq/cluster-operator) installed in the k8s cluster +3. A [RabbitMQ cluster](https://github.com/rabbitmq/cluster-operator/tree/main/docs/examples) deployed using the Cluster Operator +4. (Optional) [cert-manager](https://cert-manager.io/docs/installation/kubernetes/) `1.2.0` or above, installed in the k8s cluster If you have `kubectl` configured to access your running k8s cluster, you can then run the following command to install the Messaging Topology Operator: @@ -28,6 +28,10 @@ You can create RabbitMQ resources: 5. [Vhost](./docs/examples/vhosts) 6. [Policy](./docs/examples/policies) +## Install without cert-manager + +If you do not have cert-manager in your k8s cluster, you need to generate certificates used by admission webhooks yourself and include them in the operator deployment, crds, and webhooks manifests. + ## Contributing This project follows the typical GitHub pull request model. Before starting any work, please either comment on an [existing issue](https://github.com/rabbitmq/messaging-topology-operator/issues), or file a new one.