Skip to content

Commit

Permalink
Merge pull request #1 from sarmad-abualkaz/ft/parameter-values-key
Browse files Browse the repository at this point in the history
ft: adding dataKey option
  • Loading branch information
kuuji authored Mar 11, 2022
2 parents 701ff63 + 895d279 commit f7d29f1
Show file tree
Hide file tree
Showing 9 changed files with 110 additions and 22 deletions.
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ Usage:
helm-external-val cm <name> [flags]
Flags:
--dataKey string The key to get the cm from (default "values.yaml")
-h, --help help for cm
--kube_namespace string The namespace to get the cm from (default "default")
-o, --out string The file to output the values to (default "values-cm.yaml")
Expand All @@ -128,6 +129,7 @@ Usage:
helm-external-val secret <name> [flags]
Flags:
--dataKey string The key to get the data from a secret (default "values.yaml")
-h, --help help for secret
--kube_namespace string The namespace to get the secret from (default "default")
-o, --out string The file to output the values to (default "values-secret.yaml")
Expand All @@ -140,15 +142,16 @@ Helm will invoke the downloader plugin with 4 parameters `certFile keyFile caFil
The url has to be formatted as follows

```
<source>://<namespace>/<name>
<source>://<namespace>/<name>/<key>
```

- source (required) : the protocol to use (`cm` and `secret` are currently supported)
- namespace (optional) : the namespace in which to look for the resource (defaults to `default`)
- name (required) : the name of the resource to fetch
- key (optional) : the key in which to look for the data in the resource (defaults to `values.yaml`)

for example the url below will fetch the ConfigMap named `helm-values` from the namespace `kuuji`.
for example the url below will fetch the data under `my-values` from ConfigMap named `helm-values` in the namespace `kuuji`.

```
cm://kuuji/helm-values
cm://kuuji/helm-values/my-values
```
4 changes: 3 additions & 1 deletion cmd/cm.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
)

var kubeNamespace string
var dataKey string
var output string

var cmCmd = &cobra.Command{
Expand All @@ -25,7 +26,7 @@ var cmCmd = &cobra.Command{
cmd.PrintErrln(err)
os.Exit(1)
}
values := k8s.ComposeValues(cm)
values := k8s.ComposeValues(cm, dataKey)
util.WriteValuesToFile(values, output)
fmt.Printf("%s written to %s\n", cmName, output)
},
Expand All @@ -34,5 +35,6 @@ var cmCmd = &cobra.Command{
func init() {
rootCmd.AddCommand(cmCmd)
cmCmd.PersistentFlags().StringVar(&kubeNamespace, "kube_namespace", "default", "The namespace to get the cm from")
cmCmd.PersistentFlags().StringVar(&dataKey, "dataKey", "values.yaml", "The key to get the data from a cm")
cmCmd.PersistentFlags().StringVarP(&output, "out", "o", "values-cm.yaml", "The file to output the values to")
}
19 changes: 18 additions & 1 deletion cmd/dowloader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ func TestParseUrl(t *testing.T) {
wantProtocol string
wantNamespace string
wantConfigMapName string
wantKey string
wantErr error
}{
{
Expand All @@ -23,6 +24,7 @@ func TestParseUrl(t *testing.T) {
wantProtocol: "cm",
wantNamespace: "default",
wantConfigMapName: "helm-values",
wantKey: "values.yaml",
wantErr: nil,
},
{
Expand All @@ -31,6 +33,16 @@ func TestParseUrl(t *testing.T) {
wantProtocol: "cm",
wantNamespace: "kuuji",
wantConfigMapName: "helm-values",
wantKey: "values.yaml",
wantErr: nil,
},
{
name: "Should return namespace and name",
args: args{"cm://kuuji/helm-values/values-key"},
wantProtocol: "cm",
wantNamespace: "kuuji",
wantConfigMapName: "helm-values",
wantKey: "values-key",
wantErr: nil,
},
{
Expand All @@ -39,6 +51,7 @@ func TestParseUrl(t *testing.T) {
wantProtocol: "cm",
wantNamespace: "",
wantConfigMapName: "",
wantKey: "",
wantErr: errors.New("no config provided after protocol"),
},
{
Expand All @@ -47,12 +60,13 @@ func TestParseUrl(t *testing.T) {
wantProtocol: "weird",
wantNamespace: "",
wantConfigMapName: "",
wantKey: "",
wantErr: errors.New(":// missing after protocol"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotProtocol, gotNamespace, gotConfigMapName, err := ParseUrl(tt.args.url)
gotProtocol, gotNamespace, gotConfigMapName, gotKey, err := ParseUrl(tt.args.url)
if err != nil && errors.Is(err, tt.wantErr) {
t.Errorf("ParseUrl() error = %v, wantErr %v", err, tt.wantErr)
}
Expand All @@ -65,6 +79,9 @@ func TestParseUrl(t *testing.T) {
if gotConfigMapName != tt.wantConfigMapName {
t.Errorf("ParseUrl() gotConfigMapName = %v, want %v", gotConfigMapName, tt.wantConfigMapName)
}
if gotKey != tt.wantKey {
t.Errorf("ParseUrl() gotKey = %v, want %v", gotKey, tt.wantKey)
}
})
}
}
26 changes: 16 additions & 10 deletions cmd/downloader.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,50 +16,50 @@ var downloaderCmd = &cobra.Command{
Short: "Get value from a remote source and output it to stdout",
Long: `Get value from a remote source and output it to stdout.
URL is formatted like below
<protocol_required>://<namespace_optional>/<name_required>
<protocol_required>://<namespace_optional>/<name_required>/<key_optional>
Helm will invoke this command with the url in the 4th parameter.
See https://helm.sh/docs/topics/plugins/#downloader-plugins.`,
Args: cobra.ExactArgs(4),
Args: cobra.ExactArgs(5),
Run: func(cmd *cobra.Command, args []string) {
protocol, ns, name, err := ParseUrl(args[3])
protocol, ns, name, key, err := ParseUrl(args[4])
if err != nil {
cmd.PrintErrln(err)
os.Exit(1)
}
switch protocol {
case "cm":
ComposeCM(ns, name, cmd)
ComposeCM(ns, name, key, cmd)
case "secret":
ComposeSecret(ns, name, cmd)
ComposeSecret(ns, name, key, cmd)
}

},
}

