Skip to content

Commit 265195c

Browse files
authored
Merge pull request #5430 from stormqueen1990/fix/treat-empty-ns-as-default-ns
fix: handle empty namespace as default
2 parents 8b52e04 + 4d7b8ef commit 265195c

File tree

6 files changed

+369
-12
lines changed

6 files changed

+369
-12
lines changed

kustomize/commands/edit/add/configmap.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ func addConfigMap(
148148

149149
func findOrMakeConfigMapArgs(m *types.Kustomization, name, namespace string) *types.ConfigMapArgs {
150150
for i, v := range m.ConfigMapGenerator {
151-
if name == v.Name && namespace == v.Namespace {
151+
if name == v.Name && util.NamespaceEqual(v.Namespace, namespace) {
152152
return &m.ConfigMapGenerator[i]
153153
}
154154
}

kustomize/commands/edit/add/configmap_test.go

Lines changed: 148 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ const (
2626

2727
func TestNewAddConfigMapIsNotNil(t *testing.T) {
2828
fSys := filesys.MakeFsInMemory()
29-
assert.NotNil(t, newCmdAddConfigMap(
29+
require.NotNil(t, newCmdAddConfigMap(
3030
fSys,
3131
kv.NewLoader(
3232
loader.NewFileLoaderAtCwd(fSys),
@@ -41,15 +41,14 @@ func TestMakeConfigMapArgs(t *testing.T) {
4141
NamePrefix: "test-name-prefix",
4242
}
4343

44-
if len(kustomization.ConfigMapGenerator) != 0 {
45-
t.Fatal("Initial kustomization should not have any configmaps")
46-
}
44+
require.Len(t, kustomization.ConfigMapGenerator, 0, "Initial kustomization should not have any configmaps")
45+
4746
args := findOrMakeConfigMapArgs(kustomization, cmName, configMapNamespace)
48-
assert.NotNil(t, args)
49-
assert.Equal(t, 1, len(kustomization.ConfigMapGenerator))
50-
assert.Equal(t, &kustomization.ConfigMapGenerator[len(kustomization.ConfigMapGenerator)-1], args)
51-
assert.Equal(t, args, findOrMakeConfigMapArgs(kustomization, cmName, configMapNamespace))
52-
assert.Equal(t, 1, len(kustomization.ConfigMapGenerator))
47+
require.NotNil(t, args)
48+
require.Equal(t, 1, len(kustomization.ConfigMapGenerator))
49+
require.Equal(t, &kustomization.ConfigMapGenerator[len(kustomization.ConfigMapGenerator)-1], args)
50+
require.Equal(t, args, findOrMakeConfigMapArgs(kustomization, cmName, configMapNamespace))
51+
require.Equal(t, 1, len(kustomization.ConfigMapGenerator))
5352
}
5453

5554
func TestMergeFlagsIntoConfigMapArgs_LiteralSources(t *testing.T) {
@@ -352,3 +351,143 @@ func TestEditAddConfigMapWithFileSource(t *testing.T) {
352351
})
353352
}
354353
}
354+
355+
// TestEditAddConfigMapNamespaced tests situations regarding namespacing. For example, it
356+
// verifies that the empty namespace and the default namespace are treated the
357+
// same when adding a configmap to a kustomization file.
358+
func TestEditAddConfigMapNamespaced(t *testing.T) {
359+
testCases := []struct {
360+
name string
361+
configMapName string
362+
configMapNamespace string
363+
literalSources []string
364+
initialArgs string
365+
expectedResult []types.ConfigMapArgs
366+
expectedSliceLength int
367+
}{
368+
{
369+
name: "adds new key to configmap when default namespace matches empty",
370+
configMapName: "test-cm",
371+
configMapNamespace: "default",
372+
literalSources: []string{"key1=value1"},
373+
initialArgs: `---
374+
apiVersion: kustomize.config.k8s.io/v1beta1
375+
kind: Kustomization
376+
configMapGenerator:
377+
- literals:
378+
- key=value
379+
name: test-cm
380+
`,
381+
expectedResult: []types.ConfigMapArgs{
382+
{
383+
GeneratorArgs: types.GeneratorArgs{
384+
Namespace: "",
385+
Name: "test-cm",
386+
KvPairSources: types.KvPairSources{
387+
LiteralSources: []string{"key=value", "key1=value1"},
388+
},
389+
},
390+
},
391+
},
392+
expectedSliceLength: 1,
393+
},
394+
{
395+
name: "adds new key to configmap when empty namespace matches default",
396+
configMapName: "test-cm",
397+
configMapNamespace: "",
398+
literalSources: []string{"key1=value1"},
399+
initialArgs: `---
400+
apiVersion: kustomize.config.k8s.io/v1beta1
401+
kind: Kustomization
402+
configMapGenerator:
403+
- literals:
404+
- key=value
405+
name: test-cm
406+
namespace: default
407+
`,
408+
expectedResult: []types.ConfigMapArgs{
409+
{
410+
GeneratorArgs: types.GeneratorArgs{
411+
Namespace: "default",
412+
Name: "test-cm",
413+
KvPairSources: types.KvPairSources{
414+
LiteralSources: []string{"key=value", "key1=value1"},
415+
},
416+
},
417+
},
418+
},
419+
expectedSliceLength: 1,
420+
},
421+
{
422+
name: "creates a new generator when namespaces don't match",
423+
configMapName: "test-cm",
424+
configMapNamespace: "",
425+
literalSources: []string{"key1=value1"},
426+
initialArgs: `---
427+
apiVersion: kustomize.config.k8s.io/v1beta1
428+
kind: Kustomization
429+
configMapGenerator:
430+
- literals:
431+
- key=value
432+
name: test-cm
433+
namespace: ns1
434+
`,
435+
expectedResult: []types.ConfigMapArgs{
436+
{
437+
GeneratorArgs: types.GeneratorArgs{
438+
Namespace: "ns1",
439+
Name: "test-cm",
440+
KvPairSources: types.KvPairSources{
441+
LiteralSources: []string{"key=value"},
442+
},
443+
},
444+
},
445+
{
446+
GeneratorArgs: types.GeneratorArgs{
447+
Namespace: "",
448+
Name: "test-cm",
449+
KvPairSources: types.KvPairSources{
450+
LiteralSources: []string{"key1=value1"},
451+
},
452+
},
453+
},
454+
},
455+
expectedSliceLength: 2,
456+
},
457+
}
458+
459+
for _, tc := range testCases {
460+
t.Run(tc.name, func(t *testing.T) {
461+
fSys := filesys.MakeEmptyDirInMemory()
462+
testutils_test.WriteTestKustomizationWith(fSys, []byte(tc.initialArgs))
463+
464+
pvd := provider.NewDefaultDepProvider()
465+
ldr := kv.NewLoader(loader.NewFileLoaderAtCwd(fSys), pvd.GetFieldValidator())
466+
467+
args := []string{
468+
tc.configMapName,
469+
fmt.Sprintf(util.FlagFormat, util.NamespaceFlag, tc.configMapNamespace),
470+
}
471+
472+
for _, source := range tc.literalSources {
473+
args = append(args, fmt.Sprintf(util.FlagFormat, util.FromLiteralFlag, source))
474+
}
475+
476+
cmd := newCmdAddConfigMap(fSys, ldr, pvd.GetResourceFactory())
477+
cmd.SetArgs(args)
478+
require.NoError(t, cmd.Execute())
479+
480+
_, err := testutils_test.ReadTestKustomization(fSys)
481+
require.NoError(t, err)
482+
483+
mf, err := kustfile.NewKustomizationFile(fSys)
484+
require.NoError(t, err)
485+
486+
kustomization, err := mf.Read()
487+
require.NoError(t, err)
488+
489+
require.Len(t, kustomization.ConfigMapGenerator, tc.expectedSliceLength)
490+
require.ElementsMatch(t, tc.expectedResult, kustomization.ConfigMapGenerator)
491+
})
492+
}
493+
}

kustomize/commands/edit/add/secret.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ func addSecret(
140140

141141
func findOrMakeSecretArgs(m *types.Kustomization, name, namespace, secretType string) *types.SecretArgs {
142142
for i, v := range m.SecretGenerator {
143-
if name == v.Name && namespace == v.Namespace {
143+
if name == v.Name && util.NamespaceEqual(v.Namespace, namespace) {
144144
return &m.SecretGenerator[i]
145145
}
146146
}

kustomize/commands/edit/add/secret_test.go

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
"github.com/stretchr/testify/assert"
1111
"github.com/stretchr/testify/require"
12+
"sigs.k8s.io/kustomize/api/ifc"
1213
"sigs.k8s.io/kustomize/api/kv"
1314
"sigs.k8s.io/kustomize/api/pkg/loader"
1415
"sigs.k8s.io/kustomize/api/provider"
@@ -237,3 +238,150 @@ func TestEditAddSecretWithFileSource(t *testing.T) {
237238
require.Equal(t, secretName, newSecretGenerator.Name)
238239
require.Contains(t, newSecretGenerator.FileSources, fileSource)
239240
}
241+
242+
// TestEditAddSecretNamespaced tests situations regarding namespacing. For example, it
243+
// verifies that the empty namespace and the default namespace are treated the
244+
// same when adding a configmap to a kustomization file.
245+
func TestEditAddSecretNamespaced(t *testing.T) {
246+
testCases := []struct {
247+
name string
248+
secretName string
249+
secretNamespace string
250+
literalSources []string
251+
initialArgs string
252+
expectedResult []types.SecretArgs
253+
expectedSliceLength int
254+
}{
255+
{
256+
name: "adds new key to secret when default namespace matches empty",
257+
secretName: "test-secret",
258+
secretNamespace: "default",
259+
literalSources: []string{"key1=value1"},
260+
initialArgs: `---
261+
apiVersion: kustomize.config.k8s.io/v1beta1
262+
kind: Kustomization
263+
secretGenerator:
264+
- literals:
265+
- key=value
266+
name: test-secret
267+
type: Opaque
268+
`,
269+
expectedResult: []types.SecretArgs{
270+
{
271+
GeneratorArgs: types.GeneratorArgs{
272+
Namespace: "",
273+
Name: "test-secret",
274+
KvPairSources: types.KvPairSources{
275+
LiteralSources: []string{"key=value", "key1=value1"},
276+
},
277+
},
278+
Type: ifc.SecretTypeOpaque,
279+
},
280+
},
281+
expectedSliceLength: 1,
282+
},
283+
{
284+
name: "adds new key to secret when empty namespace matches default",
285+
secretName: "test-secret",
286+
secretNamespace: "",
287+
literalSources: []string{"key1=value1"},
288+
initialArgs: `---
289+
apiVersion: kustomize.config.k8s.io/v1beta1
290+
kind: Kustomization
291+
secretGenerator:
292+
- literals:
293+
- key=value
294+
name: test-secret
295+
namespace: default
296+
type: Opaque
297+
`,
298+
expectedResult: []types.SecretArgs{
299+
{
300+
GeneratorArgs: types.GeneratorArgs{
301+
Namespace: "default",
302+
Name: "test-secret",
303+
KvPairSources: types.KvPairSources{
304+
LiteralSources: []string{"key=value", "key1=value1"},
305+
},
306+
},
307+
Type: ifc.SecretTypeOpaque,
308+
},
309+
},
310+
expectedSliceLength: 1,
311+
},
312+
{
313+
name: "creates a new generator when namespaces don't match",
314+
secretName: "test-secret",
315+
secretNamespace: "",
316+
literalSources: []string{"key1=value1"},
317+
initialArgs: `---
318+
apiVersion: kustomize.config.k8s.io/v1beta1
319+
kind: Kustomization
320+
secretGenerator:
321+
- literals:
322+
- key=value
323+
name: test-secret
324+
namespace: ns1
325+
type: Opaque
326+
`,
327+
expectedResult: []types.SecretArgs{
328+
{
329+
GeneratorArgs: types.GeneratorArgs{
330+
Namespace: "ns1",
331+
Name: "test-secret",
332+
KvPairSources: types.KvPairSources{
333+
LiteralSources: []string{"key=value"},
334+
},
335+
},
336+
Type: ifc.SecretTypeOpaque,
337+
},
338+
{
339+
GeneratorArgs: types.GeneratorArgs{
340+
Namespace: "",
341+
Name: "test-secret",
342+
KvPairSources: types.KvPairSources{
343+
LiteralSources: []string{"key1=value1"},
344+
},
345+
},
346+
Type: ifc.SecretTypeOpaque,
347+
},
348+
},
349+
expectedSliceLength: 2,
350+
},
351+
}
352+
353+
for _, tc := range testCases {
354+
t.Run(tc.name, func(t *testing.T) {
355+
fSys := filesys.MakeEmptyDirInMemory()
356+
testutils_test.WriteTestKustomizationWith(fSys, []byte(tc.initialArgs))
357+
358+
pvd := provider.NewDefaultDepProvider()
359+
ldr := kv.NewLoader(loader.NewFileLoaderAtCwd(fSys), pvd.GetFieldValidator())
360+
361+
args := []string{
362+
tc.secretName,
363+
fmt.Sprintf(util.FlagFormat, util.NamespaceFlag, tc.secretNamespace),
364+
}
365+
366+
for _, source := range tc.literalSources {
367+
args = append(args, fmt.Sprintf(util.FlagFormat, util.FromLiteralFlag, source))
368+
}
369+
370+
cmd := newCmdAddSecret(fSys, ldr, pvd.GetResourceFactory())
371+
cmd.SetArgs(args)
372+
require.NoError(t, cmd.Execute())
373+
374+
_, err := testutils_test.ReadTestKustomization(fSys)
375+
require.NoError(t, err)
376+
377+
mf, err := kustfile.NewKustomizationFile(fSys)
378+
require.NoError(t, err)
379+
380+
kustomization, err := mf.Read()
381+
require.NoError(t, err)
382+
383+
require.Len(t, kustomization.SecretGenerator, tc.expectedSliceLength)
384+
require.ElementsMatch(t, tc.expectedResult, kustomization.SecretGenerator)
385+
})
386+
}
387+
}

kustomize/commands/internal/util/util.go

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ import (
1212
"sigs.k8s.io/kustomize/kyaml/filesys"
1313
)
1414

15+
// DefaultNamespace is the default namespace name in Kubernetes.
16+
const DefaultNamespace = "default"
17+
1518
// GlobPatterns accepts a slice of glob strings and returns the set of
1619
// matching file paths.
1720
func GlobPatterns(fSys filesys.FileSystem, patterns []string) ([]string, error) {
@@ -30,7 +33,7 @@ func GlobPatterns(fSys filesys.FileSystem, patterns []string) ([]string, error)
3033
return result, nil
3134
}
3235

33-
// GlobPatterns accepts a slice of glob strings and returns the set of matching file paths.
36+
// GlobPatternsWithLoader accepts a slice of glob strings and returns the set of matching file paths.
3437
// If validation is skipped, then it will return the patterns as provided.
3538
// Otherwise, It will try to load the files from the filesystem.
3639
// If files are not found in the filesystem, it will try to load from remote.
@@ -109,3 +112,18 @@ func trimQuotes(s string) string {
109112
}
110113
return s
111114
}
115+
116+
// NamespaceEqual checks if two namespaces are the same. It considers the empty namespace and the default namespace to
117+
// be the same. As such, when one namespace is the empty string ('""') and the other namespace is "default", this function
118+
// will return true.
119+
func NamespaceEqual(namespace string, otherNamespace string) bool {
120+
if "" == namespace {
121+
namespace = DefaultNamespace
122+
}
123+
124+
if "" == otherNamespace {
125+
otherNamespace = DefaultNamespace
126+
}
127+
128+
return namespace == otherNamespace
129+
}

0 commit comments

Comments
 (0)