try old patch after new patch fails

pull/6/head
ymqytw 2016-11-17 10:46:23 -08:00
parent 5efdea63b2
commit f32696e734
18 changed files with 58 additions and 123 deletions

View File

@ -244,9 +244,8 @@ func (e *eventLogger) eventObserve(newEvent *api.Event) (*api.Event, []byte, err
newData, _ := json.Marshal(event)
oldData, _ := json.Marshal(eventCopy2)
// TODO: need to figure out if we need to let eventObserve() use the new behavior of StrategicMergePatch.
// Currently default to old behavior now. Ref: issue #35936
patch, err = strategicpatch.CreateStrategicMergePatch(oldData, newData, event, strategicpatch.SMPatchVersion_1_0)
// Defaulting to SMPatchVersion_1_5 is safe, since we only update Count and LastTimestamp, and none of them has list of primitives
patch, err = strategicpatch.CreateStrategicMergePatch(oldData, newData, event, strategicpatch.SMPatchVersion_1_5)
}
// record our new observation

View File

@ -59,10 +59,6 @@ type nodeStatusUpdater struct {
}
func (nsu *nodeStatusUpdater) UpdateNodeStatuses() error {
smPatchVersion, err := strategicpatch.GetServerSupportedSMPatchVersion(nsu.kubeClient.Discovery())
if err != nil {
return err
}
nodesToUpdate := nsu.actualStateOfWorld.GetVolumesToReportAttached()
for nodeName, attachedVolumes := range nodesToUpdate {
nodeObj, exists, err := nsu.nodeInformer.GetStore().GetByKey(string(nodeName))
@ -111,8 +107,9 @@ func (nsu *nodeStatusUpdater) UpdateNodeStatuses() error {
err)
}
// Defaulting to SMPatchVersion_1_5 is safe, since updateNodeStatus doesn't update any lists of primitives
patchBytes, err :=
strategicpatch.CreateStrategicMergePatch(oldData, newData, node, smPatchVersion)
strategicpatch.CreateStrategicMergePatch(oldData, newData, node, strategicpatch.SMPatchVersion_1_5)
if err != nil {
return fmt.Errorf(
"failed to CreateStrategicMergePatch for node %q. %v",

View File

@ -223,12 +223,6 @@ func (o AnnotateOptions) RunAnnotate(f cmdutil.Factory, cmd *cobra.Command) erro
}
outputObj = obj
} else {
// retrieves server version to determine which SMPatchVersion to use.
smPatchVersion, err := cmdutil.GetServerSupportedSMPatchVersionFromFactory(f)
if err != nil {
return err
}
name, namespace := info.Name, info.Namespace
oldData, err := json.Marshal(obj)
if err != nil {
@ -245,7 +239,8 @@ func (o AnnotateOptions) RunAnnotate(f cmdutil.Factory, cmd *cobra.Command) erro
if err != nil {
return err
}
patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, obj, smPatchVersion)
// Defaulting to SMPatchVersion_1_5 is safe, since it just update the annotation which is a map[string]string
patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, obj, strategicpatch.SMPatchVersion_1_5)
createdPatch := err == nil
if err != nil {
glog.V(2).Infof("couldn't compute patch: %v", err)

View File

@ -195,11 +195,6 @@ func RunApply(f cmdutil.Factory, cmd *cobra.Command, out io.Writer, options *App
visitedUids := sets.NewString()
visitedNamespaces := sets.NewString()
smPatchVersion, err := cmdutil.GetServerSupportedSMPatchVersionFromFactory(f)
if err != nil {
return err
}
count := 0
err = r.Visit(func(info *resource.Info, err error) error {
// In this method, info.Object contains the object retrieved from the server
@ -270,13 +265,13 @@ func RunApply(f cmdutil.Factory, cmd *cobra.Command, out io.Writer, options *App
gracePeriod: options.GracePeriod,
}
patchBytes, err := patcher.patch(info.Object, modified, info.Source, info.Namespace, info.Name, smPatchVersion)
patchBytes, err := patcher.patch(info.Object, modified, info.Source, info.Namespace, info.Name)
if err != nil {
return cmdutil.AddSourceToErr(fmt.Sprintf("applying patch:\n%s\nto:\n%v\nfor:", patchBytes, info), info.Source, err)
}
if cmdutil.ShouldRecord(cmd, info) {
patch, err := cmdutil.ChangeResourcePatch(info, f.Command(), smPatchVersion)
patch, err := cmdutil.ChangeResourcePatch(info, f.Command())
if err != nil {
return err
}
@ -512,7 +507,7 @@ type patcher struct {
gracePeriod int
}
func (p *patcher) patchSimple(obj runtime.Object, modified []byte, source, namespace, name string, smPatchVersion strategicpatch.StrategicMergePatchVersion) ([]byte, error) {
func (p *patcher) patchSimple(obj runtime.Object, modified []byte, source, namespace, name string) ([]byte, error) {
// Serialize the current configuration of the object from the server.
current, err := runtime.Encode(p.encoder, obj)
if err != nil {
@ -536,20 +531,27 @@ func (p *patcher) patchSimple(obj runtime.Object, modified []byte, source, names
}
// Compute a three way strategic merge patch to send to server.
patch, err := strategicpatch.CreateThreeWayMergePatch(original, modified, current, versionedObject, p.overwrite, smPatchVersion)
patch, err := strategicpatch.CreateThreeWayMergePatch(original, modified, current, versionedObject, p.overwrite, strategicpatch.SMPatchVersion_1_5)
if err != nil {
format := "creating patch with:\noriginal:\n%s\nmodified:\n%s\ncurrent:\n%s\nfor:"
return nil, cmdutil.AddSourceToErr(fmt.Sprintf(format, original, modified, current), source, err)
}
_, err = p.helper.Patch(namespace, name, api.StrategicMergePatchType, patch)
if err != nil {
// Retry SMPatchVersion_1_0 when applying the SMPatchVersion_1_5 patch
patch, err = strategicpatch.CreateThreeWayMergePatch(original, modified, current, versionedObject, p.overwrite, strategicpatch.SMPatchVersion_1_0)
if err != nil {
format := "creating patch with:\noriginal:\n%s\nmodified:\n%s\ncurrent:\n%s\nfor:"
return nil, cmdutil.AddSourceToErr(fmt.Sprintf(format, original, modified, current), source, err)
}
_, err = p.helper.Patch(namespace, name, api.StrategicMergePatchType, patch)
}
return patch, err
}
func (p *patcher) patch(current runtime.Object, modified []byte, source, namespace, name string, smPatchVersion strategicpatch.StrategicMergePatchVersion) ([]byte, error) {
func (p *patcher) patch(current runtime.Object, modified []byte, source, namespace, name string) ([]byte, error) {
var getErr error
patchBytes, err := p.patchSimple(current, modified, source, namespace, name, smPatchVersion)
patchBytes, err := p.patchSimple(current, modified, source, namespace, name)
for i := 1; i <= maxPatchRetry && errors.IsConflict(err); i++ {
if i > triesBeforeBackOff {
p.backOff.Sleep(backOffPeriod)
@ -558,7 +560,7 @@ func (p *patcher) patch(current runtime.Object, modified []byte, source, namespa
if getErr != nil {
return nil, getErr
}
patchBytes, err = p.patchSimple(current, modified, source, namespace, name, smPatchVersion)
patchBytes, err = p.patchSimple(current, modified, source, namespace, name)
}
if err != nil && p.force {
patchBytes, err = p.deleteAndCreate(modified, namespace, name)

View File

@ -424,13 +424,8 @@ func visitToPatch(originalObj runtime.Object, updates *resource.Info,
results *editResults,
file string) error {
smPatchVersion, err := cmdutil.GetServerSupportedSMPatchVersionFromFactory(f)
if err != nil {
return err
}
patchVisitor := resource.NewFlattenListVisitor(updates, resourceMapper)
err = patchVisitor.Visit(func(info *resource.Info, incomingErr error) error {
err := patchVisitor.Visit(func(info *resource.Info, incomingErr error) error {
currOriginalObj := originalObj
// if we're editing a list, then navigate the list to find the item that we're currently trying to edit
@ -491,7 +486,7 @@ func visitToPatch(originalObj runtime.Object, updates *resource.Info,
preconditions := []strategicpatch.PreconditionFunc{strategicpatch.RequireKeyUnchanged("apiVersion"),
strategicpatch.RequireKeyUnchanged("kind"), strategicpatch.RequireMetadataKeyUnchanged("name")}
patch, err := strategicpatch.CreateTwoWayMergePatch(originalJS, editedJS, currOriginalObj, smPatchVersion, preconditions...)
patch, err := strategicpatch.CreateTwoWayMergePatch(originalJS, editedJS, currOriginalObj, strategicpatch.SMPatchVersion_1_5, preconditions...)
if err != nil {
glog.V(4).Infof("Unable to calculate diff, no merge is possible: %v", err)
if strategicpatch.IsPreconditionFailed(err) {
@ -503,8 +498,17 @@ func visitToPatch(originalObj runtime.Object, updates *resource.Info,
results.version = defaultVersion
patched, err := resource.NewHelper(info.Client, info.Mapping).Patch(info.Namespace, info.Name, api.StrategicMergePatchType, patch)
if err != nil {
fmt.Fprintln(out, results.addError(err, info))
return nil
// Retry SMPatchVersion_1_0 when applying the SMPatchVersion_1_5 patch
patch, err = strategicpatch.CreateTwoWayMergePatch(originalJS, editedJS, currOriginalObj, strategicpatch.SMPatchVersion_1_0)
if err != nil {
glog.V(4).Infof("Unable to calculate diff, no merge is possible: %v", err)
return err
}
patched, err = resource.NewHelper(info.Client, info.Mapping).Patch(info.Namespace, info.Name, api.StrategicMergePatchType, patch)
if err != nil {
fmt.Fprintln(out, results.addError(err, info))
return nil
}
}
info.Refresh(patched, true)
cmdutil.PrintSuccess(mapper, false, out, info.Mapping.Resource, info.Name, false, "edited")

View File

@ -192,14 +192,6 @@ func (o *LabelOptions) RunLabel(f cmdutil.Factory, cmd *cobra.Command) error {
return err
}
smPatchVersion := strategicpatch.SMPatchVersionLatest
if !o.local {
smPatchVersion, err = cmdutil.GetServerSupportedSMPatchVersionFromFactory(f)
if err != nil {
return err
}
}
// only apply resource version locking on a single resource
if !one && len(o.resourceVersion) > 0 {
return fmt.Errorf("--resource-version may only be used with a single resource")
@ -254,7 +246,8 @@ func (o *LabelOptions) RunLabel(f cmdutil.Factory, cmd *cobra.Command) error {
if !reflect.DeepEqual(oldData, newData) {
dataChangeMsg = "labeled"
}
patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, obj, smPatchVersion)
// Defaulting to SMPatchVersion_1_5 is safe, since we only update labels and change cause, and none of them has list of primitives
patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, obj, strategicpatch.SMPatchVersion_1_5)
createdPatch := err == nil
if err != nil {
glog.V(2).Infof("couldn't compute patch: %v", err)

View File

@ -154,14 +154,6 @@ func RunPatch(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []strin
return err
}
smPatchVersion := strategicpatch.SMPatchVersionLatest
if !options.Local {
smPatchVersion, err = cmdutil.GetServerSupportedSMPatchVersionFromFactory(f)
if err != nil {
return err
}
}
count := 0
err = r.Visit(func(info *resource.Info, err error) error {
if err != nil {
@ -185,7 +177,7 @@ func RunPatch(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []strin
// don't bother checking for failures of this replace, because a failure to indicate the hint doesn't fail the command
// also, don't force the replacement. If the replacement fails on a resourceVersion conflict, then it means this
// record hint is likely to be invalid anyway, so avoid the bad hint
patch, err := cmdutil.ChangeResourcePatch(info, f.Command(), smPatchVersion)
patch, err := cmdutil.ChangeResourcePatch(info, f.Command())
if err == nil {
helper.Patch(info.Namespace, info.Name, api.StrategicMergePatchType, patch)
}

View File

@ -32,6 +32,7 @@ go_library(
"//pkg/runtime:go_default_library",
"//pkg/util/errors:go_default_library",
"//pkg/util/interrupt:go_default_library",
"//pkg/util/strategicpatch:go_default_library",
"//pkg/watch:go_default_library",
"//vendor:github.com/renstrom/dedent",
"//vendor:github.com/spf13/cobra",

View File

@ -31,6 +31,7 @@ import (
"k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/runtime"
utilerrors "k8s.io/kubernetes/pkg/util/errors"
"k8s.io/kubernetes/pkg/util/strategicpatch"
)
// PauseConfig is the start of the data required to perform the operation. As new fields are added, add them here instead of
@ -134,7 +135,8 @@ func (o *PauseConfig) CompletePause(f cmdutil.Factory, cmd *cobra.Command, out i
func (o PauseConfig) RunPause() error {
allErrs := []error{}
for _, patch := range set.CalculatePatches(o.f, o.Infos, o.Encoder, false, o.Pauser) {
// Defaulting to SMPatchVersion_1_5 is safe, since Pauser only update a boolean variable
for _, patch := range set.CalculatePatches(o.f, o.Infos, o.Encoder, strategicpatch.SMPatchVersion_1_5, o.Pauser) {
info := patch.Info
if patch.Err != nil {
allErrs = append(allErrs, fmt.Errorf("error: %s %q %v", info.Mapping.Resource, info.Name, patch.Err))

View File

@ -31,6 +31,7 @@ import (
"k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/runtime"
utilerrors "k8s.io/kubernetes/pkg/util/errors"
"k8s.io/kubernetes/pkg/util/strategicpatch"
)
// ResumeConfig is the start of the data required to perform the operation. As new fields are added, add them here instead of
@ -138,7 +139,8 @@ func (o *ResumeConfig) CompleteResume(f cmdutil.Factory, cmd *cobra.Command, out
func (o ResumeConfig) RunResume() error {
allErrs := []error{}
for _, patch := range set.CalculatePatches(o.f, o.Infos, o.Encoder, false, o.Resumer) {
// Defaulting to SMPatchVersion_1_5 is safe, since Resumer only update a boolean variable
for _, patch := range set.CalculatePatches(o.f, o.Infos, o.Encoder, strategicpatch.SMPatchVersion_1_5, o.Resumer) {
info := patch.Info
if patch.Err != nil {

View File

@ -139,11 +139,6 @@ func RunScale(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []strin
return fmt.Errorf("cannot use --resource-version with multiple resources")
}
smPatchVersion, err := cmdutil.GetServerSupportedSMPatchVersionFromFactory(f)
if err != nil {
return err
}
counter := 0
err = r.Visit(func(info *resource.Info, err error) error {
if err != nil {
@ -169,7 +164,7 @@ func RunScale(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []strin
return err
}
if cmdutil.ShouldRecord(cmd, info) {
patchBytes, err := cmdutil.ChangeResourcePatch(info, f.Command(), smPatchVersion)
patchBytes, err := cmdutil.ChangeResourcePatch(info, f.Command())
if err != nil {
return err
}

View File

@ -123,17 +123,8 @@ type Patch struct {
// If local is true, it will be default to use SMPatchVersionLatest to calculate a patch without contacting the server to
// get the server supported SMPatchVersion. If you are using a patch's Patch field generated in local mode, be careful.
// If local is false, it will talk to the server to check which StategicMergePatchVersion to use.
func CalculatePatches(f cmdutil.Factory, infos []*resource.Info, encoder runtime.Encoder, local bool, mutateFn func(*resource.Info) (bool, error)) []*Patch {
func CalculatePatches(f cmdutil.Factory, infos []*resource.Info, encoder runtime.Encoder, smPatchVersion strategicpatch.StrategicMergePatchVersion, mutateFn func(*resource.Info) (bool, error)) []*Patch {
var patches []*Patch
smPatchVersion := strategicpatch.SMPatchVersionLatest
var err error
if !local {
smPatchVersion, err = cmdutil.GetServerSupportedSMPatchVersionFromFactory(f)
if err != nil {
return patches
}
}
for _, info := range infos {
patch := &Patch{Info: info}
patch.Before, patch.Err = runtime.Encode(encoder, info.Object)

View File

@ -164,8 +164,8 @@ func (o *ImageOptions) Validate() error {
func (o *ImageOptions) Run() error {
allErrs := []error{}
patches := CalculatePatches(o.f, o.Infos, o.Encoder, o.Local, func(info *resource.Info) (bool, error) {
// Defauting to SMPatchVersion_1_5, since the func passed in doesn't update any lists of primitive
patches := CalculatePatches(o.f, o.Infos, o.Encoder, strategicpatch.SMPatchVersion_1_5, func(info *resource.Info) (bool, error) {
transformed := false
_, err := o.UpdatePodSpecForObject(info.Object, func(spec *api.PodSpec) error {
for name, image := range o.ContainerImages {
@ -189,14 +189,6 @@ func (o *ImageOptions) Run() error {
return transformed, err
})
smPatchVersion := strategicpatch.SMPatchVersionLatest
var err error
if !o.Local {
smPatchVersion, err = cmdutil.GetServerSupportedSMPatchVersionFromFactory(o.f)
if err != nil {
return err
}
}
for _, patch := range patches {
info := patch.Info
if patch.Err != nil {
@ -223,7 +215,7 @@ func (o *ImageOptions) Run() error {
// record this change (for rollout history)
if o.Record || cmdutil.ContainsChangeCause(info) {
if patch, err := cmdutil.ChangeResourcePatch(info, o.ChangeCause, smPatchVersion); err == nil {
if patch, err := cmdutil.ChangeResourcePatch(info, o.ChangeCause); err == nil {
if obj, err = resource.NewHelper(info.Client, info.Mapping).Patch(info.Namespace, info.Name, api.StrategicMergePatchType, patch); err != nil {
fmt.Fprintf(o.Err, "WARNING: changes to %s/%s can't be recorded: %v\n", info.Mapping.Resource, info.Name, err)
}

View File

@ -31,6 +31,7 @@ import (
"k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/runtime"
utilerrors "k8s.io/kubernetes/pkg/util/errors"
"k8s.io/kubernetes/pkg/util/strategicpatch"
)
var (
@ -176,7 +177,8 @@ func (o *ResourcesOptions) Validate() error {
func (o *ResourcesOptions) Run() error {
allErrs := []error{}
patches := CalculatePatches(o.f, o.Infos, o.Encoder, cmdutil.GetDryRunFlag(o.Cmd), func(info *resource.Info) (bool, error) {
// Defauting to SMPatchVersion_1_5, since the func passed in doesn't update any lists of primitive
patches := CalculatePatches(o.f, o.Infos, o.Encoder, strategicpatch.SMPatchVersion_1_5, func(info *resource.Info) (bool, error) {
transformed := false
_, err := o.UpdatePodSpecForObject(info.Object, func(spec *api.PodSpec) error {
containers, _ := selectContainers(spec.Containers, o.ContainerSelector)

View File

@ -321,11 +321,6 @@ func (o TaintOptions) RunTaint() error {
return err
}
smPatchVersion, err := cmdutil.GetServerSupportedSMPatchVersionFromFactory(o.f)
if err != nil {
return err
}
return r.Visit(func(info *resource.Info, err error) error {
if err != nil {
return err
@ -348,7 +343,8 @@ func (o TaintOptions) RunTaint() error {
if err != nil {
return err
}
patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, obj, smPatchVersion)
// Defaulting to SMPatchVersion_1_5 is safe, since we don't update list of primitives.
patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, obj, strategicpatch.SMPatchVersion_1_5)
createdPatch := err == nil
if err != nil {
glog.V(2).Infof("couldn't compute patch: %v", err)

View File

@ -521,7 +521,7 @@ func RecordChangeCause(obj runtime.Object, changeCause string) error {
// ChangeResourcePatch creates a strategic merge patch between the origin input resource info
// and the annotated with change-cause input resource info.
func ChangeResourcePatch(info *resource.Info, changeCause string, smPatchVersion strategicpatch.StrategicMergePatchVersion) ([]byte, error) {
func ChangeResourcePatch(info *resource.Info, changeCause string) ([]byte, error) {
oldData, err := json.Marshal(info.Object)
if err != nil {
return nil, err
@ -533,7 +533,8 @@ func ChangeResourcePatch(info *resource.Info, changeCause string, smPatchVersion
if err != nil {
return nil, err
}
return strategicpatch.CreateTwoWayMergePatch(oldData, newData, info.Object, smPatchVersion)
// Using SMPatchVersion_1_5, since RecordChangeCause() just update the annotation which is a map[string]string
return strategicpatch.CreateTwoWayMergePatch(oldData, newData, info.Object, strategicpatch.SMPatchVersion_1_5)
}
// containsChangeCause checks if input resource info contains change-cause annotation.
@ -725,13 +726,3 @@ func RequireNoArguments(c *cobra.Command, args []string) {
CheckErr(UsageError(c, fmt.Sprintf(`unknown command %q`, strings.Join(args, " "))))
}
}
// GetServerSupportedSMPatchVersionFromFactory is a wrapper of GetServerSupportedSMPatchVersion(),
// It takes a Factory, returns the max version the server supports.
func GetServerSupportedSMPatchVersionFromFactory(f Factory) (strategicpatch.StrategicMergePatchVersion, error) {
clientSet, err := f.ClientSet()
if err != nil {
return strategicpatch.Unknown, err
}
return strategicpatch.GetServerSupportedSMPatchVersion(clientSet.Discovery())
}

View File

@ -15,7 +15,6 @@ go_library(
srcs = ["patch.go"],
tags = ["automanaged"],
deps = [
"//pkg/client/typed/discovery:go_default_library",
"//pkg/util/json:go_default_library",
"//third_party/forked/golang/json:go_default_library",
"//vendor:github.com/davecgh/go-spew/spew",

View File

@ -21,7 +21,6 @@ import (
"reflect"
"sort"
"k8s.io/kubernetes/pkg/client/typed/discovery"
"k8s.io/kubernetes/pkg/util/json"
forkedjson "k8s.io/kubernetes/third_party/forked/golang/json"
@ -1430,20 +1429,3 @@ func toYAML(v interface{}) (string, error) {
return string(y), nil
}
// GetServerSupportedSMPatchVersion takes a discoveryClient,
// returns the max StrategicMergePatch version supported
func GetServerSupportedSMPatchVersion(discoveryClient discovery.DiscoveryInterface) (StrategicMergePatchVersion, error) {
serverVersion, err := discoveryClient.ServerVersion()
if err != nil {
return Unknown, err
}
serverGitVersion := serverVersion.GitVersion
if serverGitVersion >= string(SMPatchVersion_1_5) {
return SMPatchVersion_1_5, nil
}
if serverGitVersion >= string(SMPatchVersion_1_0) {
return SMPatchVersion_1_0, nil
}
return Unknown, fmt.Errorf("The version is too old: %v\n", serverVersion)
}