feat(dashboard): initial support for studio & pg-meta services
This commit is contained in:
parent
7d9e518f86
commit
0b551325b9
31 changed files with 2151 additions and 492 deletions
internal/webhook/v1alpha1
|
@ -111,7 +111,7 @@ func (d *CoreCustomDefaulter) defaultJWT(ctx context.Context, core *supabasev1al
|
|||
corelog.Info("Defaulting JWT")
|
||||
|
||||
if core.Spec.JWT == nil {
|
||||
core.Spec.JWT = new(supabasev1alpha1.JwtSpec)
|
||||
core.Spec.JWT = new(supabasev1alpha1.CoreJwtSpec)
|
||||
}
|
||||
|
||||
if core.Spec.JWT.SecretRef == nil {
|
||||
|
|
114
internal/webhook/v1alpha1/dashboard_webhook.go
Normal file
114
internal/webhook/v1alpha1/dashboard_webhook.go
Normal file
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
Copyright 2024 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 dashboardlog = logf.Log.WithName("dashboard-resource")
|
||||
|
||||
// +kubebuilder:webhook:path=/mutate-supabase-k8s-icb4dc0-de-v1alpha1-dashboard,mutating=true,failurePolicy=fail,sideEffects=None,groups=supabase.k8s.icb4dc0.de,resources=dashboards,verbs=create;update,versions=v1alpha1,name=mdashboard-v1alpha1.kb.io,admissionReviewVersions=v1
|
||||
|
||||
// DashboardCustomDefaulter struct is responsible for setting default values on the custom resource of the
|
||||
// Kind Dashboard 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 DashboardCustomDefaulter struct {
|
||||
// TODO(user): Add more fields as needed for defaulting
|
||||
}
|
||||
|
||||
var _ webhook.CustomDefaulter = &DashboardCustomDefaulter{}
|
||||
|
||||
// Default implements webhook.CustomDefaulter so a webhook will be registered for the Kind Dashboard.
|
||||
func (d *DashboardCustomDefaulter) Default(ctx context.Context, obj runtime.Object) error {
|
||||
dashboard, ok := obj.(*supabasev1alpha1.Dashboard)
|
||||
|
||||
if !ok {
|
||||
return fmt.Errorf("expected an Dashboard object but got %T", obj)
|
||||
}
|
||||
dashboardlog.Info("Defaulting for Dashboard", "name", dashboard.GetName())
|
||||
|
||||
// TODO(user): fill in your defaulting logic.
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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-dashboard,mutating=false,failurePolicy=fail,sideEffects=None,groups=supabase.k8s.icb4dc0.de,resources=dashboards,verbs=create;update,versions=v1alpha1,name=vdashboard-v1alpha1.kb.io,admissionReviewVersions=v1
|
||||
|
||||
// DashboardCustomValidator struct is responsible for validating the Dashboard 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 DashboardCustomValidator struct {
|
||||
// TODO(user): Add more fields as needed for validation
|
||||
}
|
||||
|
||||
var _ webhook.CustomValidator = &DashboardCustomValidator{}
|
||||
|
||||
// ValidateCreate implements webhook.CustomValidator so a webhook will be registered for the type Dashboard.
|
||||
func (v *DashboardCustomValidator) ValidateCreate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
|
||||
dashboard, ok := obj.(*supabasev1alpha1.Dashboard)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expected a Dashboard object but got %T", obj)
|
||||
}
|
||||
dashboardlog.Info("Validation for Dashboard upon creation", "name", dashboard.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 Dashboard.
|
||||
func (v *DashboardCustomValidator) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (admission.Warnings, error) {
|
||||
dashboard, ok := newObj.(*supabasev1alpha1.Dashboard)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expected a Dashboard object for the newObj but got %T", newObj)
|
||||
}
|
||||
dashboardlog.Info("Validation for Dashboard upon update", "name", dashboard.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 Dashboard.
|
||||
func (v *DashboardCustomValidator) ValidateDelete(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
|
||||
dashboard, ok := obj.(*supabasev1alpha1.Dashboard)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expected a Dashboard object but got %T", obj)
|
||||
}
|
||||
dashboardlog.Info("Validation for Dashboard upon deletion", "name", dashboard.GetName())
|
||||
|
||||
// TODO(user): fill in your validation logic upon object deletion.
|
||||
|
||||
return nil, nil
|
||||
}
|
86
internal/webhook/v1alpha1/dashboard_webhook_test.go
Normal file
86
internal/webhook/v1alpha1/dashboard_webhook_test.go
Normal file
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
Copyright 2024 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("Dashboard Webhook", func() {
|
||||
var (
|
||||
obj *supabasev1alpha1.Dashboard
|
||||
oldObj *supabasev1alpha1.Dashboard
|
||||
validator DashboardCustomValidator
|
||||
defaulter DashboardCustomDefaulter
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
obj = &supabasev1alpha1.Dashboard{}
|
||||
oldObj = &supabasev1alpha1.Dashboard{}
|
||||
validator = DashboardCustomValidator{}
|
||||
Expect(validator).NotTo(BeNil(), "Expected validator to be initialized")
|
||||
defaulter = DashboardCustomDefaulter{}
|
||||
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 Dashboard 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 Dashboard 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())
|
||||
// })
|
||||
})
|
||||
})
|
|
@ -29,3 +29,11 @@ func SetupCoreWebhookWithManager(mgr ctrl.Manager) error {
|
|||
WithDefaulter(&CoreCustomDefaulter{Client: mgr.GetClient()}).
|
||||
Complete()
|
||||
}
|
||||
|
||||
// SetupDashboardWebhookWithManager registers the webhook for Dashboard in the manager.
|
||||
func SetupDashboardWebhookWithManager(mgr ctrl.Manager) error {
|
||||
return ctrl.NewWebhookManagedBy(mgr).For(&supabasev1alpha1.Dashboard{}).
|
||||
WithValidator(&DashboardCustomValidator{}).
|
||||
WithDefaulter(&DashboardCustomDefaulter{}).
|
||||
Complete()
|
||||
}
|
||||
|
|
|
@ -124,6 +124,9 @@ var _ = BeforeSuite(func() {
|
|||
err = SetupAPIGatewayWebhookWithManager(mgr, WebhookConfig{CurrentNamespace: "default"})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
err = SetupDashboardWebhookWithManager(mgr)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
// +kubebuilder:scaffold:webhook
|
||||
|
||||
go func() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue