...
1
16
17 package rollout
18
19 import (
20 "fmt"
21
22 "github.com/spf13/cobra"
23
24 "k8s.io/cli-runtime/pkg/genericclioptions"
25 "k8s.io/cli-runtime/pkg/genericiooptions"
26 "k8s.io/cli-runtime/pkg/printers"
27 "k8s.io/cli-runtime/pkg/resource"
28 cmdutil "k8s.io/kubectl/pkg/cmd/util"
29 "k8s.io/kubectl/pkg/polymorphichelpers"
30 "k8s.io/kubectl/pkg/scheme"
31 "k8s.io/kubectl/pkg/util/completion"
32 "k8s.io/kubectl/pkg/util/i18n"
33 "k8s.io/kubectl/pkg/util/templates"
34 )
35
36
37
38 type UndoOptions struct {
39 PrintFlags *genericclioptions.PrintFlags
40 ToPrinter func(string) (printers.ResourcePrinter, error)
41
42 Builder func() *resource.Builder
43 ToRevision int64
44 DryRunStrategy cmdutil.DryRunStrategy
45 Resources []string
46 Namespace string
47 LabelSelector string
48 EnforceNamespace bool
49 RESTClientGetter genericclioptions.RESTClientGetter
50
51 resource.FilenameOptions
52 genericiooptions.IOStreams
53 }
54
55 var (
56 undoLong = templates.LongDesc(i18n.T(`
57 Roll back to a previous rollout.`))
58
59 undoExample = templates.Examples(`
60 # Roll back to the previous deployment
61 kubectl rollout undo deployment/abc
62
63 # Roll back to daemonset revision 3
64 kubectl rollout undo daemonset/abc --to-revision=3
65
66 # Roll back to the previous deployment with dry-run
67 kubectl rollout undo --dry-run=server deployment/abc`)
68 )
69
70
71 func NewRolloutUndoOptions(streams genericiooptions.IOStreams) *UndoOptions {
72 return &UndoOptions{
73 PrintFlags: genericclioptions.NewPrintFlags("rolled back").WithTypeSetter(scheme.Scheme),
74 IOStreams: streams,
75 ToRevision: int64(0),
76 }
77 }
78
79
80 func NewCmdRolloutUndo(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command {
81 o := NewRolloutUndoOptions(streams)
82
83 validArgs := []string{"deployment", "daemonset", "statefulset"}
84
85 cmd := &cobra.Command{
86 Use: "undo (TYPE NAME | TYPE/NAME) [flags]",
87 DisableFlagsInUseLine: true,
88 Short: i18n.T("Undo a previous rollout"),
89 Long: undoLong,
90 Example: undoExample,
91 ValidArgsFunction: completion.SpecifiedResourceTypeAndNameCompletionFunc(f, validArgs),
92 Run: func(cmd *cobra.Command, args []string) {
93 cmdutil.CheckErr(o.Complete(f, cmd, args))
94 cmdutil.CheckErr(o.Validate())
95 cmdutil.CheckErr(o.RunUndo())
96 },
97 }
98
99 cmd.Flags().Int64Var(&o.ToRevision, "to-revision", o.ToRevision, "The revision to rollback to. Default to 0 (last revision).")
100 usage := "identifying the resource to get from a server."
101 cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, usage)
102 cmdutil.AddDryRunFlag(cmd)
103 cmdutil.AddLabelSelectorFlagVar(cmd, &o.LabelSelector)
104 o.PrintFlags.AddFlags(cmd)
105 return cmd
106 }
107
108
109 func (o *UndoOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
110 o.Resources = args
111 var err error
112 o.DryRunStrategy, err = cmdutil.GetDryRunStrategy(cmd)
113 if err != nil {
114 return err
115 }
116
117 if o.Namespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace(); err != nil {
118 return err
119 }
120
121 o.ToPrinter = func(operation string) (printers.ResourcePrinter, error) {
122 o.PrintFlags.NamePrintFlags.Operation = operation
123 cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy)
124 return o.PrintFlags.ToPrinter()
125 }
126
127 o.RESTClientGetter = f
128 o.Builder = f.NewBuilder
129
130 return err
131 }
132
133 func (o *UndoOptions) Validate() error {
134 if len(o.Resources) == 0 && cmdutil.IsFilenameSliceEmpty(o.Filenames, o.Kustomize) {
135 return fmt.Errorf("required resource not specified")
136 }
137 return nil
138 }
139
140
141 func (o *UndoOptions) RunUndo() error {
142 r := o.Builder().
143 WithScheme(scheme.Scheme, scheme.Scheme.PrioritizedVersionsAllGroups()...).
144 NamespaceParam(o.Namespace).DefaultNamespace().
145 LabelSelectorParam(o.LabelSelector).
146 FilenameParam(o.EnforceNamespace, &o.FilenameOptions).
147 ResourceTypeOrNameArgs(true, o.Resources...).
148 ContinueOnError().
149 Latest().
150 Flatten().
151 Do()
152 if err := r.Err(); err != nil {
153 return err
154 }
155
156 err := r.Visit(func(info *resource.Info, err error) error {
157 if err != nil {
158 return err
159 }
160 rollbacker, err := polymorphichelpers.RollbackerFn(o.RESTClientGetter, info.ResourceMapping())
161 if err != nil {
162 return err
163 }
164
165 result, err := rollbacker.Rollback(info.Object, nil, o.ToRevision, o.DryRunStrategy)
166 if err != nil {
167 return err
168 }
169
170 printer, err := o.ToPrinter(result)
171 if err != nil {
172 return err
173 }
174
175 return printer.PrintObj(info.Object, o.Out)
176 })
177
178 return err
179 }
180
View as plain text