Skip to content

Commit c3c5bca

Browse files
raukadahopenshift-merge-bot[bot]
authored andcommitted
Add webhook validation for empty database and rabbitmq
databaseInstance and rabbitMqClusterName are required fields. If an user specify databaseInstance and rabbitMqClusterName field as empty string. The webhook should fail it saying as there cannot be empty. This pr adds the validations for the same. Jira: https://issues.redhat.com/browse/OSPRH-11933 Signed-off-by: Chandan Kumar (raukadah) <[email protected]>
1 parent 2f7815b commit c3c5bca

File tree

5 files changed

+102
-17
lines changed

5 files changed

+102
-17
lines changed

api/v1beta1/common_types.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ type WatcherTemplate struct {
6767
// +kubebuilder:default=rabbitmq
6868
// RabbitMQ instance name
6969
// Needed to request a transportURL that is created and used in Watcher
70-
RabbitMqClusterName string `json:"rabbitMqClusterName"`
70+
RabbitMqClusterName *string `json:"rabbitMqClusterName"`
7171

7272
// +kubebuilder:validation:Optional
7373
// +kubebuilder:default=osp-secret
@@ -77,7 +77,7 @@ type WatcherTemplate struct {
7777
// +kubebuilder:validation:Required
7878
// MariaDB instance name
7979
// Required to use the mariadb-operator instance to create the DB and user
80-
DatabaseInstance string `json:"databaseInstance"`
80+
DatabaseInstance *string `json:"databaseInstance"`
8181

8282
// +kubebuilder:validation:Optional
8383
// +kubebuilder:default=watcher

api/v1beta1/watcher_webhook.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ limitations under the License.
1717
package v1beta1
1818

1919
import (
20+
"errors"
21+
2022
"k8s.io/apimachinery/pkg/runtime"
2123
logf "sigs.k8s.io/controller-runtime/pkg/log"
2224
"sigs.k8s.io/controller-runtime/pkg/webhook"
@@ -64,13 +66,29 @@ var _ webhook.Validator = &Watcher{}
6466
func (r *Watcher) ValidateCreate() (admission.Warnings, error) {
6567
watcherlog.Info("validate create", "name", r.Name)
6668

69+
if *r.Spec.DatabaseInstance == "" || r.Spec.DatabaseInstance == nil {
70+
return nil, errors.New("databaseInstance field should not be empty")
71+
}
72+
73+
if *r.Spec.RabbitMqClusterName == "" || r.Spec.RabbitMqClusterName == nil {
74+
return nil, errors.New("rabbitMqClusterName field should not be empty")
75+
}
76+
6777
return nil, nil
6878
}
6979

7080
// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type
7181
func (r *Watcher) ValidateUpdate(runtime.Object) (admission.Warnings, error) {
7282
watcherlog.Info("validate update", "name", r.Name)
7383

84+
if *r.Spec.DatabaseInstance == "" || r.Spec.DatabaseInstance == nil {
85+
return nil, errors.New("databaseInstance field should not be empty")
86+
}
87+
88+
if *r.Spec.RabbitMqClusterName == "" || r.Spec.RabbitMqClusterName == nil {
89+
return nil, errors.New("rabbitMqClusterName field should not be empty")
90+
}
91+
7492
return nil, nil
7593
}
7694

api/v1beta1/zz_generated.deepcopy.go

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

controllers/watcher_controller.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -457,11 +457,11 @@ func (r *WatcherReconciler) ensureDB(
457457
// create watcher DB instance
458458
//
459459
db := mariadbv1.NewDatabaseForAccount(
460-
instance.Spec.DatabaseInstance, // mariadb/galera service to target
461-
watcher.DatabaseName, // name used in CREATE DATABASE in mariadb
462-
watcher.DatabaseCRName, // CR name for MariaDBDatabase
463-
instance.Spec.DatabaseAccount, // CR name for MariaDBAccount
464-
instance.Namespace, // namespace
460+
*instance.Spec.DatabaseInstance, // mariadb/galera service to target
461+
watcher.DatabaseName, // name used in CREATE DATABASE in mariadb
462+
watcher.DatabaseCRName, // CR name for MariaDBDatabase
463+
instance.Spec.DatabaseAccount, // CR name for MariaDBAccount
464+
instance.Namespace, // namespace
465465
)
466466

467467
// create or patch the DB
@@ -528,7 +528,7 @@ func (r *WatcherReconciler) ensureMQ(
528528
}
529529

530530
op, err := controllerutil.CreateOrUpdate(ctx, r.Client, transportURL, func() error {
531-
transportURL.Spec.RabbitmqClusterName = instance.Spec.RabbitMqClusterName
531+
transportURL.Spec.RabbitmqClusterName = *instance.Spec.RabbitMqClusterName
532532

533533
err := controllerutil.SetControllerReference(instance, transportURL, r.Scheme)
534534
return err

tests/functional/watcher_controller_test.go

Lines changed: 66 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@ import (
1515
mariadbv1 "github.com/openstack-k8s-operators/mariadb-operator/api/v1beta1"
1616
watcherv1beta1 "github.com/openstack-k8s-operators/watcher-operator/api/v1beta1"
1717
corev1 "k8s.io/api/core/v1"
18+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
1819
"k8s.io/apimachinery/pkg/fields"
1920
"k8s.io/apimachinery/pkg/types"
2021
"k8s.io/utils/ptr"
2122
"sigs.k8s.io/controller-runtime/pkg/client"
23+
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
2224
)
2325

2426
var (
@@ -42,11 +44,11 @@ var _ = Describe("Watcher controller with minimal spec values", func() {
4244

4345
It("should have the Spec fields defaulted", func() {
4446
Watcher := GetWatcher(watcherTest.Instance)
45-
Expect(Watcher.Spec.DatabaseInstance).Should(Equal("openstack"))
47+
Expect(*(Watcher.Spec.DatabaseInstance)).Should(Equal("openstack"))
4648
Expect(Watcher.Spec.DatabaseAccount).Should(Equal("watcher"))
4749
Expect(Watcher.Spec.Secret).Should(Equal("osp-secret"))
4850
Expect(Watcher.Spec.PasswordSelectors).Should(Equal(watcherv1beta1.PasswordSelector{Service: "WatcherPassword"}))
49-
Expect(Watcher.Spec.RabbitMqClusterName).Should(Equal("rabbitmq"))
51+
Expect(*(Watcher.Spec.RabbitMqClusterName)).Should(Equal("rabbitmq"))
5052
Expect(Watcher.Spec.ServiceUser).Should(Equal("watcher"))
5153
Expect(Watcher.Spec.PreserveJobs).Should(BeFalse())
5254
})
@@ -84,11 +86,11 @@ var _ = Describe("Watcher controller", func() {
8486

8587
It("should have the Spec fields defaulted", func() {
8688
Watcher := GetWatcher(watcherTest.Instance)
87-
Expect(Watcher.Spec.DatabaseInstance).Should(Equal("openstack"))
89+
Expect(*(Watcher.Spec.DatabaseInstance)).Should(Equal("openstack"))
8890
Expect(Watcher.Spec.DatabaseAccount).Should(Equal("watcher"))
8991
Expect(Watcher.Spec.ServiceUser).Should(Equal("watcher"))
9092
Expect(Watcher.Spec.Secret).Should(Equal("test-osp-secret"))
91-
Expect(Watcher.Spec.RabbitMqClusterName).Should(Equal("rabbitmq"))
93+
Expect(*(Watcher.Spec.RabbitMqClusterName)).Should(Equal("rabbitmq"))
9294
Expect(Watcher.Spec.PreserveJobs).Should(BeFalse())
9395
})
9496

@@ -197,7 +199,7 @@ var _ = Describe("Watcher controller", func() {
197199
mariadb.DeleteDBService,
198200
mariadb.CreateDBService(
199201
watcherTest.Instance.Namespace,
200-
GetWatcher(watcherTest.Instance).Spec.DatabaseInstance,
202+
*GetWatcher(watcherTest.Instance).Spec.DatabaseInstance,
201203
corev1.ServiceSpec{
202204
Ports: []corev1.ServicePort{{Port: 3306}},
203205
},
@@ -459,7 +461,7 @@ var _ = Describe("Watcher controller", func() {
459461
mariadb.DeleteDBService,
460462
mariadb.CreateDBService(
461463
watcherTest.Instance.Namespace,
462-
GetWatcher(watcherTest.Instance).Spec.DatabaseInstance,
464+
*GetWatcher(watcherTest.Instance).Spec.DatabaseInstance,
463465
corev1.ServiceSpec{
464466
Ports: []corev1.ServicePort{{Port: 3306}},
465467
},
@@ -531,6 +533,61 @@ var _ = Describe("Watcher controller", func() {
531533
Expect(Watcher.Spec.ApplierContainerImageURL).To(Equal("watcher-applier-custom-image-env"))
532534
})
533535
})
536+
537+
When("Watcher rejects when empty databaseinstance is used", func() {
538+
It("should raise an error for empty databaseInstance", func() {
539+
spec := GetDefaultWatcherAPISpec()
540+
spec["databaseInstance"] = ""
541+
542+
raw := map[string]interface{}{
543+
"apiVersion": "watcher.openstack.org/v1beta1",
544+
"kind": "watcher",
545+
"metadata": map[string]interface{}{
546+
"name": watcherName.Name,
547+
"namespace": watcherName.Namespace,
548+
},
549+
"spec": spec,
550+
}
551+
552+
unstructuredObj := &unstructured.Unstructured{Object: raw}
553+
_, err := controllerutil.CreateOrPatch(
554+
th.Ctx, th.K8sClient, unstructuredObj, func() error { return nil })
555+
Expect(err).To(HaveOccurred())
556+
Expect(err.Error()).To(
557+
ContainSubstring(
558+
"admission webhook \"vwatcher.kb.io\" denied the request: " +
559+
"databaseInstance field should not be empty"),
560+
)
561+
562+
})
563+
})
564+
565+
When("Watcher is created with empty RabbitMqClusterName", func() {
566+
It("should raise an error for empty RabbitMqClusterName", func() {
567+
spec := GetDefaultWatcherAPISpec()
568+
spec["rabbitMqClusterName"] = ""
569+
570+
raw := map[string]interface{}{
571+
"apiVersion": "watcher.openstack.org/v1beta1",
572+
"kind": "watcher",
573+
"metadata": map[string]interface{}{
574+
"name": watcherName.Name,
575+
"namespace": watcherName.Namespace,
576+
},
577+
"spec": spec,
578+
}
579+
580+
unstructuredObj := &unstructured.Unstructured{Object: raw}
581+
_, err := controllerutil.CreateOrPatch(
582+
th.Ctx, th.K8sClient, unstructuredObj, func() error { return nil })
583+
Expect(err).To(HaveOccurred())
584+
Expect(err.Error()).To(
585+
ContainSubstring(
586+
"admission webhook \"vwatcher.kb.io\" denied the request: " +
587+
"rabbitMqClusterName field should not be empty"),
588+
)
589+
})
590+
})
534591
When("Watcher with non-default values are created", func() {
535592
BeforeEach(func() {
536593
DeferCleanup(th.DeleteInstance, CreateWatcher(watcherTest.Instance, GetNonDefaultWatcherSpec()))
@@ -546,7 +603,7 @@ var _ = Describe("Watcher controller", func() {
546603
mariadb.DeleteDBService,
547604
mariadb.CreateDBService(
548605
watcherTest.Instance.Namespace,
549-
GetWatcher(watcherTest.Instance).Spec.DatabaseInstance,
606+
*GetWatcher(watcherTest.Instance).Spec.DatabaseInstance,
550607
corev1.ServiceSpec{
551608
Ports: []corev1.ServicePort{{Port: 3306}},
552609
},
@@ -557,12 +614,12 @@ var _ = Describe("Watcher controller", func() {
557614

558615
It("should have the Spec fields with the expected values", func() {
559616
Watcher := GetWatcher(watcherTest.Instance)
560-
Expect(Watcher.Spec.DatabaseInstance).Should(Equal("fakeopenstack"))
617+
Expect(*(Watcher.Spec.DatabaseInstance)).Should(Equal("fakeopenstack"))
561618
Expect(Watcher.Spec.DatabaseAccount).Should(Equal("watcher"))
562619
Expect(Watcher.Spec.ServiceUser).Should(Equal("fakeuser"))
563620
Expect(Watcher.Spec.Secret).Should(Equal("test-osp-secret"))
564621
Expect(Watcher.Spec.PreserveJobs).Should(BeTrue())
565-
Expect(Watcher.Spec.RabbitMqClusterName).Should(Equal("rabbitmq"))
622+
Expect(*(Watcher.Spec.RabbitMqClusterName)).Should(Equal("rabbitmq"))
566623
})
567624

568625
It("Should create watcher service with custom values", func() {

0 commit comments

Comments
 (0)