Skip to content

Commit 76ac0d3

Browse files
committed
#30 multiline configmap values
1 parent 50a39b7 commit 76ac0d3

File tree

9 files changed

+111
-96
lines changed

9 files changed

+111
-96
lines changed

examples/app/templates/my-config-props.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ metadata:
77
data:
88
my.prop1: {{ .Values.myConfigProps.myProp1 | quote }}
99
my.prop2: {{ .Values.myConfigProps.myProp2 | quote }}
10-
my.prop3: {{ .Values.myConfigProps.myProp3 | quote }}
10+
my.prop3: {{ .Values.myConfigProps.myProp3 | quote }}
11+
myval.yaml: {{ .Values.myConfigProps.myvalYaml | toYaml | indent 1 }}

examples/app/values.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,16 @@ myConfigProps:
2121
myProp1: "1"
2222
myProp2: val 1
2323
myProp3: "true"
24+
myvalYaml: |-
25+
apiVersion: clickhouse.altinity.com/v1
26+
kind: ClickHouseInstallationTemplate
27+
metadata:
28+
name: default-oneperhost-pod-template
29+
spec:
30+
templates:
31+
podTemplates:
32+
- name: default-oneperhost-pod-template
33+
distribution: "OnePerHost"
2434
mySecretCa:
2535
caCrt: ""
2636
mySecretVars:

examples/operator/templates/manager-config.yaml

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,6 @@ metadata:
55
labels:
66
{{- include "operator.labels" . | nindent 4 }}
77
data:
8-
controller_manager_config.yaml: |
9-
apiVersion: controller-runtime.sigs.k8s.io/v1alpha1
10-
health:
11-
healthProbeBindAddress: {{ .Values.managerConfig.controllerManagerConfigYaml.health.healthProbeBindAddress
12-
| quote }}
13-
kind: ControllerManagerConfig
14-
leaderElection:
15-
leaderElect: {{ .Values.managerConfig.controllerManagerConfigYaml.leaderElection.leaderElect
16-
}}
17-
resourceName: {{ .Values.managerConfig.controllerManagerConfigYaml.leaderElection.resourceName
18-
| quote }}
19-
metrics:
20-
bindAddress: {{ .Values.managerConfig.controllerManagerConfigYaml.metrics.bindAddress
21-
| quote }}
22-
rook:
23-
namespace: {{ .Values.managerConfig.controllerManagerConfigYaml.rook.namespace
24-
| quote }}
25-
toolboxPodLabel: {{ .Values.managerConfig.controllerManagerConfigYaml.rook.toolboxPodLabel
26-
| quote }}
27-
webhook:
28-
port: {{ .Values.managerConfig.controllerManagerConfigYaml.webhook.port }}
8+
controller_manager_config.yaml: {{ .Values.managerConfig.controllerManagerConfigYaml
9+
| toYaml | indent 1 }}
2910
dummyconfigmapkey: {{ .Values.managerConfig.dummyconfigmapkey | quote }}

examples/operator/values.yaml

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,19 +37,21 @@ controllerManager:
3737
replicas: 1
3838
kubernetesClusterDomain: cluster.local
3939
managerConfig:
40-
controllerManagerConfigYaml:
40+
controllerManagerConfigYaml: |-
41+
apiVersion: controller-runtime.sigs.k8s.io/v1alpha1
42+
kind: ControllerManagerConfig
4143
health:
4244
healthProbeBindAddress: :8081
45+
metrics:
46+
bindAddress: 127.0.0.1:8080
47+
webhook:
48+
port: 9443
4349
leaderElection:
4450
leaderElect: true
4551
resourceName: 3a2e09e9.example.com
46-
metrics:
47-
bindAddress: 127.0.0.1:8080
4852
rook:
4953
namespace: rook-ceph
5054
toolboxPodLabel: rook-ceph-tools
51-
webhook:
52-
port: 9443
5355
dummyconfigmapkey: dummyconfigmapvalue
5456
metricsService:
5557
ports:

