That template looks great. You need the wrapping with to guard the range function until the variable data is available, since consul-template uses multiple rendering passes over the template—so this is spot on. As Nomad 1.4 moves to GA, Nomad Variable support will make its way into consul-template mainline releases, which will expand access to Nomad Variables for templating outside of Nomad and also facilitate template development and troubleshooting without having to necessarily make a lot of round trip job submissions.
I did golf it down a little, and there is an interesting dance because these dependencies have real types.
Necrobumping for a related issue I am trying (noob alert, started using nomad this week)…
I want to use a single SQL template to initialize multiple databases with the same template.
For this, I defined a task variable within the job spec (later get this from Vault or so)
variable "dbases" {
type = list(object({
dbname = string
dbuser = string
dbpass = string
}))
default = [
{
dbname = "db1"
dbuser = "user1"
dbpass = "pass1"
},
{
dbname = "db2"
dbuser = "user2"
dbpass = "pass2"
}
]
}
....
task "task-postgres" {
driver = "podman"
config {
image = "docker.io/postgres:16-alpine"
ports = ["postgrestcp"]
}
env {
POSTGRES_PASSWORD = var.pgpass
}
template {
data = <<EOTPL
{{ range var.dbases }}
DO $$
BEGIN
CREATE ROLE {{ .dbuser }} WITH LOGIN PASSWORD '{{ .dbpass }}' CREATEDB;
EXCEPTION WHEN duplicate_object THEN RAISE NOTICE '%, skipping', SQLERRM USING ERRCODE = SQLSTATE;
END
$$;
SELECT 'CREATE DATABASE {{ .dbname }}'
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = '{{ .dbname }}')\gexec
GRANT ALL PRIVILEGES ON DATABASE {{ .dbname }} TO {{ .dbuser }};
\c {{ .dbname }}
GRANT ALL PRIVILEGES ON SCHEMA public TO {{ .dbuser }};
{{ end }}
EOTPL
destination = "/docker-entrypoint-initdb.d/dbinit.sql"
error_on_missing_key = true
change_mode = "noop" # this is just a DB mutation, so no restarts needed
}
but I can’t find the right reference for var.dbases, nomad complains it can’t find the variable.
Incidentally, another issue: is there a way to use an external template (e.g. with template { source = "..." }) where the template file resides with the job specification (i.e. not on the nomad client) without having to “pull” the file from an external address? (artifact would also be acceptable, as long as I can have a path local to the job spec for source).