Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: handle empty namespace as default #5430

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion kustomize/commands/edit/add/configmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ func addConfigMap(

func findOrMakeConfigMapArgs(m *types.Kustomization, name, namespace string) *types.ConfigMapArgs {
for i, v := range m.ConfigMapGenerator {
if name == v.Name && namespace == v.Namespace {
if name == v.Name && util.NamespaceEqual(v.Namespace, namespace) {
return &m.ConfigMapGenerator[i]
}
}
Expand Down
157 changes: 148 additions & 9 deletions kustomize/commands/edit/add/configmap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const (

func TestNewAddConfigMapIsNotNil(t *testing.T) {
fSys := filesys.MakeFsInMemory()
assert.NotNil(t, newCmdAddConfigMap(
require.NotNil(t, newCmdAddConfigMap(
stormqueen1990 marked this conversation as resolved.
Show resolved Hide resolved
fSys,
kv.NewLoader(
loader.NewFileLoaderAtCwd(fSys),
Expand All @@ -41,15 +41,14 @@ func TestMakeConfigMapArgs(t *testing.T) {
NamePrefix: "test-name-prefix",
}

if len(kustomization.ConfigMapGenerator) != 0 {
t.Fatal("Initial kustomization should not have any configmaps")
}
require.Len(t, kustomization.ConfigMapGenerator, 0, "Initial kustomization should not have any configmaps")

args := findOrMakeConfigMapArgs(kustomization, cmName, configMapNamespace)
assert.NotNil(t, args)
assert.Equal(t, 1, len(kustomization.ConfigMapGenerator))
assert.Equal(t, &kustomization.ConfigMapGenerator[len(kustomization.ConfigMapGenerator)-1], args)
assert.Equal(t, args, findOrMakeConfigMapArgs(kustomization, cmName, configMapNamespace))
assert.Equal(t, 1, len(kustomization.ConfigMapGenerator))
require.NotNil(t, args)
require.Equal(t, 1, len(kustomization.ConfigMapGenerator))
require.Equal(t, &kustomization.ConfigMapGenerator[len(kustomization.ConfigMapGenerator)-1], args)
require.Equal(t, args, findOrMakeConfigMapArgs(kustomization, cmName, configMapNamespace))
require.Equal(t, 1, len(kustomization.ConfigMapGenerator))
}

func TestMergeFlagsIntoConfigMapArgs_LiteralSources(t *testing.T) {
Expand Down Expand Up @@ -352,3 +351,143 @@ func TestEditAddConfigMapWithFileSource(t *testing.T) {
})
}
}

// TestEditAddConfigMapNamespaced tests situations regarding namespacing. For example, it
// verifies that the empty namespace and the default namespace are treated the
// same when adding a configmap to a kustomization file.
func TestEditAddConfigMapNamespaced(t *testing.T) {
testCases := []struct {
name string
configMapName string
configMapNamespace string
literalSources []string
initialArgs string
expectedResult []types.ConfigMapArgs
expectedSliceLength int
}{
{
name: "adds new key to configmap when default namespace matches empty",
configMapName: "test-cm",
configMapNamespace: "default",
literalSources: []string{"key1=value1"},
initialArgs: `---
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
configMapGenerator:
- literals:
- key=value
name: test-cm
`,
expectedResult: []types.ConfigMapArgs{
{
GeneratorArgs: types.GeneratorArgs{
Namespace: "",
Name: "test-cm",
KvPairSources: types.KvPairSources{
LiteralSources: []string{"key=value", "key1=value1"},
},
},
},
},
expectedSliceLength: 1,
},
{
name: "adds new key to configmap when empty namespace matches default",
configMapName: "test-cm",
configMapNamespace: "",
literalSources: []string{"key1=value1"},
initialArgs: `---
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
configMapGenerator:
- literals:
- key=value
name: test-cm
namespace: default
`,
expectedResult: []types.ConfigMapArgs{
{
GeneratorArgs: types.GeneratorArgs{
Namespace: "default",
Name: "test-cm",
KvPairSources: types.KvPairSources{
LiteralSources: []string{"key=value", "key1=value1"},
},
},
},
},
expectedSliceLength: 1,
},
{
name: "creates a new generator when namespaces don't match",
configMapName: "test-cm",
configMapNamespace: "",
literalSources: []string{"key1=value1"},
initialArgs: `---
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
configMapGenerator:
- literals:
- key=value
name: test-cm
namespace: ns1
`,
expectedResult: []types.ConfigMapArgs{
{
GeneratorArgs: types.GeneratorArgs{
Namespace: "ns1",
Name: "test-cm",
KvPairSources: types.KvPairSources{
LiteralSources: []string{"key=value"},
},
},
},
{
GeneratorArgs: types.GeneratorArgs{
Namespace: "",
Name: "test-cm",
KvPairSources: types.KvPairSources{
LiteralSources: []string{"key1=value1"},
},
},
},
},
expectedSliceLength: 2,
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
fSys := filesys.MakeEmptyDirInMemory()
testutils_test.WriteTestKustomizationWith(fSys, []byte(tc.initialArgs))

pvd := provider.NewDefaultDepProvider()
ldr := kv.NewLoader(loader.NewFileLoaderAtCwd(fSys), pvd.GetFieldValidator())

args := []string{
tc.configMapName,
fmt.Sprintf(util.FlagFormat, util.NamespaceFlag, tc.configMapNamespace),
}

for _, source := range tc.literalSources {
args = append(args, fmt.Sprintf(util.FlagFormat, util.FromLiteralFlag, source))
}

cmd := newCmdAddConfigMap(fSys, ldr, pvd.GetResourceFactory())
cmd.SetArgs(args)
require.NoError(t, cmd.Execute())

_, err := testutils_test.ReadTestKustomization(fSys)
require.NoError(t, err)

mf, err := kustfile.NewKustomizationFile(fSys)
require.NoError(t, err)

kustomization, err := mf.Read()
require.NoError(t, err)

require.Len(t, kustomization.ConfigMapGenerator, tc.expectedSliceLength)
require.ElementsMatch(t, tc.expectedResult, kustomization.ConfigMapGenerator)
})
}
}
2 changes: 1 addition & 1 deletion kustomize/commands/edit/add/secret.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ func addSecret(

func findOrMakeSecretArgs(m *types.Kustomization, name, namespace, secretType string) *types.SecretArgs {
for i, v := range m.SecretGenerator {
if name == v.Name && namespace == v.Namespace {
if name == v.Name && util.NamespaceEqual(v.Namespace, namespace) {
return &m.SecretGenerator[i]
}
}
Expand Down
148 changes: 148 additions & 0 deletions kustomize/commands/edit/add/secret_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/kustomize/api/kv"
"sigs.k8s.io/kustomize/api/pkg/loader"
"sigs.k8s.io/kustomize/api/provider"
Expand Down Expand Up @@ -237,3 +238,150 @@ func TestEditAddSecretWithFileSource(t *testing.T) {
require.Equal(t, secretName, newSecretGenerator.Name)
require.Contains(t, newSecretGenerator.FileSources, fileSource)
}

// TestEditAddSecretNamespaced tests situations regarding namespacing. For example, it
// verifies that the empty namespace and the default namespace are treated the
// same when adding a configmap to a kustomization file.
func TestEditAddSecretNamespaced(t *testing.T) {
testCases := []struct {
name string
secretName string
secretNamespace string
literalSources []string
initialArgs string
expectedResult []types.SecretArgs
expectedSliceLength int
}{
{
name: "adds new key to secret when default namespace matches empty",
secretName: "test-secret",
secretNamespace: "default",
literalSources: []string{"key1=value1"},
initialArgs: `---
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
secretGenerator:
- literals:
- key=value
name: test-secret
type: Opaque
`,
expectedResult: []types.SecretArgs{
{
GeneratorArgs: types.GeneratorArgs{
Namespace: "",
Name: "test-secret",
KvPairSources: types.KvPairSources{
LiteralSources: []string{"key=value", "key1=value1"},
},
},
Type: ifc.SecretTypeOpaque,
},
},
expectedSliceLength: 1,
},
{
name: "adds new key to secret when empty namespace matches default",
secretName: "test-secret",
secretNamespace: "",
literalSources: []string{"key1=value1"},
initialArgs: `---
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
secretGenerator:
- literals:
- key=value
name: test-secret
namespace: default
type: Opaque
`,
expectedResult: []types.SecretArgs{
{
GeneratorArgs: types.GeneratorArgs{
Namespace: "default",
Name: "test-secret",
KvPairSources: types.KvPairSources{
LiteralSources: []string{"key=value", "key1=value1"},
},
},
Type: ifc.SecretTypeOpaque,
},
},
expectedSliceLength: 1,
},
{
name: "creates a new generator when namespaces don't match",
secretName: "test-secret",
secretNamespace: "",
literalSources: []string{"key1=value1"},
initialArgs: `---
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
secretGenerator:
- literals:
- key=value
name: test-secret
namespace: ns1
type: Opaque
`,
expectedResult: []types.SecretArgs{
{
GeneratorArgs: types.GeneratorArgs{
Namespace: "ns1",
Name: "test-secret",
KvPairSources: types.KvPairSources{
LiteralSources: []string{"key=value"},
},
},
Type: ifc.SecretTypeOpaque,
},
{
GeneratorArgs: types.GeneratorArgs{
Namespace: "",
Name: "test-secret",
KvPairSources: types.KvPairSources{
LiteralSources: []string{"key1=value1"},
},
},
Type: ifc.SecretTypeOpaque,
},
},
expectedSliceLength: 2,
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
fSys := filesys.MakeEmptyDirInMemory()
testutils_test.WriteTestKustomizationWith(fSys, []byte(tc.initialArgs))

pvd := provider.NewDefaultDepProvider()
ldr := kv.NewLoader(loader.NewFileLoaderAtCwd(fSys), pvd.GetFieldValidator())

args := []string{
tc.secretName,
fmt.Sprintf(util.FlagFormat, util.NamespaceFlag, tc.secretNamespace),
}

for _, source := range tc.literalSources {
args = append(args, fmt.Sprintf(util.FlagFormat, util.FromLiteralFlag, source))
}

cmd := newCmdAddSecret(fSys, ldr, pvd.GetResourceFactory())
cmd.SetArgs(args)
require.NoError(t, cmd.Execute())

_, err := testutils_test.ReadTestKustomization(fSys)
require.NoError(t, err)

mf, err := kustfile.NewKustomizationFile(fSys)
require.NoError(t, err)

kustomization, err := mf.Read()
require.NoError(t, err)

require.Len(t, kustomization.SecretGenerator, tc.expectedSliceLength)
require.ElementsMatch(t, tc.expectedResult, kustomization.SecretGenerator)
})
}
}
20 changes: 19 additions & 1 deletion kustomize/commands/internal/util/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ import (
"sigs.k8s.io/kustomize/kyaml/filesys"
)

// DefaultNamespace is the default namespace name in Kubernetes.
const DefaultNamespace = "default"

// GlobPatterns accepts a slice of glob strings and returns the set of
// matching file paths.
func GlobPatterns(fSys filesys.FileSystem, patterns []string) ([]string, error) {
Expand All @@ -30,7 +33,7 @@ func GlobPatterns(fSys filesys.FileSystem, patterns []string) ([]string, error)
return result, nil
}

// GlobPatterns accepts a slice of glob strings and returns the set of matching file paths.
// GlobPatternsWithLoader accepts a slice of glob strings and returns the set of matching file paths.
// If validation is skipped, then it will return the patterns as provided.
// Otherwise, It will try to load the files from the filesystem.
// If files are not found in the filesystem, it will try to load from remote.
Expand Down Expand Up @@ -109,3 +112,18 @@ func trimQuotes(s string) string {
}
return s
}

// NamespaceEqual checks if two namespaces are the same. It considers the empty namespace and the default namespace to
// be the same. As such, when one namespace is the empty string ('""') and the other namespace is "default", this function
// will return true.
func NamespaceEqual(namespace string, otherNamespace string) bool {
if "" == namespace {
namespace = DefaultNamespace
}

if "" == otherNamespace {
otherNamespace = DefaultNamespace
}

return namespace == otherNamespace
}
Loading
Loading