Stencil Placeholders syntax
Overview
Stencil Placeholders are a simple yet powerful syntax for the rendering of Stencils. They are focused on simplicity of use and maintenance.
Stencil Placeholders lack control flows like if then else
or for loops
to encourage simplicity in configuration templates. We provide tools to manage groups of Stencils through Formations, Base Templates and tags, and encourage the breaking up of large and complex Stencils.
Syntax basics
- All Stencil Placeholders are placed inside
${...}
. - Placeholders are always used in a single line. Multi-line placeholders are not valid although the result of a placeholder could be multiple lines.
- Strings should be enclosed in quotes while Directives and Functions should not. For example this is valid:
${concat(service, "-dep")}
but this is not${concat("service", -dep)}
Dot notation
You can call hierarchical elements of an application via Placeholders using dot notation. For example ${service.port.container}
will fetch the targetport
for a particular service.
As with all Stencil Placeholders, this notation is dependent on the rendering context of the Stencil itself. When you add Stencils to a Formation, they can apply to either a service or the application as a whole. So our example above only applies to Stencils that are service-related, and the ${service.port.container}
call would simply fail in an application-level Stencil.
Data types and operators
The Placeholders syntax supports some common data formats and operators:
Arrays:
These use a similar format to Ruby arrays - comma separated values with quote-delimited strings.
Example: [1, 2, "abc", formation]
Hashes:
These use a similar format to Ruby hashes - comma separated key:value pairs with with quote-delimited strings. Note that Directives are not quote-delimited.
Example:
{ "foo": 1, "formation_name" : formation, "complex" : concat("hey", " you")}
Locals:
Locals
are local variables defined within the context of the current template. These are useful for inline
functions (see below) because they allow you to set or call values contextually (e.g. "pull in my _deployspec.yml
and but set the port to 8080
")
Simple if
statements:
These use the format if(CONDITION, TRUE_RESULT, FALSE_RESULT)
where CONDITION is any boolean condition (no AND or OR). Comparisons supported are ==
, !=
>=
, <=
, >
and <
. True
and False
are also supported conditions.
Example:
namespace: ${if(formation != "production", "dev", "live")}
This would set the namespace to "live" if the formation is named "production" or to "dev" if it's named anything else.
Placeholder types
There are 2 types of placeholders:
- Directives
- Functions
Directives
Directives are like constants that are set at the beginning of rendering. Their value doesn't change throughout the rendering and they are not used to manipulate data, only to retrieve it. An example is formation
which returns the name of the formation or snapshot
which returns the unique ID of the snapshot being used for rendering a Stencil.
It is possible for a Directive to have multiple attributes. For example, the service
Directive has attributes like image
and tag
which return the service's Docker image name and image tag. To address the different attributes of a Directive, use dot notation: e.g. service.image
.
Functions
Functions are used to retrieve or manipulate data. For example you can use the concat("foo", "bar")
function to concatenate 2 or more strings together. Another example is now()
which returns the time now. Functions are always followed by (arguments)
. If no argument is passed to a function, the ()
should still be present.
Directives
application
Usage: ${application.attribute}
Returns the attributes of an application. Default (with no attribute) returns the Kubernetes-friendly name of a Skycap application (stack). All invalid characters are replaced with -
(dash).
Attributes:
name
(default) – Name of the applicationconfigstore_namspace
- UID of the application's ConfigStore
formation
Usage: ${formation}
Default (with no attribute) returns the Kubernetes-friendly name of the Formation. All invalid characters are replaced with -
(dash).
Attributes:
name
(default) – Name of the formationUUID
- Unique identifier for the formation
service
Usage: ${service.attribute}
Returns the attributes of a service.
Default (with no attribute) returns the Kubernetes-friendly name of the service that's relevant for this Stencil. You can choose the relevant service when creating and editing a Stencil.
Attributes:
name
(default) – Name of the serviceimage
– Docker image nametag
– Image tagdisplay_name
– Display name of the serviceaddress
– Services DNS addresstags
– Array of all tags for this servicesource_type
– Base of this service:image
orgit
ports
- Array of all ports defined for the serviceport
- the first port within theports
array.
snapshot
Usage: ${snapshot.attribute}
Returns attributes of a snapshot. Defaults to the Snapshot's UID if no attribute is supplied.
Attributes:
uid
(default) – Unique ID of the Snapshotgitref
– Gitref for a Stencil from that Stencil's git repository
Functions
base64
Usage: base64({hash})
Encodes a set of values in Base64 format. Only the values are encoded - not the keys.
concat
Usage: concat("stringA", "stringB",...)
Concatenates the specified strings into a single string.
configstore
Usage:
configstore("key", account.configstore_namespace)
ORconfigstore("key", application.configstore_namespace)
Returns the value for a key from a Cloud 66 ConfigStore. If no namespace is specified this will default to the application-level ConfigStore of the current app.
You can also fetch values from an account-level ConfigStore using the namespace UID as the lookup. The same can be done using the application
parameter to fetch values from another application-level ConfigStore.
For example:
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
namespace: ${formation}
name: mysql-pvc
spec:
accessModes:
- ${configstore("mysql_access_mode", account.configstore_namespace)}
resources:
requests:
storage: ${configstore("mysql_storage", application.configstore_namespace)}
count
Usage: count([array values])
Returns the number of items in an array or any countable objects e.g. strings. For example:
count([4578, 2178] # returns 2
count([dog, fish, bird] # returns 3
count("abc") # returns 3
digest
Usage: digest(text, algorithm, encoding)
Returns an encoded and digested copy of the given text. The options for algorithm are:
md5
sha1
sha2
The options for encoding are:
base64
hex
env
Usage: env(name, default)
Returns the value of an environment variable from the Stack Environment Variables. For example env("RAILS_ENV")
returns the value for RAILS_ENV
. env("RAILS_ENV", "production")
returns production
if there is no value available for RAILS_ENV
.
If an environment variable is defined in both Stack Environment Variables and service.yml
for the service this Stencil is related to, the service defined environment variable will be returned.
envlist
Usage: envlist(tag)
Returns a YAML compatible list of all Stack Environment Variables. This is useful when you don't want to keep adding new environment variables to every deployment one by one. For example envlist
returns the following:
- RAILS_ENV: 'production'
- USER_ID: 'e25fa2bhc'
- API_ENDPOINT: '[https://api.acme.org](https://api.acme.org/)'
Using tag
returns only the environment variables that match it. You can set the tags for each environment variable on the Stack Environment Variables page on Skycap dashboard.
Example: envlist("secret")
returns only the list of environment variables tagged with secret
.
inline
Usage: inline(stencil, indent, locals)
Returns the rendered content of a Stencil. For example: inline("disks.yml")
will return the rendered value of an inline Stencil called _disks.yml
.
As Stencils are almost always yaml files, indentation is important. The indent
argument ensures all returned values are indented by the contextually-appropriate number of spaces.
The locals
parameter is optional and can be a hash. It will use any keys provided as Directives. For example inline("test.yml", 2, { "foo": "bar" })
will fetch the contents of test.yml, indent it by two spaces and then set the Placeholder named ${locals.foo}
to the value "bar".
Example:
kind: Deployment
metadata:
namespace: ${formation}
name: ${concat(service, "-dep")}
spec:
template:
metadata:
labels:
app: ${stackname}
tier: ${service}
spec:
$inline("_deploy_spec.yml",4,{ "service.port.http": "8080" })
This example fetches the contents of a partial Stencil called deploy_spec
, indents it by four spaces and then sets the service.port.http
to 8080.
now
Usage: now([formatting])
Returns the time of rendering. If no formatting is provided, it will return the date and time like this 2018-03-07 09:57:36 UTC
. Valid values for the formatting are:
year
month
day
hour
minute
second
epoch
Alternatively you can use the following:
%Y - Year with century (can be negative, 4 digits at least)
-0001, 0000, 1995, 2009, 14292, etc.
%C - year / 100 (round down. 20 in 2009)
%y - year % 100 (00..99)
%m - Month of the year, zero-padded (01..12)
%_m blank-padded ( 1..12)
%-m no-padded (1..12)
%B - The full month name (`January'') %^B uppercased (`JANUARY'')
%b - The abbreviated month name (`Jan'') %^b uppercased (`JAN'')
%h - Equivalent to %b
%d - Day of the month, zero-padded (01..31)
%-d no-padded (1..31)
%e - Day of the month, blank-padded ( 1..31)
%j - Day of the year (001..366)
Time (Hour, Minute, Second, Subsecond):
%H - Hour of the day, 24-hour clock, zero-padded (00..23)
%k - Hour of the day, 24-hour clock, blank-padded ( 0..23)
%I - Hour of the day, 12-hour clock, zero-padded (01..12)
%l - Hour of the day, 12-hour clock, blank-padded ( 1..12)
%P - Meridian indicator, lowercase (`am'' or`pm'')
%p - Meridian indicator, uppercase (`AM'' or`PM'')
%M - Minute of the hour (00..59)
%S - Second of the minute (00..59)
%L - Millisecond of the second (000..999)
%N - Fractional seconds digits, default is 9 digits (nanosecond)
%3N millisecond (3 digits)
%6N microsecond (6 digits)
%9N nanosecond (9 digits)
%12N picosecond (12 digits)
Time zone:
%z - Time zone as hour and minute offset from UTC (e.g. +0900)
%:z - hour and minute offset from UTC with a colon (e.g. +09:00)
%::z - hour, minute and second offset from UTC (e.g. +09:00:00)
%:::z - hour, minute and second offset from UTC
(e.g. +09, +09:30, +09:30:30)
%Z - Time zone abbreviation name
Weekday:
%A - The full weekday name (`Sunday'') %^A uppercased (`SUNDAY'')
%a - The abbreviated name (`Sun'') %^a uppercased (`SUN'')
%u - Day of the week (Monday is 1, 1..7)
%w - Day of the week (Sunday is 0, 0..6)
ISO 8601 week-based year and week number:
The week 1 of YYYY starts with a Monday and includes YYYY-01-04.
The days in the year before the first week are in the last week of
the previous year.
%G - The week-based year
%g - The last 2 digits of the week-based year (00..99)
%V - Week number of the week-based year (01..53)
Week number:
The week 1 of YYYY starts with a Sunday or Monday (according to %U
or %W). The days in the year before the first week are in week 0.
%U - Week number of the year. The week starts with Sunday. (00..53)
%W - Week number of the year. The week starts with Monday. (00..53)
Seconds since the Unix Epoch:
%s - Number of seconds since 1970-01-01 00:00:00 UTC.
%Q - Number of microseconds since 1970-01-01 00:00:00 UTC.
Literal string:
%n - Newline character (\n)
%t - Tab character (\t)
%% - Literal ``%'' character
Combination:
%c - date and time (%a %b %e %T %Y)
%D - Date (%m/%d/%y)
%F - The ISO 8601 date format (%Y-%m-%d)
%v - VMS date (%e-%b-%Y)
%x - Same as %D
%X - Same as %T
%r - 12-hour time (%I:%M:%S %p)
%R - 24-hour time (%H:%M)
%T - 24-hour time (%H:%M:%S)
%+ - date(1) (%a %b %e %H:%M:%S %Z %Y)
random
Usage: random(length)
Returns a random string with the given length.
registry_credentials
Usage: registry_credentials([registry_address])
Returns the base 64 encoded version of the Kubernetes friendly credentials for a Docker registry. Read the Pulling image from a private registry in Kubernetes document for more information. The result of this function can be used directly as the value for the .dockerconfigjson
secret of kubernetes.io/dockerconfigjson
type.
If no registry_address
is given, the BuildGrid registry credentials are returned. To pull any other registry's credentials, use the name of the registry used when adding it to your Cloud 66 Skycap account under Accounts / External Keys and Services section. For example, if you have a Quay.io added to the list of your registries, you can use registry_credentials("quay.io")
to retrieve the credential.
Here is an example on how to set up a secret using registry_credentials
,
apiVersion: v1
kind: Secret
metadata:
namespace: foo
name: bar-docker-registry-secret-name
type: Opaque
data:
.dockerconfigjson: ${registry_credentials()}
...and then use it in a deployment.
apiVersion: v1
kind: Deployment
metadata:
namespace: foo
spec:
template:
spec:
imagePullSecrets:
- name: bar-docker-registry-secret-name
repeat_inline
Usage: repeat_inline(filename, indent, locals, count)
This is an extension of the inline
function (see above) which repeats an inline either by the number of variables set in locals
or by the count
parameter.
In this context locals
can be an array or hash. If it is an array, each item should be expressed as a hash. The inline will be rendered count(locals) times (i.e. if there are 3 items in the array, it will be repeated 3 times), each time using the value of each hash in the array.
For example:
${repeat_inline("test.yml", 8, [ { "foo" : "bar" }, { "foo" : "buzz" } ])} # render test twice, one with foo=bar and once with foo=buzz
If count
is provided, it should be a number. In this case inline will be repeated count
times, each time with locals
provided as the locals in the normal inline function. In this case locals
should be a hash. For example:
${repeat_inline("test.yml", 4, { "foo": "bar" }, 12)} # render test 12 times, every time with foo=bar
Repeating inlines can fetch loop information using locals_index
(for the current iteration index) and locals_count
(for the total count). For example you could use this:
This is the ${locals_index} time out of ${locals_count} renders of ${foo}
...to check which iteration of an inline is being rendered.
require
Usage: require(message)
Stops rendering of the Stencil and returns an error with the message. This is used when you would like to create a Stencil template and make sure the end user of the Stencil supplies an important value before attempting to render it. For example require("PORT")
will return a render error saying PORT is required
sanitize
Usage: sanitize(text)
Returns the "DNS friendly" version of the given text. For example sanitize("Hello World!")
will return hello-world-
.
vault
Usage: vault("/path_root/path_to_key", "key_name")
Fetches the named value from the specified path in the Vault that is attached to the current Cloud 66 account (i.e. the one which holds the current application).
For example, if your production MySQL password is stored in /production/MySQL
with the key name mysql_pass
then the placeholder would be:
{vault("/production/MySQL", "mysql_pass")}
vaultlist
Usage: vaultlist("/path_root/path_to_keys")
Fetches all the available values from any path in Vault. As above, the Vault must be attached to the current Cloud 66 account
The example below would pull all of the values from the /production/mysql
path.
apiVersion: v1
kind: Secret
metadata:
namespace: another_app
name: all_secrets
labels:
app: ${stackname}
type: Opaque
data:
${vaultlist("/production/mysql", 2)}