mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 04:08:16 +00:00 
			
		
		
		
	kubectl: refactor rollout history to be more configurable
ChangeCauseAnnotation is hardcoded in PrintRolloutHistory and it needs to be overriden since other resources that may need to be added in `kubectl rollout history` may not use it. Instead of adding one more method in the factory, refactor the existing HistoryViewer interface to accomodate the change.
This commit is contained in:
		@@ -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 {
 | 
						if len(args) == 0 && len(options.Filenames) == 0 {
 | 
				
			||||||
		return cmdutil.UsageError(cmd, "Required resource not specified.")
 | 
							return cmdutil.UsageError(cmd, "Required resource not specified.")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	revisionDetail := cmdutil.GetFlagInt64(cmd, "revision")
 | 
						revision := cmdutil.GetFlagInt64(cmd, "revision")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mapper, typer := f.Object(false)
 | 
						mapper, typer := f.Object(false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -92,7 +92,7 @@ func RunHistory(f *cmdutil.Factory, cmd *cobra.Command, out io.Writer, args []st
 | 
				
			|||||||
		return err
 | 
							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 {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -101,28 +101,17 @@ func RunHistory(f *cmdutil.Factory, cmd *cobra.Command, out io.Writer, args []st
 | 
				
			|||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		historyInfo, err := historyViewer.History(info.Namespace, info.Name)
 | 
							historyInfo, err := historyViewer.ViewHistory(info.Namespace, info.Name, revision)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if revisionDetail > 0 {
 | 
							header := fmt.Sprintf("%s %q", mapping.Resource, info.Name)
 | 
				
			||||||
			// Print details of a specific revision
 | 
							if revision > 0 {
 | 
				
			||||||
			template, ok := historyInfo.RevisionToTemplate[revisionDetail]
 | 
								header = fmt.Sprintf("%s with revision #%d", header, revision)
 | 
				
			||||||
			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)
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							fmt.Fprintf(out, "%s\n", header)
 | 
				
			||||||
 | 
							fmt.Fprintf(out, "%s\n", historyInfo)
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	return err
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,6 +17,7 @@ limitations under the License.
 | 
				
			|||||||
package kubectl
 | 
					package kubectl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -34,9 +35,9 @@ const (
 | 
				
			|||||||
	ChangeCauseAnnotation = "kubernetes.io/change-cause"
 | 
						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 {
 | 
					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) {
 | 
					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)
 | 
						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 {
 | 
					type DeploymentHistoryViewer struct {
 | 
				
			||||||
	c clientset.Interface
 | 
						c clientset.Interface
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// History returns a revision-to-replicaset map as the revision history of a deployment
 | 
					// ViewHistory returns a revision-to-replicaset map as the revision history of a deployment
 | 
				
			||||||
func (h *DeploymentHistoryViewer) History(namespace, name string) (HistoryInfo, error) {
 | 
					func (h *DeploymentHistoryViewer) ViewHistory(namespace, name string, revision int64) (string, error) {
 | 
				
			||||||
	historyInfo := HistoryInfo{
 | 
					 | 
				
			||||||
		RevisionToTemplate: make(map[int64]*api.PodTemplateSpec),
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	deployment, err := h.c.Extensions().Deployments(namespace).Get(name)
 | 
						deployment, err := h.c.Extensions().Deployments(namespace).Get(name)
 | 
				
			||||||
	if err != nil {
 | 
						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)
 | 
						_, allOldRSs, newRS, err := deploymentutil.GetAllReplicaSets(deployment, h.c)
 | 
				
			||||||
	if err != nil {
 | 
						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
 | 
						allRSs := allOldRSs
 | 
				
			||||||
	if newRS != nil {
 | 
						if newRS != nil {
 | 
				
			||||||
		allRSs = append(allRSs, newRS)
 | 
							allRSs = append(allRSs, newRS)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						historyInfo := make(map[int64]*api.PodTemplateSpec)
 | 
				
			||||||
	for _, rs := range allRSs {
 | 
						for _, rs := range allRSs {
 | 
				
			||||||
		v, err := deploymentutil.Revision(rs)
 | 
							v, err := deploymentutil.Revision(rs)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		historyInfo.RevisionToTemplate[v] = &rs.Spec.Template
 | 
							historyInfo[v] = &rs.Spec.Template
 | 
				
			||||||
		changeCause := getChangeCause(rs)
 | 
							changeCause := getChangeCause(rs)
 | 
				
			||||||
		if historyInfo.RevisionToTemplate[v].Annotations == nil {
 | 
							if historyInfo[v].Annotations == nil {
 | 
				
			||||||
			historyInfo.RevisionToTemplate[v].Annotations = make(map[string]string)
 | 
								historyInfo[v].Annotations = make(map[string]string)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if len(changeCause) > 0 {
 | 
							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
 | 
						if len(historyInfo) == 0 {
 | 
				
			||||||
func PrintRolloutHistory(historyInfo HistoryInfo, resource, name string) (string, error) {
 | 
							return "No rollout history found.", nil
 | 
				
			||||||
	if len(historyInfo.RevisionToTemplate) == 0 {
 | 
					 | 
				
			||||||
		return fmt.Sprintf("No rollout history found in %s %q", resource, name), 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
 | 
						// Sort the revisionToChangeCause map by revision
 | 
				
			||||||
	revisions := make([]int64, 0, len(historyInfo.RevisionToTemplate))
 | 
						revisions := make([]int64, 0, len(historyInfo))
 | 
				
			||||||
	for r := range historyInfo.RevisionToTemplate {
 | 
						for r := range historyInfo {
 | 
				
			||||||
		revisions = append(revisions, r)
 | 
							revisions = append(revisions, r)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	sliceutil.SortInts64(revisions)
 | 
						sliceutil.SortInts64(revisions)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return tabbedString(func(out io.Writer) error {
 | 
						return tabbedString(func(out io.Writer) error {
 | 
				
			||||||
		fmt.Fprintf(out, "%s %q:\n", resource, name)
 | 
					 | 
				
			||||||
		fmt.Fprintf(out, "REVISION\tCHANGE-CAUSE\n")
 | 
							fmt.Fprintf(out, "REVISION\tCHANGE-CAUSE\n")
 | 
				
			||||||
		for _, r := range revisions {
 | 
							for _, r := range revisions {
 | 
				
			||||||
			// Find the change-cause of revision r
 | 
								// Find the change-cause of revision r
 | 
				
			||||||
			changeCause := historyInfo.RevisionToTemplate[r].Annotations[ChangeCauseAnnotation]
 | 
								changeCause := historyInfo[r].Annotations[ChangeCauseAnnotation]
 | 
				
			||||||
			if len(changeCause) == 0 {
 | 
								if len(changeCause) == 0 {
 | 
				
			||||||
				changeCause = "<none>"
 | 
									changeCause = "<none>"
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user