Skip to content

Commit b797aef

Browse files
committed
added Go template support to annotations
1 parent b06a4bd commit b797aef

File tree

4 files changed

+89
-8
lines changed

4 files changed

+89
-8
lines changed

README.md

+23
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,26 @@ spec:
104104
apiVersion: example.crossplane.io/v1
105105
kind: XR
106106
```
107+
## Templates
108+
You could use simple Go template in function annotation for enable or disable composition resources conditionally using `.observed` and `.desired`, or even print name of resource:
109+
```yaml
110+
apiVersion: example.crossplane.io/v1
111+
kind: XR
112+
metadata:
113+
name: example-xr
114+
annotations:
115+
switcher.fn.kndp.io/enabled: 'resourceThree,resourceOne'
116+
switcher.fn.kndp.io/disabled: '{{ if ne .observed.composite.resource.status.ready true }}resourceThree{{ end }}'
117+
spec:
118+
resourceOne:
119+
field1: "one"
120+
field2: "two"
121+
resourceTwo:
122+
field1: "three"
123+
field2: "four"
124+
resourceThree:
125+
field1: "five"
126+
field2: "six"
127+
status:
128+
ready: false
129+
```

example/composition.yaml

+3-3
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ spec:
1616
- name: resourceOne
1717
base:
1818
apiVersion: example.crossplane.io/v1
19-
kind: Resource
19+
kind: ResourceOne
2020
spec:
2121
field1: ""
2222
field2: ""
@@ -31,7 +31,7 @@ spec:
3131
- name: resourceTwo
3232
base:
3333
apiVersion: example.crossplane.io/v1
34-
kind: Resource
34+
kind: ResourceTwo
3535
spec:
3636
field1: ""
3737
field2: ""
@@ -46,7 +46,7 @@ spec:
4646
- name: resourceThree
4747
base:
4848
apiVersion: example.crossplane.io/v1
49-
kind: Resource
49+
kind: ResourceThree
5050
spec:
5151
field1: ""
5252
field2: ""

example/xr.yaml

+4-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ kind: XR
33
metadata:
44
name: example-xr
55
annotations:
6-
switcher.fn.kndp.io/disabled: "resourceTwo"
6+
switcher.fn.kndp.io/enabled: 'resourceThree,resourceOne'
7+
switcher.fn.kndp.io/disabled: '{{ if ne .observed.composite.resource.status.ready true }}resourceThree{{ end }}'
78
spec:
89
resourceOne:
910
field1: "one"
@@ -14,3 +15,5 @@ spec:
1415
resourceThree:
1516
field1: "five"
1617
field2: "six"
18+
status:
19+
ready: false

fn.go

+59-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package main
22

33
import (
4+
"bytes"
45
"context"
56
"encoding/json"
7+
"html/template"
68
"slices"
79
"strings"
810

@@ -12,9 +14,15 @@ import (
1214
"github.com/crossplane/function-sdk-go/resource"
1315
"github.com/crossplane/function-sdk-go/response"
1416
"github.com/pkg/errors"
17+
"google.golang.org/protobuf/encoding/protojson"
1518
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1619
)
1720

21+
const (
22+
enableAnnotation = "switcher.fn.kndp.io/enabled"
23+
disableAnnotaion = "switcher.fn.kndp.io/disabled"
24+
)
25+
1826
// Function returns whatever response you ask it to.
1927
type Function struct {
2028
fnv1beta1.UnimplementedFunctionRunnerServiceServer
@@ -34,7 +42,7 @@ func (f *Function) RunFunction(_ context.Context, req *fnv1beta1.RunFunctionRequ
3442
return rsp, nil
3543
}
3644

37-
switchOn, switchOff, err := collectSwitches(req, rsp)
45+
switchOn, switchOff, err := f.collectSwitches(req, rsp)
3846
if err != nil {
3947
return rsp, err
4048
}
@@ -51,7 +59,8 @@ func (f *Function) RunFunction(_ context.Context, req *fnv1beta1.RunFunctionRequ
5159
return rsp, nil
5260
}
5361

54-
func collectSwitches(req *fnv1beta1.RunFunctionRequest, rsp *fnv1beta1.RunFunctionResponse) ([]string, []string, error) {
62+
// Collect enabled and disable resources names from annotations
63+
func (f *Function) collectSwitches(req *fnv1beta1.RunFunctionRequest, rsp *fnv1beta1.RunFunctionResponse) ([]string, []string, error) {
5564
oxr, err := request.GetObservedCompositeResource(req)
5665
if err != nil {
5766
response.Fatal(rsp, errors.Wrapf(err, "cannot get observed composite resource from %T", req))
@@ -67,17 +76,25 @@ func collectSwitches(req *fnv1beta1.RunFunctionRequest, rsp *fnv1beta1.RunFuncti
6776
}
6877

6978
for k, v := range meta.Annotations {
70-
if strings.Contains(k, "switcher.fn.kndp.io/enabled") {
79+
if strings.Contains(k, enableAnnotation) {
7180
if switchOn == nil {
7281
switchOn = []string{}
7382
}
83+
v, err = f.renderTemplate(v, enableAnnotation, req)
84+
if err != nil {
85+
return []string{}, []string{}, err
86+
}
7487
switchOn = append(switchOn, strings.Split(v, ",")...)
7588
}
7689

77-
if strings.Contains(k, "switcher.fn.kndp.io/disabled") {
90+
if strings.Contains(k, disableAnnotaion) {
7891
if switchOff == nil {
7992
switchOff = []string{}
8093
}
94+
v, err = f.renderTemplate(v, disableAnnotaion, req)
95+
if err != nil {
96+
return []string{}, []string{}, err
97+
}
8198
switchOff = append(switchOff, strings.Split(v, ",")...)
8299
}
83100
}
@@ -113,3 +130,41 @@ func toMeta(m interface{}) (v1.ObjectMeta, error) {
113130

114131
return meta, nil
115132
}
133+
134+
// Render Go template against request data
135+
func (f *Function) renderTemplate(tplString string, tplName string, req *fnv1beta1.RunFunctionRequest) (string, error) {
136+
reqMap, err := convertToMap(req)
137+
if err != nil {
138+
return tplString, err
139+
}
140+
141+
tmpl, err := template.New(tplName).Parse(tplString)
142+
if err != nil {
143+
return tplString, err
144+
}
145+
f.log.Debug("constructed request map", "request", reqMap)
146+
147+
buf := &bytes.Buffer{}
148+
149+
if err := tmpl.Execute(buf, reqMap); err != nil {
150+
return tplString, err
151+
}
152+
153+
f.log.Debug("rendered manifests", "manifests", buf.String())
154+
return buf.String(), nil
155+
}
156+
157+
// Convert function request to map
158+
func convertToMap(req *fnv1beta1.RunFunctionRequest) (map[string]any, error) {
159+
jReq, err := protojson.Marshal(req)
160+
if err != nil {
161+
return nil, errors.Wrap(err, "cannot marshal request from proto to json")
162+
}
163+
164+
var mReq map[string]any
165+
if err := json.Unmarshal(jReq, &mReq); err != nil {
166+
return nil, errors.Wrap(err, "cannot unmarshal json to map[string]any")
167+
}
168+
169+
return mReq, nil
170+
}

0 commit comments

Comments
 (0)