// 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, err := deploymentutil.GetOldReplicaSets(*deployment, h.c) if err != nil { return historyInfo, fmt.Errorf("failed to retrieve old replica sets from deployment %s: %v", name, err) } newRS, err := deploymentutil.GetNewReplicaSet(*deployment, h.c) if err != nil { return historyInfo, fmt.Errorf("failed to retrieve new replica set from deployment %s: %v", name, err) } allRSs := append(allOldRSs, 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) } historyInfo.RevisionToTemplate[v].Annotations[ChangeCauseAnnotation] = changeCause } return historyInfo, nil }
func maxRevision(allRSs []*extensions.ReplicaSet) int64 { max := int64(0) for _, rs := range allRSs { if v, err := deploymentutil.Revision(rs); err != nil { // Skip the replica sets when it failed to parse their revision information glog.V(4).Infof("Error: %v. Couldn't parse revision for replica set %#v, deployment controller will skip it when reconciling revisions.", err, rs) } else if v > max { max = v } } return max }
func maxRevision(allRCs []*api.ReplicationController) int64 { max := int64(0) for _, rc := range allRCs { if v, err := deploymentutil.Revision(rc); err != nil { // Skip the RCs when it failed to parse their revision information glog.V(4).Infof("Error: %v. Couldn't parse revision for rc %#v, deployment controller will skip it when reconciling revisions.", err, rc) } else if v > max { max = v } } return max }
// 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.getAllReplicaSets(*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 = 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, and increment revision number by 1 // 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) }
// History returns a revision-to-RC 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) } _, allOldRCs, err := deploymentutil.GetOldRCs(*deployment, h.c) if err != nil { return historyInfo, fmt.Errorf("failed to retrieve old RCs from deployment %s: %v", name, err) } newRC, err := deploymentutil.GetNewRC(*deployment, h.c) if err != nil { return historyInfo, fmt.Errorf("failed to retrieve new RC from deployment %s: %v", name, err) } allRCs := append(allOldRCs, newRC) for _, rc := range allRCs { v, err := deploymentutil.Revision(rc) if err != nil { return historyInfo, fmt.Errorf("failed to retrieve revision out of RC %s from deployment %s: %v", rc.Name, name, err) } historyInfo.RevisionToTemplate[v] = rc.Spec.Template changeCause, err := getChangeCause(rc) if err != nil { return historyInfo, fmt.Errorf("failed to retrieve change-cause out of RC %s from deployment %s: %v", rc.Name, name, err) } if len(changeCause) > 0 { if historyInfo.RevisionToTemplate[v].Annotations == nil { historyInfo.RevisionToTemplate[v].Annotations = make(map[string]string) } historyInfo.RevisionToTemplate[v].Annotations[ChangeCauseAnnotation] = changeCause } } return historyInfo, nil }
// ViewHistory prints 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 old replica sets from deployment %s: %v", name, err) } historyInfo := make(map[int64]*api.PodTemplateSpec) allRSs := allOldRSs if newRS != nil { allRSs = append(allRSs, newRS) } 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 var revisions []int64 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 }) }