ref(client): add overwrite option

Signed-off-by: Jan-Otto Kröpke <mail@jkroepke.de>
pull/6987/head
Jan-Otto Kröpke 6 years ago
parent 84de17e7e5
commit 104e5e8f55
No known key found for this signature in database
GPG Key ID: 3F619F17002790D8

@ -147,6 +147,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
f.BoolVar(&client.Recreate, "recreate-pods", false, "performs pods restart for the resource if applicable") f.BoolVar(&client.Recreate, "recreate-pods", false, "performs pods restart for the resource if applicable")
f.MarkDeprecated("recreate-pods", "functionality will no longer be updated. Consult the documentation for other methods to recreate pods") f.MarkDeprecated("recreate-pods", "functionality will no longer be updated. Consult the documentation for other methods to recreate pods")
f.BoolVar(&client.Force, "force", false, "force resource updates through a replacement strategy") f.BoolVar(&client.Force, "force", false, "force resource updates through a replacement strategy")
f.BoolVar(&client.Overwrite, "overwrite", true, "overwrite all outside changes")
f.BoolVar(&client.DisableHooks, "no-hooks", false, "disable pre/post upgrade hooks") f.BoolVar(&client.DisableHooks, "no-hooks", false, "disable pre/post upgrade hooks")
f.DurationVar(&client.Timeout, "timeout", 300*time.Second, "time to wait for any individual Kubernetes operation (like Jobs for hooks)") f.DurationVar(&client.Timeout, "timeout", 300*time.Second, "time to wait for any individual Kubernetes operation (like Jobs for hooks)")
f.BoolVar(&client.ResetValues, "reset-values", false, "when upgrading, reset the values to the ones built into the chart") f.BoolVar(&client.ResetValues, "reset-values", false, "when upgrading, reset the values to the ones built into the chart")

