DazWilkin
DazWilkin

Reputation: 40296

How to call parameterized Jsonnet from bash?

I can't understand how to best to parameterize a Jsonnet file so that I may call the same file from bash and from another Jsonnet file.

Assuming I have a simple template called template.jsonnet:

{
  // Required arguments
  name:: error "'name' must be specified",
  port:: error "'port' must be specified",

  ...,
}

I can readily incorporate this into another Jsonnet file and provide its required parameter values with:

{
  local template = = import "./template.jsonnet";

  template + {
    name:: "service",
    port:: 8080,
}

I'm struggling to determine the intended way that I could call template.jsonnet from bash to achieve the same result.

I can use --ext-str but this appears to require std.extVar(x)

A GitHub issue suggests that --tla-code may be an alternative to std.extVar() but I don't understand how to use it for my needs.

A follow-up question is: how do do this for a parameter this is an array:

{
  local template = = import "./template.jsonnet";

  template + {
    name:: "service",
    port:: [8080,8081,8082],
}

Upvotes: 10

Views: 10087

Answers (1)

sbarzowski
sbarzowski

Reputation: 2991

The most direct way is to use some inline jsonnet:

jsonnet -e '(import "template.jsonnet") + { name: "service", port: 8080 }'

For easier parametrization, you can use extVars or top-level-arguments (TLAs).

jsonnet -e 'function(name, port) (import "template.jsonnet") + { name: name, port: port }' --tla-str name="blah" --tla-code port='[8080, 8081]'

or

jsonnet -e '(import "template.jsonnet") + { name: std.extVar("name"), port: std.extVar("port") }' --ext-str name="blah" --ext-code port='[8080, 8081]'

A better way is to make template.jsonnet a function and use --tla-code/ --tla-str:

  function(name, port) {
    name:: name,
    port:: port
    // Sidenote: the fields are hidden here, because they use ::,
    // use : to make them appear when the object is manifested.
    // Sidenote 2: You can provide default argument values. 
    // For example function(name, port=8080) makes port optional.
  }

Then in another jsonnet file you can use it as follows:

local template = import "./template.jsonnet";
{

  filled_template: template(
    name="service",
    port=8080 // or port=[8080,8081,8082]
  )
}

And you can use the template from shell as follows:

jsonnet --tla-code name='"some name"' --tla-code port=8080 template.jsonnet

Note how quotation marks are necessary for name (without outer ' they would be interpreted by shell). That's because you can pass any jsonnet code that evaluates to any type in tla-code.

If you want to pass a string verbatim you can use --tla-str:

jsonnet --tla-str name="some name" --tla-code port=8080 template.jsonnet

On the other hand you can pass an array (or an object, or any jsonnet code) to --tla-code:

jsonnet --tla-code name='"some name"' --tla-code port='[8080, 8081, 8082]' template.jsonnet

Alternatively, if you don't want to change your template.jsonnet you can use a wrapper file to provide the interface that I described:

template_func.jsonnet:

local template = import "./template.jsonnet";
function(name, port) template + {
  name: name,
  port: port
}

Upvotes: 21

Related Questions