Add recovery for anonymous rollouts.

This commit is contained in:
Brendan Burns 2015-04-27 17:10:39 -07:00
parent ba1140a54f
commit 83cbd0cf4c
2 changed files with 59 additions and 30 deletions

View File

@ -26,6 +26,7 @@ import (
"time" "time"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
apierrors "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client" "github.com/GoogleCloudPlatform/kubernetes/pkg/client"
"github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl" "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl"
@ -155,44 +156,59 @@ func RunRollingUpdate(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, arg
} }
} }
if len(image) != 0 { if len(image) != 0 {
var err error
// load the old RC into the "new" RC
if newRc, err = client.ReplicationControllers(cmdNamespace).Get(oldName); err != nil {
return err
}
if len(newRc.Spec.Template.Spec.Containers) > 1 {
// TODO: support multi-container image update.
return errors.New("Image update is not supported for multi-container pods")
}
if len(newRc.Spec.Template.Spec.Containers) == 0 {
return cmdutil.UsageError(cmd, "Pod has no containers! (%v)", newRc)
}
newRc.Spec.Template.Spec.Containers[0].Image = image
newHash, err := hashObject(newRc, client.Codec)
if err != nil {
return err
}
var newName string var newName string
var err error
if len(args) >= 2 { if len(args) >= 2 {
newName = args[1] newName = args[1]
} else { } else {
keepOldName = true newName, _ = kubectl.GetNextControllerAnnotation(oldRc)
newName = fmt.Sprintf("%s-%s", newRc.Name, newHash)
} }
newRc.Name = newName
newRc.Spec.Selector[deploymentKey] = newHash if len(newName) > 0 {
newRc.Spec.Template.Labels[deploymentKey] = newHash newRc, err = client.ReplicationControllers(cmdNamespace).Get(newName)
// Clear resource version after hashing so that identical updates get different hashes. if err != nil && !apierrors.IsNotFound(err) {
newRc.ResourceVersion = ""
if _, found := oldRc.Spec.Selector[deploymentKey]; !found {
if err := addDeploymentKeyToReplicationController(oldRc, client, deploymentKey, cmdNamespace, out); err != nil {
return err return err
} }
fmt.Fprint(out, "Found existing update in progress (%s), resuming.\n", newName)
}
if newRc == nil {
// load the old RC into the "new" RC
if newRc, err = client.ReplicationControllers(cmdNamespace).Get(oldName); err != nil {
return err
}
if len(newRc.Spec.Template.Spec.Containers) > 1 {
// TODO: support multi-container image update.
return errors.New("Image update is not supported for multi-container pods")
}
if len(newRc.Spec.Template.Spec.Containers) == 0 {
return cmdutil.UsageError(cmd, "Pod has no containers! (%v)", newRc)
}
newRc.Spec.Template.Spec.Containers[0].Image = image
newHash, err := hashObject(newRc, client.Codec)
if err != nil {
return err
}
if len(newName) == 0 {
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 = ""
kubectl.SetNextControllerAnnotation(oldRc, newName)
if _, found := oldRc.Spec.Selector[deploymentKey]; !found {
if err := addDeploymentKeyToReplicationController(oldRc, client, deploymentKey, cmdNamespace, out); err != nil {
return err
}
}
} }
} }
newName := newRc.Name newName := newRc.Name

View File

@ -82,8 +82,21 @@ func NewRollingUpdater(namespace string, c RollingUpdaterClient) *RollingUpdater
const ( const (
sourceIdAnnotation = kubectlAnnotationPrefix + "update-source-id" sourceIdAnnotation = kubectlAnnotationPrefix + "update-source-id"
desiredReplicasAnnotation = kubectlAnnotationPrefix + "desired-replicas" desiredReplicasAnnotation = kubectlAnnotationPrefix + "desired-replicas"
nextControllerAnnotation = kubectlAnnotationPrefix + "next-controller-id"
) )
func GetNextControllerAnnotation(rc *api.ReplicationController) (string, bool) {
res, found := rc.Annotations[nextControllerAnnotation]
return res, found
}
func SetNextControllerAnnotation(rc *api.ReplicationController, name string) {
if rc.Annotations == nil {
rc.Annotations = map[string]string{}
}
rc.Annotations[nextControllerAnnotation] = name
}
// Update all pods for a ReplicationController (oldRc) by creating a new // Update all pods for a ReplicationController (oldRc) by creating a new
// controller (newRc) with 0 replicas, and synchronously resizing oldRc,newRc // controller (newRc) with 0 replicas, and synchronously resizing oldRc,newRc
// by 1 until oldRc has 0 replicas and newRc has the original # of desired // by 1 until oldRc has 0 replicas and newRc has the original # of desired