From ebdeeb47b15bdb1a135fcf24e30ff8637b43fed9 Mon Sep 17 00:00:00 2001 From: "antoine.leveugle" Date: Wed, 18 Oct 2023 10:06:36 +0200 Subject: [PATCH] fix: --disable-openapi-validation option was never applied Signed-off-by: antoine.leveugle --- pkg/action/hooks.go | 2 +- pkg/action/install.go | 8 ++++---- pkg/action/rollback.go | 2 +- pkg/action/upgrade.go | 2 +- pkg/kube/client.go | 42 +++++++++++++++++++++++++++------------- pkg/kube/client_test.go | 6 +++--- pkg/kube/fake/fake.go | 8 ++++---- pkg/kube/fake/printer.go | 4 ++-- pkg/kube/interface.go | 4 ++-- 9 files changed, 47 insertions(+), 31 deletions(-) diff --git a/pkg/action/hooks.go b/pkg/action/hooks.go index 40c1ffdb6..a176907d1 100644 --- a/pkg/action/hooks.go +++ b/pkg/action/hooks.go @@ -73,7 +73,7 @@ func (cfg *Configuration) execHook(rl *release.Release, hook release.HookEvent, h.LastRun.Phase = release.HookPhaseUnknown // Create hook resources - if _, err := cfg.KubeClient.Create(resources); err != nil { + if _, err := cfg.KubeClient.Create(resources, false); err != nil { h.LastRun.CompletedAt = helmtime.Now() h.LastRun.Phase = release.HookPhaseFailed return errors.Wrapf(err, "warning: Hook %s %s failed", hook, h.Path) diff --git a/pkg/action/install.go b/pkg/action/install.go index e3538a4f5..c4924672a 100644 --- a/pkg/action/install.go +++ b/pkg/action/install.go @@ -161,7 +161,7 @@ func (i *Install) installCRDs(crds []chart.CRD) error { } // Send them to Kube - if _, err := i.cfg.KubeClient.Create(res); err != nil { + if _, err := i.cfg.KubeClient.Create(res, !i.DisableOpenAPIValidation); err != nil { // If the error is CRD already exists, continue. if apierrors.IsAlreadyExists(err) { crdName := res[0].Name @@ -368,7 +368,7 @@ func (i *Install) RunWithContext(ctx context.Context, chrt *chart.Chart, vals ma if err != nil { return nil, err } - if _, err := i.cfg.KubeClient.Create(resourceList); err != nil && !apierrors.IsAlreadyExists(err) { + if _, err := i.cfg.KubeClient.Create(resourceList, !i.DisableOpenAPIValidation); err != nil && !apierrors.IsAlreadyExists(err) { return nil, err } } @@ -437,9 +437,9 @@ func (i *Install) performInstall(rel *release.Release, toBeAdopted kube.Resource // do an update, but it's not clear whether we WANT to do an update if the re-use is set // to true, since that is basically an upgrade operation. if len(toBeAdopted) == 0 && len(resources) > 0 { - _, err = i.cfg.KubeClient.Create(resources) + _, err = i.cfg.KubeClient.Create(resources, !i.DisableOpenAPIValidation) } else if len(resources) > 0 { - _, err = i.cfg.KubeClient.Update(toBeAdopted, resources, i.Force) + _, err = i.cfg.KubeClient.Update(toBeAdopted, resources, i.Force, !i.DisableOpenAPIValidation) } if err != nil { return rel, err diff --git a/pkg/action/rollback.go b/pkg/action/rollback.go index f4ae896e3..bcb208c97 100644 --- a/pkg/action/rollback.go +++ b/pkg/action/rollback.go @@ -187,7 +187,7 @@ func (r *Rollback) performRollback(currentRelease, targetRelease *release.Releas if err != nil { return targetRelease, errors.Wrap(err, "unable to set metadata visitor from target release") } - results, err := r.cfg.KubeClient.Update(current, target, r.Force) + results, err := r.cfg.KubeClient.Update(current, target, r.Force, false) if err != nil { msg := fmt.Sprintf("Rollback %q failed: %s", targetRelease.Name, err) diff --git a/pkg/action/upgrade.go b/pkg/action/upgrade.go index c74b502e2..d1f342b5e 100644 --- a/pkg/action/upgrade.go +++ b/pkg/action/upgrade.go @@ -405,7 +405,7 @@ func (u *Upgrade) releasingUpgrade(c chan<- resultMessage, upgradedRelease *rele u.cfg.Log("upgrade hooks disabled for %s", upgradedRelease.Name) } - results, err := u.cfg.KubeClient.Update(current, target, u.Force) + results, err := u.cfg.KubeClient.Update(current, target, u.Force, !u.DisableOpenAPIValidation) if err != nil { u.cfg.recordRelease(originalRelease) u.reportToPerformUpgrade(c, upgradedRelease, results.Created, err) diff --git a/pkg/kube/client.go b/pkg/kube/client.go index 0772678d1..07ce3b6e2 100644 --- a/pkg/kube/client.go +++ b/pkg/kube/client.go @@ -138,9 +138,9 @@ func (c *Client) IsReachable() error { } // Create creates Kubernetes resources specified in the resource list. -func (c *Client) Create(resources ResourceList) (*Result, error) { +func (c *Client) Create(resources ResourceList, validate bool) (*Result, error) { c.Log("creating %d resource(s)", len(resources)) - if err := perform(resources, createResource); err != nil { + if err := perform(resources, getCreateResource(getValidationDirective(validate))); err != nil { return nil, err } return &Result{Created: resources}, nil @@ -386,10 +386,12 @@ func (c *Client) BuildTable(reader io.Reader, validate bool) (ResourceList, erro // occurs, a Result will still be returned with the error, containing all // resource updates, creations, and deletions that were attempted. These can be // used for cleanup or other logging purposes. -func (c *Client) Update(original, target ResourceList, force bool) (*Result, error) { +func (c *Client) Update(original, target ResourceList, force bool, validate bool) (*Result, error) { updateErrors := []string{} res := &Result{} + validationDirective := getValidationDirective(validate) + c.Log("checking %d resources for changes", len(target)) err := target.Visit(func(info *resource.Info, err error) error { if err != nil { @@ -406,7 +408,7 @@ func (c *Client) Update(original, target ResourceList, force bool) (*Result, err res.Created = append(res.Created, info) // Since the resource does not exist, create it. - if err := createResource(info); err != nil { + if err := getCreateResource(validationDirective)(info); err != nil { return errors.Wrap(err, "failed to create resource") } @@ -421,7 +423,7 @@ func (c *Client) Update(original, target ResourceList, force bool) (*Result, err return errors.Errorf("no %s with the name %q found", kind, info.Name) } - if err := updateResource(c, info, originalInfo.Object, force); err != nil { + if err := updateResource(c, info, originalInfo.Object, force, validationDirective); err != nil { c.Log("error updating the resource %q:\n\t %v", info.Name, err) updateErrors = append(updateErrors, err.Error()) } @@ -595,12 +597,17 @@ func batchPerform(infos ResourceList, fn func(*resource.Info) error, errs chan<- } } -func createResource(info *resource.Info) error { - obj, err := resource.NewHelper(info.Client, info.Mapping).WithFieldManager(getManagedFieldsManager()).Create(info.Namespace, true, info.Object) - if err != nil { - return err +func getCreateResource(validationDirective string) func(info *resource.Info) error { + return func(info *resource.Info) error { + obj, err := resource.NewHelper(info.Client, info.Mapping). + WithFieldManager(getManagedFieldsManager()). + WithFieldValidation(validationDirective). + Create(info.Namespace, true, info.Object) + if err != nil { + return err + } + return info.Refresh(obj, true) } - return info.Refresh(obj, true) } func deleteResource(info *resource.Info, policy metav1.DeletionPropagation) error { @@ -659,11 +666,13 @@ func createPatch(target *resource.Info, current runtime.Object) ([]byte, types.P return patch, types.StrategicMergePatchType, err } -func updateResource(c *Client, target *resource.Info, currentObj runtime.Object, force bool) error { +func updateResource(c *Client, target *resource.Info, currentObj runtime.Object, force bool, validationDirective string) error { var ( obj runtime.Object - helper = resource.NewHelper(target.Client, target.Mapping).WithFieldManager(getManagedFieldsManager()) - kind = target.Mapping.GroupVersionKind.Kind + helper = resource.NewHelper(target.Client, target.Mapping). + WithFieldManager(getManagedFieldsManager()). + WithFieldValidation(validationDirective) + kind = target.Mapping.GroupVersionKind.Kind ) // if --force is applied, attempt to replace the existing resource with the new object. @@ -848,3 +857,10 @@ func (c *Client) WaitAndGetCompletedPodPhase(name string, timeout time.Duration) return v1.PodUnknown, err } + +func getValidationDirective(validate bool) string { + if !validate { + return metav1.FieldValidationIgnore + } + return metav1.FieldValidationWarn +} diff --git a/pkg/kube/client_test.go b/pkg/kube/client_test.go index 55aa5d8ed..dcff7adce 100644 --- a/pkg/kube/client_test.go +++ b/pkg/kube/client_test.go @@ -166,7 +166,7 @@ func TestUpdate(t *testing.T) { t.Fatal(err) } - result, err := c.Update(first, second, false) + result, err := c.Update(first, second, false, false) if err != nil { t.Fatal(err) } @@ -348,7 +348,7 @@ func TestReal(t *testing.T) { if err != nil { t.Fatal(err) } - if _, err := c.Create(resources); err != nil { + if _, err := c.Create(resources, false); err != nil { t.Fatal(err) } @@ -358,7 +358,7 @@ func TestReal(t *testing.T) { if err != nil { t.Fatal(err) } - if _, err := c.Create(resources); err != nil { + if _, err := c.Create(resources, false); err != nil { t.Fatal(err) } diff --git a/pkg/kube/fake/fake.go b/pkg/kube/fake/fake.go index 267020d57..d4064622e 100644 --- a/pkg/kube/fake/fake.go +++ b/pkg/kube/fake/fake.go @@ -50,11 +50,11 @@ type FailingKubeClient struct { } // Create returns the configured error if set or prints -func (f *FailingKubeClient) Create(resources kube.ResourceList) (*kube.Result, error) { +func (f *FailingKubeClient) Create(resources kube.ResourceList, validate bool) (*kube.Result, error) { if f.CreateError != nil { return nil, f.CreateError } - return f.PrintingKubeClient.Create(resources) + return f.PrintingKubeClient.Create(resources, validate) } // Get returns the configured error if set or prints @@ -107,11 +107,11 @@ func (f *FailingKubeClient) WatchUntilReady(resources kube.ResourceList, d time. } // Update returns the configured error if set or prints -func (f *FailingKubeClient) Update(r, modified kube.ResourceList, ignoreMe bool) (*kube.Result, error) { +func (f *FailingKubeClient) Update(r, modified kube.ResourceList, ignoreMe bool, validate bool) (*kube.Result, error) { if f.UpdateError != nil { return &kube.Result{}, f.UpdateError } - return f.PrintingKubeClient.Update(r, modified, ignoreMe) + return f.PrintingKubeClient.Update(r, modified, ignoreMe, validate) } // Build returns the configured error if set or prints diff --git a/pkg/kube/fake/printer.go b/pkg/kube/fake/printer.go index e6c4b6207..fca0b08e3 100644 --- a/pkg/kube/fake/printer.go +++ b/pkg/kube/fake/printer.go @@ -41,7 +41,7 @@ func (p *PrintingKubeClient) IsReachable() error { } // Create prints the values of what would be created with a real KubeClient. -func (p *PrintingKubeClient) Create(resources kube.ResourceList) (*kube.Result, error) { +func (p *PrintingKubeClient) Create(resources kube.ResourceList, _ bool) (*kube.Result, error) { _, err := io.Copy(p.Out, bufferize(resources)) if err != nil { return nil, err @@ -90,7 +90,7 @@ func (p *PrintingKubeClient) WatchUntilReady(resources kube.ResourceList, _ time } // Update implements KubeClient Update. -func (p *PrintingKubeClient) Update(_, modified kube.ResourceList, _ bool) (*kube.Result, error) { +func (p *PrintingKubeClient) Update(_, modified kube.ResourceList, _ bool, _ bool) (*kube.Result, error) { _, err := io.Copy(p.Out, bufferize(modified)) if err != nil { return nil, err diff --git a/pkg/kube/interface.go b/pkg/kube/interface.go index ce42ed950..81b01f9c1 100644 --- a/pkg/kube/interface.go +++ b/pkg/kube/interface.go @@ -30,7 +30,7 @@ import ( // A KubernetesClient must be concurrency safe. type Interface interface { // Create creates one or more resources. - Create(resources ResourceList) (*Result, error) + Create(resources ResourceList, validate bool) (*Result, error) // Wait waits up to the given timeout for the specified resources to be ready. Wait(resources ResourceList, timeout time.Duration) error @@ -54,7 +54,7 @@ type Interface interface { // Update updates one or more resources or creates the resource // if it doesn't exist. - Update(original, target ResourceList, force bool) (*Result, error) + Update(original, target ResourceList, force bool, validate bool) (*Result, error) // Build creates a resource list from a Reader. //