feat(storage): prepare custom resource for storage API
This commit is contained in:
parent
d02e2d4653
commit
b55afea477
34 changed files with 1110 additions and 369 deletions
|
@ -63,44 +63,32 @@ func (d *CoreCustomDefaulter) Default(ctx context.Context, obj runtime.Object) e
|
|||
return fmt.Errorf("ensuring JWT secret: %w", err)
|
||||
}
|
||||
|
||||
// TODO copy plain text DSN to secret if present
|
||||
|
||||
corelog.Info("Defaulting database roles")
|
||||
if !core.Spec.Database.Roles.SelfManaged {
|
||||
const roleCredsSecretNameTemplate = "db-roles-creds-%s"
|
||||
if core.Spec.Database.Roles.Secrets.Admin == nil {
|
||||
const roleCredsSecretNameTemplate = "%s-db-creds-%s"
|
||||
if core.Spec.Database.Roles.Secrets.Admin == "" {
|
||||
corelog.Info("Defaulting role", "role_name", supabase.DBRoleSupabaseAdmin)
|
||||
core.Spec.Database.Roles.Secrets.Admin = &corev1.LocalObjectReference{
|
||||
Name: fmt.Sprintf(roleCredsSecretNameTemplate, supabase.DBRoleSupabaseAdmin.K8sString()),
|
||||
}
|
||||
core.Spec.Database.Roles.Secrets.Admin = fmt.Sprintf(roleCredsSecretNameTemplate, core.Name, supabase.DBRoleSupabaseAdmin.K8sString())
|
||||
}
|
||||
|
||||
if core.Spec.Database.Roles.Secrets.Authenticator == nil {
|
||||
if core.Spec.Database.Roles.Secrets.Authenticator == "" {
|
||||
corelog.Info("Defaulting role", "role_name", supabase.DBRoleAuthenticator)
|
||||
core.Spec.Database.Roles.Secrets.Authenticator = &corev1.LocalObjectReference{
|
||||
Name: fmt.Sprintf(roleCredsSecretNameTemplate, supabase.DBRoleAuthenticator.K8sString()),
|
||||
}
|
||||
core.Spec.Database.Roles.Secrets.Authenticator = fmt.Sprintf(roleCredsSecretNameTemplate, core.Name, supabase.DBRoleAuthenticator.K8sString())
|
||||
}
|
||||
|
||||
if core.Spec.Database.Roles.Secrets.AuthAdmin == nil {
|
||||
if core.Spec.Database.Roles.Secrets.AuthAdmin == "" {
|
||||
corelog.Info("Defaulting role", "role_name", supabase.DBRoleAuthAdmin)
|
||||
core.Spec.Database.Roles.Secrets.AuthAdmin = &corev1.LocalObjectReference{
|
||||
Name: fmt.Sprintf(roleCredsSecretNameTemplate, supabase.DBRoleAuthAdmin.K8sString()),
|
||||
}
|
||||
core.Spec.Database.Roles.Secrets.AuthAdmin = fmt.Sprintf(roleCredsSecretNameTemplate, core.Name, supabase.DBRoleAuthAdmin.K8sString())
|
||||
}
|
||||
|
||||
if core.Spec.Database.Roles.Secrets.FunctionsAdmin == nil {
|
||||
if core.Spec.Database.Roles.Secrets.FunctionsAdmin == "" {
|
||||
corelog.Info("Defaulting role", "role_name", supabase.DBRoleFunctionsAdmin)
|
||||
core.Spec.Database.Roles.Secrets.FunctionsAdmin = &corev1.LocalObjectReference{
|
||||
Name: fmt.Sprintf(roleCredsSecretNameTemplate, supabase.DBRoleFunctionsAdmin.K8sString()),
|
||||
}
|
||||
core.Spec.Database.Roles.Secrets.FunctionsAdmin = fmt.Sprintf(roleCredsSecretNameTemplate, core.Name, supabase.DBRoleFunctionsAdmin.K8sString())
|
||||
}
|
||||
|
||||
if core.Spec.Database.Roles.Secrets.StorageAdmin == nil {
|
||||
if core.Spec.Database.Roles.Secrets.StorageAdmin == "" {
|
||||
corelog.Info("Defaulting role", "role_name", supabase.DBRoleStorageAdmin)
|
||||
core.Spec.Database.Roles.Secrets.StorageAdmin = &corev1.LocalObjectReference{
|
||||
Name: fmt.Sprintf(roleCredsSecretNameTemplate, supabase.DBRoleStorageAdmin.K8sString()),
|
||||
}
|
||||
core.Spec.Database.Roles.Secrets.StorageAdmin = fmt.Sprintf(roleCredsSecretNameTemplate, core.Name, supabase.DBRoleStorageAdmin.K8sString())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,10 +102,8 @@ func (d *CoreCustomDefaulter) defaultJWT(ctx context.Context, core *supabasev1al
|
|||
core.Spec.JWT = new(supabasev1alpha1.CoreJwtSpec)
|
||||
}
|
||||
|
||||
if core.Spec.JWT.SecretRef == nil {
|
||||
core.Spec.JWT.SecretRef = &corev1.LocalObjectReference{
|
||||
Name: supabase.ServiceConfig.JWT.ObjectName(core),
|
||||
}
|
||||
if core.Spec.JWT.SecretName == "" {
|
||||
core.Spec.JWT.SecretName = supabase.ServiceConfig.JWT.ObjectName(core)
|
||||
}
|
||||
|
||||
if core.Spec.JWT.SecretKey == "" {
|
||||
|
@ -138,7 +124,7 @@ func (d *CoreCustomDefaulter) defaultJWT(ctx context.Context, core *supabasev1al
|
|||
|
||||
jwtSecret := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: core.Spec.JWT.SecretRef.Name,
|
||||
Name: core.Spec.JWT.SecretName,
|
||||
Namespace: core.Namespace,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -127,47 +127,47 @@ func (v *CoreCustomValidator) validateDb(
|
|||
}
|
||||
}
|
||||
|
||||
if authenticator := dbSpec.Roles.Secrets.Authenticator; authenticator == nil {
|
||||
if authenticator := dbSpec.Roles.Secrets.Authenticator; authenticator == "" {
|
||||
return warnings, fmt.Errorf("%w: %s", ErrManagedCredentialsNotSpecified, supabase.DBRoleAuthenticator)
|
||||
} else {
|
||||
exists, err := doesSecretExists(ctx, authenticator.Name)
|
||||
exists, err := doesSecretExists(ctx, authenticator)
|
||||
if err != nil {
|
||||
return warnings, err
|
||||
} else if !exists {
|
||||
return warnings, fmt.Errorf("%w: %s", ErrManagedCredentialsSecretMissing, authenticator.Name)
|
||||
return warnings, fmt.Errorf("%w: %s", ErrManagedCredentialsSecretMissing, authenticator)
|
||||
}
|
||||
}
|
||||
|
||||
if authAdmin := dbSpec.Roles.Secrets.AuthAdmin; authAdmin == nil {
|
||||
if authAdmin := dbSpec.Roles.Secrets.AuthAdmin; authAdmin == "" {
|
||||
return warnings, fmt.Errorf("%w: %s", ErrManagedCredentialsNotSpecified, supabase.DBRoleAuthAdmin)
|
||||
} else {
|
||||
exists, err := doesSecretExists(ctx, authAdmin.Name)
|
||||
exists, err := doesSecretExists(ctx, authAdmin)
|
||||
if err != nil {
|
||||
return warnings, err
|
||||
} else if !exists {
|
||||
return warnings, fmt.Errorf("%w: %s", ErrManagedCredentialsSecretMissing, authAdmin.Name)
|
||||
return warnings, fmt.Errorf("%w: %s", ErrManagedCredentialsSecretMissing, authAdmin)
|
||||
}
|
||||
}
|
||||
|
||||
if functionsAdmin := dbSpec.Roles.Secrets.FunctionsAdmin; functionsAdmin == nil {
|
||||
if functionsAdmin := dbSpec.Roles.Secrets.FunctionsAdmin; functionsAdmin == "" {
|
||||
return warnings, fmt.Errorf("%w: %s", ErrManagedCredentialsNotSpecified, supabase.DBRoleFunctionsAdmin)
|
||||
} else {
|
||||
exists, err := doesSecretExists(ctx, functionsAdmin.Name)
|
||||
exists, err := doesSecretExists(ctx, functionsAdmin)
|
||||
if err != nil {
|
||||
return warnings, err
|
||||
} else if !exists {
|
||||
return warnings, fmt.Errorf("%w: %s", ErrManagedCredentialsSecretMissing, functionsAdmin.Name)
|
||||
return warnings, fmt.Errorf("%w: %s", ErrManagedCredentialsSecretMissing, functionsAdmin)
|
||||
}
|
||||
}
|
||||
|
||||
if storageAdmin := dbSpec.Roles.Secrets.StorageAdmin; storageAdmin == nil {
|
||||
if storageAdmin := dbSpec.Roles.Secrets.StorageAdmin; storageAdmin == "" {
|
||||
return warnings, fmt.Errorf("%w: %s", ErrManagedCredentialsNotSpecified, supabase.DBRoleStorageAdmin)
|
||||
} else {
|
||||
exists, err := doesSecretExists(ctx, storageAdmin.Name)
|
||||
exists, err := doesSecretExists(ctx, storageAdmin)
|
||||
if err != nil {
|
||||
return warnings, err
|
||||
} else if !exists {
|
||||
return warnings, fmt.Errorf("%w: %s", ErrManagedCredentialsSecretMissing, storageAdmin.Name)
|
||||
return warnings, fmt.Errorf("%w: %s", ErrManagedCredentialsSecretMissing, storageAdmin)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,3 +53,11 @@ func SetupDashboardWebhookWithManager(mgr ctrl.Manager) error {
|
|||
WithDefaulter(&DashboardCustomDefaulter{}).
|
||||
Complete()
|
||||
}
|
||||
|
||||
// SetupStorageWebhookWithManager registers the webhook for Storage in the manager.
|
||||
func SetupStorageWebhookWithManager(mgr ctrl.Manager) error {
|
||||
return ctrl.NewWebhookManagedBy(mgr).For(&supabasev1alpha1.Storage{}).
|
||||
WithValidator(&StorageCustomValidator{}).
|
||||
WithDefaulter(&StorageCustomDefaulter{Client: mgr.GetClient()}).
|
||||
Complete()
|
||||
}
|
||||
|
|
109
internal/webhook/v1alpha1/storage_webhook_defaulter.go
Normal file
109
internal/webhook/v1alpha1/storage_webhook_defaulter.go
Normal file
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
Copyright 2025 Peter Kurfer.
|
||||
|
||||
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 v1alpha1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"maps"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
"sigs.k8s.io/controller-runtime/pkg/webhook"
|
||||
|
||||
supabasev1alpha1 "code.icb4dc0.de/prskr/supabase-operator/api/v1alpha1"
|
||||
"code.icb4dc0.de/prskr/supabase-operator/internal/meta"
|
||||
"code.icb4dc0.de/prskr/supabase-operator/internal/pw"
|
||||
)
|
||||
|
||||
// +kubebuilder:webhook:path=/mutate-supabase-k8s-icb4dc0-de-v1alpha1-storage,mutating=true,failurePolicy=fail,sideEffects=None,groups=supabase.k8s.icb4dc0.de,resources=storages,verbs=create;update,versions=v1alpha1,name=mstorage-v1alpha1.kb.io,admissionReviewVersions=v1
|
||||
|
||||
// StorageCustomDefaulter struct is responsible for setting default values on the custom resource of the
|
||||
// Kind Storage when those are created or updated.
|
||||
//
|
||||
// NOTE: The +kubebuilder:object:generate=false marker prevents controller-gen from generating DeepCopy methods,
|
||||
// as it is used only for temporary operations and does not need to be deeply copied.
|
||||
type StorageCustomDefaulter struct {
|
||||
client.Client
|
||||
}
|
||||
|
||||
var _ webhook.CustomDefaulter = &StorageCustomDefaulter{}
|
||||
|
||||
// Default implements webhook.CustomDefaulter so a webhook will be registered for the Kind Storage.
|
||||
func (d *StorageCustomDefaulter) Default(ctx context.Context, obj runtime.Object) error {
|
||||
storage, ok := obj.(*supabasev1alpha1.Storage)
|
||||
|
||||
if !ok {
|
||||
return fmt.Errorf("expected an Storage object but got %T", obj)
|
||||
}
|
||||
storagelog.Info("Defaulting for Storage", "name", storage.GetName())
|
||||
|
||||
if err := d.defaultS3Protocol(ctx, storage); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *StorageCustomDefaulter) defaultS3Protocol(ctx context.Context, storage *supabasev1alpha1.Storage) error {
|
||||
if storage.Spec.S3 == nil {
|
||||
storage.Spec.S3 = new(supabasev1alpha1.S3ProtocolSpec)
|
||||
}
|
||||
|
||||
if storage.Spec.S3.CredentialsSecretRef == nil {
|
||||
storage.Spec.S3.CredentialsSecretRef = &supabasev1alpha1.S3CredentialsRef{
|
||||
AccessKeyIdKey: "accessKeyId",
|
||||
AccessSecretKeyKey: "secretAccessKey",
|
||||
SecretName: fmt.Sprintf("%s-storage-protocol-s3-credentials", storage.Name),
|
||||
}
|
||||
}
|
||||
|
||||
credentialsSecret := corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: storage.Spec.S3.CredentialsSecretRef.SecretName,
|
||||
Namespace: storage.Namespace,
|
||||
},
|
||||
}
|
||||
|
||||
_, err := controllerutil.CreateOrUpdate(ctx, d.Client, &credentialsSecret, func() error {
|
||||
credentialsSecret.Labels = maps.Clone(storage.Labels)
|
||||
if credentialsSecret.Labels == nil {
|
||||
credentialsSecret.Labels = make(map[string]string)
|
||||
}
|
||||
|
||||
credentialsSecret.Labels[meta.SupabaseLabel.Reload] = ""
|
||||
|
||||
if credentialsSecret.Data == nil {
|
||||
credentialsSecret.Data = make(map[string][]byte, 2)
|
||||
}
|
||||
|
||||
if _, ok := credentialsSecret.Data[storage.Spec.S3.CredentialsSecretRef.AccessKeyIdKey]; !ok {
|
||||
credentialsSecret.Data[storage.Spec.S3.CredentialsSecretRef.AccessKeyIdKey] = pw.GeneratePW(32, nil)
|
||||
}
|
||||
|
||||
if _, ok := credentialsSecret.Data[storage.Spec.S3.CredentialsSecretRef.AccessSecretKeyKey]; !ok {
|
||||
credentialsSecret.Data[storage.Spec.S3.CredentialsSecretRef.AccessSecretKeyKey] = pw.GeneratePW(64, nil)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return err
|
||||
}
|
86
internal/webhook/v1alpha1/storage_webhook_test.go
Normal file
86
internal/webhook/v1alpha1/storage_webhook_test.go
Normal file
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
Copyright 2025 Peter Kurfer.
|
||||
|
||||
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 v1alpha1
|
||||
|
||||
import (
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
supabasev1alpha1 "code.icb4dc0.de/prskr/supabase-operator/api/v1alpha1"
|
||||
// TODO (user): Add any additional imports if needed
|
||||
)
|
||||
|
||||
var _ = Describe("Storage Webhook", func() {
|
||||
var (
|
||||
obj *supabasev1alpha1.Storage
|
||||
oldObj *supabasev1alpha1.Storage
|
||||
validator StorageCustomValidator
|
||||
defaulter StorageCustomDefaulter
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
obj = &supabasev1alpha1.Storage{}
|
||||
oldObj = &supabasev1alpha1.Storage{}
|
||||
validator = StorageCustomValidator{}
|
||||
Expect(validator).NotTo(BeNil(), "Expected validator to be initialized")
|
||||
defaulter = StorageCustomDefaulter{}
|
||||
Expect(defaulter).NotTo(BeNil(), "Expected defaulter to be initialized")
|
||||
Expect(oldObj).NotTo(BeNil(), "Expected oldObj to be initialized")
|
||||
Expect(obj).NotTo(BeNil(), "Expected obj to be initialized")
|
||||
// TODO (user): Add any setup logic common to all tests
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
// TODO (user): Add any teardown logic common to all tests
|
||||
})
|
||||
|
||||
Context("When creating Storage under Defaulting Webhook", func() {
|
||||
// TODO (user): Add logic for defaulting webhooks
|
||||
// Example:
|
||||
// It("Should apply defaults when a required field is empty", func() {
|
||||
// By("simulating a scenario where defaults should be applied")
|
||||
// obj.SomeFieldWithDefault = ""
|
||||
// By("calling the Default method to apply defaults")
|
||||
// defaulter.Default(ctx, obj)
|
||||
// By("checking that the default values are set")
|
||||
// Expect(obj.SomeFieldWithDefault).To(Equal("default_value"))
|
||||
// })
|
||||
})
|
||||
|
||||
Context("When creating or updating Storage under Validating Webhook", func() {
|
||||
// TODO (user): Add logic for validating webhooks
|
||||
// Example:
|
||||
// It("Should deny creation if a required field is missing", func() {
|
||||
// By("simulating an invalid creation scenario")
|
||||
// obj.SomeRequiredField = ""
|
||||
// Expect(validator.ValidateCreate(ctx, obj)).Error().To(HaveOccurred())
|
||||
// })
|
||||
//
|
||||
// It("Should admit creation if all required fields are present", func() {
|
||||
// By("simulating an invalid creation scenario")
|
||||
// obj.SomeRequiredField = "valid_value"
|
||||
// Expect(validator.ValidateCreate(ctx, obj)).To(BeNil())
|
||||
// })
|
||||
//
|
||||
// It("Should validate updates correctly", func() {
|
||||
// By("simulating a valid update scenario")
|
||||
// oldObj.SomeRequiredField = "updated_value"
|
||||
// obj.SomeRequiredField = "updated_value"
|
||||
// Expect(validator.ValidateUpdate(ctx, oldObj, obj)).To(BeNil())
|
||||
// })
|
||||
})
|
||||
})
|
87
internal/webhook/v1alpha1/storage_webhook_validator.go
Normal file
87
internal/webhook/v1alpha1/storage_webhook_validator.go
Normal file
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
Copyright 2025 Peter Kurfer.
|
||||
|
||||
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 v1alpha1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/webhook"
|
||||
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
|
||||
|
||||
supabasev1alpha1 "code.icb4dc0.de/prskr/supabase-operator/api/v1alpha1"
|
||||
)
|
||||
|
||||
// nolint:unused
|
||||
// log is for logging in this package.
|
||||
var storagelog = logf.Log.WithName("storage-resource")
|
||||
|
||||
// NOTE: The 'path' attribute must follow a specific pattern and should not be modified directly here.
|
||||
// Modifying the path for an invalid path can cause API server errors; failing to locate the webhook.
|
||||
// +kubebuilder:webhook:path=/validate-supabase-k8s-icb4dc0-de-v1alpha1-storage,mutating=false,failurePolicy=fail,sideEffects=None,groups=supabase.k8s.icb4dc0.de,resources=storages,verbs=create;update,versions=v1alpha1,name=vstorage-v1alpha1.kb.io,admissionReviewVersions=v1
|
||||
|
||||
// StorageCustomValidator struct is responsible for validating the Storage resource
|
||||
// when it is created, updated, or deleted.
|
||||
//
|
||||
// NOTE: The +kubebuilder:object:generate=false marker prevents controller-gen from generating DeepCopy methods,
|
||||
// as this struct is used only for temporary operations and does not need to be deeply copied.
|
||||
type StorageCustomValidator struct {
|
||||
// TODO(user): Add more fields as needed for validation
|
||||
}
|
||||
|
||||
var _ webhook.CustomValidator = &StorageCustomValidator{}
|
||||
|
||||
// ValidateCreate implements webhook.CustomValidator so a webhook will be registered for the type Storage.
|
||||
func (v *StorageCustomValidator) ValidateCreate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
|
||||
storage, ok := obj.(*supabasev1alpha1.Storage)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expected a Storage object but got %T", obj)
|
||||
}
|
||||
storagelog.Info("Validation for Storage upon creation", "name", storage.GetName())
|
||||
|
||||
// TODO(user): fill in your validation logic upon object creation.
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// ValidateUpdate implements webhook.CustomValidator so a webhook will be registered for the type Storage.
|
||||
func (v *StorageCustomValidator) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (admission.Warnings, error) {
|
||||
storage, ok := newObj.(*supabasev1alpha1.Storage)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expected a Storage object for the newObj but got %T", newObj)
|
||||
}
|
||||
storagelog.Info("Validation for Storage upon update", "name", storage.GetName())
|
||||
|
||||
// TODO(user): fill in your validation logic upon object update.
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// ValidateDelete implements webhook.CustomValidator so a webhook will be registered for the type Storage.
|
||||
func (v *StorageCustomValidator) ValidateDelete(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
|
||||
storage, ok := obj.(*supabasev1alpha1.Storage)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expected a Storage object but got %T", obj)
|
||||
}
|
||||
storagelog.Info("Validation for Storage upon deletion", "name", storage.GetName())
|
||||
|
||||
// TODO(user): fill in your validation logic upon object deletion.
|
||||
|
||||
return nil, nil
|
||||
}
|
|
@ -127,6 +127,9 @@ var _ = BeforeSuite(func() {
|
|||
err = SetupDashboardWebhookWithManager(mgr)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
err = SetupStorageWebhookWithManager(mgr)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
// +kubebuilder:scaffold:webhook
|
||||
|
||||
go func() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue