JaaS is a webservice that evaluates Jsonnet snippets on the fly.
You can find pre-built binaries on our GitHub release page, a container image at docker.io/metio/jaas:latest, and a helm chart here.
JaaS is controlled through command line flags. The minimal way to run it is just:
./jaasYou can then use the service by sending a GET request to http://127.0.0.1:8080/jsonnet/<SNIPPET>. <SNIPPET> is the name of Jsonnet snippet you want to evaluate. The service will return the evaluated Jsonnet snippet as JSON.
Snippets can be declared in two ways:
- Directory Snippets: Specify directories with
-snippet-directoryand place your Jsonnet files in subdirectories of the given directory. For example, if you have a filemain.jsonnetin a directorysnippet/directory/something, you can access it via the URLhttp://<IP>:<PORT>/jsonnet/somethingif-snippet-directoryis set tosnippet/directory. - File Snippets: You can also specify individual Jsonnet files using the
-snippetflag. For example, if you have a filepath/to/somewhere/something.jsonnet, you can access it via the URLhttp://<IP>:<PORT>/jsonnet/path/to/somewhere/something.jsonnet.
Consider the examples directory of this repository:
examples
└── snippets
├── dashboards
│ └── example1
│ └── main.jsonnet
└── example.jsonnet
Using -snippet-directory examples/snippets/dashboards exposes all subdirectories as retrievable snippets, so you can access example1 via http://<IP>:<PORT>/jsonnet/example1.
Similarly, using -snippet examples/snippets/example.jsonnet allows you to access the example.jsonnet snippet directly via http://<IP>:<PORT>/jsonnet/examples/snippets/example.jsonnet.
Libraries can be declared using the -library-path flag. This allows you to specify directories containing Jsonnet libraries that can be used in your snippets. The rightmost matching library will be used if multiple library paths match.
Consider the following directory structure:
examples
└── libraries
└── examplonet
└── main.libsonnet
Using -library-path examples/libraries allows you to use the examplonet library in your Jsonnet snippets. You can then import it in your Jsonnet files like this:
local examplonet = import 'examplonet/main.libsonnet';
{
...
}You can set the value for external variables by defining environment variables starting with the prefix JAAS_EXT_VAR_, e.g., JAAS_EXT_VAR_your_external_var=something will expose the external variable your_external_var and set it to the value something.
You can specify top level arguments using URL query parameters like this:
http://<IP>:<PORT>/jsonnet/snippet?var1=value1&var2=value2: Setvar1tovalue1andvar2tovalue2for the snippet evaluation.http://<IP>:<PORT>/jsonnet/snippet?var1=value1&var2: Setvar1tovalue1andvar2to an empty string for the snippet evaluation.http://<IP>:<PORT>/jsonnet/snippet?var1=value1&var1=value2: Setvar1to a list containingvalue1andvalue2for the snippet evaluation.
Non-2xx responses carry a JSON body with Content-Type: application/json so programmatic callers can pick the failure apart:
{
"error": "snippet_not_found",
"message": "snippet \"missing\" not found",
"snippet": "missing"
}error is a stable identifier — callers may match on it. The currently defined codes are:
| code | HTTP status | When |
|---|---|---|
method_not_allowed |
405 |
Anything other than GET on /jsonnet/… |
snippet_not_found |
404 |
The requested snippet name resolves to no file |
evaluation_timeout |
504 |
Evaluation exceeded -evaluation-timeout |
evaluation_failed |
400 |
go-jsonnet returned an error (syntax, missing import, stack…) |
message is human-readable detail; for evaluation_failed it is the raw go-jsonnet diagnostic, including file and line numbers from the snippet on disk. snippet echoes the requested snippet name when one was parsed, and is omitted otherwise.
A client that closes the connection mid-evaluation receives no body and no status line — the handler detects the cancellation and bails without writing anything.
JaaS evaluates Jsonnet on the server and serves the result over HTTP. Before exposing it to a wider audience, operators should be aware of the following:
Library paths are an unrestricted read scope. Any file reachable under a configured -library-path (or under the snippet's own directory) can be import-ed or importstr-ed by any snippet — go-jsonnet's FileImporter does not sandbox per snippet. Scope -library-path directories tightly; do not point them at /, /etc, or anywhere holding credentials.
Snippets are operator-controlled, not caller-controlled. Callers only supply Top Level Arguments via URL query parameters; jsonnet's import / importstr require string literals, so TLAs and external variables cannot be used to construct arbitrary import paths. That said, deploying a snippet authored by someone you don't trust is equivalent to running their code on the server.
Snippet name resolution is sandboxed. The URL's {snippet...} segment is resolved via Go's os.Root, which rejects .. traversal and symlinks that escape the configured -snippet-directory. So a malicious URL like /jsonnet/../etc/passwd is rejected with 404, even though the OS would otherwise resolve it.
Evaluation has caps but isn't cancellable mid-flight. -evaluation-timeout bounds wall-clock time per request and -max-stack bounds Jsonnet's call-stack depth, but go-jsonnet has no mid-evaluation cancellation — a slow snippet keeps consuming CPU on the server until it finishes naturally or the timeout fires the HTTP response. Size container CPU/memory limits accordingly.
See all available command line flags with jaas --help:
-evaluation-timeout duration
Maximum duration a single Jsonnet evaluation is allowed to take. Set to 0 to disable. (default 5s)
-jsonnet-endpoint-path string
The path to the jsonnet endpoint (default "jsonnet")
-library-path value
The path of a directory containing jsonnet libraries (can be specified multiple times). Rightmost matching library will be used.
-listen-address string
The listen address to bind to for the Jsonnet server (default "127.0.0.1")
-log-level string
The log level to use (debug, info, warn, error) (default "info")
-management-listen-address string
The listen address to bind to for the management server (default "127.0.0.1")
-management-port string
The port to bind to for the management server (default "8081")
-management-read-timeout duration
maximum duration for reading the entire request, including the body in the management server (default 10s)
-management-write-timeout duration
The maximum duration before timing out writes of the response in the management server (default 10s)
-max-stack int
Maximum Jsonnet call-stack depth. Set to 0 to use go-jsonnet's default. (default 500)
-port string
The port to bind to for the Jsonnet server (default "8080")
-read-timeout duration
maximum duration for reading the entire request, including the body in the Jsonnet server (default 10s)
-shutdown-delay duration
Time to wait after readiness flips to false before initiating graceful shutdown; gives Kubernetes time to propagate the not-ready status to endpoint controllers. Set to 0 to disable. (default 5s)
-snippet value
The path of a jsonnet file or directory containing snippets (can be specified multiple times). Snippets will be loaded from the given path, where the file name is the snippet name.
-snippet-directory value
The path of a directory containing snippets as subdirectories (can be specified multiple times). Snippets will be loaded from subdirectories of the given path, where the directory name is the snippet name.
-version
Print version and exit
-write-timeout duration
The maximum duration before timing out writes of the response in the Jsonnet server (default 10s)