mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-09 12:07:47 +00:00
create secret from-env-file
This commit is contained in:
parent
7eb49628c6
commit
f2815156b0
@ -19,6 +19,7 @@ go_library(
|
|||||||
"configmap.go",
|
"configmap.go",
|
||||||
"deployment.go",
|
"deployment.go",
|
||||||
"doc.go",
|
"doc.go",
|
||||||
|
"env_file.go",
|
||||||
"explain.go",
|
"explain.go",
|
||||||
"generate.go",
|
"generate.go",
|
||||||
"history.go",
|
"history.go",
|
||||||
|
@ -64,7 +64,10 @@ var (
|
|||||||
kubectl create secret generic my-secret --from-file=ssh-privatekey=~/.ssh/id_rsa --from-file=ssh-publickey=~/.ssh/id_rsa.pub
|
kubectl create secret generic my-secret --from-file=ssh-privatekey=~/.ssh/id_rsa --from-file=ssh-publickey=~/.ssh/id_rsa.pub
|
||||||
|
|
||||||
# Create a new secret named my-secret with key1=supersecret and key2=topsecret
|
# Create a new secret named my-secret with key1=supersecret and key2=topsecret
|
||||||
kubectl create secret generic my-secret --from-literal=key1=supersecret --from-literal=key2=topsecret`)
|
kubectl create secret generic my-secret --from-literal=key1=supersecret --from-literal=key2=topsecret
|
||||||
|
|
||||||
|
# Create a new secret named my-secret from an env file
|
||||||
|
kubectl create secret generic my-secret --from-env-file=path/to/bar.env`)
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewCmdCreateSecretGeneric is a command to create generic secrets from files, directories, or literal values
|
// NewCmdCreateSecretGeneric is a command to create generic secrets from files, directories, or literal values
|
||||||
@ -85,6 +88,7 @@ func NewCmdCreateSecretGeneric(f cmdutil.Factory, cmdOut io.Writer) *cobra.Comma
|
|||||||
cmdutil.AddGeneratorFlags(cmd, cmdutil.SecretV1GeneratorName)
|
cmdutil.AddGeneratorFlags(cmd, cmdutil.SecretV1GeneratorName)
|
||||||
cmd.Flags().StringSlice("from-file", []string{}, "Key files can be specified using their file path, in which case a default name will be given to them, or optionally with a name and file path, in which case the given name will be used. Specifying a directory will iterate each named file in the directory that is a valid secret key.")
|
cmd.Flags().StringSlice("from-file", []string{}, "Key files can be specified using their file path, in which case a default name will be given to them, or optionally with a name and file path, in which case the given name will be used. Specifying a directory will iterate each named file in the directory that is a valid secret key.")
|
||||||
cmd.Flags().StringArray("from-literal", []string{}, "Specify a key and literal value to insert in secret (i.e. mykey=somevalue)")
|
cmd.Flags().StringArray("from-literal", []string{}, "Specify a key and literal value to insert in secret (i.e. mykey=somevalue)")
|
||||||
|
cmd.Flags().String("from-env-file", "", "Specify the path to a file to read lines of key=val pairs to create a secret (i.e. a Docker .env file).")
|
||||||
cmd.Flags().String("type", "", i18n.T("The type of secret to create"))
|
cmd.Flags().String("type", "", i18n.T("The type of secret to create"))
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
@ -103,6 +107,7 @@ func CreateSecretGeneric(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command
|
|||||||
Type: cmdutil.GetFlagString(cmd, "type"),
|
Type: cmdutil.GetFlagString(cmd, "type"),
|
||||||
FileSources: cmdutil.GetFlagStringSlice(cmd, "from-file"),
|
FileSources: cmdutil.GetFlagStringSlice(cmd, "from-file"),
|
||||||
LiteralSources: cmdutil.GetFlagStringArray(cmd, "from-literal"),
|
LiteralSources: cmdutil.GetFlagStringArray(cmd, "from-literal"),
|
||||||
|
EnvFileSource: cmdutil.GetFlagString(cmd, "from-env-file"),
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return cmdutil.UsageError(cmd, fmt.Sprintf("Generator: %s not supported.", generatorName))
|
return cmdutil.UsageError(cmd, fmt.Sprintf("Generator: %s not supported.", generatorName))
|
||||||
|
@ -221,7 +221,10 @@ func handleConfigMapFromEnvFileSource(configMap *api.ConfigMap, envFileSource st
|
|||||||
if info.IsDir() {
|
if info.IsDir() {
|
||||||
return fmt.Errorf("must be a file")
|
return fmt.Errorf("must be a file")
|
||||||
}
|
}
|
||||||
return addFromEnvFileToConfigMap(configMap, envFileSource)
|
|
||||||
|
return addFromEnvFile(envFileSource, func(key, value string) error {
|
||||||
|
return addKeyFromLiteralToConfigMap(configMap, key, value)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// addKeyFromFileToConfigMap adds a key with the given name to a ConfigMap, populating
|
// addKeyFromFileToConfigMap adds a key with the given name to a ConfigMap, populating
|
||||||
|
@ -38,6 +38,8 @@ type SecretGeneratorV1 struct {
|
|||||||
FileSources []string
|
FileSources []string
|
||||||
// LiteralSources to derive the secret from (optional)
|
// LiteralSources to derive the secret from (optional)
|
||||||
LiteralSources []string
|
LiteralSources []string
|
||||||
|
// EnvFileSource to derive the secret from (optional)
|
||||||
|
EnvFileSource string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure it supports the generator pattern that uses parameter injection
|
// Ensure it supports the generator pattern that uses parameter injection
|
||||||
@ -71,6 +73,15 @@ func (s SecretGeneratorV1) Generate(genericParams map[string]interface{}) (runti
|
|||||||
delegate.LiteralSources = fromLiteralArray
|
delegate.LiteralSources = fromLiteralArray
|
||||||
delete(genericParams, "from-literal")
|
delete(genericParams, "from-literal")
|
||||||
}
|
}
|
||||||
|
fromEnvFileString, found := genericParams["from-env-file"]
|
||||||
|
if found {
|
||||||
|
fromEnvFile, isString := fromEnvFileString.(string)
|
||||||
|
if !isString {
|
||||||
|
return nil, fmt.Errorf("expected string, found :%v", fromEnvFileString)
|
||||||
|
}
|
||||||
|
delegate.EnvFileSource = fromEnvFile
|
||||||
|
delete(genericParams, "from-env-file")
|
||||||
|
}
|
||||||
params := map[string]string{}
|
params := map[string]string{}
|
||||||
for key, value := range genericParams {
|
for key, value := range genericParams {
|
||||||
strVal, isString := value.(string)
|
strVal, isString := value.(string)
|
||||||
@ -91,6 +102,7 @@ func (s SecretGeneratorV1) ParamNames() []GeneratorParam {
|
|||||||
{"type", false},
|
{"type", false},
|
||||||
{"from-file", false},
|
{"from-file", false},
|
||||||
{"from-literal", false},
|
{"from-literal", false},
|
||||||
|
{"from-env-file", false},
|
||||||
{"force", false},
|
{"force", false},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -116,6 +128,11 @@ func (s SecretGeneratorV1) StructuredGenerate() (runtime.Object, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if len(s.EnvFileSource) > 0 {
|
||||||
|
if err := handleFromEnvFileSource(secret, s.EnvFileSource); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
return secret, nil
|
return secret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,6 +141,9 @@ func (s SecretGeneratorV1) validate() error {
|
|||||||
if len(s.Name) == 0 {
|
if len(s.Name) == 0 {
|
||||||
return fmt.Errorf("name must be specified")
|
return fmt.Errorf("name must be specified")
|
||||||
}
|
}
|
||||||
|
if len(s.EnvFileSource) > 0 && (len(s.FileSources) > 0 || len(s.LiteralSources) > 0) {
|
||||||
|
return fmt.Errorf("from-env-file cannot be combined with from-file or from-literal")
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,6 +207,27 @@ func handleFromFileSources(secret *api.Secret, fileSources []string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handleFromEnvFileSource adds the specified env file source information
|
||||||
|
// into the provided secret
|
||||||
|
func handleFromEnvFileSource(secret *api.Secret, envFileSource string) error {
|
||||||
|
info, err := os.Stat(envFileSource)
|
||||||
|
if err != nil {
|
||||||
|
switch err := err.(type) {
|
||||||
|
case *os.PathError:
|
||||||
|
return fmt.Errorf("error reading %s: %v", envFileSource, err.Err)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("error reading %s: %v", envFileSource, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if info.IsDir() {
|
||||||
|
return fmt.Errorf("must be a file")
|
||||||
|
}
|
||||||
|
|
||||||
|
return addFromEnvFile(envFileSource, func(key, value string) error {
|
||||||
|
return addKeyFromLiteralToSecret(secret, key, []byte(value))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func addKeyFromFileToSecret(secret *api.Secret, keyName, filePath string) error {
|
func addKeyFromFileToSecret(secret *api.Secret, keyName, filePath string) error {
|
||||||
data, err := ioutil.ReadFile(filePath)
|
data, err := ioutil.ReadFile(filePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
package kubectl
|
package kubectl
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@ -26,6 +27,7 @@ import (
|
|||||||
|
|
||||||
func TestSecretGenerate(t *testing.T) {
|
func TestSecretGenerate(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
|
setup func(t *testing.T, params map[string]interface{}) func()
|
||||||
params map[string]interface{}
|
params map[string]interface{}
|
||||||
expected *api.Secret
|
expected *api.Secret
|
||||||
expectErr bool
|
expectErr bool
|
||||||
@ -108,9 +110,84 @@ func TestSecretGenerate(t *testing.T) {
|
|||||||
},
|
},
|
||||||
expectErr: false,
|
expectErr: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
setup: setupEnvFile("key1=value1", "#", "", "key2=value2"),
|
||||||
|
params: map[string]interface{}{
|
||||||
|
"name": "valid_env",
|
||||||
|
"from-env-file": "file.env",
|
||||||
|
},
|
||||||
|
expected: &api.Secret{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "valid_env",
|
||||||
|
},
|
||||||
|
Data: map[string][]byte{
|
||||||
|
"key1": []byte("value1"),
|
||||||
|
"key2": []byte("value2"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
setup: func() func(t *testing.T, params map[string]interface{}) func() {
|
||||||
|
os.Setenv("g_key1", "1")
|
||||||
|
os.Setenv("g_key2", "2")
|
||||||
|
return setupEnvFile("g_key1", "g_key2=")
|
||||||
|
}(),
|
||||||
|
params: map[string]interface{}{
|
||||||
|
"name": "getenv",
|
||||||
|
"from-env-file": "file.env",
|
||||||
|
},
|
||||||
|
expected: &api.Secret{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "getenv",
|
||||||
|
},
|
||||||
|
Data: map[string][]byte{
|
||||||
|
"g_key1": []byte("1"),
|
||||||
|
"g_key2": []byte(""),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
params: map[string]interface{}{
|
||||||
|
"name": "too_many_args",
|
||||||
|
"from-literal": []string{"key1=value1"},
|
||||||
|
"from-env-file": "file.env",
|
||||||
|
},
|
||||||
|
expectErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
setup: setupEnvFile("key.1=value1"),
|
||||||
|
params: map[string]interface{}{
|
||||||
|
"name": "invalid_key",
|
||||||
|
"from-env-file": "file.env",
|
||||||
|
},
|
||||||
|
expectErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
setup: setupEnvFile(" key1= value1"),
|
||||||
|
params: map[string]interface{}{
|
||||||
|
"name": "with_spaces",
|
||||||
|
"from-env-file": "file.env",
|
||||||
|
},
|
||||||
|
expected: &api.Secret{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "with_spaces",
|
||||||
|
},
|
||||||
|
Data: map[string][]byte{
|
||||||
|
"key1": []byte(" value1"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectErr: false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
generator := SecretGeneratorV1{}
|
generator := SecretGeneratorV1{}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
|
if test.setup != nil {
|
||||||
|
if teardown := test.setup(t, test.params); teardown != nil {
|
||||||
|
defer teardown()
|
||||||
|
}
|
||||||
|
}
|
||||||
obj, err := generator.Generate(test.params)
|
obj, err := generator.Generate(test.params)
|
||||||
if !test.expectErr && err != nil {
|
if !test.expectErr && err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
Loading…
Reference in New Issue
Block a user