1/* 2Copyright 2016 The Kubernetes Authors. 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15*/ 16 17package rollout 18 19import ( 20 "fmt" 21 22 "github.com/spf13/cobra" 23 24 "k8s.io/cli-runtime/pkg/genericclioptions" 25 "k8s.io/cli-runtime/pkg/printers" 26 "k8s.io/cli-runtime/pkg/resource" 27 cmdutil "k8s.io/kubectl/pkg/cmd/util" 28 "k8s.io/kubectl/pkg/polymorphichelpers" 29 "k8s.io/kubectl/pkg/scheme" 30 "k8s.io/kubectl/pkg/util/i18n" 31 "k8s.io/kubectl/pkg/util/templates" 32) 33 34var ( 35 historyLong = templates.LongDesc(i18n.T(` 36 View previous rollout revisions and configurations.`)) 37 38 historyExample = templates.Examples(` 39 # View the rollout history of a deployment 40 kubectl rollout history deployment/abc 41 42 # View the details of daemonset revision 3 43 kubectl rollout history daemonset/abc --revision=3`) 44) 45 46// RolloutHistoryOptions holds the options for 'rollout history' sub command 47type RolloutHistoryOptions struct { 48 PrintFlags *genericclioptions.PrintFlags 49 ToPrinter func(string) (printers.ResourcePrinter, error) 50 51 Revision int64 52 53 Builder func() *resource.Builder 54 Resources []string 55 Namespace string 56 EnforceNamespace bool 57 58 HistoryViewer polymorphichelpers.HistoryViewerFunc 59 RESTClientGetter genericclioptions.RESTClientGetter 60 61 resource.FilenameOptions 62 genericclioptions.IOStreams 63} 64 65// NewRolloutHistoryOptions returns an initialized RolloutHistoryOptions instance 66func NewRolloutHistoryOptions(streams genericclioptions.IOStreams) *RolloutHistoryOptions { 67 return &RolloutHistoryOptions{ 68 PrintFlags: genericclioptions.NewPrintFlags("").WithTypeSetter(scheme.Scheme), 69 IOStreams: streams, 70 } 71} 72 73// NewCmdRolloutHistory returns a Command instance for RolloutHistory sub command 74func NewCmdRolloutHistory(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command { 75 o := NewRolloutHistoryOptions(streams) 76 77 validArgs := []string{"deployment", "daemonset", "statefulset"} 78 79 cmd := &cobra.Command{ 80 Use: "history (TYPE NAME | TYPE/NAME) [flags]", 81 DisableFlagsInUseLine: true, 82 Short: i18n.T("View rollout history"), 83 Long: historyLong, 84 Example: historyExample, 85 Run: func(cmd *cobra.Command, args []string) { 86 cmdutil.CheckErr(o.Complete(f, cmd, args)) 87 cmdutil.CheckErr(o.Validate()) 88 cmdutil.CheckErr(o.Run()) 89 }, 90 ValidArgs: validArgs, 91 } 92 93 cmd.Flags().Int64Var(&o.Revision, "revision", o.Revision, "See the details, including podTemplate of the revision specified") 94 95 usage := "identifying the resource to get from a server." 96 cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, usage) 97 98 o.PrintFlags.AddFlags(cmd) 99 100 return cmd 101} 102 103// Complete completes al the required options 104func (o *RolloutHistoryOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { 105 o.Resources = args 106 107 var err error 108 if o.Namespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace(); err != nil { 109 return err 110 } 111 112 o.ToPrinter = func(operation string) (printers.ResourcePrinter, error) { 113 o.PrintFlags.NamePrintFlags.Operation = operation 114 return o.PrintFlags.ToPrinter() 115 } 116 117 o.HistoryViewer = polymorphichelpers.HistoryViewerFn 118 o.RESTClientGetter = f 119 o.Builder = f.NewBuilder 120 121 return nil 122} 123 124// Validate makes sure all the provided values for command-line options are valid 125func (o *RolloutHistoryOptions) Validate() error { 126 if len(o.Resources) == 0 && cmdutil.IsFilenameSliceEmpty(o.Filenames, o.Kustomize) { 127 return fmt.Errorf("required resource not specified") 128 } 129 if o.Revision < 0 { 130 return fmt.Errorf("revision must be a positive integer: %v", o.Revision) 131 } 132 133 return nil 134} 135 136// Run performs the execution of 'rollout history' sub command 137func (o *RolloutHistoryOptions) Run() error { 138 139 r := o.Builder(). 140 WithScheme(scheme.Scheme, scheme.Scheme.PrioritizedVersionsAllGroups()...). 141 NamespaceParam(o.Namespace).DefaultNamespace(). 142 FilenameParam(o.EnforceNamespace, &o.FilenameOptions). 143 ResourceTypeOrNameArgs(true, o.Resources...). 144 ContinueOnError(). 145 Latest(). 146 Flatten(). 147 Do() 148 if err := r.Err(); err != nil { 149 return err 150 } 151 152 return r.Visit(func(info *resource.Info, err error) error { 153 if err != nil { 154 return err 155 } 156 157 mapping := info.ResourceMapping() 158 historyViewer, err := o.HistoryViewer(o.RESTClientGetter, mapping) 159 if err != nil { 160 return err 161 } 162 historyInfo, err := historyViewer.ViewHistory(info.Namespace, info.Name, o.Revision) 163 if err != nil { 164 return err 165 } 166 167 withRevision := "" 168 if o.Revision > 0 { 169 withRevision = fmt.Sprintf("with revision #%d", o.Revision) 170 } 171 172 printer, err := o.ToPrinter(fmt.Sprintf("%s\n%s", withRevision, historyInfo)) 173 if err != nil { 174 return err 175 } 176 177 return printer.PrintObj(info.Object, o.Out) 178 }) 179} 180