Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to call parameterized Jsonnet from bash?

Tags:

jsonnet

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],
}
like image 825
DazWilkin Avatar asked Jan 23 '18 23:01

DazWilkin


People also ask

What is the difference between JSON and Jsonnet?

JSON is used to describe data literally. Jsonnet extends JSON. Jsonnet has relaxed syntax and comments to make it easier for humans to write. Jsonnet also adds constructs for generating, translating and refining data.

What is Jsonnet used for?

Jsonnet is a new domain specific configuration language from Google which allows you to define data templates. These data templates are transformed into JSON objects using Jsonnet library or command line tool. As a language, Jsonnet is extension of JSON - a valid JSON object is always valid Jsonnet template.

What is Libsonnet file?

libsonnet is a library Jsonnet file, containing the base configuration for a service. Suppose that test_config. jsonnet is a test configuration file that is used to test base_config. jsonnet , and test_config. json is the expected JSON output from compiling test_config.

How to pass parameters to a bash script?

We can pass parameters just after the name of the script while running the bash interpreter command. You can pass parameters or arguments to the file. Just the command for running the script normally by adding the value of the parameters directly to the script.

How do I pass data to jsonnet?

The preferred way of passing data to Jsonnet is through Top-level Arguments. This mechanism allows calling a Jsonnet program like a function. Consider the following simple program add.jsonnet: It can be called jsonnet add.jsonnet --tla-code a=1 --tla-code b=2. The result of the evaluation will be 3.

Should you refer to the fields of jsonnet objects?

You need to make a decision whether to refer to the fields of the objects as they are currently defined or to allow overriding. Jsonnet objects have a concept of visibility which affects manifestation (printing out objects) and equality checks. This concept has nothing to do with the notion of private/public fields from other languages.

How do I change the type of a jsonnet value?

All Jsonnet values are immutable. It is not possible to change a value of a field of an object or an element of an array – you can only create a new one with the desired change applied. You can check the type of any value using std.type.


Video Answer


1 Answers

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
}
like image 98
sbarzowski Avatar answered Oct 01 '22 19:10

sbarzowski