fix --record to work with unstructured objects

pull/6/head
Jordan Liggitt 2017-01-22 21:15:10 -05:00
parent c317f92990
commit 408a978f26
No known key found for this signature in database
GPG Key ID: 24E7ADF9A3B42012
6 changed files with 38 additions and 27 deletions

View File

@ -22,6 +22,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/golang/glog"
"github.com/jonboulle/clockwork" "github.com/jonboulle/clockwork"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -295,13 +296,10 @@ func RunApply(f cmdutil.Factory, cmd *cobra.Command, out, errOut io.Writer, opti
} }
if cmdutil.ShouldRecord(cmd, info) { if cmdutil.ShouldRecord(cmd, info) {
patch, err := cmdutil.ChangeResourcePatch(info, f.Command()) if patch, patchType, err := cmdutil.ChangeResourcePatch(info, f.Command()); err == nil {
if err != nil { if _, err = helper.Patch(info.Namespace, info.Name, patchType, patch); err != nil {
return err glog.V(4).Infof("error recording reason: %v", err)
} }
_, err = helper.Patch(info.Namespace, info.Name, types.StrategicMergePatchType, patch)
if err != nil {
return cmdutil.AddSourceToErr(fmt.Sprintf("applying patch:\n%s\nto:\n%v\nfor:", patch, info), info.Source, err)
} }
} }

View File

