1
1
package main
2
2
3
3
import (
4
+ "bytes"
4
5
"context"
5
6
"encoding/json"
7
+ "html/template"
6
8
"slices"
7
9
"strings"
8
10
@@ -12,9 +14,15 @@ import (
12
14
"github.com/crossplane/function-sdk-go/resource"
13
15
"github.com/crossplane/function-sdk-go/response"
14
16
"github.com/pkg/errors"
17
+ "google.golang.org/protobuf/encoding/protojson"
15
18
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
16
19
)
17
20
21
+ const (
22
+ enableAnnotation = "switcher.fn.kndp.io/enabled"
23
+ disableAnnotaion = "switcher.fn.kndp.io/disabled"
24
+ )
25
+
18
26
// Function returns whatever response you ask it to.
19
27
type Function struct {
20
28
fnv1beta1.UnimplementedFunctionRunnerServiceServer
@@ -34,7 +42,7 @@ func (f *Function) RunFunction(_ context.Context, req *fnv1beta1.RunFunctionRequ
34
42
return rsp , nil
35
43
}
36
44
37
- switchOn , switchOff , err := collectSwitches (req , rsp )
45
+ switchOn , switchOff , err := f . collectSwitches (req , rsp )
38
46
if err != nil {
39
47
return rsp , err
40
48
}
@@ -51,7 +59,8 @@ func (f *Function) RunFunction(_ context.Context, req *fnv1beta1.RunFunctionRequ
51
59
return rsp , nil
52
60
}
53
61
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 ) {
55
64
oxr , err := request .GetObservedCompositeResource (req )
56
65
if err != nil {
57
66
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
67
76
}
68
77
69
78
for k , v := range meta .Annotations {
70
- if strings .Contains (k , "switcher.fn.kndp.io/enabled" ) {
79
+ if strings .Contains (k , enableAnnotation ) {
71
80
if switchOn == nil {
72
81
switchOn = []string {}
73
82
}
83
+ v , err = f .renderTemplate (v , enableAnnotation , req )
84
+ if err != nil {
85
+ return []string {}, []string {}, err
86
+ }
74
87
switchOn = append (switchOn , strings .Split (v , "," )... )
75
88
}
76
89
77
- if strings .Contains (k , "switcher.fn.kndp.io/disabled" ) {
90
+ if strings .Contains (k , disableAnnotaion ) {
78
91
if switchOff == nil {
79
92
switchOff = []string {}
80
93
}
94
+ v , err = f .renderTemplate (v , disableAnnotaion , req )
95
+ if err != nil {
96
+ return []string {}, []string {}, err
97
+ }
81
98
switchOff = append (switchOff , strings .Split (v , "," )... )
82
99
}
83
100
}
@@ -113,3 +130,41 @@ func toMeta(m interface{}) (v1.ObjectMeta, error) {
113
130
114
131
return meta , nil
115
132
}
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