Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Jack Baldry <jack.baldry@grafana.com>
- Loading branch information
Showing
4 changed files
with
188 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
# Jsonnet prototype | ||
|
||
Jsonnet prototype presents an approach to writing Jsonnet libraries that provides easier inspection by an end-user. | ||
|
||
- Every Jsonnet file should be able to be manifested individually using the standard Jsonnet tool. | ||
- Every field should be manifested. | ||
- Every Jsonnet file should a corresponding `.proto.libsonnet` file. | ||
|
||
If every field of every library file can be manfiested individually, the end-user can easily use the Jsonnet tool to | ||
understand the data that your library produces. Furthermore, the `.proto.libsonnet` file provides easy insight into the | ||
high level structure of your library. | ||
|
||
## Inspecting a Jsonnet file | ||
|
||
A discussion of the usefulness of runtime errors is outside of the scope of this demonstration. | ||
```console | ||
$ jsonnet -e "(import 'deployment.jsonnet')" | ||
RUNTIME ERROR: an image must be provided as $._config.image | ||
deployment.jsonnet:4:12-64 object <anonymous> | ||
deployment.jsonnet:(2:12)-(5:4) object <anonymous> | ||
During manifestation | ||
$ jsonnet -e "(import 'deployment.jsonnet') { _config+: { image: 'foo' } }" | ||
RUNTIME ERROR: a name must be provided as $._config.name | ||
deployment.jsonnet:3:11-60 object <anonymous> | ||
<cmdline>:1:31-61 object <anonymous> | ||
During manifestation | ||
$ jsonnet -e "(import 'deployment.jsonnet') { _config+: { image: 'foo', name: 'bar' } }" | ||
{ | ||
"_config": { | ||
"image": "foo", | ||
"name": "bar" | ||
}, | ||
"deployment": { | ||
"apiVersion": "apps/v1", | ||
"kind": "Deployment", | ||
"metadata": { | ||
"labels": { | ||
"name": "bar" | ||
}, | ||
"name": "bar" | ||
}, | ||
"spec": { | ||
"replicas": 1, | ||
"selector": { | ||
"matchLabels": { | ||
"name": "bar" | ||
}, | ||
"template": { | ||
"metadata": { | ||
"labels": { | ||
"name": "bar" | ||
} | ||
}, | ||
"spec": { | ||
"containers": [ | ||
{ | ||
"image": "foo", | ||
"name": "bar" | ||
} | ||
] | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
``` | ||
|
||
## Producing intended output | ||
|
||
The previous example resulted in manifesting the completely expanded JSON representation of the Jsonnet file. | ||
It is often the case that one or more fields should not be present in the manifested JSON. In this example, the `_config: {}` field is not a desired output. | ||
The `deployment.proto.libsonnet` file is what determines the final output of the Jsonnet evaluation. | ||
|
||
```console | ||
$ jsonnet -e "(import 'deployment.proto.libsonnet') + (import 'deployment.jsonnet') { _config+: { image: 'foo', name: 'bar' } }" | ||
{ | ||
"deployment": { | ||
"apiVersion": "apps/v1", | ||
"kind": "Deployment", | ||
"metadata": { | ||
"labels": { | ||
"name": "bar" | ||
}, | ||
"name": "bar" | ||
}, | ||
"spec": { | ||
"replicas": 1, | ||
"selector": { | ||
"matchLabels": { | ||
"name": "bar" | ||
}, | ||
"template": { | ||
"metadata": { | ||
"labels": { | ||
"name": "bar" | ||
} | ||
}, | ||
"spec": { | ||
"containers": [ | ||
{ | ||
"image": "foo", | ||
"name": "bar" | ||
} | ||
] | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
``` | ||
|
||
## Downsides | ||
|
||
- Changes to the library structure must be reflected in two places. Though this is only true of the top level objects. | ||
- The prototype file is not actually able to be fully manifested without additional Jsonnet code: | ||
```console | ||
$ jsonnet -e "(import 'deployment.proto.libsonnet')" | ||
{ | ||
"deployment": { } | ||
} | ||
$ # Workaround to show all fields. | ||
$ jsonnet --tla-code "expr=(import 'deployment.proto.libsonnet')" prototype.jsonnet | ||
{ | ||
"_config": "hidden object", | ||
"deployment": "object" | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
{ | ||
_config: { | ||
name: error 'a name must be provided as $._config.name', | ||
image: error 'an image must be provided as $._config.image', | ||
}, | ||
|
||
deployment: { | ||
local name = $._config.name, | ||
local image = $._config.image, | ||
|
||
apiVersion: 'apps/v1', | ||
kind: 'Deployment', | ||
metadata: { | ||
name: name, | ||
labels: { | ||
name: name, | ||
}, | ||
}, | ||
spec: { | ||
replicas: 1, | ||
selector: { | ||
matchLabels: { | ||
name: name, | ||
}, | ||
template: { | ||
metadata: { | ||
labels: { | ||
name: name, | ||
}, | ||
}, | ||
spec: { | ||
containers: [{ name: name, image: image }], | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
// deployment.proto.libsonnet describes the prototypical structure of the Jsonnet library. | ||
{ | ||
// The `_config+:: {}` field is hidden as it is considered "input" to the library. | ||
_config:: {}, | ||
|
||
// The `deployment: {}` field is visible as it is considered "output" of the library. | ||
deployment: {}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
// prototype.jsonnet shows the prototypical structure of a file with hidden fields. | ||
function(expr) | ||
std.foldl( | ||
function(acc, field) acc { [field]: 'hidden %s' % std.type(expr[field]) }, | ||
std.objectFieldsAll(expr), | ||
{}, | ||
) | ||
+ | ||
std.foldl( | ||
function(acc, field) acc { [field]: std.type(expr[field]) }, | ||
std.objectFields(expr), | ||
{}, | ||
) |