1
2
3
4 package preview
5
6 import (
7 "context"
8 "fmt"
9 "strings"
10 "time"
11
12 "github.com/spf13/cobra"
13 "k8s.io/cli-runtime/pkg/genericclioptions"
14 cmdutil "k8s.io/kubectl/pkg/cmd/util"
15 "k8s.io/kubectl/pkg/util/i18n"
16 "sigs.k8s.io/cli-utils/cmd/flagutils"
17 "sigs.k8s.io/cli-utils/pkg/apply"
18 "sigs.k8s.io/cli-utils/pkg/apply/event"
19 "sigs.k8s.io/cli-utils/pkg/common"
20 "sigs.k8s.io/cli-utils/pkg/inventory"
21 "sigs.k8s.io/cli-utils/pkg/manifestreader"
22 "sigs.k8s.io/cli-utils/pkg/printers"
23 )
24
25 var (
26 noPrune = false
27 previewDestroy = false
28 )
29
30
31 func GetRunner(factory cmdutil.Factory, invFactory inventory.ClientFactory,
32 loader manifestreader.ManifestLoader, ioStreams genericclioptions.IOStreams) *Runner {
33 r := &Runner{
34 factory: factory,
35 invFactory: invFactory,
36 loader: loader,
37 ioStreams: ioStreams,
38 }
39 cmd := &cobra.Command{
40 Use: "preview (DIRECTORY | STDIN)",
41 DisableFlagsInUseLine: true,
42 Short: i18n.T("Preview the apply of a configuration"),
43 Args: cobra.MaximumNArgs(1),
44 RunE: r.RunE,
45 }
46
47 cmd.Flags().BoolVar(&noPrune, "no-prune", noPrune, "If true, do not prune previously applied objects.")
48 cmd.Flags().BoolVar(&r.serverSideOptions.ServerSideApply, "server-side", false,
49 "If true, preview runs in the server instead of the client.")
50 cmd.Flags().BoolVar(&r.serverSideOptions.ForceConflicts, "force-conflicts", false,
51 "If true during server-side preview, do not report field conflicts.")
52 cmd.Flags().StringVar(&r.serverSideOptions.FieldManager, "field-manager", common.DefaultFieldManager,
53 "If true during server-side preview, sets field owner.")
54 cmd.Flags().BoolVar(&previewDestroy, "destroy", previewDestroy, "If true, preview of destroy operations will be displayed.")
55 cmd.Flags().StringVar(&r.output, "output", printers.DefaultPrinter(),
56 fmt.Sprintf("Output format, must be one of %s", strings.Join(printers.SupportedPrinters(), ",")))
57 cmd.Flags().StringVar(&r.inventoryPolicy, flagutils.InventoryPolicyFlag, flagutils.InventoryPolicyStrict,
58 "It determines the behavior when the resources don't belong to current inventory. Available options "+
59 fmt.Sprintf("%q, %q and %q.", flagutils.InventoryPolicyStrict, flagutils.InventoryPolicyAdopt, flagutils.InventoryPolicyForceAdopt))
60 cmd.Flags().DurationVar(&r.timeout, "timeout", 0,
61 "How long to wait before exiting")
62
63 r.Command = cmd
64 return r
65 }
66
67
68 func Command(f cmdutil.Factory, invFactory inventory.ClientFactory, loader manifestreader.ManifestLoader,
69 ioStreams genericclioptions.IOStreams) *cobra.Command {
70 return GetRunner(f, invFactory, loader, ioStreams).Command
71 }
72
73
74 type Runner struct {
75 Command *cobra.Command
76 factory cmdutil.Factory
77 invFactory inventory.ClientFactory
78 loader manifestreader.ManifestLoader
79 ioStreams genericclioptions.IOStreams
80
81 serverSideOptions common.ServerSideOptions
82 output string
83 inventoryPolicy string
84 timeout time.Duration
85 }
86
87
88 func (r *Runner) RunE(cmd *cobra.Command, args []string) error {
89 ctx := cmd.Context()
90
91 if r.timeout != 0 {
92 var cancel context.CancelFunc
93 ctx, cancel = context.WithTimeout(ctx, r.timeout)
94 defer cancel()
95 }
96
97 var ch <-chan event.Event
98
99 drs := common.DryRunClient
100 if r.serverSideOptions.ServerSideApply {
101 drs = common.DryRunServer
102 }
103
104 inventoryPolicy, err := flagutils.ConvertInventoryPolicy(r.inventoryPolicy)
105 if err != nil {
106 return err
107 }
108
109 reader, err := r.loader.ManifestReader(cmd.InOrStdin(), flagutils.PathFromArgs(args))
110 if err != nil {
111 return err
112 }
113
114 if found := printers.ValidatePrinterType(r.output); !found {
115 return fmt.Errorf("unknown output type %q", r.output)
116 }
117
118 objs, err := reader.Read()
119 if err != nil {
120 return err
121 }
122
123 invObj, objs, err := inventory.SplitUnstructureds(objs)
124 if err != nil {
125 return err
126 }
127 inv := inventory.WrapInventoryInfoObj(invObj)
128
129 invClient, err := r.invFactory.NewClient(r.factory)
130 if err != nil {
131 return err
132 }
133
134
135
136 if !previewDestroy {
137 _, err = common.DemandOneDirectory(args)
138 if err != nil {
139 return err
140 }
141 a, err := apply.NewApplierBuilder().
142 WithFactory(r.factory).
143 WithInventoryClient(invClient).
144 Build()
145 if err != nil {
146 return err
147 }
148
149
150
151 ch = a.Run(ctx, inv, objs, apply.ApplierOptions{
152 EmitStatusEvents: false,
153 NoPrune: noPrune,
154 DryRunStrategy: drs,
155 ServerSideOptions: r.serverSideOptions,
156 InventoryPolicy: inventoryPolicy,
157 })
158 } else {
159 d, err := apply.NewDestroyerBuilder().
160 WithFactory(r.factory).
161 WithInventoryClient(invClient).
162 Build()
163 if err != nil {
164 return err
165 }
166 ch = d.Run(ctx, inv, apply.DestroyerOptions{
167 InventoryPolicy: inventoryPolicy,
168 DryRunStrategy: drs,
169 })
170 }
171
172
173 if r.output != printers.JSONPrinter {
174 if drs.ServerDryRun() {
175 fmt.Println("Preview strategy: server")
176 } else {
177 fmt.Println("Preview strategy: client")
178 }
179 }
180
181
182
183 printer := printers.GetPrinter(r.output, r.ioStreams)
184 return printer.Print(ch, drs, false)
185 }
186
View as plain text