// Status returns a message describing deployment status, and a bool value indicating if the status is considered done func (s *DeploymentStatusViewer) Status(namespace, name string, revision int64) (string, bool, error) { deployment, err := s.c.Deployments(namespace).Get(name) if err != nil { return "", false, err } if revision > 0 { deploymentRev, err := util.Revision(deployment) if err != nil { return "", false, fmt.Errorf("cannot get the revision of deployment %q: %v", deployment.Name, err) } if revision != deploymentRev { return "", false, fmt.Errorf("desired revision (%d) is different from the running revision (%d)", revision, deploymentRev) } } if deployment.Generation <= deployment.Status.ObservedGeneration { if deployment.Status.UpdatedReplicas < deployment.Spec.Replicas { return fmt.Sprintf("Waiting for rollout to finish: %d out of %d new replicas have been updated...\n", deployment.Status.UpdatedReplicas, deployment.Spec.Replicas), false, nil } if deployment.Status.Replicas > deployment.Status.UpdatedReplicas { return fmt.Sprintf("Waiting for rollout to finish: %d old replicas are pending termination...\n", deployment.Status.Replicas-deployment.Status.UpdatedReplicas), false, nil } if deployment.Status.AvailableReplicas < deployment.Status.UpdatedReplicas { return fmt.Sprintf("Waiting for rollout to finish: %d of %d updated replicas are available...\n", deployment.Status.AvailableReplicas, deployment.Status.UpdatedReplicas), false, nil } return fmt.Sprintf("deployment %q successfully rolled out\n", name), true, nil } return fmt.Sprintf("Waiting for deployment spec update to be observed...\n"), false, nil }
// History returns a revision-to-replicaset map as the revision history of a deployment func (h *DeploymentHistoryViewer) History(namespace, name string) (HistoryInfo, error) { historyInfo := HistoryInfo{ RevisionToTemplate: make(map[int64]*api.PodTemplateSpec), } deployment, err := h.c.Extensions().Deployments(namespace).Get(name) if err != nil { return historyInfo, fmt.Errorf("failed to retrieve deployment %s: %v", name, err) } _, allOldRSs, newRS, err := deploymentutil.GetAllReplicaSets(deployment, h.c) if err != nil { return historyInfo, fmt.Errorf("failed to retrieve replica sets from deployment %s: %v", name, err) } allRSs := allOldRSs if newRS != nil { allRSs = append(allRSs, newRS) } for _, rs := range allRSs { v, err := deploymentutil.Revision(rs) if err != nil { continue } historyInfo.RevisionToTemplate[v] = &rs.Spec.Template changeCause := getChangeCause(rs) if historyInfo.RevisionToTemplate[v].Annotations == nil { historyInfo.RevisionToTemplate[v].Annotations = make(map[string]string) } if len(changeCause) > 0 { historyInfo.RevisionToTemplate[v].Annotations[ChangeCauseAnnotation] = changeCause } } return historyInfo, nil }
func simpleDryRun(deployment *extensions.Deployment, c clientset.Interface, toRevision int64) (string, error) { externalDeployment := &externalextensions.Deployment{} if err := api.Scheme.Convert(deployment, externalDeployment, nil); err != nil { return "", fmt.Errorf("failed to convert deployment, %v", err) } versionedClient := versionedClientsetForDeployment(c) _, allOldRSs, newRS, err := deploymentutil.GetAllReplicaSets(externalDeployment, versionedClient) if err != nil { return "", fmt.Errorf("failed to retrieve replica sets from deployment %s: %v", deployment.Name, err) } allRSs := allOldRSs if newRS != nil { allRSs = append(allRSs, newRS) } revisionToSpec := make(map[int64]*v1.PodTemplateSpec) for _, rs := range allRSs { v, err := deploymentutil.Revision(rs) if err != nil { continue } revisionToSpec[v] = &rs.Spec.Template } if len(revisionToSpec) == 0 { return "No rollout history found.", nil } if toRevision > 0 { template, ok := revisionToSpec[toRevision] if !ok { return "", fmt.Errorf("unable to find specified revision") } buf := bytes.NewBuffer([]byte{}) internalTemplate := &api.PodTemplateSpec{} if err := v1.Convert_v1_PodTemplateSpec_To_api_PodTemplateSpec(template, internalTemplate, nil); err != nil { return "", fmt.Errorf("failed to convert podtemplate, %v", err) } DescribePodTemplate(internalTemplate, buf) return buf.String(), nil } // Sort the revisionToSpec map by revision revisions := make([]int64, 0, len(revisionToSpec)) for r := range revisionToSpec { revisions = append(revisions, r) } sliceutil.SortInts64(revisions) template, _ := revisionToSpec[revisions[len(revisions)-1]] buf := bytes.NewBuffer([]byte{}) buf.WriteString("\n") internalTemplate := &api.PodTemplateSpec{} if err := v1.Convert_v1_PodTemplateSpec_To_api_PodTemplateSpec(template, internalTemplate, nil); err != nil { return "", fmt.Errorf("failed to convert podtemplate, %v", err) } DescribePodTemplate(internalTemplate, buf) return buf.String(), nil }
// Rolling back to a revision; no-op if the toRevision is deployment's current revision func (dc *DeploymentController) rollback(deployment *extensions.Deployment, toRevision *int64) (*extensions.Deployment, error) { newRS, allOldRSs, err := dc.getAllReplicaSetsAndSyncRevision(deployment, true) if err != nil { return nil, err } allRSs := append(allOldRSs, newRS) // If rollback revision is 0, rollback to the last revision if *toRevision == 0 { if *toRevision = deploymentutil.LastRevision(allRSs); *toRevision == 0 { // If we still can't find the last revision, gives up rollback dc.emitRollbackWarningEvent(deployment, deploymentutil.RollbackRevisionNotFound, "Unable to find last revision.") // Gives up rollback return dc.updateDeploymentAndClearRollbackTo(deployment) } } for _, rs := range allRSs { v, err := deploymentutil.Revision(rs) if err != nil { glog.V(4).Infof("Unable to extract revision from deployment's replica set %q: %v", rs.Name, err) continue } if v == *toRevision { glog.V(4).Infof("Found replica set %q with desired revision %d", rs.Name, v) // rollback by copying podTemplate.Spec from the replica set // revision number will be incremented during the next getAllReplicaSetsAndSyncRevision call // no-op if the the spec matches current deployment's podTemplate.Spec deployment, performedRollback, err := dc.rollbackToTemplate(deployment, rs) if performedRollback && err == nil { dc.emitRollbackNormalEvent(deployment, fmt.Sprintf("Rolled back deployment %q to revision %d", deployment.Name, *toRevision)) } return deployment, err } } dc.emitRollbackWarningEvent(deployment, deploymentutil.RollbackRevisionNotFound, "Unable to find the revision to rollback to.") // Gives up rollback return dc.updateDeploymentAndClearRollbackTo(deployment) }
// ViewHistory returns a revision-to-replicaset map as the revision history of a deployment func (h *DeploymentHistoryViewer) ViewHistory(namespace, name string, revision int64) (string, error) { deployment, err := h.c.Extensions().Deployments(namespace).Get(name) if err != nil { return "", fmt.Errorf("failed to retrieve deployment %s: %v", name, err) } _, allOldRSs, newRS, err := deploymentutil.GetAllReplicaSets(deployment, h.c) if err != nil { return "", fmt.Errorf("failed to retrieve replica sets from deployment %s: %v", name, err) } allRSs := allOldRSs if newRS != nil { allRSs = append(allRSs, newRS) } historyInfo := make(map[int64]*api.PodTemplateSpec) for _, rs := range allRSs { v, err := deploymentutil.Revision(rs) if err != nil { continue } historyInfo[v] = &rs.Spec.Template changeCause := getChangeCause(rs) if historyInfo[v].Annotations == nil { historyInfo[v].Annotations = make(map[string]string) } if len(changeCause) > 0 { historyInfo[v].Annotations[ChangeCauseAnnotation] = changeCause } } if len(historyInfo) == 0 { return "No rollout history found.", nil } if revision > 0 { // Print details of a specific revision template, ok := historyInfo[revision] if !ok { return "", fmt.Errorf("unable to find the specified revision") } buf := bytes.NewBuffer([]byte{}) DescribePodTemplate(template, buf) return buf.String(), nil } // Sort the revisionToChangeCause map by revision revisions := make([]int64, 0, len(historyInfo)) for r := range historyInfo { revisions = append(revisions, r) } sliceutil.SortInts64(revisions) return tabbedString(func(out io.Writer) error { fmt.Fprintf(out, "REVISION\tCHANGE-CAUSE\n") for _, r := range revisions { // Find the change-cause of revision r changeCause := historyInfo[r].Annotations[ChangeCauseAnnotation] if len(changeCause) == 0 { changeCause = "<none>" } fmt.Fprintf(out, "%d\t%s\n", r, changeCause) } return nil }) }