2016-10-31 04:05:05 +00:00
|
|
|
---
|
2020-02-06 23:45:31 +00:00
|
|
|
layout: docs
|
|
|
|
page_title: template Stanza - Job Specification
|
|
|
|
sidebar_title: template
|
2016-10-31 04:05:05 +00:00
|
|
|
description: |-
|
|
|
|
The "template" block instantiates an instance of a template renderer. This
|
|
|
|
creates a convenient way to ship configuration files that are populated from
|
2017-01-24 17:12:42 +00:00
|
|
|
environment variables, Consul data, Vault secrets, or just general
|
|
|
|
configurations within a Nomad task.
|
2016-10-31 04:05:05 +00:00
|
|
|
---
|
|
|
|
|
|
|
|
# `template` Stanza
|
|
|
|
|
2020-02-06 23:45:31 +00:00
|
|
|
<Placement groups={['job', 'group', 'task', 'template']} />
|
2016-10-31 04:05:05 +00:00
|
|
|
|
|
|
|
The `template` block instantiates an instance of a template renderer. This
|
|
|
|
creates a convenient way to ship configuration files that are populated from
|
2017-01-24 17:12:42 +00:00
|
|
|
environment variables, Consul data, Vault secrets, or just general
|
|
|
|
configurations within a Nomad task.
|
2016-10-31 04:05:05 +00:00
|
|
|
|
|
|
|
```hcl
|
|
|
|
job "docs" {
|
|
|
|
group "example" {
|
|
|
|
task "server" {
|
|
|
|
template {
|
|
|
|
source = "local/redis.conf.tpl"
|
|
|
|
destination = "local/redis.conf"
|
|
|
|
change_mode = "signal"
|
2017-03-14 09:12:48 +00:00
|
|
|
change_signal = "SIGINT"
|
2016-10-31 04:05:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2017-01-24 01:02:13 +00:00
|
|
|
Nomad utilizes a tool called [Consul Template][ct]. Since Nomad v0.5.3, the
|
2017-03-27 21:58:04 +00:00
|
|
|
template can reference [Nomad's runtime environment variables][env]. Since Nomad
|
|
|
|
v0.5.6, the template can reference [Node attributes and metadata][nodevars]. For
|
|
|
|
a full list of the API template functions, please refer to the [Consul Template
|
2017-05-24 00:24:21 +00:00
|
|
|
README][ct]. Since Nomad v0.6.0, templates can be read as environment variables.
|
2016-10-31 04:05:05 +00:00
|
|
|
|
|
|
|
## `template` Parameters
|
|
|
|
|
2017-02-01 04:00:33 +00:00
|
|
|
- `change_mode` `(string: "restart")` - Specifies the behavior Nomad should take
|
2017-05-03 19:40:27 +00:00
|
|
|
if the rendered template changes. Nomad will always write the new contents of
|
|
|
|
the template to the specified destination. The possible values below describe
|
|
|
|
Nomad's action after writing the template to disk.
|
2017-02-01 04:00:33 +00:00
|
|
|
|
|
|
|
- `"noop"` - take no action (continue running the task)
|
|
|
|
- `"restart"` - restart the task
|
|
|
|
- `"signal"` - send a configurable signal to the task
|
|
|
|
|
2017-01-26 05:16:18 +00:00
|
|
|
- `change_signal` `(string: "")` - Specifies the signal to send to the task as a
|
|
|
|
string like `"SIGUSR1"` or `"SIGINT"`. This option is required if the
|
|
|
|
`change_mode` is `signal`.
|
2016-10-31 04:05:05 +00:00
|
|
|
|
|
|
|
- `data` `(string: "")` - Specifies the raw template to execute. One of `source`
|
|
|
|
or `data` must be specified, but not both. This is useful for smaller
|
|
|
|
templates, but we recommend using `source` for larger templates.
|
|
|
|
|
2017-01-26 05:16:18 +00:00
|
|
|
- `destination` `(string: <required>)` - Specifies the location where the
|
2020-10-15 13:53:25 +00:00
|
|
|
resulting template should be rendered, relative to the [task working
|
2020-10-16 15:38:23 +00:00
|
|
|
directory]. Only drivers without filesystem isolation (ex. `raw_exec`) or
|
2020-11-04 14:59:19 +00:00
|
|
|
that build a chroot in the task working directory (ex. `exec`) can render
|
2020-10-16 15:38:23 +00:00
|
|
|
templates outside of the `NOMAD_ALLOC_DIR`, `NOMAD_TASK_DIR`, or
|
2020-11-04 14:59:19 +00:00
|
|
|
`NOMAD_SECRETS_DIR`. For more details on how `destination` interacts with
|
|
|
|
task drivers, see the [Filesystem internals] documentation.
|
2017-01-26 05:16:18 +00:00
|
|
|
|
2017-05-24 00:24:21 +00:00
|
|
|
- `env` `(bool: false)` - Specifies the template should be read back in as
|
2020-11-23 15:02:27 +00:00
|
|
|
environment variables for the task ([see below](#environment-variables)). To
|
|
|
|
update the environment on changes, you must set `change_mode` to
|
|
|
|
`restart`. Setting `env` when the `change_mode` is `signal` will return a
|
|
|
|
validation error. Setting `env` when the `change_mode` is `noop` is
|
|
|
|
permitted but will not update the environment variables in the task.
|
2017-05-24 00:24:21 +00:00
|
|
|
|
|
|
|
- `left_delimiter` `(string: "{{")` - Specifies the left delimiter to use in the
|
2017-02-21 00:43:28 +00:00
|
|
|
template. The default is "{{" for some templates, it may be easier to use a
|
|
|
|
different delimiter that does not conflict with the output file itself.
|
|
|
|
|
2017-05-24 16:54:22 +00:00
|
|
|
- `perms` `(string: "644")` - Specifies the rendered template's permissions.
|
2019-02-21 17:47:18 +00:00
|
|
|
File permissions are given as octal of the Unix file permissions `rwxrwxrwx`.
|
2016-10-31 04:05:05 +00:00
|
|
|
|
2017-05-24 00:24:21 +00:00
|
|
|
- `right_delimiter` `(string: "}}")` - Specifies the right delimiter to use in the
|
2017-02-21 00:43:28 +00:00
|
|
|
template. The default is "}}" for some templates, it may be easier to use a
|
|
|
|
different delimiter that does not conflict with the output file itself.
|
|
|
|
|
2017-01-26 05:16:18 +00:00
|
|
|
- `source` `(string: "")` - Specifies the path to the template to be rendered.
|
|
|
|
One of `source` or `data` must be specified, but not both. This source can
|
|
|
|
optionally be fetched using an [`artifact`][artifact] resource. This template
|
|
|
|
must exist on the machine prior to starting the task; it is not possible to
|
|
|
|
reference a template inside of a Docker container, for example.
|
2016-10-31 04:05:05 +00:00
|
|
|
|
|
|
|
- `splay` `(string: "5s")` - Specifies a random amount of time to wait between
|
2017-07-17 18:41:50 +00:00
|
|
|
0 ms and the given splay value before invoking the change mode. This is
|
2016-10-31 04:05:05 +00:00
|
|
|
specified using a label suffix like "30s" or "1h", and is often used to
|
|
|
|
prevent a thundering herd problem where all task instances restart at the same
|
|
|
|
time.
|
|
|
|
|
2020-02-17 17:39:47 +00:00
|
|
|
- `vault_grace` `(string: "15s")` - [Deprecated](https://github.com/hashicorp/consul-template/issues/1268)
|
2017-08-01 21:14:08 +00:00
|
|
|
|
2016-10-31 04:05:05 +00:00
|
|
|
## `template` Examples
|
|
|
|
|
|
|
|
The following examples only show the `template` stanzas. Remember that the
|
|
|
|
`template` stanza is only valid in the placements listed above.
|
|
|
|
|
|
|
|
### Inline Template
|
|
|
|
|
2016-10-31 20:51:06 +00:00
|
|
|
This example uses an inline template to render a file to disk. This file watches
|
|
|
|
various keys in Consul for changes:
|
2016-10-31 04:05:05 +00:00
|
|
|
|
|
|
|
```hcl
|
|
|
|
template {
|
|
|
|
data = "---\nkey: {{ key \"service/my-key\" }}"
|
|
|
|
destination = "local/file.yml"
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2016-10-31 20:51:06 +00:00
|
|
|
It is also possible to use heredocs for multi-line templates, like:
|
|
|
|
|
|
|
|
```hcl
|
|
|
|
template {
|
|
|
|
data = <<EOH
|
|
|
|
---
|
2017-01-24 01:02:13 +00:00
|
|
|
bind_port: {{ env "NOMAD_PORT_db" }}
|
|
|
|
scratch_dir: {{ env "NOMAD_TASK_DIR" }}
|
2017-07-25 23:53:10 +00:00
|
|
|
node_id: {{ env "node.unique.id" }}
|
2017-01-23 23:50:38 +00:00
|
|
|
service_key: {{ key "service/my-key" }}
|
2016-10-31 20:51:06 +00:00
|
|
|
EOH
|
|
|
|
|
|
|
|
destination = "local/file.yml"
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2016-10-31 04:05:05 +00:00
|
|
|
### Remote Template
|
|
|
|
|
|
|
|
This example uses an [`artifact`][artifact] stanza to download an input template
|
|
|
|
before passing it to the template engine:
|
|
|
|
|
|
|
|
```hcl
|
|
|
|
artifact {
|
|
|
|
source = "https://example.com/file.yml.tpl"
|
|
|
|
destination = "local/file.yml.tpl"
|
|
|
|
}
|
|
|
|
|
|
|
|
template {
|
|
|
|
source = "local/file.yml.tpl"
|
|
|
|
destination = "local/file.yml"
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2017-03-27 21:58:04 +00:00
|
|
|
### Node Variables
|
|
|
|
|
|
|
|
As of Nomad v0.5.6 it is possible to access the Node's attributes and metadata.
|
|
|
|
|
|
|
|
```hcl
|
|
|
|
template {
|
|
|
|
data = <<EOH
|
|
|
|
---
|
|
|
|
node_dc: {{ env "node.datacenter" }}
|
|
|
|
node_cores: {{ env "attr.cpu.numcores" }}
|
|
|
|
meta_key: {{ env "meta.node_meta_key" }}
|
|
|
|
EOH
|
|
|
|
|
|
|
|
destination = "local/file.yml"
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2017-05-24 00:24:21 +00:00
|
|
|
### Environment Variables
|
|
|
|
|
|
|
|
Since v0.6.0 templates may be used to create environment variables for tasks.
|
2019-02-21 17:47:18 +00:00
|
|
|
Env templates work exactly like other templates except once the templates are
|
|
|
|
written, they are parsed as `KEY=value` pairs. Those key value pairs are
|
|
|
|
included in the task's environment.
|
2017-05-24 00:24:21 +00:00
|
|
|
|
|
|
|
For example the following template stanza:
|
|
|
|
|
|
|
|
```hcl
|
|
|
|
template {
|
|
|
|
data = <<EOH
|
|
|
|
# Lines starting with a # are ignored
|
|
|
|
|
|
|
|
# Empty lines are also ignored
|
2017-07-24 23:40:39 +00:00
|
|
|
LOG_LEVEL="{{key "service/geo-api/log-verbosity"}}"
|
2017-12-13 10:40:22 +00:00
|
|
|
API_KEY="{{with secret "secret/geo-api-key"}}{{.Data.value}}{{end}}"
|
2017-05-24 00:24:21 +00:00
|
|
|
EOH
|
|
|
|
|
2017-07-25 16:51:11 +00:00
|
|
|
destination = "secrets/file.env"
|
2017-05-24 00:24:21 +00:00
|
|
|
env = true
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2017-05-24 20:55:21 +00:00
|
|
|
The task's environment would then have environment variables like the
|
|
|
|
following:
|
2017-05-24 00:24:21 +00:00
|
|
|
|
|
|
|
```
|
2017-07-24 23:40:39 +00:00
|
|
|
LOG_LEVEL=DEBUG
|
|
|
|
API_KEY=12345678-1234-1234-1234-1234-123456789abc
|
2017-05-24 00:24:21 +00:00
|
|
|
```
|
|
|
|
|
|
|
|
This allows [12factor app](https://12factor.net/config) style environment
|
|
|
|
variable based configuration while keeping all of the familiar features and
|
2017-05-24 20:55:21 +00:00
|
|
|
semantics of Nomad templates.
|
2017-05-24 00:24:21 +00:00
|
|
|
|
2019-02-21 17:47:18 +00:00
|
|
|
Secrets or certificates may contain a wide variety of characters such as
|
|
|
|
newlines, quotes, and backslashes which may be difficult to quote or escape
|
|
|
|
properly.
|
|
|
|
|
|
|
|
Whenever a templated variable may include special characters, use the `toJSON`
|
|
|
|
function to ensure special characters are properly parsed by Nomad:
|
2017-06-02 22:08:08 +00:00
|
|
|
|
|
|
|
```
|
|
|
|
CERT_PEM={{ file "path/to/cert.pem" | toJSON }}
|
|
|
|
```
|
|
|
|
|
|
|
|
The parser will read the JSON string, so the `$CERT_PEM` environment variable
|
|
|
|
will be identical to the contents of the file.
|
|
|
|
|
2019-02-21 17:47:18 +00:00
|
|
|
Likewise when evaluating a password that may contain quotes or `#`, use the
|
|
|
|
`toJSON` function to ensure Nomad passes the password to task unchanged:
|
|
|
|
|
|
|
|
```
|
|
|
|
# Passwords may contain any character including special characters like:
|
|
|
|
# \"'#
|
|
|
|
# Use toJSON to ensure Nomad passes them to the environment unchanged.
|
|
|
|
{{ with secret "secrets/data/application/backend" }}
|
|
|
|
DB_PASSWD={{ .Data.data.DB_PASSWD | toJSON }}
|
|
|
|
{{ end }}
|
|
|
|
```
|
|
|
|
|
2019-08-30 15:24:34 +00:00
|
|
|
For more details see [go-envparser's README][go-envparse].
|
2017-05-24 00:24:21 +00:00
|
|
|
|
2020-10-15 13:53:25 +00:00
|
|
|
### Template Destinations
|
|
|
|
|
2020-10-16 15:38:23 +00:00
|
|
|
Templates are rendered into the task working directory. Drivers without
|
|
|
|
filesystem isolation (such as `raw_exec`) or drivers that build a chroot in
|
|
|
|
the task working directory (such as `exec`) can have templates rendered to
|
|
|
|
arbitrary paths in the task. But task drivers such as `docker` can only access
|
|
|
|
templates rendered into the `NOMAD_ALLOC_DIR`, `NOMAD_TASK_DIR`, or
|
|
|
|
`NOMAD_SECRETS_DIR`. To workaround this restriction, you can create a mount
|
|
|
|
from the template `destination` to another location in the task.
|
2020-10-15 13:53:25 +00:00
|
|
|
|
|
|
|
```hcl
|
|
|
|
task "task" {
|
|
|
|
driver = "docker"
|
|
|
|
|
|
|
|
config {
|
|
|
|
image = "redis:6.0"
|
|
|
|
mounts = [
|
|
|
|
{
|
|
|
|
type = "bind"
|
|
|
|
source = "local"
|
|
|
|
target = "/etc/redis.d"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
|
|
|
|
template {
|
|
|
|
destination = "local/redis.conf"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2018-02-26 20:41:39 +00:00
|
|
|
## Vault Integration
|
|
|
|
|
2018-07-04 00:56:22 +00:00
|
|
|
### PKI Certificate
|
|
|
|
|
2019-08-30 15:24:34 +00:00
|
|
|
Vault is a popular open source tool for managing secrets. In addition to acting
|
|
|
|
as an encrypted KV store, Vault can also generate dynamic secrets, like PKI/TLS
|
|
|
|
certificates.
|
|
|
|
|
|
|
|
When generating PKI certificates with Vault, the certificate, private key, and
|
|
|
|
any intermediate certs are all returned as part of the same API call. Most
|
|
|
|
software requires these files be placed in separate files on the system.
|
|
|
|
|
|
|
|
~> **Note**: `generate_lease` must be set to `true` (non-default) on the Vault PKI
|
|
|
|
role.<br /><br /> Failure to do so will cause the template to frequently render a new
|
|
|
|
certificate, approximately every minute. This creates a significant number of
|
|
|
|
certificates to be expired in Vault and could ultimately lead to Vault performance
|
|
|
|
impacts and failures.
|
|
|
|
|
|
|
|
#### As individual files
|
|
|
|
|
|
|
|
For templates, all dependencies are mapped into a single list. This means that
|
|
|
|
multiple templates watching the same path return the same data.
|
|
|
|
|
|
|
|
```hcl
|
|
|
|
template {
|
|
|
|
data = <<EOH
|
|
|
|
{{ with secret "pki/issue/foo" "common_name=foo.service.consul" "ip_sans=127.0.0.1" }}
|
|
|
|
{{- .Data.certificate -}}
|
|
|
|
{{ end }}
|
|
|
|
EOH
|
|
|
|
destination = "${NOMAD_SECRETS_DIR}/certificate.crt"
|
|
|
|
change_mode = "restart"
|
|
|
|
}
|
|
|
|
|
|
|
|
template {
|
|
|
|
data = <<EOH
|
|
|
|
{{ with secret "pki/issue/foo" "common_name=foo.service.consul" "ip_sans=127.0.0.1" }}
|
|
|
|
{{- .Data.issuing_ca -}}
|
|
|
|
{{ end }}
|
|
|
|
EOH
|
|
|
|
destination = "${NOMAD_SECRETS_DIR}/ca.crt"
|
|
|
|
change_mode = "restart"
|
|
|
|
}
|
|
|
|
|
|
|
|
template {
|
|
|
|
data = <<EOH
|
|
|
|
{{ with secret "pki/issue/foo" "common_name=foo.service.consul" "ip_sans=127.0.0.1" }}
|
|
|
|
{{- .Data.private_key -}}
|
|
|
|
{{ end }}
|
|
|
|
EOH
|
|
|
|
destination = "${NOMAD_SECRETS_DIR}/private_key.key"
|
|
|
|
change_mode = "restart"
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
These are three different input templates, but when run under the Nomad job,
|
|
|
|
they are compressed into a single call, sharing the resulting data.
|
|
|
|
|
|
|
|
#### As a PEM formatted file
|
2020-02-06 23:45:31 +00:00
|
|
|
|
2019-08-30 15:24:34 +00:00
|
|
|
This example acquires a PKI certificate from Vault in PEM format, concatenates
|
|
|
|
the elements into a bundle, and stores it into your application's secret
|
|
|
|
directory.
|
2018-02-26 20:41:39 +00:00
|
|
|
|
2018-03-08 18:59:56 +00:00
|
|
|
```hcl
|
2018-02-26 20:41:39 +00:00
|
|
|
template {
|
|
|
|
data = <<EOH
|
|
|
|
{{ with secret "pki/issue/foo" "common_name=foo.service.consul" "ip_sans=127.0.0.1" "format=pem" }}
|
|
|
|
{{ .Data.certificate }}
|
|
|
|
{{ .Data.issuing_ca }}
|
|
|
|
{{ .Data.private_key }}{{ end }}
|
|
|
|
EOH
|
2018-03-08 18:59:56 +00:00
|
|
|
destination = "${NOMAD_SECRETS_DIR}/bundle.pem"
|
2018-02-26 20:41:39 +00:00
|
|
|
change_mode = "restart"
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2018-07-04 00:56:22 +00:00
|
|
|
### Vault KV API v1
|
|
|
|
|
|
|
|
Under Vault KV API v1, paths start with `secret/`, and the response returns the
|
|
|
|
raw key/value data. This secret was set using
|
|
|
|
`vault kv put secret/aws/s3 aws_access_key_id=somekeyid`.
|
|
|
|
|
|
|
|
```hcl
|
|
|
|
template {
|
|
|
|
data = <<EOF
|
|
|
|
AWS_ACCESS_KEY_ID = "{{with secret "secret/aws/s3"}}{{.Data.aws_access_key_id}}{{end}}"
|
|
|
|
EOF
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2020-11-19 20:09:54 +00:00
|
|
|
Note that if the name of a secret includes the `-` character, you must access
|
|
|
|
it by index. This secret was set using `vault kv put secret/app
|
|
|
|
db-password=somepassword`.
|
|
|
|
|
|
|
|
```hcl
|
|
|
|
template {
|
|
|
|
data = <<EOF
|
|
|
|
DB_PASSWORD = "{{with secret "secret/app"}}{{index .Data "db-password"}}{{end}}"
|
|
|
|
EOF
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2018-07-04 00:56:22 +00:00
|
|
|
### Vault KV API v2
|
|
|
|
|
|
|
|
Under Vault KV API v2, paths start with `secret/data/`, and the response returns
|
|
|
|
metadata in addition to key/value data. This secret was set using
|
|
|
|
`vault kv put secret/aws/s3 aws_access_key_id=somekeyid`.
|
|
|
|
|
|
|
|
```hcl
|
|
|
|
template {
|
|
|
|
data = <<EOF
|
|
|
|
AWS_ACCESS_KEY_ID = "{{with secret "secret/data/aws/s3"}}{{.Data.data.aws_access_key_id}}{{end}}"
|
|
|
|
EOF
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
Notice the addition of `data` in both the path and the field accessor string.
|
|
|
|
Additionally, when using the Vault v2 API, the Vault policies applied to your
|
|
|
|
Nomad jobs will need to grant permissions to `read` under `secret/data/...`
|
|
|
|
rather than `secret/...`.
|
|
|
|
|
2020-11-19 20:09:54 +00:00
|
|
|
Similar to KV API v1, if the name of a secret includes the `-` character, you
|
|
|
|
must access it by index. This secret was set using `vault kv put secret/app
|
|
|
|
db-password=somepassword`.
|
|
|
|
|
|
|
|
```hcl
|
|
|
|
template {
|
|
|
|
data = <<EOF
|
|
|
|
DB_PASSWORD = "{{with secret "secret/data/app"}}{{index .Data.data "db-password"}}{{end}}"
|
|
|
|
EOF
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2017-03-27 21:58:04 +00:00
|
|
|
## Client Configuration
|
2016-11-02 20:03:54 +00:00
|
|
|
|
|
|
|
The `template` block has the following [client configuration
|
2020-02-06 23:45:31 +00:00
|
|
|
options](/docs/configuration/client#options):
|
2016-11-02 20:03:54 +00:00
|
|
|
|
2020-10-30 19:56:37 +00:00
|
|
|
- `function_denylist` `([]string: ["plugin"])` - Specifies a list of template
|
|
|
|
rendering functions that should be disallowed in job specs. By default the
|
|
|
|
`plugin` function is disallowed as it allows running arbitrary commands on
|
|
|
|
the host as root (unless Nomad is configured to run as a non-root user).
|
|
|
|
|
|
|
|
- `disable_file_sandbox` `(bool: false)` - Allows templates access to arbitrary
|
|
|
|
files on the client host via the `file` function. By default templates can
|
|
|
|
access files only within the [task working directory].
|
2016-11-02 20:03:54 +00:00
|
|
|
|
2020-02-06 23:45:31 +00:00
|
|
|
[ct]: https://github.com/hashicorp/consul-template 'Consul Template by HashiCorp'
|
|
|
|
[artifact]: /docs/job-specification/artifact 'Nomad artifact Job Specification'
|
|
|
|
[env]: /docs/runtime/environment 'Nomad Runtime Environment'
|
|
|
|
[nodevars]: /docs/runtime/interpolation#interpreted_node_vars 'Nomad Node Variables'
|
|
|
|
[go-envparse]: https://github.com/hashicorp/go-envparse#readme 'The go-envparse Readme'
|
2020-10-15 14:20:56 +00:00
|
|
|
[task working directory]: /docs/runtime/environment#task-directories 'Task Directories'
|
2020-11-04 14:59:19 +00:00
|
|
|
[Filesystem internals]: /docs/internals/filesystem#templates-artifacts-and-dispatch-payloads
|