Build Status

rjsone (Render JSON-e) is a simple wrapper around the JSON-e templating language.

It’s a safe and easy way to have templates of moderate complexity for configuration as code ‘languages’ like Kubernetes and CloudFormation.

Usage: rjsone [options] [context ...]
  -d    performs a deep merge of contexts
  -i int
        indentation of JSON output; 0 means no pretty-printing (default 2)
  -o string
        output to a file (default is -, which is stdout) (default "-")
  -t string
        file to use for template (- is stdin) (default "-")
  -v    show information about processing on stderr
  -y    output YAML rather than JSON (always reads YAML/JSON)

Context is usually provided by a list of arguments. By default, these are interpreted as files. Data is loaded as YAML/JSON by default and merged into the main context. If the ‘filename’ begins with a +, the rest of the argument is interpreted as a raw string rather than reading the file. For example:

rjsone -t template.yaml context.yaml '+{"foo": 1}'

When duplicate keys are found, later entries replace earlier at the top level only unless the -d flag is passed to perform deep merging.

You can specify a particular context key to load a YAML/JSON file into using keyname:filename.yaml. You can also use keyname:.. to indicate that subsequent entries without keys should be loaded as a list element into that key. If you instead use keyname:..., metadata information is loaded as well and each list element is an object containing {filename, basename, content}.

When loading the context, the default input format is YAML but you can also use JSON, plain text, and kv (key value pairs, space separated, as used by bazel and many unix tools). To specify the format, rather than using a : you use :format:. For example:

:yaml:ctx.yaml :kv:ctx.kv :json:ctx.json mykey:text:ctx.txt

Note that you must specify a key name under which to load the plain text file, since it cannot define keys (i.e. is a plain text string). Also, although the default format is yaml, the default format with :: is text. So the following equivalencies hold:

mykey::context.txt == mykey:text:context.txt
context.yaml == :context.yaml == :yaml:context.yaml

A common pattern, therefore, is to provide plain text arguments to the template:

rjsone -t template.yaml env::+production context.yaml

For complex applications, single argument functions can be added by prefixing the filename with a - (or a -- for raw string input). For example:

b64decode::--'base64 -d'

This adds a base64 decode function to the context which accepts two arguments as input, an array (command line arguments) and string (stdin), and outputs a string. In your template, you would use this function by like b64decode([], 'Zm9vCg=='). As with before, you can use format specifiers (:- is yaml on both sides for the default behaviour, and you can explicitly specify kv/json/text/yaml between both :: and --).

Getting it

Grab the latest binary or build it yourself:

go get github.com/wryun/rjsone

Rationale

I often want to template JSON/YAML for declarative infrastructure as code things (e.g. Kubernetes, CloudFormation, …), and JSON-e is one of the few languages that is also valid YAML/JSON, unlike the common option of hijacking languages designed for plain text (or HTML) templating. If your template is valid YAML/JSON, your editor can help you out with syntax highlighting, and after you apply the template you will always have valid YAML/JSON.

I also want to be ‘declarative configuration language’ agnostic (i.e. avoiding Kubernetes specific templating tools…).

Before I discovered JSON-e, I wrote o-stache. There are a list of other structured templating options there, the most prominent of which is Jsonnet.

Basic usage example

Please see the JSON-e documentation for how to really use it.

template.yaml

a: ${foo}
b: ${bar}
c: ${foobar}

context1.yaml

foo: something

context2.yaml

bar: nothing

named.yaml

everything

Use YAML files for context:

$ rjsone -y -t template.yaml context1.yaml context2.yaml foobar:named.yaml
a: something
b: nothing
c: everything

Use context on command line (:: rather than : means interpret as raw string not as JSON/YAML, and + means treat it as a string rather than a filename):

$ rjsone -y -t template.yaml foo::+something bar::+nothing foobar::+everything
a: something
b: nothing
c: everything

Warning: if you need to construct anything that’s not a pure string from templated input, you’ll probably need to understand JSON-e’s ‘$eval’ operator.