Skip to content

Commit 7386ea4

Browse files
Function configs must have dedicated file (#434)
* Function configs must have dedicated file * Suggested changes * Fix empty value cases and old setter comments for array nodes
1 parent 2d89e9b commit 7386ea4

File tree

25 files changed

+219
-69
lines changed

25 files changed

+219
-69
lines changed

examples/fix-simple/.expected/diff.patch

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
diff --git a/Kptfile b/Kptfile
2-
index a8e7f27..0d91da2 100644
2+
index a8e7f27..cccb738 100644
33
--- a/Kptfile
44
+++ b/Kptfile
55
@@ -1,20 +1,24 @@
@@ -37,7 +37,7 @@ index a8e7f27..0d91da2 100644
3737
+pipeline:
3838
+ mutators:
3939
+ - image: gcr.io/kpt-fn/apply-setters:v0.1
40-
+ configPath: setters-config.yaml
40+
+ configPath: setters.yaml
4141
diff --git a/resources.yaml b/resources.yaml
4242
index 9e30767..dae3005 100644
4343
--- a/resources.yaml
@@ -50,15 +50,15 @@ index 9e30767..dae3005 100644
5050
+ name: the-map # kpt-set: ${name}
5151
data:
5252
some-key: some-value
53-
diff --git a/setters-config.yaml b/setters-config.yaml
53+
diff --git a/setters.yaml b/setters.yaml
5454
new file mode 100644
55-
index 0000000..f39bb00
55+
index 0000000..b67bc21
5656
--- /dev/null
57-
+++ b/setters-config.yaml
57+
+++ b/setters.yaml
5858
@@ -0,0 +1,6 @@
5959
+apiVersion: v1
6060
+kind: ConfigMap
6161
+metadata:
62-
+ name: setters-config
62+
+ name: setters
6363
+data:
6464
+ name: the-map

examples/fix-simple/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ info:
8383
pipeline:
8484
mutators:
8585
- image: gcr.io/kpt-fn/apply-setters:v0.1
86-
configPath: setters-config.yaml
86+
configPath: setters.yaml
8787
```
8888

8989
The transformed package is compatible with kpt 1.0 binary.

functions/go/fix/fixpkg/fix.go

Lines changed: 54 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"sigs.k8s.io/kustomize/kyaml/fieldmeta"
1515
"sigs.k8s.io/kustomize/kyaml/fn/runtime/runtimeutil"
1616
"sigs.k8s.io/kustomize/kyaml/kio"
17+
"sigs.k8s.io/kustomize/kyaml/kio/filters"
1718
"sigs.k8s.io/kustomize/kyaml/kio/kioutil"
1819
"sigs.k8s.io/kustomize/kyaml/openapi"
1920
"sigs.k8s.io/kustomize/kyaml/sets"
@@ -55,7 +56,7 @@ type Result struct {
5556
Message string
5657
}
5758

58-
const SettersConfigFileName = "setters-config.yaml"
59+
const SettersConfigFileName = "setters.yaml"
5960

6061
// Filter implements Fix as a yaml.Filter
6162
func (s *Fix) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
@@ -230,15 +231,18 @@ func (s *Fix) FunctionsInPkg(nodes []*yaml.RNode, pkgPath string) []v1.Function
230231
}
231232
fnSpec := runtimeutil.GetFunctionSpec(node)
232233
if fnSpec != nil {
234+
// in order to make sure there is only one function config per file,
235+
// rename the file with the name(and hash(name)) of the function config resource
236+
fnFileName := fmt.Sprintf("%s.yaml", node.GetName())
233237
// in v1, fn-config must be present in the package directory
234238
// so configPath must be just the file name
235-
fnFileName := filepath.Base(meta.Annotations[kioutil.PathAnnotation])
239+
fnFilePath := filepath.Join(pkgPath, fnFileName)
236240
res = append(res, v1.Function{
237241
Image: fnSpec.Container.Image,
238242
ConfigPath: fnFileName,
239243
})
240244
// move the fn-config to the top level directory of the package
241-
meta.Annotations[kioutil.PathAnnotation] = filepath.Join(pkgPath, fnFileName)
245+
meta.Annotations[kioutil.PathAnnotation] = fnFilePath
242246
delete(meta.Annotations, runtimeutil.FunctionAnnotationKey)
243247
delete(meta.Annotations, "config.k8s.io/function")
244248
err = node.SetAnnotations(meta.Annotations)
@@ -278,7 +282,7 @@ func (s *Fix) FixKptfile(node *yaml.RNode, functions []v1.Function) (*yaml.RNode
278282
if kf.Pipeline != nil {
279283
for i, fn := range kf.Pipeline.Mutators {
280284
if strings.Contains(fn.Image, "apply-setters:v0.1") && len(fn.ConfigMap) > 0 {
281-
settersConfig, err := ConfigFromSetters(kf.Pipeline.Mutators[0].ConfigMap, settersConfigFilePath)
285+
settersConfig, err := SettersNodeFromSetters(kf.Pipeline.Mutators[0].ConfigMap, settersConfigFilePath)
282286
if err != nil {
283287
return node, err
284288
}
@@ -392,9 +396,9 @@ func (s *Fix) FixKptfile(node *yaml.RNode, functions []v1.Function) (*yaml.RNode
392396
if len(setters) > 0 {
393397
fn := v1.Function{
394398
Image: "gcr.io/kpt-fn/apply-setters:v0.1",
395-
ConfigPath: "setters-config.yaml",
399+
ConfigPath: SettersConfigFileName,
396400
}
397-
settersConfig, err := ConfigFromSetters(setters, settersConfigFilePath)
401+
settersConfig, err := SettersNodeFromSetters(setters, settersConfigFilePath)
398402
if err != nil {
399403
return node, err
400404
}
@@ -431,12 +435,12 @@ func (s *Fix) FixKptfile(node *yaml.RNode, functions []v1.Function) (*yaml.RNode
431435
return kNode, err
432436
}
433437

434-
// ConfigFromSetters returns the ConfigMap node with input setters in data field
435-
func ConfigFromSetters(setters map[string]string, path string) (*yaml.RNode, error) {
438+
// SettersNodeFromSetters returns the ConfigMap node with input setters in data field
439+
func SettersNodeFromSetters(setters map[string]string, path string) (*yaml.RNode, error) {
436440
configNode, err := yaml.Parse(fmt.Sprintf(`apiVersion: v1
437441
kind: ConfigMap
438442
metadata:
439-
name: setters-config
443+
name: setters
440444
annotations:
441445
%s: %s
442446
%s: "0"
@@ -452,28 +456,48 @@ metadata:
452456
sort.Strings(keys)
453457

454458
for _, k := range keys {
455-
v := setters[k]
456-
vNode, err := yaml.Parse(v)
459+
v, err := standardizeArrayValue(setters[k])
457460
if err != nil {
458461
return nil, err
459462
}
460-
if vNode.YNode().Kind == yaml.SequenceNode {
461-
// standardize array values to folded style
462-
vNode.YNode().Style = yaml.FoldedStyle
463-
v, err = vNode.String()
464-
if err != nil {
465-
return nil, err
466-
}
463+
vNode := yaml.NewScalarRNode(v)
464+
if v == "" {
465+
vNode.YNode().Style = yaml.DoubleQuotedStyle
467466
}
468-
469467
err = configNode.PipeE(
470468
yaml.LookupCreate(yaml.ScalarNode, "data", k),
471-
yaml.FieldSetter{Value: yaml.NewScalarRNode(v)})
469+
yaml.FieldSetter{Value: vNode, OverrideStyle: true})
472470
if err != nil {
473471
return nil, err
474472
}
475473
}
476-
return configNode, nil
474+
// format the created resource
475+
_, err = filters.FormatFilter{UseSchema: true}.Filter([]*yaml.RNode{configNode})
476+
return configNode, err
477+
}
478+
479+
// standardizeArrayValue returns the folded style array node string
480+
// e.g. for input value [foo, bar], it returns
481+
// - foo
482+
// - bar
483+
func standardizeArrayValue(val string) (string, error) {
484+
if !strings.HasPrefix(val, "[") {
485+
// the value is either standardized, or is not a sequence node value
486+
return val, nil
487+
}
488+
vNode, err := yaml.Parse(val)
489+
if err != nil {
490+
return val, fmt.Errorf("failed to parse the array node value %q with error %q", val, err.Error())
491+
}
492+
if vNode.YNode().Kind == yaml.SequenceNode {
493+
// standardize array values to folded style
494+
vNode.YNode().Style = yaml.FoldedStyle
495+
val, err = vNode.String()
496+
if err != nil {
497+
return val, fmt.Errorf("failed to serialize the array node value %q with error %q", val, err.Error())
498+
}
499+
}
500+
return val, nil
477501
}
478502

