mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-10 08:20:59 +00:00
feat: edit set secret
* Add new functionality to allow editing a secret in a kustomization file. Initial implementation supports only --from-literal option. * Refactor edit set configmap to reuse some testing bits.
This commit is contained in:
@@ -27,12 +27,19 @@ func NewCmdSet(
|
||||
|
||||
# Sets the namesuffix field
|
||||
kustomize edit set namesuffix <suffix-value>
|
||||
|
||||
# Edits a field in an existing configmap in the kustomization file
|
||||
kustomize edit set configmap my-configmap --from-literal=key1=value1
|
||||
|
||||
# Edits a field in an existing secret in the kustomization file
|
||||
kustomize edit set secret my-secret --from-literal=key1=value1
|
||||
`,
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
}
|
||||
|
||||
c.AddCommand(
|
||||
newCmdSetConfigMap(fSys, ldr, rf),
|
||||
newCmdSetSecret(fSys, ldr, rf),
|
||||
newCmdSetNamePrefix(fSys),
|
||||
newCmdSetNameSuffix(fSys),
|
||||
newCmdSetNamespace(fSys, v),
|
||||
|
||||
@@ -1,245 +1,204 @@
|
||||
// Copyright 2023 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// The duplicate linter is reporting that setsecret_test.go and this file are duplicates, which is not true.
|
||||
// Disabling lint for these two files specifically to work around that.
|
||||
//
|
||||
//nolint:dupl
|
||||
package set
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"sigs.k8s.io/kustomize/api/kv"
|
||||
"sigs.k8s.io/kustomize/api/pkg/loader"
|
||||
"sigs.k8s.io/kustomize/api/provider"
|
||||
"sigs.k8s.io/kustomize/kustomize/v5/commands/internal/kustfile"
|
||||
testutils_test "sigs.k8s.io/kustomize/kustomize/v5/commands/internal/testutils"
|
||||
"sigs.k8s.io/kustomize/kyaml/filesys"
|
||||
testutils_test "sigs.k8s.io/kustomize/kustomize/v5/commands/internal/configmapsecret"
|
||||
)
|
||||
|
||||
func TestEditSetConfigMapError(t *testing.T) {
|
||||
fSys := filesys.MakeFsInMemory()
|
||||
pvd := provider.NewDefaultDepProvider()
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
input string
|
||||
args []string
|
||||
expectedErrorMsg string
|
||||
}{
|
||||
func TestErrorCasesEditSetConfigMap(t *testing.T) {
|
||||
testCases := []testutils_test.FailureCase{
|
||||
{
|
||||
name: "fails to set a value because key doesn't exist",
|
||||
input: `---
|
||||
Name: "fails to set a value because key doesn't exist",
|
||||
KustomizationFileContent: `
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
configMapGenerator:
|
||||
- literals:
|
||||
- test=value
|
||||
- test-cm-key=value
|
||||
- key1=val1
|
||||
name: test-cm
|
||||
- literals:
|
||||
- key3=val1
|
||||
name: test-cm-2
|
||||
namespace: test-ns
|
||||
`,
|
||||
args: []string{"test-cm", "--from-literal=key3=val2"},
|
||||
expectedErrorMsg: "key 'key3' not found in resource",
|
||||
Args: []string{"test-cm", "--from-literal=test-key=test-value"},
|
||||
ExpectedErrorMsg: "key 'test-key' not found in resource",
|
||||
},
|
||||
{
|
||||
name: "fails to set a value because configmap doesn't exist",
|
||||
input: `---
|
||||
Name: "fails to set a value because configmap doesn't exist",
|
||||
KustomizationFileContent: `
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
configMapGenerator:
|
||||
- literals:
|
||||
- test=value
|
||||
- key1=val1
|
||||
- key2=val2
|
||||
name: test-cm
|
||||
`,
|
||||
args: []string{"test-cm2", "--from-literal=key3=val2"},
|
||||
expectedErrorMsg: "unable to find ConfigMap with name '\"test-cm2\"'",
|
||||
Args: []string{"test-cm2", "--from-literal=test-key=test-value"},
|
||||
ExpectedErrorMsg: "unable to find ConfigMap with name '\"test-cm2\"'",
|
||||
},
|
||||
{
|
||||
name: "fails validation because no attributes are being changed",
|
||||
input: `---
|
||||
Name: "fails validation because no attributes are being changed",
|
||||
KustomizationFileContent: `
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
configMapGenerator:
|
||||
- literals:
|
||||
- test=value
|
||||
- key1=val1
|
||||
- test-key=test-value
|
||||
name: test-cm
|
||||
namespace: test-ns
|
||||
`,
|
||||
args: []string{"test-cm", "--namespace=test-ns"},
|
||||
expectedErrorMsg: "at least one of [--from-literal, --new-namespace] must be specified",
|
||||
Args: []string{"test-cm", "--namespace=test-ns"},
|
||||
ExpectedErrorMsg: "at least one of [--from-literal, --new-namespace] must be specified",
|
||||
},
|
||||
{
|
||||
name: "fails when a literal source doesn't have a key",
|
||||
input: `---
|
||||
Name: "fails when a literal source doesn't have a key",
|
||||
KustomizationFileContent: `
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
configMapGenerator:
|
||||
- literals:
|
||||
- test=value
|
||||
- key1=val1
|
||||
- test-key=test-value
|
||||
- key3=other-value
|
||||
name: test-cm
|
||||
`,
|
||||
args: []string{"test-cm", "--from-literal=value"},
|
||||
expectedErrorMsg: "literal values must be specified in the key=value format",
|
||||
Args: []string{"test-cm", "--from-literal=value"},
|
||||
ExpectedErrorMsg: "literal values must be specified in the key=value format",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
cmd := newCmdSetConfigMap(
|
||||
fSys,
|
||||
kv.NewLoader(
|
||||
loader.NewFileLoaderAtCwd(fSys),
|
||||
pvd.GetFieldValidator()),
|
||||
pvd.GetResourceFactory(),
|
||||
)
|
||||
|
||||
testutils_test.WriteTestKustomizationWith(fSys, []byte(tc.input))
|
||||
|
||||
cmd.SetArgs(tc.args)
|
||||
err := cmd.Execute()
|
||||
t.Run(tc.Name, func(t *testing.T) {
|
||||
kustomization, err := testutils_test.SetupEditSetConfigMapSecretTest(t, newCmdSetConfigMap, tc.KustomizationFileContent, tc.Args)
|
||||
|
||||
require.Nil(t, kustomization)
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), tc.expectedErrorMsg)
|
||||
require.Contains(t, err.Error(), tc.ExpectedErrorMsg)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEditSetConfigMapSuccess(t *testing.T) {
|
||||
fSys := filesys.MakeFsInMemory()
|
||||
pvd := provider.NewDefaultDepProvider()
|
||||
testCases := []struct {
|
||||
name string
|
||||
input string
|
||||
args []string
|
||||
expectedLiterals []string
|
||||
expectedNamespace string
|
||||
}{
|
||||
func TestSuccessCasesEditSetConfigMap(t *testing.T) {
|
||||
testCases := []testutils_test.SuccessCase{
|
||||
{
|
||||
name: "set a value successfully",
|
||||
input: `---
|
||||
Name: "set a value successfully",
|
||||
KustomizationFileContent: `
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
configMapGenerator:
|
||||
- literals:
|
||||
- a-key=a-value
|
||||
- key1=val1
|
||||
- test=value
|
||||
name: test-cm
|
||||
- literals:
|
||||
- another-key=another-value
|
||||
- key1=value-from-cm-2
|
||||
name: test-cm-2
|
||||
namespace: another-ns
|
||||
`,
|
||||
expectedLiterals: []string{"key1=val2", "test=value"},
|
||||
args: []string{"test-cm", "--from-literal=key1=val2"},
|
||||
ExpectedLiterals: []string{"a-key=a-value", "key1=val2"},
|
||||
Args: []string{"test-cm", "--from-literal=key1=val2"},
|
||||
},
|
||||
{
|
||||
name: "successfully update namespace of target configmap",
|
||||
input: `---
|
||||
Name: "successfully update namespace of target configmap",
|
||||
KustomizationFileContent: `
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
configMapGenerator:
|
||||
- literals:
|
||||
- test=value
|
||||
- key1=val1
|
||||
- yet-another-key=value
|
||||
name: test-cm
|
||||
namespace: test-ns
|
||||
`,
|
||||
args: []string{"test-cm", "--namespace=test-ns", "--new-namespace=test-new-ns"},
|
||||
expectedNamespace: "test-new-ns",
|
||||
Args: []string{"test-cm", "--namespace=test-ns", "--new-namespace=test-new-ns"},
|
||||
ExpectedNamespace: "test-new-ns",
|
||||
},
|
||||
{
|
||||
name: "successfully update namespace of target configmap with empty namespace in file and namespace specified in command",
|
||||
input: `---
|
||||
Name: "successfully update namespace of target configmap with empty namespace in file and namespace specified in command",
|
||||
KustomizationFileContent: `
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
configMapGenerator:
|
||||
- literals:
|
||||
- test=value
|
||||
- key1=val1
|
||||
- found-key=found-value
|
||||
- a-key=a-value
|
||||
name: test-cm
|
||||
`,
|
||||
args: []string{"test-cm", "--namespace=default", "--new-namespace=test-new-ns"},
|
||||
expectedNamespace: "test-new-ns",
|
||||
Args: []string{"test-cm", "--namespace=default", "--new-namespace=test-new-ns"},
|
||||
ExpectedNamespace: "test-new-ns",
|
||||
},
|
||||
{
|
||||
name: "successfully update namespace of target configmap with default namespace and no namespace specified in command",
|
||||
input: `---
|
||||
Name: "successfully update namespace of target configmap with default namespace and no namespace specified in command",
|
||||
KustomizationFileContent: `
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
configMapGenerator:
|
||||
- literals:
|
||||
- test=value
|
||||
- a-different-key=a-different-value
|
||||
- key2=value
|
||||
name: test-cm
|
||||
namespace: default
|
||||
`,
|
||||
Args: []string{"test-cm", "--new-namespace=test-new-ns"},
|
||||
ExpectedNamespace: "test-new-ns",
|
||||
},
|
||||
{
|
||||
Name: "successfully update literal source of target configmap with empty namespace in file and namespace specified in command",
|
||||
KustomizationFileContent: `
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
configMapGenerator:
|
||||
- literals:
|
||||
- key1=value
|
||||
- a-separate-key=a-separate-value
|
||||
name: test-cm
|
||||
`,
|
||||
Args: []string{"test-cm", "--namespace=default", "--from-literal=key1=val2"},
|
||||
ExpectedLiterals: []string{"key1=val2", "a-separate-key=a-separate-value"},
|
||||
},
|
||||
{
|
||||
Name: "successfully update namespace of target configmap with default namespace and no namespace specified in command",
|
||||
KustomizationFileContent: `
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
configMapGenerator:
|
||||
- literals:
|
||||
- a-random-key=a-random-value
|
||||
- key1=val1
|
||||
name: test-cm
|
||||
namespace: default
|
||||
`,
|
||||
args: []string{"test-cm", "--new-namespace=test-new-ns"},
|
||||
expectedNamespace: "test-new-ns",
|
||||
},
|
||||
{
|
||||
name: "successfully update literal source of target configmap with empty namespace in file and namespace specified in command",
|
||||
input: `---
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
configMapGenerator:
|
||||
- literals:
|
||||
- test=value
|
||||
- key1=val1
|
||||
name: test-cm
|
||||
`,
|
||||
args: []string{"test-cm", "--namespace=default", "--from-literal=key1=val2"},
|
||||
expectedLiterals: []string{"test=value", "key1=val2"},
|
||||
},
|
||||
{
|
||||
name: "successfully update namespace of target configmap with default namespace and no namespace specified in command",
|
||||
input: `---
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
configMapGenerator:
|
||||
- literals:
|
||||
- test=value
|
||||
- key1=val1
|
||||
name: test-cm
|
||||
namespace: default
|
||||
`,
|
||||
args: []string{"test-cm", "--namespace=default", "--from-literal=key1=val2"},
|
||||
expectedLiterals: []string{"test=value", "key1=val2"},
|
||||
Args: []string{"test-cm", "--from-literal=key1=val2"},
|
||||
ExpectedLiterals: []string{"a-random-key=a-random-value", "key1=val2"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
cmd := newCmdSetConfigMap(
|
||||
fSys,
|
||||
kv.NewLoader(
|
||||
loader.NewFileLoaderAtCwd(fSys),
|
||||
pvd.GetFieldValidator()),
|
||||
pvd.GetResourceFactory(),
|
||||
)
|
||||
|
||||
testutils_test.WriteTestKustomizationWith(fSys, []byte(tc.input))
|
||||
|
||||
cmd.SetArgs(tc.args)
|
||||
err := cmd.Execute()
|
||||
t.Run(tc.Name, func(t *testing.T) {
|
||||
kustomization, err := testutils_test.SetupEditSetConfigMapSecretTest(t, newCmdSetConfigMap, tc.KustomizationFileContent, tc.Args)
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
_, 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.NotNil(t, kustomization)
|
||||
require.NotEmpty(t, kustomization.ConfigMapGenerator)
|
||||
require.Greater(t, len(kustomization.ConfigMapGenerator), 0)
|
||||
|
||||
if tc.expectedNamespace != "" {
|
||||
require.Equal(t, tc.expectedNamespace, kustomization.ConfigMapGenerator[0].Namespace)
|
||||
if tc.ExpectedNamespace != "" {
|
||||
require.Equal(t, tc.ExpectedNamespace, kustomization.ConfigMapGenerator[0].Namespace)
|
||||
}
|
||||
|
||||
if len(tc.expectedLiterals) > 0 {
|
||||
require.ElementsMatch(t, tc.expectedLiterals, kustomization.ConfigMapGenerator[0].LiteralSources)
|
||||
if len(tc.ExpectedLiterals) > 0 {
|
||||
require.ElementsMatch(t, tc.ExpectedLiterals, kustomization.ConfigMapGenerator[0].LiteralSources)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
152
kustomize/commands/edit/set/setsecret.go
Normal file
152
kustomize/commands/edit/set/setsecret.go
Normal file
@@ -0,0 +1,152 @@
|
||||
// Copyright 2023 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package set
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"golang.org/x/exp/slices"
|
||||
"sigs.k8s.io/kustomize/api/ifc"
|
||||
"sigs.k8s.io/kustomize/api/konfig"
|
||||
"sigs.k8s.io/kustomize/api/resource"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/kustomize/kustomize/v5/commands/internal/kustfile"
|
||||
"sigs.k8s.io/kustomize/kustomize/v5/commands/internal/util"
|
||||
"sigs.k8s.io/kustomize/kyaml/filesys"
|
||||
)
|
||||
|
||||
func newCmdSetSecret(
|
||||
fSys filesys.FileSystem,
|
||||
ldr ifc.KvLoader,
|
||||
rf *resource.Factory,
|
||||
) *cobra.Command {
|
||||
var flags util.ConfigMapSecretFlagsAndArgs
|
||||
cmd := &cobra.Command{
|
||||
Use: "secret NAME [--from-literal=key1=value1] [--namespace=namespace-name] [--new-namespace=new-namespace-name]",
|
||||
Short: fmt.Sprintf("Edits the value for an existing key for a secret in the %s file", konfig.DefaultKustomizationFileName()),
|
||||
Long: fmt.Sprintf(`Edits the value for an existing key in an existing secret in the %s file.
|
||||
Both secret name and key name must exist for this command to succeed.`, konfig.DefaultKustomizationFileName()),
|
||||
Example: fmt.Sprintf(`
|
||||
# Edits an existing secret in the %[1]s file, changing the value of key1 to 2
|
||||
kustomize edit set secret my-secret --from-literal=key1=2
|
||||
|
||||
# Edits an existing secret in the %[1]s file, changing namespace to 'new-namespace'
|
||||
kustomize edit set secret my-secret --namespace=current-namespace --new-namespace=new-namespace
|
||||
`, konfig.DefaultKustomizationFileName()),
|
||||
RunE: func(_ *cobra.Command, args []string) error {
|
||||
return runEditSetSecret(flags, fSys, args, ldr, rf)
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().StringArrayVar(
|
||||
&flags.LiteralSources,
|
||||
util.FromLiteralFlag,
|
||||
[]string{},
|
||||
"Specify an existing key and a new value to update a Secret (i.e. mykey=newvalue)")
|
||||
cmd.Flags().StringVar(
|
||||
&flags.Namespace,
|
||||
util.NamespaceFlag,
|
||||
"",
|
||||
"Current namespace of the target Secret")
|
||||
cmd.Flags().StringVar(
|
||||
&flags.NewNamespace,
|
||||
util.NewNamespaceFlag,
|
||||
"",
|
||||
"New namespace value for the target Secret")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runEditSetSecret(
|
||||
flags util.ConfigMapSecretFlagsAndArgs,
|
||||
fSys filesys.FileSystem,
|
||||
args []string,
|
||||
ldr ifc.KvLoader,
|
||||
rf *resource.Factory,
|
||||
) error {
|
||||
err := flags.ExpandFileSource(fSys)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to expand file source: %w", err)
|
||||
}
|
||||
|
||||
err = flags.ValidateSet(args)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to validate flags: %w", err)
|
||||
}
|
||||
|
||||
// Load the kustomization file.
|
||||
mf, err := kustfile.NewKustomizationFile(fSys)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load kustomization file: %w", err)
|
||||
}
|
||||
|
||||
kustomization, err := mf.Read()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read kustomization file: %w", err)
|
||||
}
|
||||
|
||||
// Updates the existing Secret
|
||||
err = setSecret(ldr, kustomization, flags, rf)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create secret: %w", err)
|
||||
}
|
||||
|
||||
// Write out the kustomization file with added secret.
|
||||
err = mf.Write(kustomization)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to write kustomization file: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func setSecret(
|
||||
ldr ifc.KvLoader,
|
||||
k *types.Kustomization,
|
||||
flags util.ConfigMapSecretFlagsAndArgs,
|
||||
rf *resource.Factory,
|
||||
) error {
|
||||
args, err := findSecretArgs(k, flags.Name, flags.Namespace)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not set new Secret value: %w", err)
|
||||
}
|
||||
|
||||
if len(flags.LiteralSources) > 0 {
|
||||
err := util.UpdateLiteralSources(&args.GeneratorArgs, flags)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to update literal sources: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// update namespace to new one
|
||||
if flags.NewNamespace != "" {
|
||||
args.Namespace = flags.NewNamespace
|
||||
}
|
||||
|
||||
// Validate by trying to create corev1.secret.
|
||||
args.Options = types.MergeGlobalOptionsIntoLocal(
|
||||
args.Options, k.GeneratorOptions)
|
||||
|
||||
_, err = rf.MakeSecret(ldr, args)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to validate Secret structure: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// findSecretArgs finds the generator arguments corresponding to the specified
|
||||
// Secret name. Secret must exist for this command to be successful.
|
||||
func findSecretArgs(m *types.Kustomization, name, namespace string) (*types.SecretArgs, error) {
|
||||
cmIndex := slices.IndexFunc(m.SecretGenerator, func(cmArgs types.SecretArgs) bool {
|
||||
return name == cmArgs.Name && util.NamespaceEqual(namespace, cmArgs.Namespace)
|
||||
})
|
||||
|
||||
if cmIndex == -1 {
|
||||
return nil, fmt.Errorf("unable to find Secret with name '%q'", name)
|
||||
}
|
||||
|
||||
return &m.SecretGenerator[cmIndex], nil
|
||||
}
|
||||
213
kustomize/commands/edit/set/setsecret_test.go
Normal file
213
kustomize/commands/edit/set/setsecret_test.go
Normal file
@@ -0,0 +1,213 @@
|
||||
// Copyright 2023 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// The duplicate linter is reporting that setconfigmap_test.go and this file are duplicates, which is not true.
|
||||
// Disabling lint for these two files specifically to work around that.
|
||||
//
|
||||
//nolint:dupl
|
||||
package set
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
testutils_test "sigs.k8s.io/kustomize/kustomize/v5/commands/internal/configmapsecret"
|
||||
)
|
||||
|
||||
func TestFailureCasesEditSetSecret(t *testing.T) {
|
||||
testCases := []testutils_test.FailureCase{
|
||||
{
|
||||
Name: "fails to set a value because key doesn't exist",
|
||||
KustomizationFileContent: `
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
secretGenerator:
|
||||
- literals:
|
||||
- key1=val1
|
||||
name: test-secret
|
||||
type: Opaque
|
||||
- literals:
|
||||
- key3=val1
|
||||
name: test-secret-2
|
||||
namespace: test-ns
|
||||
type: Opaque
|
||||
`,
|
||||
Args: []string{"test-secret", "--from-literal=key3=val2"},
|
||||
ExpectedErrorMsg: "key 'key3' not found in resource",
|
||||
},
|
||||
{
|
||||
Name: "fails to set a value because secret doesn't exist",
|
||||
KustomizationFileContent: `
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
secretGenerator:
|
||||
- literals:
|
||||
- key1=val1
|
||||
name: test-secret
|
||||
type: Opaque
|
||||
- literals:
|
||||
- key2=value
|
||||
name: another-secret
|
||||
namespace: a-namespace
|
||||
type: Opaque
|
||||
`,
|
||||
Args: []string{"test-secret2", "--from-literal=key3=val2"},
|
||||
ExpectedErrorMsg: "unable to find Secret with name '\"test-secret2\"'",
|
||||
},
|
||||
{
|
||||
Name: "fails validation because no attributes are being changed",
|
||||
KustomizationFileContent: `
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
secretGenerator:
|
||||
- literals:
|
||||
- a-test-key=a-test-value
|
||||
name: test-secret
|
||||
namespace: test-ns
|
||||
type: Opaque
|
||||
`,
|
||||
Args: []string{"test-secret", "--namespace=test-ns"},
|
||||
ExpectedErrorMsg: "at least one of [--from-literal, --new-namespace] must be specified",
|
||||
},
|
||||
{
|
||||
Name: "fails when a literal source doesn't have a key",
|
||||
KustomizationFileContent: `
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
secretGenerator:
|
||||
- literals:
|
||||
- some-key=some-value
|
||||
name: test-secret
|
||||
type: Opaque
|
||||
`,
|
||||
Args: []string{"test-secret", "--from-literal=value"},
|
||||
ExpectedErrorMsg: "literal values must be specified in the key=value format",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.Name, func(t *testing.T) {
|
||||
kustomization, err := testutils_test.SetupEditSetConfigMapSecretTest(t, newCmdSetSecret, tc.KustomizationFileContent, tc.Args)
|
||||
|
||||
require.Nil(t, kustomization)
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), tc.ExpectedErrorMsg)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSuccessCasesEditSetSecret(t *testing.T) {
|
||||
testCases := []testutils_test.SuccessCase{
|
||||
{
|
||||
Name: "set a value successfully",
|
||||
KustomizationFileContent: `
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
secretGenerator:
|
||||
- literals:
|
||||
- random-key=random-value
|
||||
- key1=value
|
||||
name: test-secret
|
||||
type: Opaque
|
||||
`,
|
||||
ExpectedLiterals: []string{"key1=val2", "random-key=random-value"},
|
||||
Args: []string{"test-secret", "--from-literal=key1=val2"},
|
||||
},
|
||||
{
|
||||
Name: "successfully update namespace of target secret",
|
||||
KustomizationFileContent: `
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
secretGenerator:
|
||||
- literals:
|
||||
- a-key=test
|
||||
- another-key=value
|
||||
name: test-secret
|
||||
namespace: test-ns
|
||||
type: Opaque
|
||||
`,
|
||||
Args: []string{"test-secret", "--namespace=test-ns", "--new-namespace=test-new-ns"},
|
||||
ExpectedNamespace: "test-new-ns",
|
||||
},
|
||||
{
|
||||
Name: "successfully update namespace of target secret with empty namespace in file and namespace specified in command",
|
||||
KustomizationFileContent: `
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
secretGenerator:
|
||||
- literals:
|
||||
- key1=value1
|
||||
- another-key=another-value
|
||||
name: test-secret
|
||||
type: Opaque
|
||||
`,
|
||||
Args: []string{"test-secret", "--namespace=default", "--new-namespace=test-new-ns"},
|
||||
ExpectedNamespace: "test-new-ns",
|
||||
},
|
||||
{
|
||||
Name: "successfully update namespace of target secret with default namespace and no namespace specified in command",
|
||||
KustomizationFileContent: `
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
secretGenerator:
|
||||
- literals:
|
||||
- random-key=random-value
|
||||
name: test-secret
|
||||
namespace: default
|
||||
type: Opaque
|
||||
`,
|
||||
Args: []string{"test-secret", "--new-namespace=test-new-ns"},
|
||||
ExpectedNamespace: "test-new-ns",
|
||||
},
|
||||
{
|
||||
Name: "successfully update literal source of target secret with empty namespace in file and namespace specified in command",
|
||||
KustomizationFileContent: `
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
secretGenerator:
|
||||
- literals:
|
||||
- a-key=a-value
|
||||
- key1=value
|
||||
name: test-secret
|
||||
type: Opaque
|
||||
`,
|
||||
Args: []string{"test-secret", "--namespace=default", "--from-literal=key1=val2"},
|
||||
ExpectedLiterals: []string{"a-key=a-value", "key1=val2"},
|
||||
},
|
||||
{
|
||||
Name: "successfully update namespace of target secret with default namespace and no namespace specified in command",
|
||||
KustomizationFileContent: `
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
secretGenerator:
|
||||
- literals:
|
||||
- test-secret-key=value
|
||||
- key1=val1
|
||||
name: test-secret
|
||||
namespace: default
|
||||
type: Opaque
|
||||
`,
|
||||
Args: []string{"test-secret", "--from-literal=key1=val2"},
|
||||
ExpectedLiterals: []string{"test-secret-key=value", "key1=val2"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.Name, func(t *testing.T) {
|
||||
kustomization, err := testutils_test.SetupEditSetConfigMapSecretTest(t, newCmdSetSecret, tc.KustomizationFileContent, tc.Args)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, kustomization)
|
||||
require.NotEmpty(t, kustomization.SecretGenerator)
|
||||
require.Greater(t, len(kustomization.SecretGenerator), 0)
|
||||
|
||||
if tc.ExpectedNamespace != "" {
|
||||
require.Equal(t, tc.ExpectedNamespace, kustomization.SecretGenerator[0].Namespace)
|
||||
}
|
||||
|
||||
if len(tc.ExpectedLiterals) > 0 {
|
||||
require.ElementsMatch(t, tc.ExpectedLiterals, kustomization.SecretGenerator[0].LiteralSources)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
// Copyright 2023 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package configmapsecret_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"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"
|
||||
"sigs.k8s.io/kustomize/api/resource"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/kustomize/kustomize/v5/commands/internal/kustfile"
|
||||
testutils_test "sigs.k8s.io/kustomize/kustomize/v5/commands/internal/testutils"
|
||||
"sigs.k8s.io/kustomize/kyaml/filesys"
|
||||
)
|
||||
|
||||
// FailureCase specifies a test case for a failure in the 'edit set configmap'/'edit set secret' commands.
|
||||
type FailureCase struct {
|
||||
// The name of the test case
|
||||
Name string
|
||||
|
||||
// The kustomization file content for the test case in YAML format
|
||||
KustomizationFileContent string
|
||||
|
||||
// Arguments passed to the test case command
|
||||
Args []string
|
||||
|
||||
// The expected error message for the test case
|
||||
ExpectedErrorMsg string
|
||||
}
|
||||
|
||||
// SuccessCase specifies a test case for a success in the 'edit set configmap'/'edit set secret' commands.
|
||||
type SuccessCase struct {
|
||||
// The name of the test case
|
||||
Name string
|
||||
|
||||
// The kustomization file content for the test case in YAML format
|
||||
KustomizationFileContent string
|
||||
|
||||
// Arguments passed to the test case command
|
||||
Args []string
|
||||
|
||||
// List of expected literals for the result of the test case
|
||||
ExpectedLiterals []string
|
||||
|
||||
// The expected namespace for the result of the test case
|
||||
ExpectedNamespace string
|
||||
}
|
||||
|
||||
func SetupEditSetConfigMapSecretTest(
|
||||
t *testing.T,
|
||||
command func(filesys.FileSystem, ifc.KvLoader, *resource.Factory) *cobra.Command,
|
||||
input string,
|
||||
args []string,
|
||||
) (*types.Kustomization, error) {
|
||||
t.Helper()
|
||||
fSys := filesys.MakeFsInMemory()
|
||||
pvd := provider.NewDefaultDepProvider()
|
||||
|
||||
cmd := command(
|
||||
fSys,
|
||||
kv.NewLoader(
|
||||
loader.NewFileLoaderAtCwd(fSys),
|
||||
pvd.GetFieldValidator()),
|
||||
pvd.GetResourceFactory(),
|
||||
)
|
||||
|
||||
testutils_test.WriteTestKustomizationWith(fSys, []byte(input))
|
||||
|
||||
cmd.SetArgs(args)
|
||||
err := cmd.Execute()
|
||||
|
||||
//nolint: wrapcheck
|
||||
// this needs to be bubbled up for checking in the test
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
_, 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)
|
||||
|
||||
return kustomization, nil
|
||||
}
|
||||
Reference in New Issue
Block a user