Variable indirection in `env {}` stanzas
Proposal
Bash has a feature called variable indirection that lets you read the value of a value. The following example exemplifies it:
original_value="hey, im the original value"
original_value_env_var_name="original_value"
echo "${!original_value_env_var_name}"
>> hey, im the original value
echo "${original_value_env_var_name}"
>> original_value
I propose that this could potentially be useful in Nomad env{} stanzas (or perhaps elsewhere in its interpolation engine)!
Use-cases
I have an upstream with a name that changes based on vars. This makes it difficult to statically pass its NOMAD_UPSTREAM_ADDR into an env{}. Concretely, this looks like the following:
upstreams {
destination_name = "plugin-${var.plugin_id}"
# port unique but arbitrary - https://github.com/hashicorp/nomad/issues/7135
local_bind_port = 1001
}
if I wanted to pass this upstream's NOMAD_UPSTREAM_ADDR in as an env, i'm out of luck! The following obviously fails:
env {
GRAPH_QUERY_CLIENT_ADDRESS = "http://${NOMAD_UPSTREAM_ADDR_graph-query-sidecar-${var.plugin_id}}"
}
Attempted Solutions
My attempt, which led to this ticket, is the following, where I try to do the string interpolation as one step and then rely on the shell reading ${!VARIABLE_NAME} to do some variable indirection. (In this case, it means 'replace this {} with the value of GRAPH_QUERY_UPSTREAM_ADDR - so, the full NOMAD_UPSTREAM_ADDR.)
GRAPH_QUERY_UPSTREAM_ADDR = "NOMAD_UPSTREAM_ADDR_graph-query-sidecar-${var.plugin_id}"
GRAPH_QUERY_CLIENT_ADDRESS = "http://${!GRAPH_QUERY_UPSTREAM_ADDR}"
resulting in
NonzeroExitStatus stderr=\"Error getting job struct: Error parsing job file from /tmp/.tmpRgkLfK:\\n.tmpRgkLfK
:294,49-74: Invalid operand; Unsuitable value for unary operand: a bool is required.\\n.tmpRgkLfK:294,39-46: Unsuitable value type; Unsuitable value: value must be known\\n\""
If I construct the name of the UPSTREAM_ADDR at runtime, and grab it from runtime env variables, it works just fine.
However, it'd be nice and clean if I could pass it in as part of the env!
Hi @wimax-grapl! You can get the shell-scripting approach you've described to work if you escape the $ in the script as a $$. Here's an simplified example jobspec that does the job. You'll need to adapt it to your Connect use case:
variable "plugin_id" {
type = string
default = "www"
}
job "example" {
datacenters = ["dc1"]
group "group" {
task "task" {
driver = "docker"
config {
image = "debian:buster"
command = "bash"
args = ["local/run.sh"]
}
template {
data = <<EOT
export GRAPH_QUERY_CLIENT_ADDRESS="http://$${!MY_OWN_ADDR}"
echo GRAPH_QUERY_CLIENT_ADDRESS=$GRAPH_QUERY_CLIENT_ADDRESS
exec sleep 3600
EOT
destination = "local/run.sh"
}
env {
MY_OWN_ADDR = "NOMAD_ADDR_${var.plugin_id}"
}
}
network {
mode = "bridge"
port "www" {
to = 8001
}
}
service {
provider = "nomad"
port = "www"
}
}
}
$ nomad job run ./example.nomad
...
$ nomad alloc logs 9db
GRAPH_QUERY_CLIENT_ADDRESS=http://127.0.0.1:31581
Trying to do this natively in Nomad would be interesting though. One tricky bit is that interpolation happens multiple times in Nomad (the vars get interpolated on the CLI, whereas other interpolation happens on the client), and that might make it hard for users to reason about what's happening. But I'll mark this as a roadmap item for further discussion.
Thank you for the guidance!!
ah shoot, sorry for screwing up the automation
I believe that you could obtain your desired output using a template with env=true. I'd be curious to hear how it works for you if you could give it a shot. I expect the ${var.plugin_id} to be interpolated by the CLI, leaving the remainder to be interpolated on the client and included in the task environment.
template {
env = true
destination = "env.txt"
data = <<EOT
GRAPH_QUERY_CLIENT_ADDRESS="http://{{ env ( printf "NOMAD_UPSTREAM_ADDR_graph-query-sidecar-%s" "${var.plugin_id}" ) }}
EOT
}
I realize that it's longer than your proposal, but using the template block and env = true is a routinely used pattern in jobspecs and allows for a lot more expressiveness at the expense of verbosity.