@@ -43,7 +43,7 @@ import (
43
43
"k8s.io/client-go/util/csaupgrade"
44
44
"k8s.io/component-base/version"
45
45
"k8s.io/klog/v2"
46
- "k8s.io/kubectl/pkg/cmd/delete"
46
+ cmddelete "k8s.io/kubectl/pkg/cmd/delete"
47
47
cmdutil "k8s.io/kubectl/pkg/cmd/util"
48
48
"k8s.io/kubectl/pkg/scheme"
49
49
"k8s.io/kubectl/pkg/util"
@@ -61,7 +61,7 @@ type ApplyFlags struct {
61
61
RecordFlags * genericclioptions.RecordFlags
62
62
PrintFlags * genericclioptions.PrintFlags
63
63
64
- DeleteFlags * delete .DeleteFlags
64
+ DeleteFlags * cmddelete .DeleteFlags
65
65
66
66
FieldManager string
67
67
Selector string
@@ -84,7 +84,7 @@ type ApplyOptions struct {
84
84
PrintFlags * genericclioptions.PrintFlags
85
85
ToPrinter func (string ) (printers.ResourcePrinter , error )
86
86
87
- DeleteOptions * delete .DeleteOptions
87
+ DeleteOptions * cmddelete .DeleteOptions
88
88
89
89
ServerSideApply bool
90
90
ForceConflicts bool
@@ -182,7 +182,7 @@ var ApplySetToolVersion = version.Get().GitVersion
182
182
func NewApplyFlags (streams genericiooptions.IOStreams ) * ApplyFlags {
183
183
return & ApplyFlags {
184
184
RecordFlags : genericclioptions .NewRecordFlags (),
185
- DeleteFlags : delete .NewDeleteFlags ("The files that contain the configurations to apply." ),
185
+ DeleteFlags : cmddelete .NewDeleteFlags ("The files that contain the configurations to apply." ),
186
186
PrintFlags : genericclioptions .NewPrintFlags ("created" ).WithTypeSetter (scheme .Scheme ),
187
187
188
188
Overwrite : true ,
@@ -681,6 +681,12 @@ See https://kubernetes.io/docs/reference/using-api/server-side-apply/#conflicts`
681
681
return cmdutil .AddSourceToErr ("creating" , info .Source , err )
682
682
}
683
683
684
+ // prune nulls when client-side apply does a create to match what will happen when client-side applying an update.
685
+ // do this after CreateApplyAnnotation so the annotation matches what will be persisted on an update apply of the same manifest.
686
+ if u , ok := info .Object .(runtime.Unstructured ); ok {
687
+ pruneNullsFromMap (u .UnstructuredContent ())
688
+ }
689
+
684
690
if o .DryRunStrategy != cmdutil .DryRunClient {
685
691
// Then create the resource and skip the three-way merge
686
692
obj , err := helper .Create (info .Namespace , true , info .Object )
@@ -759,6 +765,29 @@ See https://kubernetes.io/docs/reference/using-api/server-side-apply/#conflicts`
759
765
return nil
760
766
}
761
767
768
+ func pruneNullsFromMap (data map [string ]interface {}) {
769
+ for k , v := range data {
770
+ if v == nil {
771
+ delete (data , k )
772
+ } else {
773
+ pruneNulls (v )
774
+ }
775
+ }
776
+ }
777
+ func pruneNullsFromSlice (data []interface {}) {
778
+ for _ , v := range data {
779
+ pruneNulls (v )
780
+ }
781
+ }
782
+ func pruneNulls (v interface {}) {
783
+ switch v := v .(type ) {
784
+ case map [string ]interface {}:
785
+ pruneNullsFromMap (v )
786
+ case []interface {}:
787
+ pruneNullsFromSlice (v )
788
+ }
789
+ }
790
+
762
791
// Saves the last-applied-configuration annotation in a separate SSA field manager
763
792
// to prevent it from being dropped by users who have transitioned to SSA.
764
793
//
0 commit comments