From c9e33e197d56d224f1be319c526f07be0ffbee1c Mon Sep 17 00:00:00 2001 From: Brendan Burns Date: Thu, 30 Apr 2015 10:28:36 -0700 Subject: [PATCH] Add support for --rollback. --- contrib/completions/bash/kubectl | 1 + docs/design/simple-rolling-update.md | 2 +- docs/kubectl_rolling-update.md | 3 ++- docs/man/man1/kubectl-rolling-update.1 | 4 ++++ pkg/kubectl/cmd/rollingupdate.go | 21 ++++++++++++++++----- pkg/kubectl/rolling_updater.go | 20 +++++++++++++++++++- 6 files changed, 43 insertions(+), 8 deletions(-) diff --git a/contrib/completions/bash/kubectl b/contrib/completions/bash/kubectl index f9fffc64e35..82fc18a2c50 100644 --- a/contrib/completions/bash/kubectl +++ b/contrib/completions/bash/kubectl @@ -424,6 +424,7 @@ _kubectl_rolling-update() two_word_flags+=("-o") flags+=("--output-version=") flags+=("--poll-interval=") + flags+=("--rollback") flags+=("--template=") two_word_flags+=("-t") flags+=("--timeout=") diff --git a/docs/design/simple-rolling-update.md b/docs/design/simple-rolling-update.md index 2d2bd8265f5..c5667b44282 100644 --- a/docs/design/simple-rolling-update.md +++ b/docs/design/simple-rolling-update.md @@ -38,7 +38,7 @@ it is assumed that the rollout is nearly completed, and ```foo-next``` is rename ### Aborting a rollout Abort is assumed to want to reverse a rollout in progress. -```kubectl rolling-update rc foo [foo-v2] --abort``` +```kubectl rolling-update rc foo [foo-v2] --rollback``` This is really just semantic sugar for: diff --git a/docs/kubectl_rolling-update.md b/docs/kubectl_rolling-update.md index 7f4dd7c98a4..bdbabaac837 100644 --- a/docs/kubectl_rolling-update.md +++ b/docs/kubectl_rolling-update.md @@ -45,6 +45,7 @@ $ kubectl rolling-update frontend --image=image:v2 -o, --output="": Output format. One of: json|yaml|template|templatefile. --output-version="": Output the formatted object with the given version (default api-version). --poll-interval="3s": Time delay between polling controller status after update. Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". + --rollback=false: If true, this is a request to abort an existing rollout that is partially rolled out. It effectively reverses current and next and runs a rollout -t, --template="": Template string or path to template file to use when -o=template or -o=templatefile. The template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview] --timeout="5m0s": Max time to wait for a controller to update before giving up. Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". --update-period="1m0s": Time to wait between updating pods. Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". @@ -83,4 +84,4 @@ $ kubectl rolling-update frontend --image=image:v2 ### SEE ALSO * [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager -###### Auto generated by spf13/cobra at 2015-04-29 15:25:11.031878187 +0000 UTC +###### Auto generated by spf13/cobra at 2015-05-02 00:22:29.503205238 +0000 UTC diff --git a/docs/man/man1/kubectl-rolling-update.1 b/docs/man/man1/kubectl-rolling-update.1 index c27317f55c2..83bb6f08046 100644 --- a/docs/man/man1/kubectl-rolling-update.1 +++ b/docs/man/man1/kubectl-rolling-update.1 @@ -58,6 +58,10 @@ existing controller and overwrite at least one (common) label in its replicaSele \fB\-\-poll\-interval\fP="3s" Time delay between polling controller status after update. Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". +.PP +\fB\-\-rollback\fP=false + If true, this is a request to abort an existing rollout that is partially rolled out. It effectively reverses current and next and runs a rollout + .PP \fB\-t\fP, \fB\-\-template\fP="" Template string or path to template file to use when \-o=template or \-o=templatefile. The template format is golang templates [ diff --git a/pkg/kubectl/cmd/rollingupdate.go b/pkg/kubectl/cmd/rollingupdate.go index 3294d31ce8b..3e161f29fed 100644 --- a/pkg/kubectl/cmd/rollingupdate.go +++ b/pkg/kubectl/cmd/rollingupdate.go @@ -82,6 +82,7 @@ func NewCmdRollingUpdate(f *cmdutil.Factory, out io.Writer) *cobra.Command { cmd.Flags().String("image", "", "Image to upgrade the controller to. Can not be used with --filename/-f") cmd.Flags().String("deployment-label-key", "deployment", "The key to use to differentiate between two different controllers, default 'deployment'. Only relevant when --image is specified, ignored otherwise") cmd.Flags().Bool("dry-run", false, "If true, print out the changes that would be made, but don't actually make them.") + cmd.Flags().Bool("rollback", false, "If true, this is a request to abort an existing rollout that is partially rolled out. It effectively reverses current and next and runs a rollout") cmdutil.AddPrinterFlags(cmd) return cmd } @@ -171,10 +172,15 @@ func RunRollingUpdate(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, arg if len(newName) > 0 { newRc, err = client.ReplicationControllers(cmdNamespace).Get(newName) - if err != nil && !apierrors.IsNotFound(err) { - return err + if err != nil { + if !apierrors.IsNotFound(err) { + return err + } else { + newRc = nil + } + } else { + fmt.Fprint(out, "Found existing update in progress (%s), resuming.\n", newName) } - fmt.Fprint(out, "Found existing update in progress (%s), resuming.\n", newName) } if newRc == nil { // load the old RC into the "new" RC @@ -257,7 +263,7 @@ func RunRollingUpdate(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, arg if keepOldName { updateCleanupPolicy = kubectl.RenameRollingUpdateCleanupPolicy } - err = updater.Update(&kubectl.RollingUpdaterConfig{ + config := &kubectl.RollingUpdaterConfig{ Out: out, OldRc: oldRc, NewRc: newRc, @@ -265,7 +271,12 @@ func RunRollingUpdate(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, arg Interval: interval, Timeout: timeout, CleanupPolicy: updateCleanupPolicy, - }) + } + if cmdutil.GetFlagBool(cmd, "rollback") { + kubectl.AbortRollingUpdate(config) + client.ReplicationControllers(config.NewRc.Namespace).Update(config.NewRc) + } + err = updater.Update(config) if err != nil { return err } diff --git a/pkg/kubectl/rolling_updater.go b/pkg/kubectl/rolling_updater.go index a1c2bd3fdea..11afeb23aa8 100644 --- a/pkg/kubectl/rolling_updater.go +++ b/pkg/kubectl/rolling_updater.go @@ -85,6 +85,24 @@ const ( nextControllerAnnotation = kubectlAnnotationPrefix + "next-controller-id" ) +func AbortRollingUpdate(c *RollingUpdaterConfig) { + // Swap the controllers + tmp := c.OldRc + c.OldRc = c.NewRc + c.NewRc = tmp + + if c.NewRc.Annotations == nil { + c.NewRc.Annotations = map[string]string{} + } + c.NewRc.Annotations[sourceIdAnnotation] = fmt.Sprintf("%s:%s", c.OldRc.Name, c.OldRc.UID) + desiredSize, found := c.OldRc.Annotations[desiredReplicasAnnotation] + if found { + fmt.Printf("Found desired replicas.") + c.NewRc.Annotations[desiredReplicasAnnotation] = desiredSize + } + c.CleanupPolicy = DeleteRollingUpdateCleanupPolicy +} + func GetNextControllerAnnotation(rc *api.ReplicationController) (string, bool) { res, found := rc.Annotations[nextControllerAnnotation] return res, found @@ -237,7 +255,7 @@ func (r *RollingUpdater) getExistingNewRc(sourceId, name string) (rc *api.Replic source := annotations[sourceIdAnnotation] _, ok := annotations[desiredReplicasAnnotation] if source != sourceId || !ok { - err = fmt.Errorf("Missing/unexpected annotations for controller %s: %s", name, annotations) + err = fmt.Errorf("Missing/unexpected annotations for controller %s, expected %s : %s", name, sourceId, annotations) } return }