pkg/format/trailing_whitespaces.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package format
2+
3+
import "regexp"
4+
5+
var removeWhitespace = regexp.MustCompile(`(\s+)(\n|$)`)
6+
7+
func RemoveTrailingWhitespaces(in string) string {
8+
return removeWhitespace.ReplaceAllString(in, "$2")
9+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package format
2+
3+
import "testing"
4+
5+
func TestRemoveTrailingWhitespaces(t *testing.T) {
6+
tests := []struct {
7+
name string
8+
in string
9+
want string
10+
}{
11+
{
12+
name: "",
13+
in: `abc `,
14+
want: `abc`,
15+
},
16+
{
17+
name: "",
18+
in: `abc
19+
edf`,
20+
want: `abc
21+
edf`,
22+
},
23+
{
24+
name: "",
25+
in: `abc
26+
edf `,
27+
want: `abc
28+
edf`,
29+
},
30+
{
31+
name: "",
32+
in: `abc .
33+
edf .`,
34+
want: `abc .
35+
edf .`,
36+
},
37+
}
38+
for _, tt := range tests {
39+
t.Run(tt.name, func(t *testing.T) {
40+
if got := RemoveTrailingWhitespaces(tt.in); got != tt.want {
41+
t.Errorf("RemoveTrailingWhitespaces() = %v, want %v", got, tt.want)
42+
}
43+
})
44+
}
45+
}

pkg/helmify/values.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,20 @@ func (v *Values) Add(value interface{}, name ...string) (string, error) {
4141
return "{{ .Values." + strings.Join(name, ".") + " }}", nil
4242
}
4343

44+
// AddYaml - adds given value to values and returns its helm template representation as Yaml {{ .Values.<valueName> | toYaml | indent i }}
45+
// indent <= 0 will be omitted.
46+
func (v *Values) AddYaml(value interface{}, indent int, name ...string) (string, error) {
47+
name = toCamelCase(name)
48+
err := unstructured.SetNestedField(*v, value, name...)
49+
if err != nil {
50+
return "", errors.Wrapf(err, "unable to set value: %v", name)
51+
}
52+
if indent > 0 {
53+
return "{{ .Values." + strings.Join(name, ".") + fmt.Sprintf(" | toYaml | indent %d }}", indent), nil
54+
}
55+
return "{{ .Values." + strings.Join(name, ".") + " | toYaml }}", nil
56+
}
57+
4458
// AddSecret - adds empty value to values and returns its helm template representation {{ required "<valueName>" .Values.<valueName> }}.
4559
// Set toBase64=true for Secret data to be base64 encoded and set false for Secret stringData.
4660
func (v *Values) AddSecret(toBase64 bool, name ...string) (string, error) {

pkg/processor/configmap/configmap.go

Lines changed: 12 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package configmap
22

33
import (
4-
"fmt"
4+
"github.com/arttor/helmify/pkg/format"
55
"io"
66
"strings"
77
"text/template"
@@ -14,7 +14,6 @@ import (
1414
"github.com/sirupsen/logrus"
1515
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
1616
"k8s.io/apimachinery/pkg/runtime/schema"
17-
"sigs.k8s.io/yaml"
1817
)
1918

2019
var configMapTempl, _ = template.New("configMap").Parse(
@@ -68,7 +67,7 @@ func (d configMap) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstru
6867

6968
name := appMeta.TrimName(obj.GetName())
7069
var values helmify.Values
71-
if field, exists, _ := unstructured.NestedMap(obj.Object, "data"); exists {
70+
if field, exists, _ := unstructured.NestedStringMap(obj.Object, "data"); exists {
7271
field, values = parseMapData(field, name)
7372
data, err = yamlformat.Marshal(map[string]interface{}{"data": field}, 0)
7473
if err != nil {
@@ -89,28 +88,31 @@ func (d configMap) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstru
8988
}, nil
9089
}
9190

92-
func parseMapData(data map[string]interface{}, configName string) (map[string]interface{}, helmify.Values) {
91+
func parseMapData(data map[string]string, configName string) (map[string]string, helmify.Values) {
9392
values := helmify.Values{}
9493
for key, value := range data {
9594
valuesNamePath := []string{configName, key}
96-
if strings.HasSuffix(key, ".yaml") || strings.HasSuffix(key, ".yml") {
97-
templated, err := parseYaml(value, valuesNamePath, values)
95+
if strings.HasSuffix(key, ".properties") {
96+
// handle properties
97+
templated, err := parseProperties(value, valuesNamePath, values)
9898
if err != nil {
9999
logrus.WithError(err).Errorf("unable to process configmap data: %v", valuesNamePath)
100100
continue
101101
}
102102
data[key] = templated
103103
continue
104104
}
105-
if strings.HasSuffix(key, ".properties") {
106-
templated, err := parseProperties(value, valuesNamePath, values)
105+
if strings.Contains(value, "\n") {
106+
value = format.RemoveTrailingWhitespaces(value)
107+
templatedVal, err := values.AddYaml(value, 1, valuesNamePath...)
107108
if err != nil {
108-
logrus.WithError(err).Errorf("unable to process configmap data: %v", valuesNamePath)
109+
logrus.WithError(err).Errorf("unable to process multiline configmap data: %v", valuesNamePath)
109110
continue
110111
}
111-
data[key] = templated
112+
data[key] = templatedVal
112113
continue
113114
}
115+
// handle plain string
114116
templatedVal, err := values.Add(value, valuesNamePath...)
115117
if err != nil {
116118
logrus.WithError(err).Errorf("unable to process configmap data: %v", valuesNamePath)
@@ -121,20 +123,6 @@ func parseMapData(data map[string]interface{}, configName string) (map[string]in
121123
return data, values
122124
}
123125

124-
func parseYaml(value interface{}, path []string, values helmify.Values) (string, error) {
125-
config := map[string]interface{}{}
126-
err := yaml.Unmarshal([]byte(value.(string)), &config)
127-
if err != nil {
128-
return "", errors.Wrapf(err, "unable to unmarshal configmap %v", path)
129-
}
130-
parseConfig(config, values, path)
131-
confBytes, err := yaml.Marshal(config)
132-
if err != nil {
133-
return "", errors.Wrapf(err, "unable to marshal configmap %v", path)
134-
}
135-
return string(confBytes), nil
136-
}
137-
138126
// func parseProperties(properties string, path []string, values helmify.Values) (string, error) {
139127
func parseProperties(properties interface{}, path []string, values helmify.Values) (string, error) {
140128
var res strings.Builder
@@ -157,51 +145,6 @@ func parseProperties(properties interface{}, path []string, values helmify.Value
157145
return res.String(), nil
158146
}
159147

160-
func parseConfig(config map[string]interface{}, values helmify.Values, path []string) {
161-
for k, v := range config {
162-
switch t := v.(type) {
163-
case string, bool, float64, int64:
164-
if k == "kind" || k == "apiVersion" {
165-
continue
166-
}
167-
templated, err := values.Add(v, append(path, k)...)
168-
if err != nil {
169-
logrus.WithError(err).Error()
170-
continue
171-
}
172-
config[k] = templated
173-
case []interface{}:
174-
templated, err := values.Add(v, append(path, k)...)
175-
if err != nil {
176-
logrus.WithError(err).Error()
177-
continue
178-
}
179-
config[k] = templated
180-
case map[string]interface{}:
181-
if len(t) == 0 {
182-
templated, err := values.Add(v, append(path, k)...)
183-
if err != nil {
184-
logrus.WithError(err).Error()
185-
continue
186-
}
187-
config[k] = templated
188-
continue
189-
}
190-
parseConfig(t, values, append(path, k))
191-
case map[interface{}]interface{}:
192-
c, ok := v.(map[string]interface{})
193-
if !ok {
194-
logrus.Warn("configmap: unable to cast to map[string]interface{}")
195-
continue
196-
}
197-
parseConfig(c, values, append(path, k))
198-
default:
199-
logrus.Warn("configmap: unknown type ", t)
200-
fmt.Printf("\n%T\n", t)
201-
}
202-
}
203-
}
204-
205148
type result struct {
206149
name string
207150
data struct {

test_data/sample-app.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,16 @@ data:
193193
my.prop1: "1"
194194
my.prop2: "val 1"
195195
my.prop3: "true"
196+
myval.yaml: |
197+
apiVersion: clickhouse.altinity.com/v1
198+
kind: ClickHouseInstallationTemplate
199+
metadata:
200+
name: default-oneperhost-pod-template
201+
spec:
202+
templates:
203+
podTemplates:
204+
- name: default-oneperhost-pod-template
205+
distribution: "OnePerHost"
196206
---
197207
apiVersion: apps/v1
198208
kind: DaemonSet

0 commit comments

Comments
 (0)