mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-11 17:12:51 +00:00
configMap factory refactor for #86
This commit is contained in:
@@ -20,8 +20,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
// dataConfig encapsulates the options for add configmap/Secret commands.
|
// cMapFlagsAndArgs encapsulates the options for add configmap commands.
|
||||||
type dataConfig struct {
|
type cMapFlagsAndArgs struct {
|
||||||
// Name of configMap/Secret (required)
|
// Name of configMap/Secret (required)
|
||||||
Name string
|
Name string
|
||||||
// FileSources to derive the configMap/Secret from (optional)
|
// FileSources to derive the configMap/Secret from (optional)
|
||||||
@@ -34,7 +34,7 @@ type dataConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Validate validates required fields are set to support structured generation.
|
// Validate validates required fields are set to support structured generation.
|
||||||
func (a *dataConfig) Validate(args []string) error {
|
func (a *cMapFlagsAndArgs) Validate(args []string) error {
|
||||||
if len(args) != 1 {
|
if len(args) != 1 {
|
||||||
return fmt.Errorf("name must be specified once")
|
return fmt.Errorf("name must be specified once")
|
||||||
}
|
}
|
||||||
@@ -21,7 +21,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestDataConfigValidation_NoName(t *testing.T) {
|
func TestDataConfigValidation_NoName(t *testing.T) {
|
||||||
config := dataConfig{}
|
config := cMapFlagsAndArgs{}
|
||||||
|
|
||||||
if config.Validate([]string{}) == nil {
|
if config.Validate([]string{}) == nil {
|
||||||
t.Fatal("Validation should fail if no name is specified")
|
t.Fatal("Validation should fail if no name is specified")
|
||||||
@@ -29,7 +29,7 @@ func TestDataConfigValidation_NoName(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDataConfigValidation_MoreThanOneName(t *testing.T) {
|
func TestDataConfigValidation_MoreThanOneName(t *testing.T) {
|
||||||
config := dataConfig{}
|
config := cMapFlagsAndArgs{}
|
||||||
|
|
||||||
if config.Validate([]string{"name", "othername"}) == nil {
|
if config.Validate([]string{"name", "othername"}) == nil {
|
||||||
t.Fatal("Validation should fail if more than one name is specified")
|
t.Fatal("Validation should fail if more than one name is specified")
|
||||||
@@ -39,12 +39,12 @@ func TestDataConfigValidation_MoreThanOneName(t *testing.T) {
|
|||||||
func TestDataConfigValidation_Flags(t *testing.T) {
|
func TestDataConfigValidation_Flags(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
config dataConfig
|
config cMapFlagsAndArgs
|
||||||
shouldFail bool
|
shouldFail bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "env-file-source and literal are both set",
|
name: "env-file-source and literal are both set",
|
||||||
config: dataConfig{
|
config: cMapFlagsAndArgs{
|
||||||
LiteralSources: []string{"one", "two"},
|
LiteralSources: []string{"one", "two"},
|
||||||
EnvFileSource: "three",
|
EnvFileSource: "three",
|
||||||
},
|
},
|
||||||
@@ -52,7 +52,7 @@ func TestDataConfigValidation_Flags(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "env-file-source and from-file are both set",
|
name: "env-file-source and from-file are both set",
|
||||||
config: dataConfig{
|
config: cMapFlagsAndArgs{
|
||||||
FileSources: []string{"one", "two"},
|
FileSources: []string{"one", "two"},
|
||||||
EnvFileSource: "three",
|
EnvFileSource: "three",
|
||||||
},
|
},
|
||||||
@@ -60,12 +60,12 @@ func TestDataConfigValidation_Flags(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "we don't have any option set",
|
name: "we don't have any option set",
|
||||||
config: dataConfig{},
|
config: cMapFlagsAndArgs{},
|
||||||
shouldFail: true,
|
shouldFail: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "we have from-file and literal ",
|
name: "we have from-file and literal ",
|
||||||
config: dataConfig{
|
config: cMapFlagsAndArgs{
|
||||||
LiteralSources: []string{"one", "two"},
|
LiteralSources: []string{"one", "two"},
|
||||||
FileSources: []string{"three", "four"},
|
FileSources: []string{"three", "four"},
|
||||||
},
|
},
|
||||||
@@ -27,8 +27,8 @@ import (
|
|||||||
"github.com/kubernetes-sigs/kustomize/pkg/types"
|
"github.com/kubernetes-sigs/kustomize/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newCmdAddConfigMap(fsys fs.FileSystem) *cobra.Command {
|
func newCmdAddConfigMap(fSys fs.FileSystem) *cobra.Command {
|
||||||
var config dataConfig
|
var flagsAndArgs cMapFlagsAndArgs
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "configmap NAME [--from-file=[key=]source] [--from-literal=key1=value1]",
|
Use: "configmap NAME [--from-file=[key=]source] [--from-literal=key1=value1]",
|
||||||
Short: "Adds a configmap to the kustomization file.",
|
Short: "Adds a configmap to the kustomization file.",
|
||||||
@@ -44,47 +44,47 @@ func newCmdAddConfigMap(fsys fs.FileSystem) *cobra.Command {
|
|||||||
kustomize edit add configmap my-configmap --from-env-file=env/path.env
|
kustomize edit add configmap my-configmap --from-env-file=env/path.env
|
||||||
`,
|
`,
|
||||||
RunE: func(_ *cobra.Command, args []string) error {
|
RunE: func(_ *cobra.Command, args []string) error {
|
||||||
err := config.Validate(args)
|
err := flagsAndArgs.Validate(args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load in the kustomization file.
|
// Load the kustomization file.
|
||||||
mf, err := newKustomizationFile(constants.KustomizationFileName, fsys)
|
mf, err := newKustomizationFile(constants.KustomizationFileName, fSys)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
m, err := mf.read()
|
kustomization, err := mf.read()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the config map to the kustomization file.
|
// Add the flagsAndArgs map to the kustomization file.
|
||||||
err = addConfigMap(m, config)
|
err = addConfigMap(kustomization, flagsAndArgs, fSys)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write out the kustomization file with added configmap.
|
// Write out the kustomization file with added configmap.
|
||||||
return mf.write(m)
|
return mf.write(kustomization)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.Flags().StringSliceVar(
|
cmd.Flags().StringSliceVar(
|
||||||
&config.FileSources,
|
&flagsAndArgs.FileSources,
|
||||||
"from-file",
|
"from-file",
|
||||||
[]string{},
|
[]string{},
|
||||||
"Key file can be specified using its file path, in which case file basename will be used as configmap "+
|
"Key file can be specified using its file path, in which case file basename will be used as configmap "+
|
||||||
"key, or optionally with a key and file path, in which case the given key will be used. Specifying a "+
|
"key, or optionally with a key and file path, in which case the given key will be used. Specifying a "+
|
||||||
"directory will iterate each named file in the directory whose basename is a valid configmap key.")
|
"directory will iterate each named file in the directory whose basename is a valid configmap key.")
|
||||||
cmd.Flags().StringArrayVar(
|
cmd.Flags().StringArrayVar(
|
||||||
&config.LiteralSources,
|
&flagsAndArgs.LiteralSources,
|
||||||
"from-literal",
|
"from-literal",
|
||||||
[]string{},
|
[]string{},
|
||||||
"Specify a key and literal value to insert in configmap (i.e. mykey=somevalue)")
|
"Specify a key and literal value to insert in configmap (i.e. mykey=somevalue)")
|
||||||
cmd.Flags().StringVar(
|
cmd.Flags().StringVar(
|
||||||
&config.EnvFileSource,
|
&flagsAndArgs.EnvFileSource,
|
||||||
"from-env-file",
|
"from-env-file",
|
||||||
"",
|
"",
|
||||||
"Specify the path to a file to read lines of key=val pairs to create a configmap (i.e. a Docker .env file).")
|
"Specify the path to a file to read lines of key=val pairs to create a configmap (i.e. a Docker .env file).")
|
||||||
@@ -92,19 +92,21 @@ func newCmdAddConfigMap(fsys fs.FileSystem) *cobra.Command {
|
|||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
// addConfigMap updates a configmap within a kustomization file, using the data in config.
|
// addConfigMap adds a configmap to a kustomization file.
|
||||||
// Note: error may leave kustomization file in an undefined state. Suggest passing a copy
|
// Note: error may leave kustomization file in an undefined state. Suggest passing a copy
|
||||||
// of kustomization file.
|
// of kustomization file.
|
||||||
func addConfigMap(m *types.Kustomization, config dataConfig) error {
|
func addConfigMap(k *types.Kustomization, flagsAndArgs cMapFlagsAndArgs, fSys fs.FileSystem) error {
|
||||||
cm := getOrCreateConfigMap(m, config.Name)
|
cmArgs := makeConfigMapArgs(k, flagsAndArgs.Name)
|
||||||
|
|
||||||
err := mergeData(&cm.DataSources, config)
|
err := mergeFlagsIntoCmArgs(&cmArgs.DataSources, flagsAndArgs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
factory := configmapandsecret.NewConfigMapFactory(cmArgs, fSys)
|
||||||
|
|
||||||
// Validate by trying to create corev1.configmap.
|
// Validate by trying to create corev1.configmap.
|
||||||
_, _, err = configmapandsecret.MakeConfigmapAndGenerateName(*cm)
|
_, _, err = factory.MakeUnstructAndGenerateName()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -112,7 +114,7 @@ func addConfigMap(m *types.Kustomization, config dataConfig) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getOrCreateConfigMap(m *types.Kustomization, name string) *types.ConfigMapArgs {
|
func makeConfigMapArgs(m *types.Kustomization, name string) *types.ConfigMapArgs {
|
||||||
for i, v := range m.ConfigMapGenerator {
|
for i, v := range m.ConfigMapGenerator {
|
||||||
if name == v.Name {
|
if name == v.Name {
|
||||||
return &m.ConfigMapGenerator[i]
|
return &m.ConfigMapGenerator[i]
|
||||||
@@ -124,13 +126,12 @@ func getOrCreateConfigMap(m *types.Kustomization, name string) *types.ConfigMapA
|
|||||||
return &m.ConfigMapGenerator[len(m.ConfigMapGenerator)-1]
|
return &m.ConfigMapGenerator[len(m.ConfigMapGenerator)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
func mergeData(src *types.DataSources, config dataConfig) error {
|
func mergeFlagsIntoCmArgs(src *types.DataSources, flags cMapFlagsAndArgs) error {
|
||||||
src.LiteralSources = append(src.LiteralSources, config.LiteralSources...)
|
src.LiteralSources = append(src.LiteralSources, flags.LiteralSources...)
|
||||||
src.FileSources = append(src.FileSources, config.FileSources...)
|
src.FileSources = append(src.FileSources, flags.FileSources...)
|
||||||
if src.EnvSource != "" && src.EnvSource != config.EnvFileSource {
|
if src.EnvSource != "" && src.EnvSource != flags.EnvFileSource {
|
||||||
return fmt.Errorf("updating existing env source '%s' not allowed", src.EnvSource)
|
return fmt.Errorf("updating existing env source '%s' not allowed", src.EnvSource)
|
||||||
}
|
}
|
||||||
src.EnvSource = config.EnvFileSource
|
src.EnvSource = flags.EnvFileSource
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ func TestNewAddConfigMapIsNotNil(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetOrCreateConfigMap(t *testing.T) {
|
func TestMakeConfigMapArgs(t *testing.T) {
|
||||||
cmName := "test-config-name"
|
cmName := "test-config-name"
|
||||||
|
|
||||||
kustomization := &types.Kustomization{
|
kustomization := &types.Kustomization{
|
||||||
@@ -39,24 +39,24 @@ func TestGetOrCreateConfigMap(t *testing.T) {
|
|||||||
if len(kustomization.ConfigMapGenerator) != 0 {
|
if len(kustomization.ConfigMapGenerator) != 0 {
|
||||||
t.Fatal("Initial kustomization should not have any configmaps")
|
t.Fatal("Initial kustomization should not have any configmaps")
|
||||||
}
|
}
|
||||||
cm := getOrCreateConfigMap(kustomization, cmName)
|
args := makeConfigMapArgs(kustomization, cmName)
|
||||||
|
|
||||||
if cm == nil {
|
if args == nil {
|
||||||
t.Fatalf("ConfigMap should always be non-nil")
|
t.Fatalf("args should always be non-nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(kustomization.ConfigMapGenerator) != 1 {
|
if len(kustomization.ConfigMapGenerator) != 1 {
|
||||||
t.Fatalf("Kustomization should have newly created configmap")
|
t.Fatalf("Kustomization should have newly created configmap")
|
||||||
}
|
}
|
||||||
|
|
||||||
if &kustomization.ConfigMapGenerator[len(kustomization.ConfigMapGenerator)-1] != cm {
|
if &kustomization.ConfigMapGenerator[len(kustomization.ConfigMapGenerator)-1] != args {
|
||||||
t.Fatalf("Pointer address for newly inserted configmap should be same")
|
t.Fatalf("Pointer address for newly inserted configmap generator should be same")
|
||||||
}
|
}
|
||||||
|
|
||||||
existingCM := getOrCreateConfigMap(kustomization, cmName)
|
args2 := makeConfigMapArgs(kustomization, cmName)
|
||||||
|
|
||||||
if existingCM != cm {
|
if args2 != args {
|
||||||
t.Fatalf("should have returned an existing cm with name: %v", cmName)
|
t.Fatalf("should have returned an existing args with name: %v", cmName)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(kustomization.ConfigMapGenerator) != 1 {
|
if len(kustomization.ConfigMapGenerator) != 1 {
|
||||||
@@ -64,10 +64,10 @@ func TestGetOrCreateConfigMap(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMergeData_LiteralSources(t *testing.T) {
|
func TestMergeFlagsIntoCmArgs_LiteralSources(t *testing.T) {
|
||||||
ds := &types.DataSources{}
|
ds := &types.DataSources{}
|
||||||
|
|
||||||
err := mergeData(ds, dataConfig{LiteralSources: []string{"k1=v1"}})
|
err := mergeFlagsIntoCmArgs(ds, cMapFlagsAndArgs{LiteralSources: []string{"k1=v1"}})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Merge initial literal source should not return error")
|
t.Fatalf("Merge initial literal source should not return error")
|
||||||
}
|
}
|
||||||
@@ -76,7 +76,7 @@ func TestMergeData_LiteralSources(t *testing.T) {
|
|||||||
t.Fatalf("Initial literal source should have been added")
|
t.Fatalf("Initial literal source should have been added")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = mergeData(ds, dataConfig{LiteralSources: []string{"k2=v2"}})
|
err = mergeFlagsIntoCmArgs(ds, cMapFlagsAndArgs{LiteralSources: []string{"k2=v2"}})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Merge second literal source should not return error")
|
t.Fatalf("Merge second literal source should not return error")
|
||||||
}
|
}
|
||||||
@@ -86,10 +86,10 @@ func TestMergeData_LiteralSources(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMergeData_FileSources(t *testing.T) {
|
func TestMergeFlagsIntoCmArgs_FileSources(t *testing.T) {
|
||||||
ds := &types.DataSources{}
|
ds := &types.DataSources{}
|
||||||
|
|
||||||
err := mergeData(ds, dataConfig{FileSources: []string{"file1"}})
|
err := mergeFlagsIntoCmArgs(ds, cMapFlagsAndArgs{FileSources: []string{"file1"}})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Merge initial file source should not return error")
|
t.Fatalf("Merge initial file source should not return error")
|
||||||
}
|
}
|
||||||
@@ -98,7 +98,7 @@ func TestMergeData_FileSources(t *testing.T) {
|
|||||||
t.Fatalf("Initial file source should have been added")
|
t.Fatalf("Initial file source should have been added")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = mergeData(ds, dataConfig{FileSources: []string{"file2"}})
|
err = mergeFlagsIntoCmArgs(ds, cMapFlagsAndArgs{FileSources: []string{"file2"}})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Merge second file source should not return error")
|
t.Fatalf("Merge second file source should not return error")
|
||||||
}
|
}
|
||||||
@@ -108,12 +108,12 @@ func TestMergeData_FileSources(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMergeData_EnvSource(t *testing.T) {
|
func TestMergeFlagsIntoCmArgs_EnvSource(t *testing.T) {
|
||||||
envFileName := "env1"
|
envFileName := "env1"
|
||||||
envFileName2 := "env2"
|
envFileName2 := "env2"
|
||||||
ds := &types.DataSources{}
|
ds := &types.DataSources{}
|
||||||
|
|
||||||
err := mergeData(ds, dataConfig{EnvFileSource: envFileName})
|
err := mergeFlagsIntoCmArgs(ds, cMapFlagsAndArgs{EnvFileSource: envFileName})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Merge initial env source should not return error")
|
t.Fatalf("Merge initial env source should not return error")
|
||||||
}
|
}
|
||||||
@@ -122,7 +122,7 @@ func TestMergeData_EnvSource(t *testing.T) {
|
|||||||
t.Fatalf("Initial env source filename should have been added")
|
t.Fatalf("Initial env source filename should have been added")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = mergeData(ds, dataConfig{EnvFileSource: envFileName2})
|
err = mergeFlagsIntoCmArgs(ds, cMapFlagsAndArgs{EnvFileSource: envFileName2})
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Updating env source should return an error")
|
t.Fatalf("Updating env source should return an error")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,80 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2018 The Kubernetes Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Package configmapandsecret generates configmaps and secrets per generator rules.
|
|
||||||
package configmapandsecret
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
cutil "github.com/kubernetes-sigs/kustomize/pkg/configmapandsecret/util"
|
|
||||||
"github.com/kubernetes-sigs/kustomize/pkg/hash"
|
|
||||||
"github.com/kubernetes-sigs/kustomize/pkg/types"
|
|
||||||
corev1 "k8s.io/api/core/v1"
|
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
|
||||||
)
|
|
||||||
|
|
||||||
// MakeConfigmapAndGenerateName makes a configmap and returns the configmap and the name appended with a hash.
|
|
||||||
func MakeConfigmapAndGenerateName(cm types.ConfigMapArgs) (*unstructured.Unstructured, string, error) {
|
|
||||||
corev1CM, err := makeConfigMap(cm)
|
|
||||||
if err != nil {
|
|
||||||
return nil, "", err
|
|
||||||
}
|
|
||||||
h, err := hash.ConfigMapHash(corev1CM)
|
|
||||||
if err != nil {
|
|
||||||
return nil, "", err
|
|
||||||
}
|
|
||||||
nameWithHash := fmt.Sprintf("%s-%s", corev1CM.GetName(), h)
|
|
||||||
unstructuredCM, err := objectToUnstructured(corev1CM)
|
|
||||||
return unstructuredCM, nameWithHash, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func objectToUnstructured(in runtime.Object) (*unstructured.Unstructured, error) {
|
|
||||||
marshaled, err := json.Marshal(in)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var out unstructured.Unstructured
|
|
||||||
err = out.UnmarshalJSON(marshaled)
|
|
||||||
return &out, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeConfigMap(cm types.ConfigMapArgs) (*corev1.ConfigMap, error) {
|
|
||||||
corev1cm := &corev1.ConfigMap{}
|
|
||||||
corev1cm.APIVersion = "v1"
|
|
||||||
corev1cm.Kind = "ConfigMap"
|
|
||||||
corev1cm.Name = cm.Name
|
|
||||||
corev1cm.Data = map[string]string{}
|
|
||||||
|
|
||||||
if cm.EnvSource != "" {
|
|
||||||
if err := cutil.HandleConfigMapFromEnvFileSource(corev1cm, cm.EnvSource); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if cm.FileSources != nil {
|
|
||||||
if err := cutil.HandleConfigMapFromFileSources(corev1cm, cm.FileSources); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if cm.LiteralSources != nil {
|
|
||||||
if err := cutil.HandleConfigMapFromLiteralSources(corev1cm, cm.LiteralSources); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return corev1cm, nil
|
|
||||||
}
|
|
||||||
192
pkg/configmapandsecret/configmapfactory.go
Normal file
192
pkg/configmapandsecret/configmapfactory.go
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2018 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Package configmapandsecret generates configmaps and secrets per generator rules.
|
||||||
|
package configmapandsecret
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
cutil "github.com/kubernetes-sigs/kustomize/pkg/configmapandsecret/util"
|
||||||
|
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||||
|
"github.com/kubernetes-sigs/kustomize/pkg/hash"
|
||||||
|
"github.com/kubernetes-sigs/kustomize/pkg/types"
|
||||||
|
"k8s.io/api/core/v1"
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/util/validation"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ConfigMapFactory makes ConfigMaps.
|
||||||
|
type ConfigMapFactory struct {
|
||||||
|
args *types.ConfigMapArgs
|
||||||
|
fSys fs.FileSystem
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewConfigMapFactory returns a new ConfigMapFactory.
|
||||||
|
func NewConfigMapFactory(args *types.ConfigMapArgs, fSys fs.FileSystem) *ConfigMapFactory {
|
||||||
|
return &ConfigMapFactory{args: args, fSys: fSys}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeUnstructAndGenerateName returns an configmap and the name appended with a hash.
|
||||||
|
func (f *ConfigMapFactory) MakeUnstructAndGenerateName() (*unstructured.Unstructured, string, error) {
|
||||||
|
cm, err := f.MakeConfigMap()
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
h, err := hash.ConfigMapHash(cm)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
nameWithHash := fmt.Sprintf("%s-%s", cm.GetName(), h)
|
||||||
|
unstructuredCM, err := objectToUnstructured(cm)
|
||||||
|
return unstructuredCM, nameWithHash, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func objectToUnstructured(in runtime.Object) (*unstructured.Unstructured, error) {
|
||||||
|
marshaled, err := json.Marshal(in)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var out unstructured.Unstructured
|
||||||
|
err = out.UnmarshalJSON(marshaled)
|
||||||
|
return &out, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeConfigMap returns a new ConfigMap, or nil and an error.
|
||||||
|
func (f *ConfigMapFactory) MakeConfigMap() (*corev1.ConfigMap, error) {
|
||||||
|
cm := &corev1.ConfigMap{}
|
||||||
|
cm.APIVersion = "v1"
|
||||||
|
cm.Kind = "ConfigMap"
|
||||||
|
cm.Name = f.args.Name
|
||||||
|
cm.Data = map[string]string{}
|
||||||
|
|
||||||
|
if f.args.EnvSource != "" {
|
||||||
|
if err := f.handleConfigMapFromEnvFileSource(cm); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if f.args.FileSources != nil {
|
||||||
|
if err := f.handleConfigMapFromFileSources(cm); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if f.args.LiteralSources != nil {
|
||||||
|
if err := f.handleConfigMapFromLiteralSources(cm); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleConfigMapFromLiteralSources adds the specified literal source
|
||||||
|
// information into the provided configMap.
|
||||||
|
func (f *ConfigMapFactory) handleConfigMapFromLiteralSources(configMap *v1.ConfigMap) error {
|
||||||
|
for _, literalSource := range f.args.LiteralSources {
|
||||||
|
keyName, value, err := cutil.ParseLiteralSource(literalSource)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = addKeyFromLiteralToConfigMap(configMap, keyName, value)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleConfigMapFromFileSources adds the specified file source information
|
||||||
|
// into the provided configMap
|
||||||
|
func (f *ConfigMapFactory) handleConfigMapFromFileSources(configMap *v1.ConfigMap) error {
|
||||||
|
for _, fileSource := range f.args.FileSources {
|
||||||
|
keyName, filePath, err := cutil.ParseFileSource(fileSource)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !f.fSys.Exists(filePath) {
|
||||||
|
return fmt.Errorf("unable to read configmap source file %s", filePath)
|
||||||
|
}
|
||||||
|
if f.fSys.IsDir(filePath) {
|
||||||
|
if strings.Contains(fileSource, "=") {
|
||||||
|
return fmt.Errorf("cannot give a key name for a directory path")
|
||||||
|
}
|
||||||
|
fileList, err := ioutil.ReadDir(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error listing files in %s: %v", filePath, err)
|
||||||
|
}
|
||||||
|
for _, item := range fileList {
|
||||||
|
itemPath := path.Join(filePath, item.Name())
|
||||||
|
if item.Mode().IsRegular() {
|
||||||
|
keyName = item.Name()
|
||||||
|
err = addKeyFromFileToConfigMap(configMap, keyName, itemPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := addKeyFromFileToConfigMap(configMap, keyName, filePath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleConfigMapFromEnvFileSource adds the specified env file source information
|
||||||
|
// into the provided configMap
|
||||||
|
func (f *ConfigMapFactory) handleConfigMapFromEnvFileSource(configMap *v1.ConfigMap) error {
|
||||||
|
if !f.fSys.Exists(f.args.EnvSource) {
|
||||||
|
return fmt.Errorf("unable to read configmap env file %s", f.args.EnvSource)
|
||||||
|
}
|
||||||
|
if f.fSys.IsDir(f.args.EnvSource) {
|
||||||
|
return fmt.Errorf("env config file %s cannot be a directory", f.args.EnvSource)
|
||||||
|
}
|
||||||
|
|
||||||
|
return cutil.AddFromEnvFile(f.args.EnvSource, func(key, value string) error {
|
||||||
|
return addKeyFromLiteralToConfigMap(configMap, key, value)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// addKeyFromFileToConfigMap adds a key with the given name to a ConfigMap, populating
|
||||||
|
// the value with the content of the given file path, or returns an error.
|
||||||
|
func addKeyFromFileToConfigMap(configMap *v1.ConfigMap, keyName, filePath string) error {
|
||||||
|
data, err := ioutil.ReadFile(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return addKeyFromLiteralToConfigMap(configMap, keyName, string(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
// addKeyFromLiteralToConfigMap adds the given key and data to the given config map,
|
||||||
|
// returning an error if the key is not valid or if the key already exists.
|
||||||
|
func addKeyFromLiteralToConfigMap(configMap *v1.ConfigMap, keyName, data string) error {
|
||||||
|
// Note, the rules for ConfigMap keys are the exact same as the ones for SecretKeys.
|
||||||
|
if errs := validation.IsConfigMapKey(keyName); len(errs) != 0 {
|
||||||
|
return fmt.Errorf("%q is not a valid key name for a ConfigMap: %s", keyName, strings.Join(errs, ";"))
|
||||||
|
}
|
||||||
|
if _, entryExists := configMap.Data[keyName]; entryExists {
|
||||||
|
return fmt.Errorf("cannot add key %s, another key by that name already exists: %v", keyName, configMap.Data)
|
||||||
|
}
|
||||||
|
configMap.Data[keyName] = data
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -20,12 +20,7 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"context"
|
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/kubernetes-sigs/kustomize/pkg/types"
|
"github.com/kubernetes-sigs/kustomize/pkg/types"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
@@ -98,23 +93,6 @@ func makeLiteralConfigMap(name string) *corev1.ConfigMap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeTestSecret(name string) *corev1.Secret {
|
|
||||||
return &corev1.Secret{
|
|
||||||
TypeMeta: metav1.TypeMeta{
|
|
||||||
APIVersion: "v1",
|
|
||||||
Kind: "Secret",
|
|
||||||
},
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: name,
|
|
||||||
},
|
|
||||||
Data: map[string][]byte{
|
|
||||||
"DB_USERNAME": []byte("admin"),
|
|
||||||
"DB_PASSWORD": []byte("somepw"),
|
|
||||||
},
|
|
||||||
Type: corev1.SecretTypeOpaque,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConstructConfigMap(t *testing.T) {
|
func TestConstructConfigMap(t *testing.T) {
|
||||||
type testCase struct {
|
type testCase struct {
|
||||||
description string
|
description string
|
||||||
@@ -156,7 +134,10 @@ func TestConstructConfigMap(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
cm, err := makeConfigMap(tc.input)
|
// TODO: all tests should use a FakeFs
|
||||||
|
fSys := fs.MakeRealFS()
|
||||||
|
f := NewConfigMapFactory(&tc.input, fSys)
|
||||||
|
cm, err := f.MakeConfigMap()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@@ -166,74 +147,6 @@ func TestConstructConfigMap(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConstructSecret(t *testing.T) {
|
|
||||||
secret := types.SecretArgs{
|
|
||||||
Name: "secret",
|
|
||||||
Commands: map[string]string{
|
|
||||||
"DB_USERNAME": "printf admin",
|
|
||||||
"DB_PASSWORD": "printf somepw",
|
|
||||||
},
|
|
||||||
Type: "Opaque",
|
|
||||||
}
|
|
||||||
cm, err := makeSecret(secret, ".")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
expected := makeTestSecret("secret")
|
|
||||||
if !reflect.DeepEqual(*cm, *expected) {
|
|
||||||
t.Fatalf("%#v\ndoesn't match expected:\n%#v", *cm, *expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeSecret(secret types.SecretArgs, path string) (*corev1.Secret, error) {
|
|
||||||
corev1secret := &corev1.Secret{}
|
|
||||||
corev1secret.APIVersion = "v1"
|
|
||||||
corev1secret.Kind = "Secret"
|
|
||||||
corev1secret.Name = secret.Name
|
|
||||||
corev1secret.Type = corev1.SecretType(secret.Type)
|
|
||||||
if corev1secret.Type == "" {
|
|
||||||
corev1secret.Type = corev1.SecretTypeOpaque
|
|
||||||
}
|
|
||||||
corev1secret.Data = map[string][]byte{}
|
|
||||||
|
|
||||||
for k, v := range secret.Commands {
|
|
||||||
out, err := createSecretKey(path, v)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
corev1secret.Data[k] = out
|
|
||||||
}
|
|
||||||
|
|
||||||
return corev1secret, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSecretKey(wd string, command string) ([]byte, error) {
|
|
||||||
fi, err := os.Stat(wd)
|
|
||||||
if err != nil || !fi.IsDir() {
|
|
||||||
wd = filepath.Dir(wd)
|
|
||||||
}
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
||||||
defer cancel()
|
|
||||||
cmd := exec.CommandContext(ctx, "sh", "-c", command)
|
|
||||||
cmd.Dir = wd
|
|
||||||
|
|
||||||
return cmd.Output()
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFailConstructSecret(t *testing.T) {
|
|
||||||
secret := types.SecretArgs{
|
|
||||||
Name: "secret",
|
|
||||||
Commands: map[string]string{
|
|
||||||
"FAILURE": "false", // This will fail.
|
|
||||||
},
|
|
||||||
Type: "Opaque",
|
|
||||||
}
|
|
||||||
_, err := makeSecret(secret, ".")
|
|
||||||
if err == nil {
|
|
||||||
t.Fatalf("Expected failure.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestObjectConvertToUnstructured(t *testing.T) {
|
func TestObjectConvertToUnstructured(t *testing.T) {
|
||||||
type testCase struct {
|
type testCase struct {
|
||||||
description string
|
description string
|
||||||
@@ -1,134 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2016 The Kubernetes Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package util
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"k8s.io/api/core/v1"
|
|
||||||
"k8s.io/apimachinery/pkg/util/validation"
|
|
||||||
)
|
|
||||||
|
|
||||||
// HandleConfigMapFromLiteralSources adds the specified literal source
|
|
||||||
// information into the provided configMap.
|
|
||||||
func HandleConfigMapFromLiteralSources(configMap *v1.ConfigMap, literalSources []string) error {
|
|
||||||
for _, literalSource := range literalSources {
|
|
||||||
keyName, value, err := ParseLiteralSource(literalSource)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = addKeyFromLiteralToConfigMap(configMap, keyName, value)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// HandleConfigMapFromFileSources adds the specified file source information
|
|
||||||
// into the provided configMap
|
|
||||||
func HandleConfigMapFromFileSources(configMap *v1.ConfigMap, fileSources []string) error {
|
|
||||||
for _, fileSource := range fileSources {
|
|
||||||
keyName, filePath, err := ParseFileSource(fileSource)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
info, err := os.Stat(filePath)
|
|
||||||
if err != nil {
|
|
||||||
switch err := err.(type) {
|
|
||||||
case *os.PathError:
|
|
||||||
return fmt.Errorf("error reading %s: %v", filePath, err.Err)
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("error reading %s: %v", filePath, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if info.IsDir() {
|
|
||||||
if strings.Contains(fileSource, "=") {
|
|
||||||
return fmt.Errorf("cannot give a key name for a directory path")
|
|
||||||
}
|
|
||||||
fileList, err := ioutil.ReadDir(filePath)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error listing files in %s: %v", filePath, err)
|
|
||||||
}
|
|
||||||
for _, item := range fileList {
|
|
||||||
itemPath := path.Join(filePath, item.Name())
|
|
||||||
if item.Mode().IsRegular() {
|
|
||||||
keyName = item.Name()
|
|
||||||
err = addKeyFromFileToConfigMap(configMap, keyName, itemPath)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if err := addKeyFromFileToConfigMap(configMap, keyName, filePath); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// HandleConfigMapFromEnvFileSource adds the specified env file source information
|
|
||||||
// into the provided configMap
|
|
||||||
func HandleConfigMapFromEnvFileSource(configMap *v1.ConfigMap, 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("env config file cannot be a directory")
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
// the value with the content of the given file path, or returns an error.
|
|
||||||
func addKeyFromFileToConfigMap(configMap *v1.ConfigMap, keyName, filePath string) error {
|
|
||||||
data, err := ioutil.ReadFile(filePath)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return addKeyFromLiteralToConfigMap(configMap, keyName, string(data))
|
|
||||||
}
|
|
||||||
|
|
||||||
// addKeyFromLiteralToConfigMap adds the given key and data to the given config map,
|
|
||||||
// returning an error if the key is not valid or if the key already exists.
|
|
||||||
func addKeyFromLiteralToConfigMap(configMap *v1.ConfigMap, keyName, data string) error {
|
|
||||||
// Note, the rules for ConfigMap keys are the exact same as the ones for SecretKeys.
|
|
||||||
if errs := validation.IsConfigMapKey(keyName); len(errs) != 0 {
|
|
||||||
return fmt.Errorf("%q is not a valid key name for a ConfigMap: %s", keyName, strings.Join(errs, ";"))
|
|
||||||
}
|
|
||||||
if _, entryExists := configMap.Data[keyName]; entryExists {
|
|
||||||
return fmt.Errorf("cannot add key %s, another key by that name already exists: %v", keyName, configMap.Data)
|
|
||||||
}
|
|
||||||
configMap.Data[keyName] = data
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -69,9 +69,9 @@ func processEnvFileLine(line []byte, filePath string,
|
|||||||
return key, value, err
|
return key, value, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// addFromEnvFile processes an env file allows a generic addTo to handle the
|
// AddFromEnvFile processes an env file allows a generic addTo to handle the
|
||||||
// collection of key value pairs or returns an error.
|
// collection of key value pairs or returns an error.
|
||||||
func addFromEnvFile(filePath string, addTo func(key, value string) error) error {
|
func AddFromEnvFile(filePath string, addTo func(key, value string) error) error {
|
||||||
f, err := os.Open(filePath)
|
f, err := os.Open(filePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -1,126 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2015 The Kubernetes Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package util
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"k8s.io/api/core/v1"
|
|
||||||
"k8s.io/apimachinery/pkg/util/validation"
|
|
||||||
)
|
|
||||||
|
|
||||||
// HandleFromLiteralSources adds the specified literal source information into the provided secret
|
|
||||||
func HandleFromLiteralSources(secret *v1.Secret, literalSources []string) error {
|
|
||||||
for _, literalSource := range literalSources {
|
|
||||||
keyName, value, err := ParseLiteralSource(literalSource)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err = addKeyFromLiteralToSecret(secret, keyName, []byte(value)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// HandleFromFileSources adds the specified file source information into the provided secret
|
|
||||||
func HandleFromFileSources(secret *v1.Secret, fileSources []string) error {
|
|
||||||
for _, fileSource := range fileSources {
|
|
||||||
keyName, filePath, err := ParseFileSource(fileSource)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
info, err := os.Stat(filePath)
|
|
||||||
if err != nil {
|
|
||||||
switch err := err.(type) {
|
|
||||||
case *os.PathError:
|
|
||||||
return fmt.Errorf("error reading %s: %v", filePath, err.Err)
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("error reading %s: %v", filePath, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if info.IsDir() {
|
|
||||||
if strings.Contains(fileSource, "=") {
|
|
||||||
return fmt.Errorf("cannot give a key name for a directory path")
|
|
||||||
}
|
|
||||||
fileList, err := ioutil.ReadDir(filePath)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error listing files in %s: %v", filePath, err)
|
|
||||||
}
|
|
||||||
for _, item := range fileList {
|
|
||||||
itemPath := path.Join(filePath, item.Name())
|
|
||||||
if item.Mode().IsRegular() {
|
|
||||||
keyName = item.Name()
|
|
||||||
if err = addKeyFromFileToSecret(secret, keyName, itemPath); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if err := addKeyFromFileToSecret(secret, keyName, filePath); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// HandleFromEnvFileSource adds the specified env file source information
|
|
||||||
// into the provided secret
|
|
||||||
func HandleFromEnvFileSource(secret *v1.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("env secret file cannot be a directory")
|
|
||||||
}
|
|
||||||
|
|
||||||
return addFromEnvFile(envFileSource, func(key, value string) error {
|
|
||||||
return addKeyFromLiteralToSecret(secret, key, []byte(value))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func addKeyFromFileToSecret(secret *v1.Secret, keyName, filePath string) error {
|
|
||||||
data, err := ioutil.ReadFile(filePath)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return addKeyFromLiteralToSecret(secret, keyName, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func addKeyFromLiteralToSecret(secret *v1.Secret, keyName string, data []byte) error {
|
|
||||||
if errs := validation.IsConfigMapKey(keyName); len(errs) != 0 {
|
|
||||||
return fmt.Errorf("%q is not a valid key name for a Secret: %s", keyName, strings.Join(errs, ";"))
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, entryExists := secret.Data[keyName]; entryExists {
|
|
||||||
return fmt.Errorf("cannot add key %s, another key by that name already exists: %v", keyName, secret.Data)
|
|
||||||
}
|
|
||||||
secret.Data[keyName] = data
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -18,38 +18,12 @@ limitations under the License.
|
|||||||
package util
|
package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/sha256"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ParseRFC3339 parses an RFC3339 date in either RFC3339Nano or RFC3339 format.
|
|
||||||
func ParseRFC3339(s string) (metav1.Time, error) {
|
|
||||||
if t, timeErr := time.Parse(time.RFC3339Nano, s); timeErr == nil {
|
|
||||||
return metav1.Time{Time: t}, nil
|
|
||||||
}
|
|
||||||
t, err := time.Parse(time.RFC3339, s)
|
|
||||||
if err != nil {
|
|
||||||
return metav1.Time{}, err
|
|
||||||
}
|
|
||||||
return metav1.Time{Time: t}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// HashObject encodes object using given codec and returns MD5 sum of the result.
|
|
||||||
func HashObject(obj runtime.Object, codec runtime.Encoder) (string, error) {
|
|
||||||
data, err := runtime.Encode(codec, obj)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%x", sha256.Sum256(data)), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseFileSource parses the source given.
|
// ParseFileSource parses the source given.
|
||||||
//
|
//
|
||||||
// Acceptable formats include:
|
// Acceptable formats include:
|
||||||
|
|||||||
Reference in New Issue
Block a user