From 6bf29d7562915fc3fee89c496c21647bf8c015b6 Mon Sep 17 00:00:00 2001 From: Ekaterina Kazakova Date: Wed, 4 Sep 2024 15:54:58 +0400 Subject: [PATCH] Check Deployment template validness only in case it was changed Closes #244 --- internal/webhook/deployment_webhook.go | 22 +++++--- internal/webhook/deployment_webhook_test.go | 58 ++++++++++++++++++++- 2 files changed, 71 insertions(+), 9 deletions(-) diff --git a/internal/webhook/deployment_webhook.go b/internal/webhook/deployment_webhook.go index 0aad57f6..d1660b44 100644 --- a/internal/webhook/deployment_webhook.go +++ b/internal/webhook/deployment_webhook.go @@ -77,18 +77,24 @@ func (v *DeploymentValidator) ValidateCreate(ctx context.Context, obj runtime.Ob } // ValidateUpdate implements webhook.Validator so a webhook will be registered for the type. -func (v *DeploymentValidator) ValidateUpdate(ctx context.Context, _ runtime.Object, newObj runtime.Object) (admission.Warnings, error) { +func (v *DeploymentValidator) ValidateUpdate(ctx context.Context, oldObj runtime.Object, newObj runtime.Object) (admission.Warnings, error) { + oldDeployment, ok := oldObj.(*v1alpha1.Deployment) + if !ok { + return nil, apierrors.NewBadRequest(fmt.Sprintf("expected Deployment but got a %T", oldObj)) + } newDeployment, ok := newObj.(*v1alpha1.Deployment) if !ok { return nil, apierrors.NewBadRequest(fmt.Sprintf("expected Deployment but got a %T", newObj)) } - template, err := v.getTemplate(ctx, newDeployment.Spec.Template) - if err != nil { - return nil, fmt.Errorf("%s: %v", InvalidDeploymentErr, err) - } - err = v.isTemplateValid(template) - if err != nil { - return nil, fmt.Errorf("%s: %v", InvalidDeploymentErr, err) + if oldDeployment.Spec.Template != newDeployment.Spec.Template { + template, err := v.getTemplate(ctx, newDeployment.Spec.Template) + if err != nil { + return nil, fmt.Errorf("%s: %v", InvalidDeploymentErr, err) + } + err = v.isTemplateValid(template) + if err != nil { + return nil, fmt.Errorf("%s: %v", InvalidDeploymentErr, err) + } } return nil, nil } diff --git a/internal/webhook/deployment_webhook_test.go b/internal/webhook/deployment_webhook_test.go index 5ef27d6b..651a6a2e 100644 --- a/internal/webhook/deployment_webhook_test.go +++ b/internal/webhook/deployment_webhook_test.go @@ -233,7 +233,6 @@ cluster-api installation failed: cluster-api template is invalid`, ), }, }, - { name: "update - should fail if the template is unset", operation: admissionv1.Update, @@ -273,6 +272,63 @@ cluster-api installation failed: cluster-api template is invalid`, }, err: "the deployment is invalid: the template is not valid: validation error example", }, + { + name: "update - should succeed if another field than the `spec.template` was changed even if the old template is not valid", + operation: admissionv1.Update, + oldDeployment: deployment.NewDeployment( + deployment.WithTemplate(testTemplateName), + deployment.WithConfig(`{"foo":"foo"}`), + ), + newDeployment: deployment.NewDeployment( + deployment.WithTemplate(testTemplateName), + deployment.WithConfig(`{"foo":"bar"}`), + ), + existingObjects: []runtime.Object{ + management.NewManagement( + management.WithAvailableProviders(v1alpha1.Providers{ + BootstrapProviders: []string{"k0s"}, + ControlPlaneProviders: []string{"k0s"}, + }), + management.WithComponentsStatus(map[string]v1alpha1.ComponentStatus{ + v1alpha1.DefaultCoreHMCTemplate: {Success: false}, + v1alpha1.DefaultCoreCAPITemplate: {Success: true}, + }), + ), + template.NewTemplate( + template.WithName(capzTemplateName), + template.WithValidationStatus(v1alpha1.TemplateValidationStatus{Valid: false}), + ), + template.NewTemplate( + template.WithName(newTemplateName), + template.WithTypeStatus(v1alpha1.TemplateTypeDeployment), + template.WithProvidersStatus(v1alpha1.Providers{ + InfrastructureProviders: []string{"aws"}, + BootstrapProviders: []string{"k0s"}, + ControlPlaneProviders: []string{"k0s"}, + }), + template.WithValidationStatus(v1alpha1.TemplateValidationStatus{Valid: false}), + ), + }, + }, + { + name: "update - should succeed", + operation: admissionv1.Update, + oldDeployment: deployment.NewDeployment(deployment.WithTemplate(testTemplateName)), + newDeployment: deployment.NewDeployment(deployment.WithTemplate(newTemplateName)), + existingObjects: []runtime.Object{ + mgmt, + template.NewTemplate( + template.WithName(newTemplateName), + template.WithTypeStatus(v1alpha1.TemplateTypeDeployment), + template.WithProvidersStatus(v1alpha1.Providers{ + InfrastructureProviders: []string{"aws"}, + BootstrapProviders: []string{"k0s"}, + ControlPlaneProviders: []string{"k0s"}, + }), + template.WithValidationStatus(v1alpha1.TemplateValidationStatus{Valid: true}), + ), + }, + }, } for _, tt := range tests {