mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-10-31 18:28:13 +00:00 
			
		
		
		
	Add kubectl rollout history
This commit is contained in:
		| @@ -43,6 +43,7 @@ docs/man/man1/kubectl-port-forward.1 | |||||||
| docs/man/man1/kubectl-proxy.1 | docs/man/man1/kubectl-proxy.1 | ||||||
| docs/man/man1/kubectl-replace.1 | docs/man/man1/kubectl-replace.1 | ||||||
| docs/man/man1/kubectl-rolling-update.1 | docs/man/man1/kubectl-rolling-update.1 | ||||||
|  | docs/man/man1/kubectl-rollout-history.1 | ||||||
| docs/man/man1/kubectl-rollout.1 | docs/man/man1/kubectl-rollout.1 | ||||||
| docs/man/man1/kubectl-run.1 | docs/man/man1/kubectl-run.1 | ||||||
| docs/man/man1/kubectl-scale.1 | docs/man/man1/kubectl-scale.1 | ||||||
| @@ -90,6 +91,7 @@ docs/user-guide/kubectl/kubectl_proxy.md | |||||||
| docs/user-guide/kubectl/kubectl_replace.md | docs/user-guide/kubectl/kubectl_replace.md | ||||||
| docs/user-guide/kubectl/kubectl_rolling-update.md | docs/user-guide/kubectl/kubectl_rolling-update.md | ||||||
| docs/user-guide/kubectl/kubectl_rollout.md | docs/user-guide/kubectl/kubectl_rollout.md | ||||||
|  | docs/user-guide/kubectl/kubectl_rollout_history.md | ||||||
| docs/user-guide/kubectl/kubectl_run.md | docs/user-guide/kubectl/kubectl_run.md | ||||||
| docs/user-guide/kubectl/kubectl_scale.md | docs/user-guide/kubectl/kubectl_scale.md | ||||||
| docs/user-guide/kubectl/kubectl_uncordon.md | docs/user-guide/kubectl/kubectl_uncordon.md | ||||||
|   | |||||||
| @@ -1656,10 +1656,57 @@ _kubectl_autoscale() | |||||||
|     must_have_one_noun=() |     must_have_one_noun=() | ||||||
| } | } | ||||||
|  |  | ||||||
|  | _kubectl_rollout_history() | ||||||
|  | { | ||||||
|  |     last_command="kubectl_rollout_history" | ||||||
|  |     commands=() | ||||||
|  |  | ||||||
|  |     flags=() | ||||||
|  |     two_word_flags=() | ||||||
|  |     flags_with_completion=() | ||||||
|  |     flags_completion=() | ||||||
|  |  | ||||||
|  |     flags+=("--filename=") | ||||||
|  |     flags_with_completion+=("--filename") | ||||||
|  |     flags_completion+=("__handle_filename_extension_flag json|yaml|yml") | ||||||
|  |     two_word_flags+=("-f") | ||||||
|  |     flags_with_completion+=("-f") | ||||||
|  |     flags_completion+=("__handle_filename_extension_flag json|yaml|yml") | ||||||
|  |     flags+=("--revision=") | ||||||
|  |     flags+=("--alsologtostderr") | ||||||
|  |     flags+=("--api-version=") | ||||||
|  |     flags+=("--certificate-authority=") | ||||||
|  |     flags+=("--client-certificate=") | ||||||
|  |     flags+=("--client-key=") | ||||||
|  |     flags+=("--cluster=") | ||||||
|  |     flags+=("--context=") | ||||||
|  |     flags+=("--insecure-skip-tls-verify") | ||||||
|  |     flags+=("--kubeconfig=") | ||||||
|  |     flags+=("--log-backtrace-at=") | ||||||
|  |     flags+=("--log-dir=") | ||||||
|  |     flags+=("--log-flush-frequency=") | ||||||
|  |     flags+=("--logtostderr") | ||||||
|  |     flags+=("--match-server-version") | ||||||
|  |     flags+=("--namespace=") | ||||||
|  |     flags+=("--password=") | ||||||
|  |     flags+=("--server=") | ||||||
|  |     two_word_flags+=("-s") | ||||||
|  |     flags+=("--stderrthreshold=") | ||||||
|  |     flags+=("--token=") | ||||||
|  |     flags+=("--user=") | ||||||
|  |     flags+=("--username=") | ||||||
|  |     flags+=("--v=") | ||||||
|  |     flags+=("--vmodule=") | ||||||
|  |  | ||||||
|  |     must_have_one_flag=() | ||||||
|  |     must_have_one_noun=() | ||||||
|  | } | ||||||
|  |  | ||||||
| _kubectl_rollout() | _kubectl_rollout() | ||||||
| { | { | ||||||
|     last_command="kubectl_rollout" |     last_command="kubectl_rollout" | ||||||
|     commands=() |     commands=() | ||||||
|  |     commands+=("history") | ||||||
|  |  | ||||||
|     flags=() |     flags=() | ||||||
|     two_word_flags=() |     two_word_flags=() | ||||||
|   | |||||||
							
								
								
									
										142
									
								
								docs/man/man1/kubectl-rollout-history.1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								docs/man/man1/kubectl-rollout-history.1
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,142 @@ | |||||||
|  | .TH "KUBERNETES" "1" " kubernetes User Manuals" "Eric Paris" "Jan 2015"  "" | ||||||
|  |  | ||||||
|  |  | ||||||
|  | .SH NAME | ||||||
|  | .PP | ||||||
|  | kubectl rollout history \- view rollout history | ||||||
|  |  | ||||||
|  |  | ||||||
|  | .SH SYNOPSIS | ||||||
|  | .PP | ||||||
|  | \fBkubectl rollout history\fP [OPTIONS] | ||||||
|  |  | ||||||
|  |  | ||||||
|  | .SH DESCRIPTION | ||||||
|  | .PP | ||||||
|  | view previous rollout revisions and configurations. | ||||||
|  |  | ||||||
|  |  | ||||||
|  | .SH OPTIONS | ||||||
|  | .PP | ||||||
|  | \fB\-f\fP, \fB\-\-filename\fP=[] | ||||||
|  |     Filename, directory, or URL to a file identifying the resource to get from a server. | ||||||
|  |  | ||||||
|  | .PP | ||||||
|  | \fB\-\-revision\fP=0 | ||||||
|  |     See the details, including podTemplate of the revision specified | ||||||
|  |  | ||||||
|  |  | ||||||
|  | .SH OPTIONS INHERITED FROM PARENT COMMANDS | ||||||
|  | .PP | ||||||
|  | \fB\-\-alsologtostderr\fP=false | ||||||
|  |     log to standard error as well as files | ||||||
|  |  | ||||||
|  | .PP | ||||||
|  | \fB\-\-api\-version\fP="" | ||||||
|  |     The API version to use when talking to the server | ||||||
|  |  | ||||||
|  | .PP | ||||||
|  | \fB\-\-certificate\-authority\fP="" | ||||||
|  |     Path to a cert. file for the certificate authority. | ||||||
|  |  | ||||||
|  | .PP | ||||||
|  | \fB\-\-client\-certificate\fP="" | ||||||
|  |     Path to a client certificate file for TLS. | ||||||
|  |  | ||||||
|  | .PP | ||||||
|  | \fB\-\-client\-key\fP="" | ||||||
|  |     Path to a client key file for TLS. | ||||||
|  |  | ||||||
|  | .PP | ||||||
|  | \fB\-\-cluster\fP="" | ||||||
|  |     The name of the kubeconfig cluster to use | ||||||
|  |  | ||||||
|  | .PP | ||||||
|  | \fB\-\-context\fP="" | ||||||
|  |     The name of the kubeconfig context to use | ||||||
|  |  | ||||||
|  | .PP | ||||||
|  | \fB\-\-insecure\-skip\-tls\-verify\fP=false | ||||||
|  |     If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure. | ||||||
|  |  | ||||||
|  | .PP | ||||||
|  | \fB\-\-kubeconfig\fP="" | ||||||
|  |     Path to the kubeconfig file to use for CLI requests. | ||||||
|  |  | ||||||
|  | .PP | ||||||
|  | \fB\-\-log\-backtrace\-at\fP=:0 | ||||||
|  |     when logging hits line file:N, emit a stack trace | ||||||
|  |  | ||||||
|  | .PP | ||||||
|  | \fB\-\-log\-dir\fP="" | ||||||
|  |     If non\-empty, write log files in this directory | ||||||
|  |  | ||||||
|  | .PP | ||||||
|  | \fB\-\-log\-flush\-frequency\fP=5s | ||||||
|  |     Maximum number of seconds between log flushes | ||||||
|  |  | ||||||
|  | .PP | ||||||
|  | \fB\-\-logtostderr\fP=true | ||||||
|  |     log to standard error instead of files | ||||||
|  |  | ||||||
|  | .PP | ||||||
|  | \fB\-\-match\-server\-version\fP=false | ||||||
|  |     Require server version to match client version | ||||||
|  |  | ||||||
|  | .PP | ||||||
|  | \fB\-\-namespace\fP="" | ||||||
|  |     If present, the namespace scope for this CLI request. | ||||||
|  |  | ||||||
|  | .PP | ||||||
|  | \fB\-\-password\fP="" | ||||||
|  |     Password for basic authentication to the API server. | ||||||
|  |  | ||||||
|  | .PP | ||||||
|  | \fB\-s\fP, \fB\-\-server\fP="" | ||||||
|  |     The address and port of the Kubernetes API server | ||||||
|  |  | ||||||
|  | .PP | ||||||
|  | \fB\-\-stderrthreshold\fP=2 | ||||||
|  |     logs at or above this threshold go to stderr | ||||||
|  |  | ||||||
|  | .PP | ||||||
|  | \fB\-\-token\fP="" | ||||||
|  |     Bearer token for authentication to the API server. | ||||||
|  |  | ||||||
|  | .PP | ||||||
|  | \fB\-\-user\fP="" | ||||||
|  |     The name of the kubeconfig user to use | ||||||
|  |  | ||||||
|  | .PP | ||||||
|  | \fB\-\-username\fP="" | ||||||
|  |     Username for basic authentication to the API server. | ||||||
|  |  | ||||||
|  | .PP | ||||||
|  | \fB\-\-v\fP=0 | ||||||
|  |     log level for V logs | ||||||
|  |  | ||||||
|  | .PP | ||||||
|  | \fB\-\-vmodule\fP= | ||||||
|  |     comma\-separated list of pattern=N settings for file\-filtered logging | ||||||
|  |  | ||||||
|  |  | ||||||
|  | .SH EXAMPLE | ||||||
|  | .PP | ||||||
|  | .RS | ||||||
|  |  | ||||||
|  | .nf | ||||||
|  | # View the rollout history of a deployment | ||||||
|  | $ kubectl rollout history deployment/abc | ||||||
|  |  | ||||||
|  | .fi | ||||||
|  | .RE | ||||||
|  |  | ||||||
|  |  | ||||||
|  | .SH SEE ALSO | ||||||
|  | .PP | ||||||
|  | \fBkubectl\-rollout(1)\fP, | ||||||
|  |  | ||||||
|  |  | ||||||
|  | .SH HISTORY | ||||||
|  | .PP | ||||||
|  | January 2015, Originally compiled by Eric Paris (eparis at redhat dot com) based on the kubernetes source material, but hopefully they have been automatically generated since! | ||||||
| @@ -112,7 +112,7 @@ rollout manages a deployment using subcommands | |||||||
|  |  | ||||||
| .SH SEE ALSO | .SH SEE ALSO | ||||||
| .PP | .PP | ||||||
| \fBkubectl(1)\fP, | \fBkubectl(1)\fP, \fBkubectl\-rollout\-history(1)\fP, | ||||||
|  |  | ||||||
|  |  | ||||||
| .SH HISTORY | .SH HISTORY | ||||||
|   | |||||||
| @@ -71,6 +71,7 @@ kubectl rollout SUBCOMMAND | |||||||
| ### SEE ALSO | ### SEE ALSO | ||||||
|  |  | ||||||
| * [kubectl](kubectl.md)	 - kubectl controls the Kubernetes cluster manager | * [kubectl](kubectl.md)	 - kubectl controls the Kubernetes cluster manager | ||||||
|  | * [kubectl rollout history](kubectl_rollout_history.md)	 - view rollout history | ||||||
|  |  | ||||||
| ###### Auto generated by spf13/cobra on 20-Jan-2016 | ###### Auto generated by spf13/cobra on 20-Jan-2016 | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										93
									
								
								docs/user-guide/kubectl/kubectl_rollout_history.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								docs/user-guide/kubectl/kubectl_rollout_history.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,93 @@ | |||||||
|  | <!-- BEGIN MUNGE: UNVERSIONED_WARNING --> | ||||||
|  |  | ||||||
|  | <!-- BEGIN STRIP_FOR_RELEASE --> | ||||||
|  |  | ||||||
|  | <img src="http://kubernetes.io/img/warning.png" alt="WARNING" | ||||||
|  |      width="25" height="25"> | ||||||
|  | <img src="http://kubernetes.io/img/warning.png" alt="WARNING" | ||||||
|  |      width="25" height="25"> | ||||||
|  | <img src="http://kubernetes.io/img/warning.png" alt="WARNING" | ||||||
|  |      width="25" height="25"> | ||||||
|  | <img src="http://kubernetes.io/img/warning.png" alt="WARNING" | ||||||
|  |      width="25" height="25"> | ||||||
|  | <img src="http://kubernetes.io/img/warning.png" alt="WARNING" | ||||||
|  |      width="25" height="25"> | ||||||
|  |  | ||||||
|  | <h2>PLEASE NOTE: This document applies to the HEAD of the source tree</h2> | ||||||
|  |  | ||||||
|  | If you are using a released version of Kubernetes, you should | ||||||
|  | refer to the docs that go with that version. | ||||||
|  |  | ||||||
|  | Documentation for other releases can be found at | ||||||
|  | [releases.k8s.io](http://releases.k8s.io). | ||||||
|  | </strong> | ||||||
|  | -- | ||||||
|  |  | ||||||
|  | <!-- END STRIP_FOR_RELEASE --> | ||||||
|  |  | ||||||
|  | <!-- END MUNGE: UNVERSIONED_WARNING --> | ||||||
|  |  | ||||||
|  | ## kubectl rollout history | ||||||
|  |  | ||||||
|  | view rollout history | ||||||
|  |  | ||||||
|  | ### Synopsis | ||||||
|  |  | ||||||
|  |  | ||||||
|  | view previous rollout revisions and configurations. | ||||||
|  |  | ||||||
|  | ``` | ||||||
|  | kubectl rollout history (TYPE NAME | TYPE/NAME) [flags] | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ### Examples | ||||||
|  |  | ||||||
|  | ``` | ||||||
|  | # View the rollout history of a deployment | ||||||
|  | $ kubectl rollout history deployment/abc | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ### Options | ||||||
|  |  | ||||||
|  | ``` | ||||||
|  |   -f, --filename=[]: Filename, directory, or URL to a file identifying the resource to get from a server. | ||||||
|  |       --revision=0: See the details, including podTemplate of the revision specified | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ### Options inherited from parent commands | ||||||
|  |  | ||||||
|  | ``` | ||||||
|  |       --alsologtostderr[=false]: log to standard error as well as files | ||||||
|  |       --api-version="": The API version to use when talking to the server | ||||||
|  |       --certificate-authority="": Path to a cert. file for the certificate authority. | ||||||
|  |       --client-certificate="": Path to a client certificate file for TLS. | ||||||
|  |       --client-key="": Path to a client key file for TLS. | ||||||
|  |       --cluster="": The name of the kubeconfig cluster to use | ||||||
|  |       --context="": The name of the kubeconfig context to use | ||||||
|  |       --insecure-skip-tls-verify[=false]: If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure. | ||||||
|  |       --kubeconfig="": Path to the kubeconfig file to use for CLI requests. | ||||||
|  |       --log-backtrace-at=:0: when logging hits line file:N, emit a stack trace | ||||||
|  |       --log-dir="": If non-empty, write log files in this directory | ||||||
|  |       --log-flush-frequency=5s: Maximum number of seconds between log flushes | ||||||
|  |       --logtostderr[=true]: log to standard error instead of files | ||||||
|  |       --match-server-version[=false]: Require server version to match client version | ||||||
|  |       --namespace="": If present, the namespace scope for this CLI request. | ||||||
|  |       --password="": Password for basic authentication to the API server. | ||||||
|  |   -s, --server="": The address and port of the Kubernetes API server | ||||||
|  |       --stderrthreshold=2: logs at or above this threshold go to stderr | ||||||
|  |       --token="": Bearer token for authentication to the API server. | ||||||
|  |       --user="": The name of the kubeconfig user to use | ||||||
|  |       --username="": Username for basic authentication to the API server. | ||||||
|  |       --v=0: log level for V logs | ||||||
|  |       --vmodule=: comma-separated list of pattern=N settings for file-filtered logging | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ### SEE ALSO | ||||||
|  |  | ||||||
|  | * [kubectl rollout](kubectl_rollout.md)	 - rollout manages a deployment | ||||||
|  |  | ||||||
|  | ###### Auto generated by spf13/cobra on 29-Jan-2016 | ||||||
|  |  | ||||||
|  | <!-- BEGIN MUNGE: GENERATED_ANALYTICS --> | ||||||
|  | []() | ||||||
|  | <!-- END MUNGE: GENERATED_ANALYTICS --> | ||||||
| @@ -451,7 +451,7 @@ func (dc *DeploymentController) rollback(deployment *extensions.Deployment, toRe | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	for _, rc := range allRCs { | 	for _, rc := range allRCs { | ||||||
| 		v, err := revision(rc) | 		v, err := deploymentutil.Revision(rc) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			glog.V(4).Infof("Unable to extract revision from deployment's rc %q: %v", rc.Name, err) | 			glog.V(4).Infof("Unable to extract revision from deployment's rc %q: %v", rc.Name, err) | ||||||
| 			continue | 			continue | ||||||
| @@ -617,18 +617,10 @@ func (dc *DeploymentController) getNewRCAndAllOldRCs(deployment extensions.Deplo | |||||||
| 	return dc.getNewRCAndMaybeFilteredOldRCs(deployment, false) | 	return dc.getNewRCAndMaybeFilteredOldRCs(deployment, false) | ||||||
| } | } | ||||||
|  |  | ||||||
| func revision(rc *api.ReplicationController) (int64, error) { |  | ||||||
| 	v, ok := rc.Annotations[deploymentutil.RevisionAnnotation] |  | ||||||
| 	if !ok { |  | ||||||
| 		return 0, nil |  | ||||||
| 	} |  | ||||||
| 	return strconv.ParseInt(v, 10, 64) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func maxRevision(allRCs []*api.ReplicationController) int64 { | func maxRevision(allRCs []*api.ReplicationController) int64 { | ||||||
| 	max := int64(0) | 	max := int64(0) | ||||||
| 	for _, rc := range allRCs { | 	for _, rc := range allRCs { | ||||||
| 		if v, err := revision(rc); err != nil { | 		if v, err := deploymentutil.Revision(rc); err != nil { | ||||||
| 			// Skip the RCs when it failed to parse their revision information | 			// 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) | 			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 { | 		} else if v > max { | ||||||
| @@ -642,7 +634,7 @@ func maxRevision(allRCs []*api.ReplicationController) int64 { | |||||||
| func lastRevision(allRCs []*api.ReplicationController) int64 { | func lastRevision(allRCs []*api.ReplicationController) int64 { | ||||||
| 	max, secMax := int64(0), int64(0) | 	max, secMax := int64(0), int64(0) | ||||||
| 	for _, rc := range allRCs { | 	for _, rc := range allRCs { | ||||||
| 		if v, err := revision(rc); err != nil { | 		if v, err := deploymentutil.Revision(rc); err != nil { | ||||||
| 			// Skip the RCs when it failed to parse their revision information | 			// 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) | 			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 { | 		} else if v >= max { | ||||||
|   | |||||||
| @@ -43,5 +43,7 @@ func NewCmdRollout(f *cmdutil.Factory, out io.Writer) *cobra.Command { | |||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	cmd.AddCommand(NewCmdRolloutHistory(f, out)) | ||||||
|  |  | ||||||
| 	return cmd | 	return cmd | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										122
									
								
								pkg/kubectl/cmd/rollout/rollout_history.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								pkg/kubectl/cmd/rollout/rollout_history.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,122 @@ | |||||||
|  | /* | ||||||
|  | Copyright 2016 The Kubernetes Authors All rights reserved. | ||||||
|  |  | ||||||
|  | Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  | you may not use this file except in compliance with the License. | ||||||
|  | You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  | Unless required by applicable law or agreed to in writing, software | ||||||
|  | distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  | See the License for the specific language governing permissions and | ||||||
|  | limitations under the License. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | package rollout | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"io" | ||||||
|  |  | ||||||
|  | 	"k8s.io/kubernetes/pkg/kubectl" | ||||||
|  | 	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" | ||||||
|  | 	"k8s.io/kubernetes/pkg/kubectl/resource" | ||||||
|  | 	"k8s.io/kubernetes/pkg/util/errors" | ||||||
|  |  | ||||||
|  | 	"github.com/spf13/cobra" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // HistoryOptions is the start of the data required to perform the operation.  As new fields are added, add them here instead of | ||||||
|  | // referencing the cmd.Flags() | ||||||
|  | type HistoryOptions struct { | ||||||
|  | 	Filenames []string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	history_long    = `view previous rollout revisions and configurations.` | ||||||
|  | 	history_example = `# View the rollout history of a deployment | ||||||
|  | $ kubectl rollout history deployment/abc` | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func NewCmdRolloutHistory(f *cmdutil.Factory, out io.Writer) *cobra.Command { | ||||||
|  | 	options := &HistoryOptions{} | ||||||
|  |  | ||||||
|  | 	cmd := &cobra.Command{ | ||||||
|  | 		Use:     "history (TYPE NAME | TYPE/NAME) [flags]", | ||||||
|  | 		Short:   "view rollout history", | ||||||
|  | 		Long:    history_long, | ||||||
|  | 		Example: history_example, | ||||||
|  | 		Run: func(cmd *cobra.Command, args []string) { | ||||||
|  | 			cmdutil.CheckErr(RunHistory(f, cmd, out, args, options)) | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	cmd.Flags().Int64("revision", 0, "See the details, including podTemplate of the revision specified") | ||||||
|  | 	usage := "Filename, directory, or URL to a file identifying the resource to get from a server." | ||||||
|  | 	kubectl.AddJsonFilenameFlag(cmd, &options.Filenames, usage) | ||||||
|  | 	return cmd | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func RunHistory(f *cmdutil.Factory, cmd *cobra.Command, out io.Writer, args []string, options *HistoryOptions) error { | ||||||
|  | 	if len(args) == 0 && len(options.Filenames) == 0 { | ||||||
|  | 		return cmdutil.UsageError(cmd, "Required resource not specified.") | ||||||
|  | 	} | ||||||
|  | 	revisionDetail := cmdutil.GetFlagInt64(cmd, "revision") | ||||||
|  |  | ||||||
|  | 	mapper, typer := f.Object() | ||||||
|  |  | ||||||
|  | 	cmdNamespace, enforceNamespace, err := f.DefaultNamespace() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	infos, err := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)). | ||||||
|  | 		NamespaceParam(cmdNamespace).DefaultNamespace(). | ||||||
|  | 		FilenameParam(enforceNamespace, options.Filenames...). | ||||||
|  | 		ResourceTypeOrNameArgs(true, args...). | ||||||
|  | 		Latest(). | ||||||
|  | 		Flatten(). | ||||||
|  | 		Do(). | ||||||
|  | 		Infos() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	errs := []error{} | ||||||
|  | 	for _, info := range infos { | ||||||
|  | 		mapping := info.ResourceMapping() | ||||||
|  | 		historyViewer, err := f.HistoryViewer(mapping) | ||||||
|  | 		if err != nil { | ||||||
|  | 			errs = append(errs, err) | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		historyInfo, err := historyViewer.History(info.Namespace, info.Name) | ||||||
|  | 		if err != nil { | ||||||
|  | 			errs = append(errs, err) | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		formattedOutput := "" | ||||||
|  | 		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) | ||||||
|  | 			formattedOutput, err = kubectl.DescribePodTemplate(template) | ||||||
|  | 		} else { | ||||||
|  | 			// Print all revisions | ||||||
|  | 			formattedOutput, err = kubectl.PrintRolloutHistory(historyInfo, mapping.Resource, info.Name) | ||||||
|  | 		} | ||||||
|  | 		if err != nil { | ||||||
|  | 			errs = append(errs, err) | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		fmt.Fprintf(out, "%s\n", formattedOutput) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return errors.NewAggregate(errs) | ||||||
|  | } | ||||||
| @@ -39,6 +39,7 @@ import ( | |||||||
| 	"k8s.io/kubernetes/pkg/api/validation" | 	"k8s.io/kubernetes/pkg/api/validation" | ||||||
| 	"k8s.io/kubernetes/pkg/apimachinery/registered" | 	"k8s.io/kubernetes/pkg/apimachinery/registered" | ||||||
| 	"k8s.io/kubernetes/pkg/apis/extensions" | 	"k8s.io/kubernetes/pkg/apis/extensions" | ||||||
|  | 	clientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_1" | ||||||
| 	client "k8s.io/kubernetes/pkg/client/unversioned" | 	client "k8s.io/kubernetes/pkg/client/unversioned" | ||||||
| 	"k8s.io/kubernetes/pkg/client/unversioned/clientcmd" | 	"k8s.io/kubernetes/pkg/client/unversioned/clientcmd" | ||||||
| 	"k8s.io/kubernetes/pkg/kubectl" | 	"k8s.io/kubernetes/pkg/kubectl" | ||||||
| @@ -85,6 +86,8 @@ type Factory struct { | |||||||
| 	Scaler func(mapping *meta.RESTMapping) (kubectl.Scaler, error) | 	Scaler func(mapping *meta.RESTMapping) (kubectl.Scaler, error) | ||||||
| 	// Returns a Reaper for gracefully shutting down resources. | 	// Returns a Reaper for gracefully shutting down resources. | ||||||
| 	Reaper func(mapping *meta.RESTMapping) (kubectl.Reaper, error) | 	Reaper func(mapping *meta.RESTMapping) (kubectl.Reaper, error) | ||||||
|  | 	// Returns a HistoryViewer for viewing change history | ||||||
|  | 	HistoryViewer func(mapping *meta.RESTMapping) (kubectl.HistoryViewer, error) | ||||||
| 	// PodSelectorForObject returns the pod selector associated with the provided object | 	// PodSelectorForObject returns the pod selector associated with the provided object | ||||||
| 	PodSelectorForObject func(object runtime.Object) (string, error) | 	PodSelectorForObject func(object runtime.Object) (string, error) | ||||||
| 	// PortsForObject returns the ports associated with the provided object | 	// PortsForObject returns the ports associated with the provided object | ||||||
| @@ -313,6 +316,15 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory { | |||||||
| 			} | 			} | ||||||
| 			return kubectl.ReaperFor(mapping.GroupVersionKind.GroupKind(), client) | 			return kubectl.ReaperFor(mapping.GroupVersionKind.GroupKind(), client) | ||||||
| 		}, | 		}, | ||||||
|  | 		HistoryViewer: func(mapping *meta.RESTMapping) (kubectl.HistoryViewer, error) { | ||||||
|  | 			mappingVersion := mapping.GroupVersionKind.GroupVersion() | ||||||
|  | 			client, err := clients.ClientForVersion(&mappingVersion) | ||||||
|  | 			clientset := clientset.FromUnversionedClient(client) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return nil, err | ||||||
|  | 			} | ||||||
|  | 			return kubectl.HistoryViewerFor(mapping.GroupVersionKind.GroupKind(), clientset) | ||||||
|  | 		}, | ||||||
| 		Validator: func(validate bool, cacheDir string) (validation.Schema, error) { | 		Validator: func(validate bool, cacheDir string) (validation.Schema, error) { | ||||||
| 			if validate { | 			if validate { | ||||||
| 				client, err := clients.ClientForVersion(nil) | 				client, err := clients.ClientForVersion(nil) | ||||||
|   | |||||||
| @@ -885,6 +885,20 @@ func describeReplicationController(controller *api.ReplicationController, events | |||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func DescribePodTemplate(template *api.PodTemplateSpec) (string, error) { | ||||||
|  | 	return tabbedString(func(out io.Writer) error { | ||||||
|  | 		if template == nil { | ||||||
|  | 			fmt.Fprintf(out, "<no template>") | ||||||
|  | 			return nil | ||||||
|  | 		} | ||||||
|  | 		fmt.Fprintf(out, "Labels:\t%s\n", labels.FormatLabels(template.Labels)) | ||||||
|  | 		fmt.Fprintf(out, "Annotations:\t%s\n", labels.FormatLabels(template.Annotations)) | ||||||
|  | 		fmt.Fprintf(out, "Image(s):\t%s\n", makeImageList(&template.Spec)) | ||||||
|  | 		describeVolumes(template.Spec.Volumes, out) | ||||||
|  | 		return nil | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  |  | ||||||
| // JobDescriber generates information about a job and the pods it has created. | // JobDescriber generates information about a job and the pods it has created. | ||||||
| type JobDescriber struct { | type JobDescriber struct { | ||||||
| 	client *client.Client | 	client *client.Client | ||||||
|   | |||||||
							
								
								
									
										139
									
								
								pkg/kubectl/history.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								pkg/kubectl/history.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,139 @@ | |||||||
|  | /* | ||||||
|  | Copyright 2016 The Kubernetes Authors All rights reserved. | ||||||
|  |  | ||||||
|  | Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  | you may not use this file except in compliance with the License. | ||||||
|  | You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  | Unless required by applicable law or agreed to in writing, software | ||||||
|  | distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  | See the License for the specific language governing permissions and | ||||||
|  | limitations under the License. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | package kubectl | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"io" | ||||||
|  | 	"sort" | ||||||
|  | 	"strconv" | ||||||
|  |  | ||||||
|  | 	"k8s.io/kubernetes/pkg/api" | ||||||
|  | 	"k8s.io/kubernetes/pkg/api/unversioned" | ||||||
|  | 	"k8s.io/kubernetes/pkg/apis/extensions" | ||||||
|  | 	clientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_1" | ||||||
|  | 	"k8s.io/kubernetes/pkg/runtime" | ||||||
|  | 	deploymentutil "k8s.io/kubernetes/pkg/util/deployment" | ||||||
|  | 	"k8s.io/kubernetes/pkg/util/errors" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	ChangeCauseAnnotation = "kubernetes.io/change-cause" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // HistoryViewer provides an interface for resources that can be rolled back. | ||||||
|  | type HistoryViewer interface { | ||||||
|  | 	History(namespace, name string) (HistoryInfo, error) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func HistoryViewerFor(kind unversioned.GroupKind, c clientset.Interface) (HistoryViewer, error) { | ||||||
|  | 	switch kind { | ||||||
|  | 	case extensions.Kind("Deployment"): | ||||||
|  | 		return &DeploymentHistoryViewer{c}, nil | ||||||
|  | 	} | ||||||
|  | 	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-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 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // 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 | ||||||
|  | 	} | ||||||
|  | 	// Sort the revisionToChangeCause map by revision | ||||||
|  | 	var revisions []string | ||||||
|  | 	for k := range historyInfo.RevisionToTemplate { | ||||||
|  | 		revisions = append(revisions, strconv.FormatInt(k, 10)) | ||||||
|  | 	} | ||||||
|  | 	sort.Strings(revisions) | ||||||
|  |  | ||||||
|  | 	return tabbedString(func(out io.Writer) error { | ||||||
|  | 		fmt.Fprintf(out, "%s %q:\n", resource, name) | ||||||
|  | 		fmt.Fprintf(out, "REVISION\tCHANGE-CAUSE\n") | ||||||
|  | 		errs := []error{} | ||||||
|  | 		for _, r := range revisions { | ||||||
|  | 			// Find the change-cause of revision r | ||||||
|  | 			r64, err := strconv.ParseInt(r, 10, 64) | ||||||
|  | 			if err != nil { | ||||||
|  | 				errs = append(errs, err) | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 			changeCause := historyInfo.RevisionToTemplate[r64].Annotations[ChangeCauseAnnotation] | ||||||
|  | 			if len(changeCause) == 0 { | ||||||
|  | 				changeCause = "<none>" | ||||||
|  | 			} | ||||||
|  | 			fmt.Fprintf(out, "%s\t%s\n", r, changeCause) | ||||||
|  | 		} | ||||||
|  | 		return errors.NewAggregate(errs) | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // getChangeCause returns the change-cause annotation of the input object | ||||||
|  | func getChangeCause(obj runtime.Object) (string, error) { | ||||||
|  | 	meta, err := api.ObjectMetaFor(obj) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return "", err | ||||||
|  | 	} | ||||||
|  | 	return meta.Annotations[ChangeCauseAnnotation], nil | ||||||
|  | } | ||||||
| @@ -18,6 +18,7 @@ package deployment | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"fmt" | 	"fmt" | ||||||
|  | 	"strconv" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	"k8s.io/kubernetes/pkg/api" | 	"k8s.io/kubernetes/pkg/api" | ||||||
| @@ -202,3 +203,12 @@ func getPodsForRCs(c clientset.Interface, replicationControllers []*api.Replicat | |||||||
| 	} | 	} | ||||||
| 	return allPods, nil | 	return allPods, nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // Revision returns the revision number of the input RC | ||||||
|  | func Revision(rc *api.ReplicationController) (int64, error) { | ||||||
|  | 	v, ok := rc.Annotations[RevisionAnnotation] | ||||||
|  | 	if !ok { | ||||||
|  | 		return 0, nil | ||||||
|  | 	} | ||||||
|  | 	return strconv.ParseInt(v, 10, 64) | ||||||
|  | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Janet Kuo
					Janet Kuo