Merge pull request #125646 from HirazawaUi/apply-null

Prune explicit nulls from client-side apply create

Kubernetes-commit: 991e7a8c15cbf959cd67bf92fd5e8adfd6875406
This commit is contained in:
Kubernetes Publisher 2024-06-27 10:40:14 -07:00
commit 980dabe2f2
3 changed files with 42 additions and 13 deletions

6
go.mod
View File

@ -29,10 +29,10 @@ require (
golang.org/x/sys v0.20.0 golang.org/x/sys v0.20.0
gopkg.in/evanphx/json-patch.v4 v4.12.0 gopkg.in/evanphx/json-patch.v4 v4.12.0
gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v2 v2.4.0
k8s.io/api v0.0.0-20240626222244-89b2da1f0aa2 k8s.io/api v0.0.0-20240627182225-77d4ad8e83c3
k8s.io/apimachinery v0.0.0-20240626221953-276559d39884 k8s.io/apimachinery v0.0.0-20240627181936-a0fb8b1e7eb2
k8s.io/cli-runtime v0.0.0-20240626225942-dad6f14f09b2 k8s.io/cli-runtime v0.0.0-20240626225942-dad6f14f09b2
k8s.io/client-go v0.0.0-20240626222646-b043b561b47b k8s.io/client-go v0.0.0-20240627182623-96c49b698799
k8s.io/component-base v0.0.0-20240626223637-3daec0d89dbf k8s.io/component-base v0.0.0-20240626223637-3daec0d89dbf
k8s.io/component-helpers v0.0.0-20240626223804-9c307e9c2018 k8s.io/component-helpers v0.0.0-20240626223804-9c307e9c2018
k8s.io/klog/v2 v2.130.1 k8s.io/klog/v2 v2.130.1

12
go.sum
View File

@ -277,14 +277,14 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
k8s.io/api v0.0.0-20240626222244-89b2da1f0aa2 h1:QOw2QiBBiIG84mSsdmcQytk3iZNRA4MMTrfdxq6wMqM= k8s.io/api v0.0.0-20240627182225-77d4ad8e83c3 h1:P7Op/rq70kcXXoojMkjY8VbOzIQaw5mEDLLieIez2L4=
k8s.io/api v0.0.0-20240626222244-89b2da1f0aa2/go.mod h1:XZWSQ1mG1E6aV7roOnViE6A/NQzmDs3oLr1uEdTIgho= k8s.io/api v0.0.0-20240627182225-77d4ad8e83c3/go.mod h1:ZQKk86qwk98AIUL9v2u4BNJzwSDpgqRGvk+S8YZUvS8=
k8s.io/apimachinery v0.0.0-20240626221953-276559d39884 h1:/TR/WnQHZvcTpgDyX8ekmTqXa5PsCgpEeuOVuFRqTtQ= k8s.io/apimachinery v0.0.0-20240627181936-a0fb8b1e7eb2 h1:GqxQcqxvXH3yzNTTgMupE2YxhsssdHR4AepcdRDg99g=
k8s.io/apimachinery v0.0.0-20240626221953-276559d39884/go.mod h1:FrtEnYmygkWHqq5eevqPc8AvY7pEqYQnNzaAFRnhgUI= k8s.io/apimachinery v0.0.0-20240627181936-a0fb8b1e7eb2/go.mod h1:FrtEnYmygkWHqq5eevqPc8AvY7pEqYQnNzaAFRnhgUI=
k8s.io/cli-runtime v0.0.0-20240626225942-dad6f14f09b2 h1:tgv8GHx6DjADcIdq2oPkAYXnTAn5EZY4Htm8LgKix5Q= k8s.io/cli-runtime v0.0.0-20240626225942-dad6f14f09b2 h1:tgv8GHx6DjADcIdq2oPkAYXnTAn5EZY4Htm8LgKix5Q=
k8s.io/cli-runtime v0.0.0-20240626225942-dad6f14f09b2/go.mod h1:TEKkX0EbbfrnoDZQJdx9shmLscZRVLTt3RrXPWHqdQ0= k8s.io/cli-runtime v0.0.0-20240626225942-dad6f14f09b2/go.mod h1:TEKkX0EbbfrnoDZQJdx9shmLscZRVLTt3RrXPWHqdQ0=
k8s.io/client-go v0.0.0-20240626222646-b043b561b47b h1:17HQ2cNzbTTtojzHxWoWvWuw/prNvOqk/xWU/4Zv58o= k8s.io/client-go v0.0.0-20240627182623-96c49b698799 h1:8xNkIoERfWt65xAw4lXUeUGg+Vh/szhuQ19Vsiszwhk=
k8s.io/client-go v0.0.0-20240626222646-b043b561b47b/go.mod h1:KEIO5qV0m2Nc2Xk8CbT/SpZGN2m8ZNR7AR0+31JsOLg= k8s.io/client-go v0.0.0-20240627182623-96c49b698799/go.mod h1:Up3UCbJMZiFt1oxzapxDGYUzkfFyp7vZHuUHnBVhct0=
k8s.io/component-base v0.0.0-20240626223637-3daec0d89dbf h1:9K8NcajKKj8tJ04tTt6qdhJkRt2a8jvsqZ0KSpH/rLc= k8s.io/component-base v0.0.0-20240626223637-3daec0d89dbf h1:9K8NcajKKj8tJ04tTt6qdhJkRt2a8jvsqZ0KSpH/rLc=
k8s.io/component-base v0.0.0-20240626223637-3daec0d89dbf/go.mod h1:AwjQ2315fMhEuAabFzF8WJ7/BbOqK2GXqa0t0NQyKKw= k8s.io/component-base v0.0.0-20240626223637-3daec0d89dbf/go.mod h1:AwjQ2315fMhEuAabFzF8WJ7/BbOqK2GXqa0t0NQyKKw=
k8s.io/component-helpers v0.0.0-20240626223804-9c307e9c2018 h1:/IhOYZKAk72TBGKsUpzYRm6qZ3FmcgK6t/XRqLsiWHw= k8s.io/component-helpers v0.0.0-20240626223804-9c307e9c2018 h1:/IhOYZKAk72TBGKsUpzYRm6qZ3FmcgK6t/XRqLsiWHw=

View File

@ -43,7 +43,7 @@ import (
"k8s.io/client-go/util/csaupgrade" "k8s.io/client-go/util/csaupgrade"
"k8s.io/component-base/version" "k8s.io/component-base/version"
"k8s.io/klog/v2" "k8s.io/klog/v2"
"k8s.io/kubectl/pkg/cmd/delete" cmddelete "k8s.io/kubectl/pkg/cmd/delete"
cmdutil "k8s.io/kubectl/pkg/cmd/util" cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/scheme" "k8s.io/kubectl/pkg/scheme"
"k8s.io/kubectl/pkg/util" "k8s.io/kubectl/pkg/util"
@ -61,7 +61,7 @@ type ApplyFlags struct {
RecordFlags *genericclioptions.RecordFlags RecordFlags *genericclioptions.RecordFlags
PrintFlags *genericclioptions.PrintFlags PrintFlags *genericclioptions.PrintFlags
DeleteFlags *delete.DeleteFlags DeleteFlags *cmddelete.DeleteFlags
FieldManager string FieldManager string
Selector string Selector string
@ -84,7 +84,7 @@ type ApplyOptions struct {
PrintFlags *genericclioptions.PrintFlags PrintFlags *genericclioptions.PrintFlags
ToPrinter func(string) (printers.ResourcePrinter, error) ToPrinter func(string) (printers.ResourcePrinter, error)
DeleteOptions *delete.DeleteOptions DeleteOptions *cmddelete.DeleteOptions
ServerSideApply bool ServerSideApply bool
ForceConflicts bool ForceConflicts bool
@ -182,7 +182,7 @@ var ApplySetToolVersion = version.Get().GitVersion
func NewApplyFlags(streams genericiooptions.IOStreams) *ApplyFlags { func NewApplyFlags(streams genericiooptions.IOStreams) *ApplyFlags {
return &ApplyFlags{ return &ApplyFlags{
RecordFlags: genericclioptions.NewRecordFlags(), RecordFlags: genericclioptions.NewRecordFlags(),
DeleteFlags: delete.NewDeleteFlags("The files that contain the configurations to apply."), DeleteFlags: cmddelete.NewDeleteFlags("The files that contain the configurations to apply."),
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme), PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme),
Overwrite: true, Overwrite: true,
@ -681,6 +681,12 @@ See https://kubernetes.io/docs/reference/using-api/server-side-apply/#conflicts`
return cmdutil.AddSourceToErr("creating", info.Source, err) return cmdutil.AddSourceToErr("creating", info.Source, err)
} }
// prune nulls when client-side apply does a create to match what will happen when client-side applying an update.
// do this after CreateApplyAnnotation so the annotation matches what will be persisted on an update apply of the same manifest.
if u, ok := info.Object.(runtime.Unstructured); ok {
pruneNullsFromMap(u.UnstructuredContent())
}
if o.DryRunStrategy != cmdutil.DryRunClient { if o.DryRunStrategy != cmdutil.DryRunClient {
// Then create the resource and skip the three-way merge // Then create the resource and skip the three-way merge
obj, err := helper.Create(info.Namespace, true, info.Object) 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`
return nil return nil
} }
func pruneNullsFromMap(data map[string]interface{}) {
for k, v := range data {
if v == nil {
delete(data, k)
} else {
pruneNulls(v)
}
}
}
func pruneNullsFromSlice(data []interface{}) {
for _, v := range data {
pruneNulls(v)
}
}
func pruneNulls(v interface{}) {
switch v := v.(type) {
case map[string]interface{}:
pruneNullsFromMap(v)
case []interface{}:
pruneNullsFromSlice(v)
}
}
// Saves the last-applied-configuration annotation in a separate SSA field manager // Saves the last-applied-configuration annotation in a separate SSA field manager
// to prevent it from being dropped by users who have transitioned to SSA. // to prevent it from being dropped by users who have transitioned to SSA.
// //