From 0c8f71aa0b492bacb9a353a3d97d25019dbedf74 Mon Sep 17 00:00:00 2001 From: Mike Danese Date: Mon, 22 Jun 2015 18:56:53 -0700 Subject: [PATCH] make rolling update check if the replication controller has been defaulted --- pkg/kubectl/cmd/rollingupdate.go | 35 ++++++++++++++++++++++++++++---- pkg/kubectl/resource/mapper.go | 19 +++++++++++------ pkg/kubectl/resource/visitor.go | 4 ++++ 3 files changed, 48 insertions(+), 10 deletions(-) diff --git a/pkg/kubectl/cmd/rollingupdate.go b/pkg/kubectl/cmd/rollingupdate.go index 23443fb9199..3d034db0575 100644 --- a/pkg/kubectl/cmd/rollingupdate.go +++ b/pkg/kubectl/cmd/rollingupdate.go @@ -26,6 +26,8 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors" + "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1" + "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta3" "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl" cmdutil "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/cmd/util" "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/resource" @@ -143,6 +145,7 @@ func RunRollingUpdate(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, arg } var keepOldName bool + var replicasDefaulted bool mapper, typer := f.Object() @@ -151,12 +154,12 @@ func RunRollingUpdate(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, arg if err != nil { return err } - obj, err := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()). + request := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()). Schema(schema). NamespaceParam(cmdNamespace).RequireNamespace(). FilenameParam(filename). - Do(). - Object() + Do() + obj, err := request.Object() if err != nil { return err } @@ -177,6 +180,12 @@ func RunRollingUpdate(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, arg glog.V(4).Infof("Object %#v is not a ReplicationController", obj) return cmdutil.UsageError(cmd, "%s does not specify a valid ReplicationController", filename) } + infos, err := request.Infos() + if err != nil || len(infos) != 1 { + glog.V(2).Infof("was not able to recover adequate information to discover if .spec.replicas was defaulted") + } else { + replicasDefaulted = isReplicasDefaulted(infos[0]) + } } // If the --image option is specified, we need to create a new rc with at least one different selector // than the old rc. This selector is the hash of the rc, which will differ because the new rc has a @@ -228,7 +237,7 @@ func RunRollingUpdate(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, arg filename, oldName) } // TODO: handle scales during rolling update - if newRc.Spec.Replicas == 0 { + if replicasDefaulted { newRc.Spec.Replicas = oldRc.Spec.Replicas } if dryrun { @@ -283,3 +292,21 @@ func findNewName(args []string, oldRc *api.ReplicationController) string { } return "" } + +func isReplicasDefaulted(info *resource.Info) bool { + if info == nil || info.VersionedObject == nil { + // was unable to recover versioned info + return false + } + switch info.Mapping.APIVersion { + case "v1": + if rc, ok := info.VersionedObject.(*v1.ReplicationController); ok { + return rc.Spec.Replicas == nil + } + case "v1beta3": + if rc, ok := info.VersionedObject.(*v1beta3.ReplicationController); ok { + return rc.Spec.Replicas == nil + } + } + return false +} diff --git a/pkg/kubectl/resource/mapper.go b/pkg/kubectl/resource/mapper.go index e8a1d6184c9..f46c6dc60df 100644 --- a/pkg/kubectl/resource/mapper.go +++ b/pkg/kubectl/resource/mapper.go @@ -20,6 +20,7 @@ import ( "fmt" "reflect" + "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" "github.com/GoogleCloudPlatform/kubernetes/pkg/util/yaml" @@ -64,13 +65,19 @@ func (m *Mapper) InfoForData(data []byte, source string) (*Info, error) { name, _ := mapping.MetadataAccessor.Name(obj) namespace, _ := mapping.MetadataAccessor.Namespace(obj) resourceVersion, _ := mapping.MetadataAccessor.ResourceVersion(obj) - return &Info{ - Mapping: mapping, - Client: client, - Namespace: namespace, - Name: name, - Source: source, + var versionedObject interface{} + + if vo, _, _, err := api.Scheme.Raw().DecodeToVersionedObject(data); err == nil { + versionedObject = vo + } + return &Info{ + Mapping: mapping, + Client: client, + Namespace: namespace, + Name: name, + Source: source, + VersionedObject: versionedObject, Object: obj, ResourceVersion: resourceVersion, }, nil diff --git a/pkg/kubectl/resource/visitor.go b/pkg/kubectl/resource/visitor.go index 194305fc184..a6013fa978b 100644 --- a/pkg/kubectl/resource/visitor.go +++ b/pkg/kubectl/resource/visitor.go @@ -69,6 +69,10 @@ type Info struct { // Optional, Source is the filename or URL to template file (.json or .yaml), // or stdin to use to handle the resource Source string + // Optional, this is the provided object in a versioned type before defaulting + // and conversions into its corresponding internal type. This is useful for + // reflecting on user intent which may be lost after defaulting and conversions. + VersionedObject interface{} // Optional, this is the most recent value returned by the server if available runtime.Object // Optional, this is the most recent resource version the server knows about for