diff --git a/PROJECT b/PROJECT index 0a2974be8..42684d984 100644 --- a/PROJECT +++ b/PROJECT @@ -309,7 +309,7 @@ resources: path: github.com/instaclustr/operator/apis/clusterresources/v1beta1 version: v1beta1 webhooks: - defaulting: true + validation: true webhookVersion: v1 - api: crdVersion: v1 diff --git a/apis/clusterresources/v1beta1/postgresqluser_webhook.go b/apis/clusterresources/v1beta1/postgresqluser_webhook.go new file mode 100644 index 000000000..c4a5733ef --- /dev/null +++ b/apis/clusterresources/v1beta1/postgresqluser_webhook.go @@ -0,0 +1,70 @@ +/* +Copyright 2022. + +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 v1beta1 + +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" + + "github.com/instaclustr/operator/pkg/models" +) + +var postgresqluserlog = logf.Log.WithName("postgresqluser-resource") + +func (u *PostgreSQLUser) SetupWebhookWithManager(mgr ctrl.Manager) error { + return ctrl.NewWebhookManagedBy(mgr). + For(u). + Complete() +} + +// TODO(user): change verbs to "verbs=create;update;delete" if you want to enable deletion validation. +//+kubebuilder:webhook:path=/validate-clusterresources-instaclustr-com-v1beta1-postgresqluser,mutating=false,failurePolicy=fail,sideEffects=None,groups=clusterresources.instaclustr.com,resources=postgresqlusers,verbs=create;update,versions=v1beta1,name=vpostgresqluser.kb.io,admissionReviewVersions=v1 + +var _ webhook.Validator = &PostgreSQLUser{} + +// ValidateCreate implements webhook.Validator so a webhook will be registered for the type +func (u *PostgreSQLUser) ValidateCreate() error { + postgresqluserlog.Info("validate create", "name", u.Name) + + if u.Spec.SecretRef.Name == "" || u.Spec.SecretRef.Namespace == "" { + return models.ErrEmptySecretRef + } + + return nil +} + +// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type +func (u *PostgreSQLUser) ValidateUpdate(old runtime.Object) error { + postgresqluserlog.Info("validate update", "name", u.Name) + + oldUser := old.(*PostgreSQLUser) + if *u.Spec.SecretRef != *oldUser.Spec.SecretRef { + return models.ErrImmutableSecretRef + } + + return nil +} + +// ValidateDelete implements webhook.Validator so a webhook will be registered for the type +func (u *PostgreSQLUser) ValidateDelete() error { + postgresqluserlog.Info("validate delete", "name", u.Name) + + // TODO(user): fill in your validation logic upon object deletion. + return nil +} diff --git a/apis/clusterresources/v1beta1/webhook_suite_test.go b/apis/clusterresources/v1beta1/webhook_suite_test.go index 79c3b373f..b8682394b 100644 --- a/apis/clusterresources/v1beta1/webhook_suite_test.go +++ b/apis/clusterresources/v1beta1/webhook_suite_test.go @@ -138,6 +138,9 @@ var _ = BeforeSuite(func() { err = (&ClusterBackup{}).SetupWebhookWithManager(mgr) Expect(err).NotTo(HaveOccurred()) + err = (&PostgreSQLUser{}).SetupWebhookWithManager(mgr) + Expect(err).NotTo(HaveOccurred()) + //+kubebuilder:scaffold:webhook go func() { diff --git a/config/webhook/manifests.yaml b/config/webhook/manifests.yaml index 9eb1e4c30..6fe20607d 100644 --- a/config/webhook/manifests.yaml +++ b/config/webhook/manifests.yaml @@ -672,6 +672,26 @@ webhooks: resources: - opensearchusers sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /validate-clusterresources-instaclustr-com-v1beta1-postgresqluser + failurePolicy: Fail + name: vpostgresqluser.kb.io + rules: + - apiGroups: + - clusterresources.instaclustr.com + apiVersions: + - v1beta1 + operations: + - CREATE + - UPDATE + resources: + - postgresqlusers + sideEffects: None - admissionReviewVersions: - v1 clientConfig: diff --git a/controllers/clusterresources/postgresqluser_controller.go b/controllers/clusterresources/postgresqluser_controller.go index 601627e1d..505c8882e 100644 --- a/controllers/clusterresources/postgresqluser_controller.go +++ b/controllers/clusterresources/postgresqluser_controller.go @@ -291,7 +291,6 @@ func (r *PostgreSQLUserReconciler) createUser( } // TODO: Handle scenario if there are no nodes with external IP, check private/public cluster - for _, node := range nodeList.Items { for _, nodeAddress := range node.Status.Addresses { if nodeAddress.Type == k8sCore.NodeExternalIP { diff --git a/controllers/clusters/cassandra_controller.go b/controllers/clusters/cassandra_controller.go index 02de8700c..fb8ddd35e 100644 --- a/controllers/clusters/cassandra_controller.go +++ b/controllers/clusters/cassandra_controller.go @@ -229,13 +229,13 @@ func (r *CassandraReconciler) handleCreateCluster( l.Error(err, "Cannot start cluster status job", "cassandra cluster ID", cassandra.Status.ID) - r.EventRecorder.Eventf( - cassandra, models.Warning, models.CreationFailed, - "Cluster status check job is failed. Reason: %v", - err, - ) - return reconcile.Result{}, err - } + r.EventRecorder.Eventf( + cassandra, models.Warning, models.CreationFailed, + "Cluster status check job is failed. Reason: %v", + err, + ) + return reconcile.Result{}, err + } r.EventRecorder.Eventf( cassandra, models.Normal, models.Created, @@ -248,13 +248,13 @@ func (r *CassandraReconciler) handleCreateCluster( "cluster ID", cassandra.Status.ID, ) - r.EventRecorder.Eventf( - cassandra, models.Warning, models.CreationFailed, - "Cluster backups check job is failed. Reason: %v", - err, - ) - return reconcile.Result{}, err - } + r.EventRecorder.Eventf( + cassandra, models.Warning, models.CreationFailed, + "Cluster backups check job is failed. Reason: %v", + err, + ) + return reconcile.Result{}, err + } r.EventRecorder.Eventf( cassandra, models.Normal, models.Created, diff --git a/main.go b/main.go index ac0ecfd6c..f1854f6eb 100644 --- a/main.go +++ b/main.go @@ -483,6 +483,10 @@ func main() { setupLog.Error(err, "unable to create webhook", "webhook", "ClusterBackup") os.Exit(1) } + if err = (&clusterresourcesv1beta1.PostgreSQLUser{}).SetupWebhookWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create webhook", "webhook", "PostgreSQLUser") + os.Exit(1) + } //+kubebuilder:scaffold:builder if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {