Skip to content

Commit 7ee3089

Browse files
authored
Implicit JSON Serialization (#18)
I'm guilty of missing out the json function myself at times, so add it in implicitly. While this works for straight pipelines, it won't for stuff with control flow, so outlaw this for now until we can work out how to do this. It will most likely involve parse trees and augmenting leaves.
1 parent 5b324eb commit 7ee3089

File tree

10 files changed

+165
-161
lines changed

10 files changed

+165
-161
lines changed

documentation/modules/ROOT/pages/concepts/dynamic-attributes.adoc

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,15 @@ Dynamic attributes are best thought of as functions: they accept input arguments
1919
Dynamic attributes do not have any side effects.
2020

2121
In general, dynamic attributes use the Go language https://golang.org/pkg/text/template/[template^] library with a few specializations.
22-
All actions, pipelines and functions are fully supported, providing control flow and function chaining out of the box.
22+
All pipelines and functions are fully supported.
23+
Actions involving control flow (e.g. `if` and `range`) are not supported at present.
2324
Arguments are confined to scalar values only (typically `int`, `string` and `bool`) and undefined values (`nil`).
2425

2526
=== Dynamic Attribute Typing
2627

2728
The key thing to note is that Go language templating operates on text.
2829
Text has no concept of type (other than being a string) therefore all dynamic attributes must be serialized to JSON in order to preserve type information and allow the Service Broker to make the correct decisions.
30+
The JSON serialization function is added implicitly, by the Service Broker, to all pipelines.
2931
All dynamic attributes are initially defined as strings, however the attribute itself takes on the type of the value returned by attribute template processing.
3032

3133
Internally, the templating engine treats all data as abstract values.
@@ -50,7 +52,7 @@ You can catch these types of errors earlier, and with more context, by specifyin
5052

5153
[source]
5254
----
53-
{{ parameter "/optional-parameter" | required | json }}
55+
{{ parameter "/optional-parameter" | required }}
5456
----
5557

5658
Unlike optional parameters, required parameters will raise an error if the result resolves to `nil`.
@@ -77,7 +79,7 @@ A registry source for name `foo` will return any value associated with the regis
7779

7880
[source]
7981
----
80-
{{ registry "fool" | json }}
82+
{{ registry "fool" }}
8183
----
8284

8385
==== Parameter
@@ -105,7 +107,7 @@ A dynamic attribute of:
105107

106108
[source]
107109
----
108-
{{ parameter "/size" | json }}
110+
{{ parameter "/size" }}
109111
----
110112

111113
would resolve to `"4"`.
@@ -114,7 +116,7 @@ A dynamic attribute of:
114116

115117
[source]
116118
----
117-
{{ parameter "/resources/requests" | json }}
119+
{{ parameter "/resources/requests" }}
118120
----
119121

120122
would resolve to `{"cpu":"4","memory":"16Gi"}`.
@@ -133,7 +135,7 @@ To demonstrate consider the following configuration template snippet definition:
133135
----
134136
name: label-snippet
135137
template:
136-
app: '{{ registry "my-app-name" | json }}' # <1>
138+
app: '{{ registry "my-app-name" }}' # <1>
137139
----
138140

139141
<1> The `app` attribute is dynamically set to the value defined by the `my-app-name` registry key.
@@ -149,7 +151,7 @@ template:
149151
kind: Secret
150152
metadata:
151153
name: my-secret
152-
labels: '{{ snippet "label-snippet" | json }}'
154+
labels: '{{ snippet "label-snippet" }}'
153155
----
154156

155157
This would generate the following Kubernetes resource:
@@ -174,7 +176,7 @@ The default function allows a dynamic attribute to have a value set when an opti
174176

175177
[source]
176178
----
177-
{{ parameter "/size" | default 3 | json }}
179+
{{ parameter "/size" | default 3 }}
178180
----
179181

180182
=== Generators
@@ -192,7 +194,7 @@ To generate a 32 character password:
192194

193195
[source]
194196
----
195-
{{ generatePassword 32 nil | json }}
197+
{{ generatePassword 32 nil }}
196198
----
197199

198200
==== Generate Key
@@ -205,7 +207,7 @@ For example, to generate a PKCS#8 encoded P256 elliptic curve private key:
205207

206208
[source]
207209
----
208-
{{ generatePrivateKey "EllipticP256" "PKCS#8" nil | json }}
210+
{{ generatePrivateKey "EllipticP256" "PKCS#8" nil }}
209211
----
210212

211213
==== Generate Certificate
@@ -221,7 +223,7 @@ For example, to generate a signed X.509 certificate:
221223

222224
[source]
223225
----
224-
{{ generateCertificate (registry "my-key") "My Certificate" "24h" "Server" (list "localhost") (registry "my-ca-key") (registry "my-ca-cert") | json }}
226+
{{ generateCertificate (registry "my-key") "My Certificate" "24h" "Server" (list "localhost") (registry "my-ca-key") (registry "my-ca-cert") }}
225227
----
226228

227229
.Recursive Template Processing
@@ -249,7 +251,7 @@ The required function will raise an error if the input argument is `nil`.
249251

250252
[source]
251253
----
252-
{{ parameter "/password" | required | json }}
254+
{{ parameter "/password" | required }}
253255
----
254256

255257
== Next Steps

documentation/modules/ROOT/pages/concepts/templates.adoc

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ template: # <1>
3232
apiVersion: v1
3333
kind: Secret
3434
metadata:
35-
name: '{{ registry "instance-id" | json }}' # <2>
35+
name: '{{ registry "instance-id" }}' # <2>
3636
stringData:
3737
mySecretName: TopSecret!
3838
----
@@ -44,10 +44,6 @@ Lets look in more detail at the configuration:
4444
<2> The `metadata.name` attribute is an example of using dynamic attributes
4545
Dynamic attributes are defined as strings--Go language templating operates on strings.
4646
This particular template references a value from the registry--a simple key/value store.
47-
The result from the registry lookup is then piped into a JSON converter.
48-
As Go language templating is all based on strings, then all outputs will also be strings.
49-
To allow the Service Broker to preserve structure and data types, all templated attributes must serialize their output into a JSON string.
50-
By using JSON, the Service Broker can decode it and process it correctly based on data type.
5147

5248
If, for example, our instance ID was `camelot`, the resulting resource would be:
5349

@@ -76,7 +72,7 @@ template:
7672
kind: Secret
7773
metadata:
7874
name: my-secret
79-
namespace: '{{ parameter "my-namespace" | json }}'
75+
namespace: '{{ parameter "my-namespace" }}'
8076
----
8177

8278
If the parameter did not exist, the resulting resource would look like:

documentation/modules/ROOT/pages/reference/servicebrokerconfigs.adoc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,7 @@ Configuration binding parameters are defined as follows:
429429
----
430430
registry:
431431
- name: my-key
432-
value: '{{ generatePassword 32 nil | json }}'
432+
value: '{{ generatePassword 32 nil }}'
433433
templates:
434434
- my-template
435435
readinessChecks: []
@@ -499,8 +499,8 @@ readinessChecks:
499499
- condition:
500500
apiVersion: apps/v1
501501
kind: Deployment
502-
namespace: '{{ registry "namespace" | json }}'
503-
name: '{{ registry "instance-name" | json }}'
502+
namespace: '{{ registry "namespace" }}'
503+
name: '{{ registry "instance-name" }}'
504504
type: Available
505505
status: "True"
506506
----

documentation/modules/ROOT/pages/reference/template-functions.adoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ The result type will be any type.
115115
== `json`
116116

117117
The `json` function serializes its input as a JSON string.
118+
All templates implicitly append the JSON function to their pipelines as this is required by the Service Broker for all operations.
119+
This is only performed for simple, single pipeline actions, therefore complex action involving control flow are not supported at present.
118120

119121
[source]
120122
----

examples/configurations/couchbase-server/broker.yaml

Lines changed: 47 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ spec:
264264
subjects:
265265
- kind: ServiceAccount
266266
name: couchbase-operator
267-
namespace: '{{ registry "namespace" | json }}'
267+
namespace: '{{ registry "namespace" }}'
268268
- name: couchbase-operator-deployment
269269
singleton: true
270270
template:
@@ -309,116 +309,116 @@ spec:
309309
apiVersion: v1
310310
kind: Secret
311311
metadata:
312-
name: '{{ printf "%v-admin" (registry "instance-name") | json }}'
312+
name: '{{ printf "%v-admin" (registry "instance-name") }}'
313313
stringData:
314314
username: Administrator
315-
password: '{{ parameter "/password" | json }}'
315+
password: '{{ parameter "/password" }}'
316316
- name: couchbase-operator-tls-secret
317317
template:
318318
apiVersion: v1
319319
kind: Secret
320320
metadata:
321-
name: '{{ printf "%v-operator-tls" (registry "instance-name") | json }}'
321+
name: '{{ printf "%v-operator-tls" (registry "instance-name") }}'
322322
stringData:
323-
ca.crt: '{{ registry "ca-cert" | json }}'
323+
ca.crt: '{{ registry "ca-cert" }}'
324324
- name: couchbase-server-tls-secret
325325
template:
326326
apiVersion: v1
327327
kind: Secret
328328
metadata:
329-
name: '{{ printf "%v-server-tls" (registry "instance-name") | json }}'
329+
name: '{{ printf "%v-server-tls" (registry "instance-name") }}'
330330
stringData:
331-
pkey.key: '{{ registry "server-key" | json }}'
332-
chain.pem: '{{ registry "server-cert" | json }}'
331+
pkey.key: '{{ registry "server-key" }}'
332+
chain.pem: '{{ registry "server-cert" }}'
333333
- name: selector-snippet
334334
template:
335335
matchLabels:
336-
cluster: '{{ registry "instance-name" | json }}'
336+
cluster: '{{ registry "instance-name" }}'
337337
- name: couchbase-developer-private
338338
template:
339339
apiVersion: couchbase.com/v2
340340
kind: CouchbaseCluster
341341
metadata:
342-
name: '{{ registry "instance-name" | json }}'
342+
name: '{{ registry "instance-name" }}'
343343
spec:
344-
image: '{{ parameter "/image" | default "couchbase/server:6.5.0" | json }}'
344+
image: '{{ parameter "/image" | default "couchbase/server:6.5.0" }}'
345345
security:
346-
adminSecret: '{{ printf "%v-admin" (registry "instance-name") | json }}'
346+
adminSecret: '{{ printf "%v-admin" (registry "instance-name") }}'
347347
rbac:
348348
managed: true
349-
selector: '{{ snippet "selector-snippet" | json }}'
349+
selector: '{{ snippet "selector-snippet" }}'
350350
networking:
351351
tls:
352352
static:
353-
operatorSecret: '{{ printf "%v-operator-tls" (registry "instance-name") | json }}'
354-
serverSecret: '{{ printf "%v-server-tls" (registry "instance-name") | json }}'
353+
operatorSecret: '{{ printf "%v-operator-tls" (registry "instance-name") }}'
354+
serverSecret: '{{ printf "%v-server-tls" (registry "instance-name") }}'
355355
buckets:
356356
managed: true
357-
selector: '{{ snippet "selector-snippet" | json }}'
357+
selector: '{{ snippet "selector-snippet" }}'
358358
servers:
359359
- name: default
360360
services:
361361
- data
362362
- index
363363
- query
364-
size: '{{ parameter "/size" | default 3 | json }}'
364+
size: '{{ parameter "/size" | default 3 }}'
365365
- name: couchbase-bucket
366366
template:
367367
apiVersion: couchbase.com/v2
368368
kind: CouchbaseBucket
369369
metadata:
370-
name: '{{ registry "binding-name" | json }}'
371-
labels: '{{ snippet "selector-snippet" | json }}'
370+
name: '{{ registry "binding-name" }}'
371+
labels: '{{ snippet "selector-snippet" }}'
372372
- name: couchbase-user-secret
373373
template:
374374
apiVersion: v1
375375
kind: Secret
376376
metadata:
377-
name: '{{ registry "binding-name" | json }}'
377+
name: '{{ registry "binding-name" }}'
378378
data:
379-
password: '{{ registry "password" | json }}'
379+
password: '{{ registry "password" }}'
380380
- name: couchbase-user
381381
template:
382382
apiVersion: couchbase.com/v2
383383
kind: CouchbaseUser
384384
metadata:
385-
name: '{{ registry "binding-name" | json }}'
386-
labels: '{{ snippet "selector-snippet" | json }}'
385+
name: '{{ registry "binding-name" }}'
386+
labels: '{{ snippet "selector-snippet" }}'
387387
spec:
388388
authDomain: local
389-
authSecret: '{{ registry "binding-name" | json }}'
389+
authSecret: '{{ registry "binding-name" }}'
390390
- name: couchbase-group
391391
template:
392392
apiVersion: couchbase.com/v2
393393
kind: CouchbaseGroup
394394
metadata:
395-
name: '{{ registry "binding-name" | json }}'
396-
labels: '{{ snippet "selector-snippet" | json }}'
395+
name: '{{ registry "binding-name" }}'
396+
labels: '{{ snippet "selector-snippet" }}'
397397
spec:
398398
roles:
399399
- name: bucket_admin
400-
bucket: '{{ registry "binding-name" | json }}'
400+
bucket: '{{ registry "binding-name" }}'
401401
- name: couchbase-role-binding
402402
template:
403403
apiVersion: couchbase.com/v2
404404
kind: CouchbaseRoleBinding
405405
metadata:
406-
name: '{{ registry "binding-name" | json }}'
407-
labels: '{{ snippet "selector-snippet" | json }}'
406+
name: '{{ registry "binding-name" }}'
407+
labels: '{{ snippet "selector-snippet" }}'
408408
spec:
409409
subjects:
410410
- kind: CouchbaseUser
411-
name: '{{ registry "binding-name" | json }}'
411+
name: '{{ registry "binding-name" }}'
412412
roleRef:
413413
kind: CouchbaseGroup
414-
name: '{{ registry "binding-name" | json }}'
414+
name: '{{ registry "binding-name" }}'
415415
- name: credentials
416416
template:
417-
connection-string: '{{ printf "couchbases://%v-srv.%v" (registry "instance-name") (registry "namespace") | json }}'
418-
ca.pem: '{{ registry "ca-cert" | json }}'
419-
username: '{{ registry "username" | json }}'
420-
password: '{{ registry "password" | json }}'
421-
bucket: '{{ registry "binding-name" | json }}'
417+
connection-string: '{{ printf "couchbases://%v-srv.%v" (registry "instance-name") (registry "namespace") }}'
418+
ca.pem: '{{ registry "ca-cert" }}'
419+
username: '{{ registry "username" }}'
420+
password: '{{ registry "password" }}'
421+
bucket: '{{ registry "binding-name" }}'
422422
# Bindings bind templates to service plans. These allow the specification of
423423
# exactly what templates are created when a plan is instantiated or bound to.
424424
bindings:
@@ -428,17 +428,17 @@ spec:
428428
serviceInstance:
429429
registry:
430430
- name: instance-name
431-
value: '{{ printf "instance-%s" (generatePassword 8 "abcdefghijklmnopqrstuvwxyz0123456789") | json }}'
431+
value: '{{ printf "instance-%s" (generatePassword 8 "abcdefghijklmnopqrstuvwxyz0123456789") }}'
432432
- name: dashboard-url
433-
value: '{{ printf "https://%s.%s:18091" (registry "instance-name") (registry "namespace") | json }}'
433+
value: '{{ printf "https://%s.%s:18091" (registry "instance-name") (registry "namespace") }}'
434434
- name: ca-key
435-
value: '{{ generatePrivateKey "RSA" "PKCS#8" 2048 | json}}'
435+
value: '{{ generatePrivateKey "RSA" "PKCS#8" 2048 }}'
436436
- name: ca-cert
437-
value: '{{ generateCertificate (registry "ca-key") "Couchbase Server CA" "87600h" "CA" nil nil nil | json }}'
437+
value: '{{ generateCertificate (registry "ca-key") "Couchbase Server CA" "87600h" "CA" nil nil nil }}'
438438
- name: server-key
439-
value: '{{ generatePrivateKey "RSA" "PKCS#1" 2048 | json }}'
439+
value: '{{ generatePrivateKey "RSA" "PKCS#1" 2048 }}'
440440
- name: server-cert
441-
value: '{{ generateCertificate (registry "server-key") "Couchbase Server" "87600h" "Server" (list (printf "DNS:%s-srv" (registry "instance-name")) (printf "DNS:%s-srv.%s" (registry "instance-name") (registry "namespace")) (printf "DNS:%s-srv.%s.svc" (registry "instance-name") (registry "namespace")) (printf "DNS:*.%s" (registry "instance-name")) (printf "DNS:*.%s.%s" (registry "instance-name") (registry "namespace")) (printf "DNS:*.%s.%s.svc" (registry "instance-name") (registry "namespace")) "DNS:localhost") (registry "ca-key") (registry "ca-cert") | json }}'
441+
value: '{{ generateCertificate (registry "server-key") "Couchbase Server" "87600h" "Server" (list (printf "DNS:%s-srv" (registry "instance-name")) (printf "DNS:%s-srv.%s" (registry "instance-name") (registry "namespace")) (printf "DNS:%s-srv.%s.svc" (registry "instance-name") (registry "namespace")) (printf "DNS:*.%s" (registry "instance-name")) (printf "DNS:*.%s.%s" (registry "instance-name") (registry "namespace")) (printf "DNS:*.%s.%s.svc" (registry "instance-name") (registry "namespace")) "DNS:localhost") (registry "ca-key") (registry "ca-cert") }}'
442442
templates:
443443
- couchbase-operator-serviceaccount
444444
- couchbase-operator-role
@@ -453,18 +453,18 @@ spec:
453453
condition:
454454
apiVersion: couchbase.com/v2
455455
kind: CouchbaseCluster
456-
namespace: '{{ registry "namespace" | json }}'
457-
name: '{{ registry "instance-name" | json }}'
456+
namespace: '{{ registry "namespace" }}'
457+
name: '{{ registry "instance-name" }}'
458458
type: Available
459459
status: "True"
460460
serviceBinding:
461461
registry:
462462
- name: binding-name
463-
value: '{{ printf "binding-%s" (registry "binding-id") | json }}'
463+
value: '{{ printf "binding-%s" (registry "binding-id") }}'
464464
- name: password
465-
value: '{{ generatePassword 32 nil | json }}'
465+
value: '{{ generatePassword 32 nil }}'
466466
- name: credentials
467-
value: '{{ snippet "credentials" | json }}'
467+
value: '{{ snippet "credentials" }}'
468468
templates:
469469
- couchbase-bucket
470470
- couchbase-group

0 commit comments

Comments
 (0)