@ -23,6 +23,7 @@ import (
"strings" "strings"
jsonpatch "github.com/evanphx/json-patch" jsonpatch "github.com/evanphx/json-patch"
"github.com/golang/glog"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@ -181,14 +182,16 @@ func RunPatch(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []strin
if err != nil { if err != nil {
return err return err
} }
// Record the change as a second patch to avoid trying to merge with a user's patch data
if cmdutil.ShouldRecord(cmd, info) { if cmdutil.ShouldRecord(cmd, info) {
// don't return an error on failure. The patch itself succeeded, its only the hint for that change that failed // Copy the resource info and update with the result of applying the user's patch
// don't bother checking for failures of this replace, because a failure to indicate the hint doesn't fail the command infoCopy := *info
// also, don't force the replacement. If the replacement fails on a resourceVersion conflict, then it means this infoCopy.Object = patchedObj
// record hint is likely to be invalid anyway, so avoid the bad hint infoCopy.VersionedObject = patchedObj
patch, err := cmdutil.ChangeResourcePatch(info, f.Command()) if patch, patchType, err := cmdutil.ChangeResourcePatch(&infoCopy, f.Command()); err == nil {
if err == nil { if _, err = helper.Patch(info.Namespace, info.Name, patchType, patch); err != nil {
helper.Patch(info.Namespace, info.Name, types.StrategicMergePatchType, patch) glog.V(4).Infof("error recording reason: %v", err)
}
} }
} }
count++ count++

View File

@ -23,7 +23,6 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
"k8s.io/kubernetes/pkg/kubectl" "k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates" "k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
@ -164,7 +163,7 @@ func RunScale(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []strin
return err return err
} }
if cmdutil.ShouldRecord(cmd, info) { if cmdutil.ShouldRecord(cmd, info) {
patchBytes, err := cmdutil.ChangeResourcePatch(info, f.Command()) patchBytes, patchType, err := cmdutil.ChangeResourcePatch(info, f.Command())
if err != nil { if err != nil {
return err return err
} }
@ -174,7 +173,7 @@ func RunScale(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []strin
return err return err
} }
helper := resource.NewHelper(client, mapping) helper := resource.NewHelper(client, mapping)
_, err = helper.Patch(info.Namespace, info.Name, types.StrategicMergePatchType, patchBytes) _, err = helper.Patch(info.Namespace, info.Name, patchType, patchBytes)
if err != nil { if err != nil {
return err return err
} }

View File

@ -238,8 +238,8 @@ func (o *ImageOptions) Run() error {
// record this change (for rollout history) // record this change (for rollout history)
if o.Record || cmdutil.ContainsChangeCause(info) { if o.Record || cmdutil.ContainsChangeCause(info) {
if patch, err := cmdutil.ChangeResourcePatch(info, o.ChangeCause); err == nil { if patch, patchType, err := cmdutil.ChangeResourcePatch(info, o.ChangeCause); err == nil {
if obj, err = resource.NewHelper(info.Client, info.Mapping).Patch(info.Namespace, info.Name, types.StrategicMergePatchType, patch); err != nil { if obj, err = resource.NewHelper(info.Client, info.Mapping).Patch(info.Namespace, info.Name, patchType, patch); err != nil {
fmt.Fprintf(o.Err, "WARNING: changes to %s/%s can't be recorded: %v\n", info.Mapping.Resource, info.Name, err) fmt.Fprintf(o.Err, "WARNING: changes to %s/%s can't be recorded: %v\n", info.Mapping.Resource, info.Name, err)
} }
} }

View File

@ -53,7 +53,9 @@ go_library(
"//vendor:k8s.io/apimachinery/pkg/runtime", "//vendor:k8s.io/apimachinery/pkg/runtime",
"//vendor:k8s.io/apimachinery/pkg/runtime/schema", "//vendor:k8s.io/apimachinery/pkg/runtime/schema",
"//vendor:k8s.io/apimachinery/pkg/runtime/serializer/json", "//vendor:k8s.io/apimachinery/pkg/runtime/serializer/json",
"//vendor:k8s.io/apimachinery/pkg/types",
"//vendor:k8s.io/apimachinery/pkg/util/errors", "//vendor:k8s.io/apimachinery/pkg/util/errors",
"//vendor:k8s.io/apimachinery/pkg/util/json",
"//vendor:k8s.io/apimachinery/pkg/util/sets", "//vendor:k8s.io/apimachinery/pkg/util/sets",
"//vendor:k8s.io/apimachinery/pkg/util/strategicpatch", "//vendor:k8s.io/apimachinery/pkg/util/strategicpatch",
"//vendor:k8s.io/apimachinery/pkg/version", "//vendor:k8s.io/apimachinery/pkg/version",

View File

@ -18,7 +18,6 @@ package util
import ( import (
"bytes" "bytes"
"encoding/json"
"errors" "errors"
"fmt" "fmt"
"io" "io"
@ -38,7 +37,9 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
utilerrors "k8s.io/apimachinery/pkg/util/errors" utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/apimachinery/pkg/util/json"
"k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/strategicpatch" "k8s.io/apimachinery/pkg/util/strategicpatch"
"k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/clientcmd"
@ -520,27 +521,35 @@ func RecordChangeCause(obj runtime.Object, changeCause string) error {
return nil return nil
} }
// ChangeResourcePatch creates a strategic merge patch between the origin input resource info // ChangeResourcePatch creates a patch between the origin input resource info
// and the annotated with change-cause input resource info. // and the annotated with change-cause input resource info.
func ChangeResourcePatch(info *resource.Info, changeCause string) ([]byte, error) { func ChangeResourcePatch(info *resource.Info, changeCause string) ([]byte, types.PatchType, error) {
// Get a versioned object // Get a versioned object
obj, err := info.Mapping.ConvertToVersion(info.Object, info.Mapping.GroupVersionKind.GroupVersion()) obj, err := info.Mapping.ConvertToVersion(info.Object, info.Mapping.GroupVersionKind.GroupVersion())
if err != nil { if err != nil {
return nil, err return nil, types.StrategicMergePatchType, err
} }
oldData, err := json.Marshal(obj) oldData, err := json.Marshal(obj)
if err != nil { if err != nil {
return nil, err return nil, types.StrategicMergePatchType, err
} }
if err := RecordChangeCause(obj, changeCause); err != nil { if err := RecordChangeCause(obj, changeCause); err != nil {
return nil, err return nil, types.StrategicMergePatchType, err
} }
newData, err := json.Marshal(obj) newData, err := json.Marshal(obj)
if err != nil { if err != nil {
return nil, err return nil, types.StrategicMergePatchType, err
}
switch obj := obj.(type) {
case *unstructured.Unstructured:
patch, err := jsonpatch.CreateMergePatch(oldData, newData)
return patch, types.MergePatchType, err
default:
patch, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, obj)
return patch, types.StrategicMergePatchType, err
} }
return strategicpatch.CreateTwoWayMergePatch(oldData, newData, obj)
} }
// containsChangeCause checks if input resource info contains change-cause annotation. // containsChangeCause checks if input resource info contains change-cause annotation.