Migrate to the current template syntax
Use this guide to update a pack from the original Nomad Pack
template syntax to the current syntax. The original syntax reads a pack's
variables and metadata with dotted paths such as [[ .my.name ]]. Current
templates call functions instead, such as [[ var "name" . ]].
Nomad Pack v0.1.0 and later use the current syntax by default. Earlier releases
use the original syntax. When you run a pack that uses the original syntax on
v0.1.0 or later, Nomad Pack reports an error unless you pass the --parser-v1
flag.
This guide shows you how to:
- access variables and metadata with the
varandmetafunctions - access a pack's dependencies
- update helper and output templates
- run a pack that still uses the original syntax
For an overview of writing packs, including the available template functions, refer to Create custom packs.
Requirements
- Nomad Pack v0.1.0 or later
- A pack that uses the original
.myand.nomad_packtemplate syntax
Steps
To migrate a pack, update each place its templates read variables, metadata, and dependencies, then verify the result. Complete the following steps.
Update variable references. The original syntax accesses pack variables as fields on the template context, either through the
.myalias or the pack's name. Call thevarfunction with the variable name and the context to read it from instead. For example, a template that reads a variable namedmessagechanges from[[ .my.message ]]to the following function call:[[ var "message" . ]]The trailing
.passes the current context to the function so it knows which pack to read from. The original syntax reaches nested values with additional dots, which become a single dotted key. For example,[[ .my.resources.cpu ]]becomes[[ var "resources.cpu" . ]]. A dotted key only works when the parent variable is an object. To read every variable for a pack at once, use thevarsfunction, as in[[ vars . ]]. When a variable holds a collection, callvarwherever the original template used the field, including as the target of arange:[[ range $k, $v := var "env" . ]][[ $k ]] = [[ $v | quote ]] [[ end ]]Update metadata references. The original syntax accesses pack metadata through the
.nomad_packfield. Call themetafunction instead, which works the same way asvar. A reference to the pack name changes from[[ .nomad_pack.pack.name ]]to the following function call:[[ meta "pack.name" . ]]To read every metadata value for a pack at once, use the
metasfunction, as in[[ metas . ]].Update dependency references. The original syntax puts every pack's values on a single shared context, which makes aliased or nested dependencies hard to trace. The current syntax gives each dependency its own context. Each dependency is a field on the parent context that you pass to
varormetain place of the current context:[[ var "job_name" . ]] [[ var "job_name" .child ]]The
.reads thejob_namevariable from the current pack and.childreads thejob_namevariable from a dependency namedchild. Dependencies can nest, and thedepsfunction returns a pack's direct dependencies so you can loop over them:[[ range $dep := deps . ]][[ var "job_name" $dep ]] [[ end ]]Update helper and output templates. The same rules apply everywhere a pack renders templates, not only in jobspec files. Output templates (
outputs.tpl) and named helper templates defined withdefineshare the same context and functions. A helper that receives the pack context reads variables and metadata like the main template. A helper that sets a job's name changes from the original syntax:[[ define "job_name" ]] [[- if eq .my.job_name "" -]] [[- .nomad_pack.pack.name | quote -]] [[- else -]] [[- .my.job_name | quote -]] [[- end ]] [[- end ]]to the current syntax:
[[ define "job_name" ]] [[- if eq (var "job_name" .) "" -]] [[- meta "pack.name" . | quote -]] [[- else -]] [[- var "job_name" . | quote -]] [[- end ]] [[- end ]]Invoke the helper with the pack context so the functions can resolve values, as in
job [[ template "job_name" . ]] {. A helper that receives a plain value rather than the pack context does not change, because it reads the fields of whatever value you pass in. Update only the invocation to source that value withvar, so[[ template "resources" .my.resources ]]becomes[[ template "resources" (var "resources" .) ]].Verify the migrated pack. The
varandmetafunctions return an empty string when a key is not found, so a misspelled name renders as empty instead of reporting an error. While you migrate, usemust_varandmust_meta, which stop rendering and report the missing key:[[ must_var "message" . ]]Render the pack and confirm the output matches the original. If Nomad Pack reports a field it cannot find, refer to Troubleshoot.
Complete example
The following jobspec template uses the original syntax.
example.nomad.tpl
job [[ coalesce .simple_raw_exec.job_name .nomad_pack.pack.name | quote ]] {
datacenters = [[ .simple_raw_exec.datacenters | toJson ]]
type = "service"
group "app" {
count = [[ .simple_raw_exec.count ]]
task "server" {
driver = "raw_exec"
config {
command = "/bin/bash"
args = ["-c", [[ .simple_raw_exec.command | quote ]]]
}
resources {
cpu = [[ .simple_raw_exec.resources.cpu ]]
memory = [[ .simple_raw_exec.resources.memory ]]
}
}
}
}
The same template using the current syntax.
example.nomad.tpl
job [[ coalesce (var "job_name" .) (meta "pack.name" .) | quote ]] {
datacenters = [[ var "datacenters" . | toJson ]]
type = "service"
group "app" {
count = [[ var "count" . ]]
task "server" {
driver = "raw_exec"
config {
command = "/bin/bash"
args = ["-c", [[ var "command" . | quote ]]]
}
resources {
cpu = [[ var "resources.cpu" . ]]
memory = [[ var "resources.memory" . ]]
}
}
}
}
Run legacy packs
You can still run a pack you have not migrated yet by passing the --parser-v1
flag, which parses it with the original syntax. The commands that parse pack
templates accept the flag: run, plan, render, info, stop, and
destroy.
$ nomad-pack run ./my-pack --parser-v1
Troubleshoot
When you run a legacy pack without the --parser-v1 flag, Nomad Pack reports
the field it cannot find and suggests the equivalent function call.
The legacy ".my.message" syntax should be updated to use `var "message" .`. You can run legacy packs unmodified by using the `--parser-v1` flag
The opposite happens when you run a migrated pack with the --parser-v1 flag.
The template functions are unavailable, so Nomad Pack reports that the function
is not implemented for the v1 syntax. Remove the --parser-v1 flag to parse the
pack with the current syntax.
Next steps
To learn more about authoring packs, including the full list of template functions, refer to Create custom packs.