diff --git a/docs/kubectl_rolling-update.md b/docs/kubectl_rolling-update.md index 6577204b675..d9e850bfc09 100644 --- a/docs/kubectl_rolling-update.md +++ b/docs/kubectl_rolling-update.md @@ -12,7 +12,7 @@ new PodTemplate. The new-controller.json must specify the same namespace as the existing controller and overwrite at least one (common) label in its replicaSelector. ``` -kubectl rolling-update OLD_CONTROLLER_NAME -f NEW_CONTROLLER_SPEC +kubectl rolling-update OLD_CONTROLLER_NAME ([NEW_CONTROLLER_NAME] --image=NEW_CONTAINER_IMAGE | -f NEW_CONTROLLER_SPEC) ``` ### Examples @@ -24,9 +24,13 @@ $ kubectl rolling-update frontend-v1 -f frontend-v2.json // Update pods of frontend-v1 using JSON data passed into stdin. $ cat frontend-v2.json | kubectl rolling-update frontend-v1 -f - -// Update the pods of frontend-v1 to frontend-v2 by just changing the image +// Update the pods of frontend-v1 to frontend-v2 by just changing the image, and switching the +// name of the replication controller. $ kubectl rolling-update frontend-v1 frontend-v2 --image=image:v2 +// Update the pods of frontend by just changing the image, and keeping the old name +$ kubectl rolling-update frontend --image=image:v2 + ``` ### Options @@ -79,4 +83,4 @@ $ kubectl rolling-update frontend-v1 frontend-v2 --image=image:v2 ### SEE ALSO * [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager -###### Auto generated by spf13/cobra at 2015-04-27 22:01:46.525154396 +0000 UTC +###### Auto generated by spf13/cobra at 2015-04-27 22:44:36.84341428 +0000 UTC diff --git a/docs/man/man1/kubectl-rolling-update.1 b/docs/man/man1/kubectl-rolling-update.1 index e9b79a22542..c27317f55c2 100644 --- a/docs/man/man1/kubectl-rolling-update.1 +++ b/docs/man/man1/kubectl-rolling-update.1 @@ -185,9 +185,13 @@ $ kubectl rolling\-update frontend\-v1 \-f frontend\-v2.json // Update pods of frontend\-v1 using JSON data passed into stdin. $ cat frontend\-v2.json | kubectl rolling\-update frontend\-v1 \-f \- -// Update the pods of frontend\-v1 to frontend\-v2 by just changing the image +// Update the pods of frontend\-v1 to frontend\-v2 by just changing the image, and switching the +// name of the replication controller. $ kubectl rolling\-update frontend\-v1 frontend\-v2 \-\-image=image:v2 +// Update the pods of frontend by just changing the image, and keeping the old name +$ kubectl rolling\-update frontend \-\-image=image:v2 + .fi .RE diff --git a/pkg/kubectl/cmd/rollingupdate.go b/pkg/kubectl/cmd/rollingupdate.go index 9f9b0973147..3829f347922 100644 --- a/pkg/kubectl/cmd/rollingupdate.go +++ b/pkg/kubectl/cmd/rollingupdate.go @@ -51,14 +51,18 @@ $ kubectl rolling-update frontend-v1 -f frontend-v2.json // Update pods of frontend-v1 using JSON data passed into stdin. $ cat frontend-v2.json | kubectl rolling-update frontend-v1 -f - -// Update the pods of frontend-v1 to frontend-v2 by just changing the image +// Update the pods of frontend-v1 to frontend-v2 by just changing the image, and switching the +// name of the replication controller. $ kubectl rolling-update frontend-v1 frontend-v2 --image=image:v2 + +// Update the pods of frontend by just changing the image, and keeping the old name +$ kubectl rolling-update frontend --image=image:v2 ` ) func NewCmdRollingUpdate(f *cmdutil.Factory, out io.Writer) *cobra.Command { cmd := &cobra.Command{ - Use: "rolling-update OLD_CONTROLLER_NAME -f NEW_CONTROLLER_SPEC", + Use: "rolling-update OLD_CONTROLLER_NAME ([NEW_CONTROLLER_NAME] --image=NEW_CONTAINER_IMAGE | -f NEW_CONTROLLER_SPEC)", // rollingupdate is deprecated. Aliases: []string{"rollingupdate"}, Short: "Perform a rolling update of the given ReplicationController.", @@ -94,9 +98,6 @@ func validateArguments(cmd *cobra.Command, args []string) (deploymentKey, filena if len(filename) != 0 && len(image) != 0 { return "", "", "", "", cmdutil.UsageError(cmd, "--filename and --image can not both be specified") } - if len(image) > 0 && len(args) < 2 { - return "", "", "", "", cmdutil.UsageError(cmd, "You must specify a name for your new controller") - } if len(args) < 1 { return "", "", "", "", cmdutil.UsageError(cmd, "Must specify the controller to update") } @@ -133,6 +134,8 @@ func RunRollingUpdate(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, arg return err } + keepOldName := false + mapper, typer := f.Object() var newRc *api.ReplicationController @@ -152,7 +155,6 @@ func RunRollingUpdate(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, arg } } if len(image) != 0 { - newName := args[1] var err error // load the old RC into the "new" RC if newRc, err = client.ReplicationControllers(cmdNamespace).Get(oldName); err != nil { @@ -172,10 +174,19 @@ func RunRollingUpdate(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, arg if err != nil { return err } + + var newName string + if len(args) >= 2 { + newName = args[1] + } else { + keepOldName = true + newName = fmt.Sprintf("%s-%s", newRc.Name, newHash) + } newRc.Name = newName newRc.Spec.Selector[deploymentKey] = newHash newRc.Spec.Template.Labels[deploymentKey] = newHash + // Clear resource version after hashing so that identical updates get different hashes. newRc.ResourceVersion = "" if _, found := oldRc.Spec.Selector[deploymentKey]; !found { @@ -219,6 +230,10 @@ func RunRollingUpdate(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, arg fmt.Fprintf(out, "Rolling from:\n%s\nTo:\n%s\n", string(oldRcData.Bytes()), string(newRcData.Bytes())) return nil } + updateCleanupPolicy := kubectl.DeleteRollingUpdateCleanupPolicy + if keepOldName { + updateCleanupPolicy = kubectl.RenameRollingUpdateCleanupPolicy + } err = updater.Update(&kubectl.RollingUpdaterConfig{ Out: out, OldRc: oldRc, @@ -226,13 +241,17 @@ func RunRollingUpdate(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, arg UpdatePeriod: period, Interval: interval, Timeout: timeout, - CleanupPolicy: kubectl.DeleteRollingUpdateCleanupPolicy, + CleanupPolicy: updateCleanupPolicy, }) if err != nil { return err } - fmt.Fprintf(out, "%s\n", newName) + if keepOldName { + fmt.Fprintf(out, "%s\n", oldName) + } else { + fmt.Fprintf(out, "%s\n", newName) + } return nil } diff --git a/pkg/kubectl/cmd/rollingupdate_test.go b/pkg/kubectl/cmd/rollingupdate_test.go index 61af573dbe9..440d40db241 100644 --- a/pkg/kubectl/cmd/rollingupdate_test.go +++ b/pkg/kubectl/cmd/rollingupdate_test.go @@ -59,9 +59,8 @@ func TestValidateArgs(t *testing.T) { flags: map[string]string{ "image": "foo:v2", }, - args: []string{"foo"}, - expectErr: true, - testName: "missing second image name", + args: []string{"foo"}, + testName: "missing second image name", }, { flags: map[string]string{ diff --git a/pkg/kubectl/rolling_updater.go b/pkg/kubectl/rolling_updater.go index 26afd6538d7..ed1cac54614 100644 --- a/pkg/kubectl/rolling_updater.go +++ b/pkg/kubectl/rolling_updater.go @@ -66,6 +66,9 @@ const ( DeleteRollingUpdateCleanupPolicy RollingUpdaterCleanupPolicy = "Delete" // PreserveRollingUpdateCleanupPolicy means keep the old controller. PreserveRollingUpdateCleanupPolicy RollingUpdaterCleanupPolicy = "Preserve" + // RenameRollingUpdateCleanupPolicy means delete the old controller, and rename + // the new controller to the name of the old controller. + RenameRollingUpdateCleanupPolicy RollingUpdaterCleanupPolicy = "Rename" ) // NewRollingUpdater creates a RollingUpdater from a client @@ -199,6 +202,14 @@ func (r *RollingUpdater) Update(config *RollingUpdaterConfig) error { // delete old rc fmt.Fprintf(out, "Update succeeded. Deleting %s\n", oldName) return r.c.DeleteReplicationController(r.ns, oldName) + case RenameRollingUpdateCleanupPolicy: + // delete old rc + fmt.Fprintf(out, "Update succeeded. Deleting old controller: %s\n", oldName) + if err := r.c.DeleteReplicationController(r.ns, oldName); err != nil { + return err + } + fmt.Fprintf(out, "Renaming %s to %s\n", newRc.Name, oldName) + return r.rename(newRc, oldName) case PreserveRollingUpdateCleanupPolicy: return nil default: @@ -243,6 +254,18 @@ func (r *RollingUpdater) updateAndWait(rc *api.ReplicationController, interval, return r.c.GetReplicationController(r.ns, rc.ObjectMeta.Name) } +func (r *RollingUpdater) rename(rc *api.ReplicationController, newName string) error { + oldName := rc.Name + rc.Name = newName + rc.ResourceVersion = "" + + _, err := r.c.CreateReplicationController(rc.Namespace, rc) + if err != nil { + return err + } + return r.c.DeleteReplicationController(rc.Namespace, oldName) +} + // RollingUpdaterClient abstracts access to ReplicationControllers. type RollingUpdaterClient interface { GetReplicationController(namespace, name string) (*api.ReplicationController, error)