Skip to content

Commit 30893b0

Browse files
feat: edit set configmap (#5391)
* feat: add new command 'edit set configmap' * Add a new command 'edit set configmap' to allow editing the values of an already-existing configmap in a kustomization file. * Add tests to validate the new feature. * fix: add tests, minor refactoring to use constants * Include tests to validade the new function ValidateSet, included to do necessary validations when running the 'kustomize edit set configmap' command. * Minor refactorings to use the existing constants in the 'edit set configmap' command. * Add dashes before each item in the comment explaining how ExpandFileSource() works so IDEs don't try to reformat the list and remove the indentation in it. * Because this change mutates the list of literal sources, ensure that both add and set save the resulting list in a predictable order to make it easier to check when new items are added/removed and aid in testing. * Since literal sources are the only bit that's important in this test, verify that the literal sources in the actual result is equal to what we expected it to be. * fix: change format to print resource name Use '%q' formatter instead of '%s' to print resource name Co-authored-by: Varsha <[email protected]> * fix: add changes from code review * Unexport constant that is used only in the scope of a single function. * Add extra validation to ensure format is correct with one single '=' per key-value pair. * Add extra set of tests to validate format. * Update test case to match new printed format in the error message. * fix: rollback sort for edit add/set configmap * chore: rename test package and unexport functions Rename the test package from set_test back to set and unexport functions that do not need to be exported anymore for testing purposes. * feat: handle empty and default namespace as equal Handle the empty and the default namespaces as equal. Add tests to validate this scenario. --------- Co-authored-by: Varsha <[email protected]>
1 parent eb7f91f commit 30893b0

File tree

11 files changed

+764
-44
lines changed

11 files changed

+764
-44
lines changed

go.work.sum

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,12 +201,11 @@ go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
201201
go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM=
202202
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 h1:hb9wdF1z5waM+dSIICn1l0DkLVDT3hqhhQsDNUmHPRE=
203203
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
204+
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
204205
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
205-
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 h1:QE6XYQK6naiK1EPAe1g/ILLxN5RBoH5xkJk3CqlMI/Y=
206206
golang.org/x/image v0.0.0-20190802002840-cff245a6509b h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4=
207207
golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k=
208208
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 h1:4+4C/Iv2U4fMZBiMCc98MG1In4gJY5YRhtpDNeDeHWs=
209-
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
210209
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
211210
golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
212211
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
@@ -224,5 +223,35 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
224223
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
225224
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
226225
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
226+
golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY=
227+
golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
228+
golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
229+
golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ=
230+
golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
231+
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
232+
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
233+
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
234+
golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc=
235+
golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=
236+
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
237+
gomodules.xyz/jsonpatch/v2 v2.0.1 h1:xyiBuvkD2g5n7cYzx6u2sxQvsAy4QJsZFCzGVdzOXZ0=
238+
gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485 h1:OB/uP/Puiu5vS5QMRPrXCDWUPb+kt8f1KW8oQzFejQw=
239+
gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e h1:jRyg0XfpwWlhEV8mDfdNGBeSJM2fuyh9Yjrnd8kF2Ts=
240+
google.golang.org/api v0.30.0 h1:yfrXXP61wVuLb0vBcG6qaOoIoqYEzOQS8jum51jkv2w=
241+
google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368 h1:Et6SkiuvnBn+SgrSYXs/BrUpGB4mbdwt4R3vaPIlicA=
242+
google.golang.org/grpc v1.40.0 h1:AGJ0Ih4mHjSeibYkFGh1dD9KJ/eOtZ93I6hoHhukQ5Q=
243+
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
244+
gopkg.in/cheggaaa/pb.v1 v1.0.25 h1:Ev7yu1/f6+d+b3pi5vPdRPc6nNtP1umSfcWiEfRqv6I=
245+
gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8=
246+
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
247+
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
248+
gopkg.in/resty.v1 v1.12.0 h1:CuXP0Pjfw9rOuY6EP+UvtNvt5DSqHpIxILZKT/quCZI=
249+
gopkg.in/square/go-jose.v2 v2.2.2 h1:orlkJ3myw8CN1nVQHBFfloD+L3egixIa4FvUP6RosSA=
250+
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
251+
honnef.co/go/tools v0.0.1-2020.1.4 h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8=
252+
k8s.io/apiserver v0.17.0 h1:XhUix+FKFDcBygWkQNp7wKKvZL030QUlH1o8vFeSgZA=
253+
k8s.io/code-generator v0.17.0 h1:y+KWtDWNqlJzJu/kUy8goJZO0X71PGIpAHLX8a0JYk0=
254+
k8s.io/component-base v0.17.0 h1:BnDFcmBDq+RPpxXjmuYnZXb59XNN9CaFrX8ba9+3xrA=
255+
k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c h1:GohjlNKauSai7gN4wsJkeZ3WAJx4Sh+oT/b5IYn5suA=
227256
k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
228257
sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06 h1:zD2IemQ4LmOcAumeiyDWXKUI2SO0NYDe3H6QGvPOVgU=

kustomize/commands/edit/add/configmap.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ func runEditAddConfigMap(
9797
return fmt.Errorf("failed to expand file source: %w", err)
9898
}
9999

100-
err = flags.Validate(args)
100+
err = flags.ValidateAdd(args)
101101
if err != nil {
102102
return fmt.Errorf("failed to validate flags: %w", err)
103103
}

kustomize/commands/edit/add/secret.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ func runEditAddSecret(
8989
return fmt.Errorf("failed to expand file source: %w", err)
9090
}
9191

92-
err = flags.Validate(args)
92+
err = flags.ValidateAdd(args)
9393
if err != nil {
9494
return fmt.Errorf("failed to validate flags: %w", err)
9595
}

kustomize/commands/edit/all.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ func NewCmdEdit(
4848
set.NewCmdSet(
4949
fSys,
5050
kv.NewLoader(ldrhelper.NewFileLoaderAtCwd(fSys), v),
51-
v),
51+
v,
52+
rf),
5253
fix.NewCmdFix(fSys, w),
5354
remove.NewCmdRemove(fSys, v),
5455
listbuiltin.NewCmdListBuiltinPlugin(),

kustomize/commands/edit/set/all.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,17 @@ package set
66
import (
77
"github.com/spf13/cobra"
88
"sigs.k8s.io/kustomize/api/ifc"
9+
"sigs.k8s.io/kustomize/api/resource"
910
"sigs.k8s.io/kustomize/kyaml/filesys"
1011
)
1112

1213
// NewCmdSet returns an instance of 'set' subcommand.
13-
func NewCmdSet(fSys filesys.FileSystem, ldr ifc.KvLoader, v ifc.Validator) *cobra.Command {
14+
func NewCmdSet(
15+
fSys filesys.FileSystem,
16+
ldr ifc.KvLoader,
17+
v ifc.Validator,
18+
rf *resource.Factory,
19+
) *cobra.Command {
1420
c := &cobra.Command{
1521
Use: "set",
1622
Short: "Sets the value of different fields in kustomization file",
@@ -26,6 +32,7 @@ func NewCmdSet(fSys filesys.FileSystem, ldr ifc.KvLoader, v ifc.Validator) *cobr
2632
}
2733

2834
c.AddCommand(
35+
newCmdSetConfigMap(fSys, ldr, rf),
2936
newCmdSetNamePrefix(fSys),
3037
newCmdSetNameSuffix(fSys),
3138
newCmdSetNamespace(fSys, v),
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
// Copyright 2023 The Kubernetes Authors.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package set
5+
6+
import (
7+
"fmt"
8+
9+
"github.com/spf13/cobra"
10+
"golang.org/x/exp/slices"
11+
"sigs.k8s.io/kustomize/api/ifc"
12+
"sigs.k8s.io/kustomize/api/resource"
13+
"sigs.k8s.io/kustomize/api/types"
14+
"sigs.k8s.io/kustomize/kustomize/v5/commands/internal/kustfile"
15+
"sigs.k8s.io/kustomize/kustomize/v5/commands/internal/util"
16+
"sigs.k8s.io/kustomize/kyaml/filesys"
17+
)
18+
19+
func newCmdSetConfigMap(
20+
fSys filesys.FileSystem,
21+
ldr ifc.KvLoader,
22+
rf *resource.Factory,
23+
) *cobra.Command {
24+
var flags util.ConfigMapSecretFlagsAndArgs
25+
cmd := &cobra.Command{
26+
Use: "configmap NAME [--from-literal=key1=value1] [--namespace=namespace-name] [--new-namespace=new-namespace-name]",
27+
Short: "Edits the value for an existing key for a configmap in the kustomization file",
28+
Long: `Edits the value for an existing key in an existing configmap in the kustomization file.
29+
Both configmap name and key name must exist for this command to succeed.`,
30+
Example: `
31+
# Edits an existing configmap in the kustomization file, changing value of key1 to 2
32+
kustomize edit set configmap my-configmap --from-literal=key1=2
33+
34+
# Edits an existing configmap in the kustomization file, changing namespace to 'new-namespace'
35+
kustomize edit set configmap my-configmap --namespace=current-namespace --new-namespace=new-namespace
36+
`,
37+
RunE: func(_ *cobra.Command, args []string) error {
38+
return runEditSetConfigMap(flags, fSys, args, ldr, rf)
39+
},
40+
}
41+
42+
cmd.Flags().StringArrayVar(
43+
&flags.LiteralSources,
44+
util.FromLiteralFlag,
45+
[]string{},
46+
"Specify an existing key and a new value to update a ConfigMap (i.e. mykey=newvalue)")
47+
cmd.Flags().StringVar(
48+
&flags.Namespace,
49+
util.NamespaceFlag,
50+
"",
51+
"Current namespace of the target ConfigMap")
52+
cmd.Flags().StringVar(
53+
&flags.NewNamespace,
54+
util.NewNamespaceFlag,
55+
"",
56+
"New namespace value for the target ConfigMap")
57+
58+
return cmd
59+
}
60+
61+
func runEditSetConfigMap(
62+
flags util.ConfigMapSecretFlagsAndArgs,
63+
fSys filesys.FileSystem,
64+
args []string,
65+
ldr ifc.KvLoader,
66+
rf *resource.Factory,
67+
) error {
68+
err := flags.ExpandFileSource(fSys)
69+
if err != nil {
70+
return fmt.Errorf("failed to expand file source: %w", err)
71+
}
72+
73+
err = flags.ValidateSet(args)
74+
if err != nil {
75+
return fmt.Errorf("failed to validate flags: %w", err)
76+
}
77+
78+
// Load the kustomization file.
79+
mf, err := kustfile.NewKustomizationFile(fSys)
80+
if err != nil {
81+
return fmt.Errorf("failed to load kustomization file: %w", err)
82+
}
83+
84+
kustomization, err := mf.Read()
85+
if err != nil {
86+
return fmt.Errorf("failed to read kustomization file: %w", err)
87+
}
88+
89+
// Updates the existing ConfigMap
90+
err = setConfigMap(ldr, kustomization, flags, rf)
91+
if err != nil {
92+
return fmt.Errorf("failed to create configmap: %w", err)
93+
}
94+
95+
// Write out the kustomization file with added configmap.
96+
err = mf.Write(kustomization)
97+
if err != nil {
98+
return fmt.Errorf("failed to write kustomization file: %w", err)
99+
}
100+
101+
return nil
102+
}
103+
104+
func setConfigMap(
105+
ldr ifc.KvLoader,
106+
k *types.Kustomization,
107+
flags util.ConfigMapSecretFlagsAndArgs,
108+
rf *resource.Factory,
109+
) error {
110+
args, err := findConfigMapArgs(k, flags.Name, flags.Namespace)
111+
if err != nil {
112+
return fmt.Errorf("could not set new ConfigMap value: %w", err)
113+
}
114+
115+
if len(flags.LiteralSources) > 0 {
116+
err := util.UpdateLiteralSources(&args.GeneratorArgs, flags)
117+
if err != nil {
118+
return fmt.Errorf("failed to update literal sources: %w", err)
119+
}
120+
}
121+
122+
// update namespace to new one
123+
if flags.NewNamespace != "" {
124+
args.Namespace = flags.NewNamespace
125+
}
126+
127+
// Validate by trying to create corev1.configmap.
128+
args.Options = types.MergeGlobalOptionsIntoLocal(
129+
args.Options, k.GeneratorOptions)
130+
131+
_, err = rf.MakeConfigMap(ldr, args)
132+
if err != nil {
133+
return fmt.Errorf("failed to validate ConfigMap structure: %w", err)
134+
}
135+
136+
return nil
137+
}
138+
139+
// findConfigMapArgs finds the generator arguments corresponding to the specified
140+
// ConfigMap name. ConfigMap must exist for this command to be successful.
141+
func findConfigMapArgs(m *types.Kustomization, name, namespace string) (*types.ConfigMapArgs, error) {
142+
cmIndex := slices.IndexFunc(m.ConfigMapGenerator, func(cmArgs types.ConfigMapArgs) bool {
143+
return name == cmArgs.Name && util.NamespaceEqual(namespace, cmArgs.Namespace)
144+
})
145+
146+
if cmIndex == -1 {
147+
return nil, fmt.Errorf("unable to find ConfigMap with name '%q'", name)
148+
}
149+
150+
return &m.ConfigMapGenerator[cmIndex], nil
151+
}

0 commit comments

Comments
 (0)