@@ -55,7 +55,7 @@ type kubectlResourceOperations struct {
55
55
56
56
type commandExecutor func (f cmdutil.Factory , ioStreams genericclioptions.IOStreams , fileName string ) error
57
57
58
- func (k * kubectlResourceOperations ) runResourceCommand (ctx context.Context , obj * unstructured.Unstructured , dryRunStrategy cmdutil.DryRunStrategy , executor commandExecutor ) (string , error ) {
58
+ func (k * kubectlResourceOperations ) runResourceCommand (ctx context.Context , obj * unstructured.Unstructured , dryRunStrategy cmdutil.DryRunStrategy , serverSideDiff bool , executor commandExecutor ) (string , error ) {
59
59
manifestBytes , err := json .Marshal (obj )
60
60
if err != nil {
61
61
return "" , err
@@ -91,21 +91,14 @@ func (k *kubectlResourceOperations) runResourceCommand(ctx context.Context, obj
91
91
}
92
92
93
93
var out []string
94
- if obj .GetAPIVersion () == "rbac.authorization.k8s.io/v1" {
95
- // If it is an RBAC resource, run `kubectl auth reconcile`. This is preferred over
96
- // `kubectl apply`, which cannot tolerate changes in roleRef, which is an immutable field.
97
- // See: https://github.com/kubernetes/kubernetes/issues/66353
98
- // `auth reconcile` will delete and recreate the resource if necessary
99
- outReconcile , err := func () (string , error ) {
100
- cleanup , err := k .processKubectlRun ("auth" )
101
- if err != nil {
102
- return "" , err
103
- }
104
- defer cleanup ()
105
- return k .authReconcile (ctx , obj , manifestFile .Name (), dryRunStrategy )
106
- }()
94
+ // rbac resouces are first applied with auth reconcile kubectl feature.
95
+ // serverSideDiff should avoid this step as the resources are not being actually
96
+ // applied but just running in dryrun mode. Also, kubectl auth reconcile doesn't
97
+ // currently support running dryrun in server mode.
98
+ if obj .GetAPIVersion () == "rbac.authorization.k8s.io/v1" && ! serverSideDiff {
99
+ outReconcile , err := k .rbacReconcile (ctx , obj , manifestFile .Name (), dryRunStrategy )
107
100
if err != nil {
108
- return "" , err
101
+ return "" , fmt . Errorf ( "error running rbacReconcile: %s" , err )
109
102
}
110
103
out = append (out , outReconcile )
111
104
// We still want to fallthrough and run `kubectl apply` in order set the
@@ -131,6 +124,28 @@ func (k *kubectlResourceOperations) runResourceCommand(ctx context.Context, obj
131
124
return strings .Join (out , ". " ), nil
132
125
}
133
126
127
+ // rbacReconcile will perform reconciliation for RBAC resources. It will run
128
+ // the following command:
129
+ //
130
+ // kubectl auth reconcile
131
+ //
132
+ // This is preferred over `kubectl apply`, which cannot tolerate changes in
133
+ // roleRef, which is an immutable field.
134
+ // See: https://github.com/kubernetes/kubernetes/issues/66353
135
+ // `auth reconcile` will delete and recreate the resource if necessary
136
+ func (k * kubectlResourceOperations ) rbacReconcile (ctx context.Context , obj * unstructured.Unstructured , fileName string , dryRunStrategy cmdutil.DryRunStrategy ) (string , error ) {
137
+ cleanup , err := k .processKubectlRun ("auth" )
138
+ if err != nil {
139
+ return "" , fmt .Errorf ("error processing kubectl run auth: %w" , err )
140
+ }
141
+ defer cleanup ()
142
+ outReconcile , err := k .authReconcile (ctx , obj , fileName , dryRunStrategy )
143
+ if err != nil {
144
+ return "" , fmt .Errorf ("error running kubectl auth reconcile: %w" , err )
145
+ }
146
+ return outReconcile , nil
147
+ }
148
+
134
149
func kubeCmdFactory (kubeconfig , ns string , config * rest.Config ) cmdutil.Factory {
135
150
kubeConfigFlags := genericclioptions .NewConfigFlags (true )
136
151
if ns != "" {
@@ -149,7 +164,7 @@ func (k *kubectlResourceOperations) ReplaceResource(ctx context.Context, obj *un
149
164
span .SetBaggageItem ("name" , obj .GetName ())
150
165
defer span .Finish ()
151
166
k .log .Info (fmt .Sprintf ("Replacing resource %s/%s in cluster: %s, namespace: %s" , obj .GetKind (), obj .GetName (), k .config .Host , obj .GetNamespace ()))
152
- return k .runResourceCommand (ctx , obj , dryRunStrategy , func (f cmdutil.Factory , ioStreams genericclioptions.IOStreams , fileName string ) error {
167
+ return k .runResourceCommand (ctx , obj , dryRunStrategy , false , func (f cmdutil.Factory , ioStreams genericclioptions.IOStreams , fileName string ) error {
153
168
cleanup , err := k .processKubectlRun ("replace" )
154
169
if err != nil {
155
170
return err
@@ -170,7 +185,7 @@ func (k *kubectlResourceOperations) CreateResource(ctx context.Context, obj *uns
170
185
span .SetBaggageItem ("kind" , gvk .Kind )
171
186
span .SetBaggageItem ("name" , obj .GetName ())
172
187
defer span .Finish ()
173
- return k .runResourceCommand (ctx , obj , dryRunStrategy , func (f cmdutil.Factory , ioStreams genericclioptions.IOStreams , fileName string ) error {
188
+ return k .runResourceCommand (ctx , obj , dryRunStrategy , false , func (f cmdutil.Factory , ioStreams genericclioptions.IOStreams , fileName string ) error {
174
189
cleanup , err := k .processKubectlRun ("create" )
175
190
if err != nil {
176
191
return err
@@ -230,7 +245,7 @@ func (k *kubectlResourceOperations) ApplyResource(ctx context.Context, obj *unst
230
245
span .SetBaggageItem ("name" , obj .GetName ())
231
246
defer span .Finish ()
232
247
k .log .Info (fmt .Sprintf ("Applying resource %s/%s in cluster: %s, namespace: %s" , obj .GetKind (), obj .GetName (), k .config .Host , obj .GetNamespace ()))
233
- return k .runResourceCommand (ctx , obj , dryRunStrategy , func (f cmdutil.Factory , ioStreams genericclioptions.IOStreams , fileName string ) error {
248
+ return k .runResourceCommand (ctx , obj , dryRunStrategy , serverSideDiff , func (f cmdutil.Factory , ioStreams genericclioptions.IOStreams , fileName string ) error {
234
249
cleanup , err := k .processKubectlRun ("apply" )
235
250
if err != nil {
236
251
return err
@@ -317,7 +332,7 @@ func (k *kubectlResourceOperations) newApplyOptions(ioStreams genericclioptions.
317
332
if manager != "" {
318
333
o .FieldManager = manager
319
334
}
320
- if serverSideApply {
335
+ if serverSideApply || serverSideDiff {
321
336
o .ForceConflicts = true
322
337
}
323
338
return o , nil
@@ -469,9 +484,8 @@ func (k *kubectlResourceOperations) authReconcile(ctx context.Context, obj *unst
469
484
}
470
485
reconcileOpts , err := newReconcileOptions (k .fact , kubeClient , manifestFile , ioStreams , obj .GetNamespace (), dryRunStrategy )
471
486
if err != nil {
472
- return "" , err
487
+ return "" , fmt . Errorf ( "error calling newReconcileOptions: %w" , err )
473
488
}
474
-
475
489
err = reconcileOpts .Validate ()
476
490
if err != nil {
477
491
return "" , errors .New (cleanKubectlOutput (err .Error ()))
0 commit comments