@ -159,7 +159,7 @@ func (r *Rollback) performRollback(currentRelease, targetRelease *release.Releas
r.cfg.Log("rollback hooks disabled for %s", targetRelease.Name) r.cfg.Log("rollback hooks disabled for %s", targetRelease.Name)
} }
results, err := r.cfg.KubeClient.Update(current, target, r.Force) results, err := r.cfg.KubeClient.Update(current, target, r.Force, true)
if err != nil { if err != nil {
msg := fmt.Sprintf("Rollback %q failed: %s", targetRelease.Name, err) msg := fmt.Sprintf("Rollback %q failed: %s", targetRelease.Name, err)

@ -49,6 +49,7 @@ type Upgrade struct {
DisableHooks bool DisableHooks bool
DryRun bool DryRun bool
Force bool Force bool
Overwrite bool
ResetValues bool ResetValues bool
ReuseValues bool ReuseValues bool
// Recreate will (if true) recreate pods after a rollback. // Recreate will (if true) recreate pods after a rollback.
@ -236,7 +237,7 @@ func (u *Upgrade) performUpgrade(originalRelease, upgradedRelease *release.Relea
u.cfg.Log("upgrade hooks disabled for %s", upgradedRelease.Name) 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.Overwrite)
if err != nil { if err != nil {
u.cfg.recordRelease(originalRelease) u.cfg.recordRelease(originalRelease)
return u.failRelease(upgradedRelease, results.Created, err) return u.failRelease(upgradedRelease, results.Created, err)

@ -31,6 +31,7 @@ import (
batch "k8s.io/api/batch/v1" batch "k8s.io/api/batch/v1"
v1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
apiextv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" apiextv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
apiequality "k8s.io/apimachinery/pkg/api/equality"
apierrors "k8s.io/apimachinery/pkg/api/errors" apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -142,7 +143,7 @@ func (c *Client) Build(reader io.Reader, validate bool) (ResourceList, error) {
// occurs, a Result will still be returned with the error, containing all // occurs, a Result will still be returned with the error, containing all
// resource updates, creations, and deletions that were attempted. These can be // resource updates, creations, and deletions that were attempted. These can be
// used for cleanup or other logging purposes. // 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, overwrite bool) (*Result, error) {
updateErrors := []string{} updateErrors := []string{}
res := &Result{} res := &Result{}
@ -177,7 +178,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) 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, overwrite); err != nil {
c.Log("error updating the resource %q:\n\t %v", info.Name, err) c.Log("error updating the resource %q:\n\t %v", info.Name, err)
updateErrors = append(updateErrors, err.Error()) updateErrors = append(updateErrors, err.Error())
} }
@ -323,7 +324,7 @@ func deleteResource(info *resource.Info) error {
return err return err
} }
func createPatch(target *resource.Info, current runtime.Object) ([]byte, types.PatchType, error) { func createPatch(target *resource.Info, current runtime.Object, overwrite bool) ([]byte, types.PatchType, error) {
oldData, err := json.Marshal(current) oldData, err := json.Marshal(current)
if err != nil { if err != nil {
return nil, types.StrategicMergePatchType, errors.Wrap(err, "serializing current configuration") return nil, types.StrategicMergePatchType, errors.Wrap(err, "serializing current configuration")
@ -359,6 +360,19 @@ func createPatch(target *resource.Info, current runtime.Object) ([]byte, types.P
return patch, types.MergePatchType, err return patch, types.MergePatchType, err
} }
if !overwrite {
// While different objects need different merge types, the parent function
// that calls this does not try to create a patch when the data (first
// returned object) is nil. We can skip calculating the merge type as
// the returned merge type is ignored.
if apiequality.Semantic.DeepEqual(oldData, newData) {
return nil, types.StrategicMergePatchType, nil
}
patch, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, versionedObject)
return patch, types.StrategicMergePatchType, err
}
patchMeta, err := strategicpatch.NewPatchMetaFromStruct(versionedObject) patchMeta, err := strategicpatch.NewPatchMetaFromStruct(versionedObject)
if err != nil { if err != nil {
return nil, types.StrategicMergePatchType, errors.Wrap(err, "unable to create patch metadata from object") return nil, types.StrategicMergePatchType, errors.Wrap(err, "unable to create patch metadata from object")
@ -368,14 +382,14 @@ func createPatch(target *resource.Info, current runtime.Object) ([]byte, types.P
return patch, types.StrategicMergePatchType, err 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, overwrite bool) error {
var ( var (
obj runtime.Object obj runtime.Object
helper = resource.NewHelper(target.Client, target.Mapping) helper = resource.NewHelper(target.Client, target.Mapping)
kind = target.Mapping.GroupVersionKind.Kind kind = target.Mapping.GroupVersionKind.Kind
) )
patch, patchType, err := createPatch(target, currentObj) patch, patchType, err := createPatch(target, currentObj, overwrite)
if err != nil { if err != nil {
return errors.Wrap(err, "failed to create patch") return errors.Wrap(err, "failed to create patch")
} }

@ -162,7 +162,7 @@ func TestUpdate(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
if _, err := c.Update(first, second, false); err != nil { if _, err := c.Update(first, second, false, true); err != nil {
t.Fatal(err) t.Fatal(err)
} }
// TODO: Find a way to test methods that use Client Set // TODO: Find a way to test methods that use Client Set

@ -75,11 +75,11 @@ func (f *FailingKubeClient) WatchUntilReady(resources kube.ResourceList, d time.
} }
// Update returns the configured error if set or prints // 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, ignoreMeToo bool) (*kube.Result, error) {
if f.UpdateError != nil { if f.UpdateError != nil {
return &kube.Result{}, f.UpdateError return &kube.Result{}, f.UpdateError
} }
return f.PrintingKubeClient.Update(r, modified, ignoreMe) return f.PrintingKubeClient.Update(r, modified, ignoreMe, ignoreMeToo)
} }
// Build returns the configured error if set or prints // Build returns the configured error if set or prints

@ -70,7 +70,7 @@ func (p *PrintingKubeClient) WatchUntilReady(resources kube.ResourceList, _ time
} }
// Update implements KubeClient Update. // 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)) _, err := io.Copy(p.Out, bufferize(modified))
if err != nil { if err != nil {
return nil, err return nil, err

@ -45,7 +45,7 @@ type Interface interface {
// Update updates one or more resources or creates the resource // Update updates one or more resources or creates the resource
// if it doesn't exist. // if it doesn't exist.
Update(original, target ResourceList, force bool) (*Result, error) Update(original, target ResourceList, force bool, overwrite bool) (*Result, error)
// Build creates a resource list from a Reader // Build creates a resource list from a Reader
// //

Loading…
Cancel
Save