479503
// getPkgPathToSettersSchema returns the, map of pkgPath to the setters schema in Kptfile
@@ -507,13 +531,16 @@ func (s *Fix) visitMapping(object *yaml.RNode) error {
507531
// return if it is not a sequence node
508532
return nil
509533
}
510-
534+
oldCommentPrefixes := []string{`# {"$kpt-set":"`, `# {"$ref":"#/definitions/io.k8s.cli.`}
511535
comment := node.Key.YNode().LineComment
512-
// # {"$kpt-set":"foo"} must be converted to # kpt-set: ${foo}
513-
if strings.Contains(comment, "$kpt-set") {
514-
comment := strings.TrimPrefix(comment, `# {"$kpt-set":"`)
515-
comment = strings.TrimSuffix(comment, `"}`)
516-
node.Key.YNode().LineComment = fmt.Sprintf("kpt-set: ${%s}", comment)
536+
for _, cp := range oldCommentPrefixes {
537+
// # {"$kpt-set":"foo"} must be converted to # kpt-set: ${foo}
538+
// # {"$ref":"#/definitions/io.k8s.cli.list"} must be converted to # kpt-set: ${list}
539+
if strings.Contains(comment, cp) {
540+
comment := strings.TrimPrefix(comment, cp)
541+
comment = strings.TrimSuffix(comment, `"}`)
542+
node.Key.YNode().LineComment = fmt.Sprintf("kpt-set: ${%s}", comment)
543+
}
517544
}
518545
return nil
519546
})

