Skip to content

Commit

Permalink
added "getValueByOrderedKeys" function to support more dynamic keys in
Browse files Browse the repository at this point in the history
secrets
  • Loading branch information
lynx-coding committed Nov 6, 2023
1 parent 5b57752 commit 22b2e45
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 6 deletions.
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,4 +123,18 @@ A working example can be found in `examples/k8s`. The files inside manifests dir
$ kubectl exec apache-demo-8479b98dd4-82jnn -c apache -- cat /path/to/secret/config
key1=valueFromSecret
key2=2ndValueFromSecret
```
```

## Advanced features
### getValueByOrderedKeys
This extension allows you to use dynamic keys in your secrets, which could happen if you use an external Secret operator for example.

When is this useful? E.g. if you use keys inside Secrets to represent some kind of hierarchical configuration:
```yaml
value: my-value
value_aws: aws-specific-value
value_azure: azure-specific-value
```

Use the following line to access it: `value={{ getValueByOrderedKeys (index .Secrets "secretValues") "value_aws" "value" }}`
This will return the value for the first matching key in `.Secrets.secretValues`, `aws-specific-value` but would fall back to `my-value` in case it does not find a value for key `value_aws`.
2 changes: 1 addition & 1 deletion examples/k8s/configmap.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ metadata:
name: apache-demo-cfg
data:
secret-config: |-
key1={{ index .Secrets "apache-demo" "secret1" }}
key1={{ getValueByOrderedKeys (index .Secrets "apache-demo") "secret1" }}
key2={{ index .Secrets "apache-demo" "secret2" }}
2 changes: 1 addition & 1 deletion examples/simple/templates/etc/config
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
test1={{ .Secrets.example.TEST1 }}
test1={{ getValueByOrderedKeys (index .Secrets "example") "notExistingKey" "TEST1" }}
test2={{ .Secrets.example.TEST2 }}
22 changes: 19 additions & 3 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,11 @@ func main() {
}

func renderSecretsIntoTemplates(templatePaths []string, leftDelimiter string, rightDelimiter string, continueOnMissingKey bool, targetBasePath string, templateBasePath string, secrets map[string]map[string]string) error {
funcMap := template.FuncMap{
"getValueByOrderedKeys": getValueByOrderedKeys,
}
for _, templatePath := range templatePaths {
t, err := template.ParseFiles(templatePath)
t, err := template.New(path.Base(templatePath)).Funcs(funcMap).ParseFiles(templatePath)
if err != nil {
return fmt.Errorf("failed to parse template files(%q): %w", templatePath, err)
}
Expand All @@ -67,8 +70,11 @@ func renderSecretsIntoTemplates(templatePaths []string, leftDelimiter string, ri
if err != nil {
return fmt.Errorf("failed to create target dir for %q: %w", templatePath, err)
}
targetFile, _ := os.Create(targetPath)
err = t.Execute(targetFile, struct {
targetFile, err := os.Create(targetPath)
if err != nil {
return fmt.Errorf("failed to create target file at %q: %w", targetPath, err)
}
err = t.Funcs(funcMap).Execute(targetFile, struct {
Secrets map[string]map[string]string
}{
Secrets: secrets,
Expand Down Expand Up @@ -143,3 +149,13 @@ func mkDirIfNotExists(path string) error {

return nil
}

func getValueByOrderedKeys(stringMap map[string]string, keys ...string) (string, error) {
for _, key := range keys {
val, ok := stringMap[key]
if ok {
return val, nil
}
}
return "", fmt.Errorf("no matching key found in secret")
}
58 changes: 58 additions & 0 deletions main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,61 @@ func Test_getAllTemplateFilePaths(t *testing.T) {
t.Errorf("getAllTemplateFilePaths() = %v, want %v", tempPaths, wantedResult)
}
}

func Test_getValueByOrderedKeys(t *testing.T) {
tests := []struct {
name string
stringMap map[string]string
keys []string
want string
wantErr bool
}{
{
name: "one-match",
stringMap: map[string]string{"key1": "val1"},
keys: []string{"key1"},
want: "val1",
wantErr: false,
},
{
name: "match-first",
stringMap: map[string]string{"key1": "val1", "key2": "val2"},
keys: []string{"key1"},
want: "val1",
wantErr: false,
},
{
name: "match-second",
stringMap: map[string]string{"key1": "val1", "key2": "val2"},
keys: []string{"key2"},
want: "val2",
wantErr: false,
},
{
name: "skip-first-match-second",
stringMap: map[string]string{"key1": "val1", "key2": "val2"},
keys: []string{"key3", "key2"},
want: "val2",
wantErr: false,
},
{
name: "key-not-found",
stringMap: map[string]string{"key1": "val1", "key2": "val2"},
keys: []string{"key3"},
want: "",
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := getValueByOrderedKeys(tt.stringMap, tt.keys...)
if (err != nil) != tt.wantErr {
t.Errorf("getValueByOrderedKeys() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != tt.want {
t.Errorf("getValueByOrderedKeys() got = %v, want %v", got, tt.want)
}
})
}
}

0 comments on commit 22b2e45

Please sign in to comment.