mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-10-31 02:08: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-replace.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-run.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_rolling-update.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_scale.md | ||||
| docs/user-guide/kubectl/kubectl_uncordon.md | ||||
|   | ||||
| @@ -1656,10 +1656,57 @@ _kubectl_autoscale() | ||||
|     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() | ||||
| { | ||||
|     last_command="kubectl_rollout" | ||||
|     commands=() | ||||
|     commands+=("history") | ||||
|  | ||||
|     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 | ||||
| .PP | ||||
| \fBkubectl(1)\fP, | ||||
| \fBkubectl(1)\fP, \fBkubectl\-rollout\-history(1)\fP, | ||||
|  | ||||
|  | ||||
| .SH HISTORY | ||||
|   | ||||
| @@ -71,6 +71,7 @@ kubectl rollout SUBCOMMAND | ||||
| ### SEE ALSO | ||||
|  | ||||
| * [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 | ||||
|  | ||||
|   | ||||
							
								
								
									
										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 { | ||||
| 		v, err := revision(rc) | ||||
| 		v, err := deploymentutil.Revision(rc) | ||||
| 		if err != nil { | ||||
| 			glog.V(4).Infof("Unable to extract revision from deployment's rc %q: %v", rc.Name, err) | ||||
| 			continue | ||||
| @@ -617,18 +617,10 @@ func (dc *DeploymentController) getNewRCAndAllOldRCs(deployment extensions.Deplo | ||||
| 	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 { | ||||
| 	max := int64(0) | ||||
| 	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 | ||||
| 			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 { | ||||
| @@ -642,7 +634,7 @@ func maxRevision(allRCs []*api.ReplicationController) int64 { | ||||
| func lastRevision(allRCs []*api.ReplicationController) int64 { | ||||
| 	max, secMax := int64(0), int64(0) | ||||
| 	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 | ||||
| 			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 { | ||||
|   | ||||
| @@ -43,5 +43,7 @@ func NewCmdRollout(f *cmdutil.Factory, out io.Writer) *cobra.Command { | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	cmd.AddCommand(NewCmdRolloutHistory(f, out)) | ||||
|  | ||||
| 	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/apimachinery/registered" | ||||
| 	"k8s.io/kubernetes/pkg/apis/extensions" | ||||
| 	clientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_1" | ||||
| 	client "k8s.io/kubernetes/pkg/client/unversioned" | ||||
| 	"k8s.io/kubernetes/pkg/client/unversioned/clientcmd" | ||||
| 	"k8s.io/kubernetes/pkg/kubectl" | ||||
| @@ -85,6 +86,8 @@ type Factory struct { | ||||
| 	Scaler func(mapping *meta.RESTMapping) (kubectl.Scaler, error) | ||||
| 	// Returns a Reaper for gracefully shutting down resources. | ||||
| 	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 func(object runtime.Object) (string, error) | ||||
| 	// 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) | ||||
| 		}, | ||||
| 		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) { | ||||
| 			if validate { | ||||
| 				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. | ||||
| type JobDescriber struct { | ||||
| 	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 ( | ||||
| 	"fmt" | ||||
| 	"strconv" | ||||
| 	"time" | ||||
|  | ||||
| 	"k8s.io/kubernetes/pkg/api" | ||||
| @@ -202,3 +203,12 @@ func getPodsForRCs(c clientset.Interface, replicationControllers []*api.Replicat | ||||
| 	} | ||||
| 	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