functions/go/fix/fixpkg/fix_test.go

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ func TestFixV1alpha1ToV1(t *testing.T) {
3737
message: Transformed "packageMetadata" to "info"
3838
- filepath: Kptfile
3939
message: Transformed "upstream" to "upstream" and "upstreamLock"
40+
- filepath: Kptfile
41+
message: Added "gcr.io/kpt-fn/set-annotations:v0.1" to mutators list, please move it to validators section if it is a validator function
4042
- filepath: Kptfile
4143
message: Added "gcr.io/kpt-fn/set-labels:v0.1" to mutators list, please move it to validators section if it is a validator function
4244
- filepath: Kptfile
@@ -78,11 +80,86 @@ func TestFixV1alpha2ToV1(t *testing.T) {
7880
assert.NoError(t, err)
7981
assert.Equal(t, `- filepath: Kptfile
8082
message: Updated apiVersion to kpt.dev/v1
81-
- filepath: setters-config.yaml
83+
- filepath: setters.yaml
8284
message: Moved setters from configMap to configPath
8385
- filepath: hello-world/Kptfile
8486
message: Updated apiVersion to kpt.dev/v1
85-
- filepath: hello-world/setters-config.yaml
87+
- filepath: hello-world/setters.yaml
8688
message: Moved setters from configMap to configPath
8789
`, string(results))
8890
}
91+
92+
type settersNodeTest struct {
93+
name string
94+
setters map[string]string
95+
path string
96+
expected string
97+
errMsg string
98+
}
99+
100+
var settersNodeFromSettersCases = []settersNodeTest{
101+
{
102+
name: "Create setters file with all types",
103+
path: `foo/bar`,
104+
setters: map[string]string{
105+
"environment": "",
106+
"integer": "10",
107+
"number": "1.1",
108+
"boolean": "true",
109+
"string": "foo",
110+
"region": "us-east-1",
111+
"flow-style-setter": "[dev, prod]",
112+
"folded-style-setter": "- hi\n- hello",
113+
},
114+
expected: `apiVersion: v1
115+
kind: ConfigMap
116+
metadata:
117+
name: setters
118+
annotations:
119+
config.kubernetes.io/index: "0"
120+
config.kubernetes.io/path: foo/bar
121+
data:
122+
boolean: "true"
123+
environment: ""
124+
flow-style-setter: |
125+
- dev
126+
- prod
127+
folded-style-setter: |-
128+
- hi
129+
- hello
130+
integer: "10"
131+
number: "1.1"
132+
region: us-east-1
133+
string: foo
134+
`,
135+
},
136+
{
137+
name: "invalid flow-style sequence node",
138+
path: `foo/bar`,
139+
setters: map[string]string{
140+
"setter": "[dev, prod,",
141+
},
142+
errMsg: `failed to parse the array node value "[dev, prod," with error "yaml: line 1: did not find expected node content"`,
143+
},
144+
}
145+
146+
func TestSettersNodeFromSetters(t *testing.T) {
147+
for i := range settersNodeFromSettersCases {
148+
test := settersNodeFromSettersCases[i]
149+
t.Run(test.name, func(t *testing.T) {
150+
res, err := SettersNodeFromSetters(test.setters, test.path)
151+
if test.errMsg == "" {
152+
assert.NoError(t, err)
153+
} else {
154+
assert.Error(t, err)
155+
assert.Equal(t, test.errMsg, err.Error())
156+
return
157+
}
158+
actual, err := res.String()
159+
assert.NoError(t, err)
160+
if !assert.Equal(t, test.expected, actual) {
161+
t.FailNow()
162+
}
163+
})
164+
}
165+
}

testdata/fix/nginx-v1/Kptfile

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,11 @@ info:
2929
pipeline:
3030
mutators:
3131
- image: gcr.io/kpt-fn/apply-setters:v0.1
32-
configPath: setters-config.yaml
32+
configPath: setters.yaml
33+
- image: gcr.io/kpt-fn/set-annotations:v0.1
34+
configPath: my-annotations.yaml
3335
- image: gcr.io/kpt-fn/set-labels:v0.1
34-
configPath: fn-config.yaml
36+
configPath: set-labels.yaml
3537
inventory:
3638
namespace: some-space
3739
name: inventory-00933591

testdata/fix/nginx-v1/deployment.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,6 @@ spec:
1818
env: # kpt-set: ${list}
1919
- dev
2020
- stage
21+
clusters: # kpt-set: ${clusters}
22+
- cluster1
23+
- cluster2

testdata/fix/nginx-v1/hello-world/Kptfile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ info:
2121
pipeline:
2222
mutators:
2323
- image: gcr.io/kpt-fn/apply-setters:v0.1
24-
configPath: setters-config.yaml
24+
configPath: setters.yaml
2525
- image: gcr.io/kpt-fn/set-annotations:v0.1
26-
configPath: fn-config.yaml
26+
configPath: set-annotations.yaml
2727
- image: gcr.io/kpt-fn/set-namespace:v0.1
28-
configPath: ns-config.yaml
28+
configPath: set-namespace.yaml

testdata/fix/nginx-v1alpha2/hello-world/fn-config.yaml renamed to testdata/fix/nginx-v1/hello-world/set-annotations.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
apiVersion: v1
22
kind: ConfigMap
33
metadata:
4-
name: my-config
4+
name: set-annotations
55
annotations:
66
config.kubernetes.io/local-config: "true"
77
data:

testdata/fix/nginx-v1/hello-world/ns-config.yaml renamed to testdata/fix/nginx-v1/hello-world/set-namespace.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
apiVersion: v1
22
kind: ConfigMap
33
metadata:
4-
name: my-config
4+
name: set-namespace
55
annotations:
66
config.kubernetes.io/local-config: "true"
77
data:
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
apiVersion: v1
22
kind: ConfigMap
33
metadata:
4-
name: setters-config
4+
name: setters
55
data:
6-
http-port: 80
6+
replicas: "5"
7+
http-port: "80"
78
image-tag: v0.3.0
8-
replicas: 5

0 commit comments

Comments
 (0)