func ComposeSecret(ns string, secretName string, cmd *cobra.Command) {
func ComposeSecret(ns string, secretName string, dataKey string, cmd *cobra.Command) {
client := k8s.GetK8sClient()
secret, err := k8s.GetSecret(ns, secretName, client)
if err != nil {
cmd.PrintErrln(err)
os.Exit(1)
}
values := k8s.ComposeSecretValues(secret)
values := k8s.ComposeSecretValues(secret, dataKey)
fmt.Printf("%s\n", values)
}

func ComposeCM(ns string, cmName string, cmd *cobra.Command) {
func ComposeCM(ns string, cmName string, dataKey string, cmd *cobra.Command) {
client := k8s.GetK8sClient()
cm, err := k8s.GetConfigMap(ns, cmName, client)
if err != nil {
cmd.PrintErrln(err)
os.Exit(1)
}
values := k8s.ComposeValues(cm)
values := k8s.ComposeValues(cm, dataKey)
fmt.Printf("%s\n", values)
}

func ParseUrl(url string) (protocol string, namespace string, configMapName string, err error) {
func ParseUrl(url string) (protocol string, namespace string, configMapName string, dataKey string, err error) {
parsedUrl := strings.Split(url, "://")
protocol = parsedUrl[0]
err = nil
Expand All @@ -74,9 +74,15 @@ func ParseUrl(url string) (protocol string, namespace string, configMapName stri
} else if len(config) == 1 {
namespace = "default"
configMapName = config[0]
dataKey = "values.yaml"
} else if len(config) == 2 {
namespace = config[0]
configMapName = config[1]
dataKey = "values.yaml"
} else {
namespace = config[0]
configMapName = config[1]
dataKey = config[2]
}
return
}
Expand Down
4 changes: 3 additions & 1 deletion cmd/secret.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
)

var kubeSecretNamespace string
var dataSecretKey string
var secretOutput string

// secretCmd represents the secret command
Expand All @@ -26,7 +27,7 @@ var secretCmd = &cobra.Command{
cmd.PrintErrln(err)
os.Exit(1)
}
values := k8s.ComposeSecretValues(secret)
values := k8s.ComposeSecretValues(secret, dataSecretKey)
util.WriteValuesToFile(values, secretOutput)
fmt.Printf("%s written to %s\n", secretName, secretOutput)
},
Expand All @@ -35,5 +36,6 @@ var secretCmd = &cobra.Command{
func init() {
rootCmd.AddCommand(secretCmd)
secretCmd.PersistentFlags().StringVar(&kubeSecretNamespace, "kube_namespace", "default", "The namespace to get the secret from")
secretCmd.PersistentFlags().StringVar(&dataSecretKey, "dataKey", "values.yaml", "The key to get the data from a secret")
secretCmd.PersistentFlags().StringVarP(&secretOutput, "out", "o", "values-secret.yaml", "The file to output the values to")
}
4 changes: 2 additions & 2 deletions util/kubernetes/config-map.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func GetConfigMap(namespace string, name string, client Client) (*v1.ConfigMap,
return cm, nil
}

func ComposeValues(configmap *v1.ConfigMap) (yaml string) {
yaml = configmap.Data["values.yaml"]
func ComposeValues(configmap *v1.ConfigMap, dataKey string) (yaml string) {
yaml = configmap.Data[dataKey]
return yaml
}
31 changes: 30 additions & 1 deletion util/kubernetes/config-map_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ func TestGetConfigMap(t *testing.T) {
func TestComposeValues(t *testing.T) {
type args struct {
configmap *v1.ConfigMap
dataKey string
}
tests := []struct {
name string
Expand All @@ -63,13 +64,41 @@ func TestComposeValues(t *testing.T) {
"values.yaml": "replicas: \"3\"\ndeployment:\n server:\n replicas: \"3\"\n",
},
},
dataKey: "values.yaml",
},
want: "replicas: \"3\"\ndeployment:\n server:\n replicas: \"3\"\n",
},
{
name: "Should create file",
args: args{
configmap: &v1.ConfigMap{
Data: map[string]string{
"values.yaml": "replicas: \"3\"\ndeployment:\n server:\n replicas: \"3\"\n",
"test.yaml": "replicas: \"8\"\ndeployment:\n server:\n replicas: \"2\"\n",
"ignore.yaml": "replicas: \"20\"\ndeployment:\n server:\n replicas: \"11\"\n",
},
},
dataKey: "test.yaml",
},
want: "replicas: \"8\"\ndeployment:\n server:\n replicas: \"2\"\n",
},
{
name: "Should get nothing",
args: args{
configmap: &v1.ConfigMap{
Data: map[string]string{
"test.yaml": "replicas: \"8\"\ndeployment:\n server:\n replicas: \"2\"\n",
"ignore.yaml": "replicas: \"20\"\ndeployment:\n server:\n replicas: \"11\"\n",
},
},
dataKey: "values.yaml",
},
want: "",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := ComposeValues(tt.args.configmap); !reflect.DeepEqual(got, tt.want) {
if got := ComposeValues(tt.args.configmap, tt.args.dataKey); !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetConfigMap() = %v, want %v", got, tt.want)
}
})
Expand Down
4 changes: 2 additions & 2 deletions util/kubernetes/secret.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func GetSecret(namespace string, name string, client Client) (*v1.Secret, error)
return secret, nil
}

func ComposeSecretValues(secret *v1.Secret) (yaml string) {
yaml = string(secret.Data["values.yaml"])
func ComposeSecretValues(secret *v1.Secret, dataKey string) (yaml string) {
yaml = string(secret.Data[dataKey])
return yaml
}
31 changes: 30 additions & 1 deletion util/kubernetes/secret_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ func TestGetSecret(t *testing.T) {
func TestComposeSecretValues(t *testing.T) {
type args struct {
secret *v1.Secret
dataKey string
}
tests := []struct {
name string
Expand All @@ -64,13 +65,41 @@ func TestComposeSecretValues(t *testing.T) {
"values.yaml": []byte("replicas: \"3\"\ndeployment:\n server:\n replicas: \"3\"\n"),
},
},
dataKey: "values.yaml",
},
want: "replicas: \"3\"\ndeployment:\n server:\n replicas: \"3\"\n",
},
{
name: "Should get the right value out",
args: args{
secret: &v1.Secret{
Data: map[string][]byte{
"values.yaml": []byte("replicas: \"3\"\ndeployment:\n server:\n replicas: \"3\"\n"),
"test.yaml": []byte("replicas: \"5\"\ndeployment:\n server:\n replicas: \"12\"\n"),
"ignore.yaml": []byte("replicas: \"6\"\ndeployment:\n server:\n replicas: \"14\"\n"),
},
},
dataKey: "test.yaml",
},
want: "replicas: \"5\"\ndeployment:\n server:\n replicas: \"12\"\n",
},
{
name: "Should get nothing",
args: args{
secret: &v1.Secret{
Data: map[string][]byte{
"test.yaml": []byte("replicas: \"5\"\ndeployment:\n server:\n replicas: \"12\"\n"),
"ignore.yaml": []byte("replicas: \"6\"\ndeployment:\n server:\n replicas: \"14\"\n"),
},
},
dataKey: "value.yaml",
},
want: "",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := ComposeSecretValues(tt.args.secret); !reflect.DeepEqual(got, tt.want) {
if got := ComposeSecretValues(tt.args.secret, tt.args.dataKey); !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetConfigMap() = %v, want %v", got, tt.want)
}
})
Expand Down

0 comments on commit f7d29f1

Please sign in to comment.