diff --git a/pkg/kubectl/cmd/rollout/rollout_history.go b/pkg/kubectl/cmd/rollout/rollout_history.go index 9e4b8053398..7083e448b0c 100644 --- a/pkg/kubectl/cmd/rollout/rollout_history.go +++ b/pkg/kubectl/cmd/rollout/rollout_history.go @@ -70,7 +70,7 @@ func RunHistory(f *cmdutil.Factory, cmd *cobra.Command, out io.Writer, args []st if len(args) == 0 && len(options.Filenames) == 0 { return cmdutil.UsageError(cmd, "Required resource not specified.") } - revisionDetail := cmdutil.GetFlagInt64(cmd, "revision") + revision := cmdutil.GetFlagInt64(cmd, "revision") mapper, typer := f.Object(false) @@ -92,7 +92,7 @@ func RunHistory(f *cmdutil.Factory, cmd *cobra.Command, out io.Writer, args []st return err } - err = r.Visit(func(info *resource.Info, err error) error { + return r.Visit(func(info *resource.Info, err error) error { if err != nil { return err } @@ -101,28 +101,17 @@ func RunHistory(f *cmdutil.Factory, cmd *cobra.Command, out io.Writer, args []st if err != nil { return err } - historyInfo, err := historyViewer.History(info.Namespace, info.Name) + historyInfo, err := historyViewer.ViewHistory(info.Namespace, info.Name, revision) if err != nil { return err } - if revisionDetail > 0 { - // Print details of a specific revision - template, ok := historyInfo.RevisionToTemplate[revisionDetail] - if !ok { - return fmt.Errorf("unable to find revision %d of %s %q", revisionDetail, mapping.Resource, info.Name) - } - fmt.Fprintf(out, "%s %q revision %d\n", mapping.Resource, info.Name, revisionDetail) - kubectl.DescribePodTemplate(template, out) - } else { - // Print all revisions - formattedOutput, printErr := kubectl.PrintRolloutHistory(historyInfo, mapping.Resource, info.Name) - if printErr != nil { - return printErr - } - fmt.Fprintf(out, "%s\n", formattedOutput) + header := fmt.Sprintf("%s %q", mapping.Resource, info.Name) + if revision > 0 { + header = fmt.Sprintf("%s with revision #%d", header, revision) } + fmt.Fprintf(out, "%s\n", header) + fmt.Fprintf(out, "%s\n", historyInfo) return nil }) - return err } diff --git a/pkg/kubectl/history.go b/pkg/kubectl/history.go index 067eb2f4300..8485139fe2b 100644 --- a/pkg/kubectl/history.go +++ b/pkg/kubectl/history.go @@ -17,6 +17,7 @@ limitations under the License. package kubectl import ( + "bytes" "fmt" "io" @@ -34,9 +35,9 @@ const ( ChangeCauseAnnotation = "kubernetes.io/change-cause" ) -// HistoryViewer provides an interface for resources that can be rolled back. +// HistoryViewer provides an interface for resources have historical information. type HistoryViewer interface { - History(namespace, name string) (HistoryInfo, error) + ViewHistory(namespace, name string, revision int64) (string, error) } func HistoryViewerFor(kind unversioned.GroupKind, c clientset.Interface) (HistoryViewer, error) { @@ -47,68 +48,68 @@ func HistoryViewerFor(kind unversioned.GroupKind, c clientset.Interface) (Histor return nil, fmt.Errorf("no history viewer has been implemented for %q", kind) } -// HistoryInfo stores the mapping from revision to podTemplate; -// note that change-cause annotation should be copied to podTemplate -type HistoryInfo struct { - RevisionToTemplate map[int64]*api.PodTemplateSpec -} - type DeploymentHistoryViewer struct { c clientset.Interface } -// 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), - } +// 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 historyInfo, fmt.Errorf("failed to retrieve deployment %s: %v", name, err) + return "", 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) + 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.RevisionToTemplate[v] = &rs.Spec.Template + historyInfo[v] = &rs.Spec.Template changeCause := getChangeCause(rs) - if historyInfo.RevisionToTemplate[v].Annotations == nil { - historyInfo.RevisionToTemplate[v].Annotations = make(map[string]string) + if historyInfo[v].Annotations == nil { + historyInfo[v].Annotations = make(map[string]string) } if len(changeCause) > 0 { - historyInfo.RevisionToTemplate[v].Annotations[ChangeCauseAnnotation] = changeCause + historyInfo[v].Annotations[ChangeCauseAnnotation] = changeCause } } - return historyInfo, nil -} -// PrintRolloutHistory prints a formatted table of the input revision history of the deployment -func PrintRolloutHistory(historyInfo HistoryInfo, resource, name string) (string, error) { - if len(historyInfo.RevisionToTemplate) == 0 { - return fmt.Sprintf("No rollout history found in %s %q", resource, name), nil + 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.RevisionToTemplate)) - for r := range historyInfo.RevisionToTemplate { + 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, "%s %q:\n", resource, name) fmt.Fprintf(out, "REVISION\tCHANGE-CAUSE\n") for _, r := range revisions { // Find the change-cause of revision r - changeCause := historyInfo.RevisionToTemplate[r].Annotations[ChangeCauseAnnotation] + changeCause := historyInfo[r].Annotations[ChangeCauseAnnotation] if len(changeCause) == 0 { changeCause = "" }