diff --git a/internal/resources/resource.go b/internal/resources/resource.go index 0a1ba5b..e4cb7da 100644 --- a/internal/resources/resource.go +++ b/internal/resources/resource.go @@ -34,9 +34,9 @@ import ( ) var ( - _ webhook.Defaulter = &TestResource{} - _ webhook.Validator = &TestResource{} - _ client.Object = &TestResource{} + _ webhook.CustomDefaulter = &TestResource{} + _ webhook.CustomValidator = &TestResource{} + _ client.Object = &TestResource{} ) // +kubebuilder:object:root=true @@ -50,26 +50,52 @@ type TestResource struct { Status TestResourceStatus `json:"status"` } -func (r *TestResource) Default() { +func (*TestResource) Default(ctx context.Context, obj runtime.Object) error { + r, ok := obj.(*TestResource) + if !ok { + return fmt.Errorf("expected object to be TestResource") + } + if r.Spec.Fields == nil { r.Spec.Fields = map[string]string{} } r.Spec.Fields["Defaulter"] = "ran" + + return nil } -func (r *TestResource) ValidateCreate() (admission.Warnings, error) { - return nil, r.validate().ToAggregate() +func (*TestResource) ValidateCreate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) { + r, ok := obj.(*TestResource) + if !ok { + return nil, fmt.Errorf("expected obj to be TestResource") + } + + return nil, r.validate(ctx).ToAggregate() } -func (r *TestResource) ValidateUpdate(old runtime.Object) (admission.Warnings, error) { - return nil, r.validate().ToAggregate() +func (*TestResource) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (admission.Warnings, error) { + _, ok := oldObj.(*TestResource) + if !ok { + return nil, fmt.Errorf("expected oldObj to be TestResource") + } + r, ok := newObj.(*TestResource) + if !ok { + return nil, fmt.Errorf("expected newObj to be TestResource") + } + + return nil, r.validate(ctx).ToAggregate() } -func (r *TestResource) ValidateDelete() (admission.Warnings, error) { +func (*TestResource) ValidateDelete(ctx context.Context, obj runtime.Object) (admission.Warnings, error) { + _, ok := obj.(*TestResource) + if !ok { + return nil, fmt.Errorf("expected obj to be TestResource") + } + return nil, nil } -func (r *TestResource) validate() field.ErrorList { +func (r *TestResource) validate(ctx context.Context) field.ErrorList { errs := field.ErrorList{} if r.Spec.Fields != nil { diff --git a/internal/resources/resource_with_empty_status.go b/internal/resources/resource_with_empty_status.go index a78812e..bbe1983 100644 --- a/internal/resources/resource_with_empty_status.go +++ b/internal/resources/resource_with_empty_status.go @@ -17,11 +17,15 @@ limitations under the License. package resources import ( + "context" + "fmt" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" "sigs.k8s.io/controller-runtime/pkg/webhook" ) -var _ webhook.Defaulter = &TestResourceEmptyStatus{} +var _ webhook.CustomDefaulter = &TestResourceEmptyStatus{} // +kubebuilder:object:root=true // +genclient @@ -34,11 +38,18 @@ type TestResourceEmptyStatus struct { Status TestResourceEmptyStatusStatus `json:"status"` } -func (r *TestResourceEmptyStatus) Default() { +func (*TestResourceEmptyStatus) Default(ctx context.Context, obj runtime.Object) error { + r, ok := obj.(*TestResourceEmptyStatus) + if !ok { + return fmt.Errorf("expected obj to be TestResourceEmptyStatus") + } + if r.Spec.Fields == nil { r.Spec.Fields = map[string]string{} } r.Spec.Fields["Defaulter"] = "ran" + + return nil } // +kubebuilder:object:generate=true diff --git a/internal/resources/resource_with_nilable_status.go b/internal/resources/resource_with_nilable_status.go index ad8dc3c..e8c338f 100644 --- a/internal/resources/resource_with_nilable_status.go +++ b/internal/resources/resource_with_nilable_status.go @@ -17,6 +17,9 @@ limitations under the License. package resources import ( + "context" + "fmt" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" @@ -26,9 +29,9 @@ import ( ) var ( - _ webhook.Defaulter = &TestResourceNilableStatus{} - _ webhook.Validator = &TestResourceNilableStatus{} - _ client.Object = &TestResourceNilableStatus{} + _ webhook.CustomDefaulter = &TestResourceNilableStatus{} + _ webhook.CustomValidator = &TestResourceNilableStatus{} + _ client.Object = &TestResourceNilableStatus{} ) // +kubebuilder:object:root=true @@ -42,26 +45,51 @@ type TestResourceNilableStatus struct { Status *TestResourceStatus `json:"status"` } -func (r *TestResourceNilableStatus) Default() { +func (TestResourceNilableStatus) Default(ctx context.Context, obj runtime.Object) error { + r, ok := obj.(*TestResourceNilableStatus) + if !ok { + return fmt.Errorf("expected obj to be TestResourceNilableStatus") + } if r.Spec.Fields == nil { r.Spec.Fields = map[string]string{} } r.Spec.Fields["Defaulter"] = "ran" + + return nil } -func (r *TestResourceNilableStatus) ValidateCreate() (admission.Warnings, error) { - return nil, r.validate().ToAggregate() +func (*TestResourceNilableStatus) ValidateCreate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) { + r, ok := obj.(*TestResourceNilableStatus) + if !ok { + return nil, fmt.Errorf("expected obj to be TestResourceNilableStatus") + } + + return nil, r.validate(ctx).ToAggregate() } -func (r *TestResourceNilableStatus) ValidateUpdate(old runtime.Object) (admission.Warnings, error) { - return nil, r.validate().ToAggregate() +func (*TestResourceNilableStatus) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (admission.Warnings, error) { + _, ok := oldObj.(*TestResourceNilableStatus) + if !ok { + return nil, fmt.Errorf("expected oldObj to be TestResourceNilableStatus") + } + r, ok := newObj.(*TestResourceNilableStatus) + if !ok { + return nil, fmt.Errorf("expected newObj to be TestResourceNilableStatus") + } + + return nil, r.validate(ctx).ToAggregate() } -func (r *TestResourceNilableStatus) ValidateDelete() (admission.Warnings, error) { +func (*TestResourceNilableStatus) ValidateDelete(ctx context.Context, obj runtime.Object) (admission.Warnings, error) { + _, ok := obj.(*TestResourceNilableStatus) + if !ok { + return nil, fmt.Errorf("expected obj to be TestResourceNilableStatus") + } + return nil, nil } -func (r *TestResourceNilableStatus) validate() field.ErrorList { +func (r *TestResourceNilableStatus) validate(ctx context.Context) field.ErrorList { errs := field.ErrorList{} if r.Spec.Fields != nil { diff --git a/internal/resources/resource_with_unexported_fields.go b/internal/resources/resource_with_unexported_fields.go index cd7e51c..1e649ab 100644 --- a/internal/resources/resource_with_unexported_fields.go +++ b/internal/resources/resource_with_unexported_fields.go @@ -17,6 +17,7 @@ limitations under the License. package resources import ( + "context" "encoding/json" "fmt" @@ -32,9 +33,9 @@ import ( ) var ( - _ webhook.Defaulter = &TestResourceUnexportedFields{} - _ webhook.Validator = &TestResourceUnexportedFields{} - _ client.Object = &TestResourceUnexportedFields{} + _ webhook.CustomDefaulter = &TestResourceUnexportedFields{} + _ webhook.CustomValidator = &TestResourceUnexportedFields{} + _ client.Object = &TestResourceUnexportedFields{} ) // +kubebuilder:object:root=true @@ -48,26 +49,51 @@ type TestResourceUnexportedFields struct { Status TestResourceUnexportedFieldsStatus `json:"status"` } -func (r *TestResourceUnexportedFields) Default() { +func (*TestResourceUnexportedFields) Default(ctx context.Context, obj runtime.Object) error { + r, ok := obj.(*TestResourceUnexportedFields) + if !ok { + return fmt.Errorf("expected obj to be TestResourceUnexportedFields") + } if r.Spec.Fields == nil { r.Spec.Fields = map[string]string{} } r.Spec.Fields["Defaulter"] = "ran" + + return nil } -func (r *TestResourceUnexportedFields) ValidateCreate() (admission.Warnings, error) { - return nil, r.validate().ToAggregate() +func (*TestResourceUnexportedFields) ValidateCreate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) { + r, ok := obj.(*TestResourceUnexportedFields) + if !ok { + return nil, fmt.Errorf("expected obj to be TestResourceUnexportedFields") + } + + return nil, r.validate(ctx).ToAggregate() } -func (r *TestResourceUnexportedFields) ValidateUpdate(old runtime.Object) (admission.Warnings, error) { - return nil, r.validate().ToAggregate() +func (*TestResourceUnexportedFields) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (admission.Warnings, error) { + _, ok := oldObj.(*TestResourceUnexportedFields) + if !ok { + return nil, fmt.Errorf("expected oldObj to be TestResourceUnexportedFields") + } + r, ok := newObj.(*TestResourceUnexportedFields) + if !ok { + return nil, fmt.Errorf("expected newObj to be TestResourceUnexportedFields") + } + + return nil, r.validate(ctx).ToAggregate() } -func (r *TestResourceUnexportedFields) ValidateDelete() (admission.Warnings, error) { +func (*TestResourceUnexportedFields) ValidateDelete(ctx context.Context, obj runtime.Object) (admission.Warnings, error) { + _, ok := obj.(*TestResourceUnexportedFields) + if !ok { + return nil, fmt.Errorf("expected obj to be TestResourceUnexportedFields") + } + return nil, nil } -func (r *TestResourceUnexportedFields) validate() field.ErrorList { +func (r *TestResourceUnexportedFields) validate(ctx context.Context) field.ErrorList { errs := field.ErrorList{} if r.Spec.Fields != nil { diff --git a/reconcilers/resource.go b/reconcilers/resource.go index 6325bca..6de9b2c 100644 --- a/reconcilers/resource.go +++ b/reconcilers/resource.go @@ -269,7 +269,12 @@ func (r *ResourceReconciler[T]) reconcileOuter(ctx context.Context, req Request) } resource := originalResource.DeepCopyObject().(T) - if defaulter, ok := client.Object(resource).(webhook.Defaulter); ok { + if defaulter, ok := client.Object(resource).(webhook.CustomDefaulter); ok { + // resource.Default(ctx, resource) + if err := defaulter.Default(ctx, resource); err != nil { + return Result{}, err + } + } else if defaulter, ok := client.Object(resource).(webhook.Defaulter); ok { // resource.Default() defaulter.Default() } diff --git a/reconcilers/webhook.go b/reconcilers/webhook.go index 900f6fe..c209817 100644 --- a/reconcilers/webhook.go +++ b/reconcilers/webhook.go @@ -207,7 +207,12 @@ func (r *AdmissionWebhookAdapter[T]) reconcile(ctx context.Context, req admissio return err } - if defaulter, ok := client.Object(resource).(webhook.Defaulter); ok { + if defaulter, ok := client.Object(resource).(webhook.CustomDefaulter); ok { + // resource.Default(ctx, resource) + if err := defaulter.Default(ctx, resource); err != nil { + return err + } + } else if defaulter, ok := client.Object(resource).(webhook.Defaulter); ok { // resource.Default() defaulter.Default() }