Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

operations: rename river-jsonnet to alloy-syntax-jsonnet #74

Merged
merged 1 commit into from
Mar 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions operations/alloy-syntax-jsonnet/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# `alloy-syntax-jsonnet` library

The `alloy-syntax-jsonnet` library makes it possible to create Alloy syntax
config files using Jsonnet.

To manifest a configuration file, call `alloy.manifestAlloy(value)`.

Field names from objects are expected to follow one of the three forms:

* `<name>` for Alloy attributes (e.g., `foobar`).
* `block <name>` for unlabeled Alloy blocks (e.g., `block exporter.unix`)
* `block <name> <label>` for labeled Alloy blocks (.e.g, `block prometheus.remote_write default`).

Instead of following these naming conventions, helper functions are provided to
make it easier:

* `alloy.attr(name)` returns a field name that can be used as an attribute.
* `alloy.block(name, label="", index=0)` returns a field name that represents a block.
* The `index` parameter can be provided to make sure blocks get marshaled in
a specific order. If two blocks have the same index, they will be ordered
lexicographically by name and label.

In addition to the helper functions, `alloy.expr(literal)` is used to inject a
literal Alloy expression, so that `alloy.expr('env("HOME")')` is manifested as
the literal Alloy expression `env("HOME")`.

## Limitations

* Manifested Alloy syntax files always have attributes and object keys in
lexicographic sort order, regardless of how they were defined in Jsonnet.
* The resulting Alloy syntax files are not pretty-printed to how the formatter
would print files.

## Example

```jsonnet
local alloy = import 'github.com/grafana/alloy/operations/alloy-syntax-jsonnet/main.libsonnet';

alloy.manifestAlloy({
attr_1: "Hello, world!",

[alloy.block("some_block", "foobar")]: {
expr: alloy.expr('env("HOME")'),
inner_attr_1: [0, 1, 2, 3],
inner_attr_2: {
first_name: "John",
last_name: "Smith",
},
},
})
```

results in

```alloy
attr_1 = "Hello, world"
some_block "foobar" {
expr = env("HOME")
inner_attr_1 = [0, 1, 2, 3]
inner_attr_2 = {
"first_name" = "John",
"last_name" = "Smith",
}
}
```
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
local utils = import './internal/utils.jsonnet';

{
// attr returns the field name that should be used for River attributes.
// attr returns the field name that should be used for Alloy attributes.
attr(name):: name,

// block returns the field name that should be used for River blocks.
// block returns the field name that should be used for Alloy blocks.
block(name, label='', index=0)::
if label == ''
then ('block %s %d' % [name, index])
else ('block %s %s %d' % [name, label, index]),

// expr returns an object which represents a literal River expression.
// expr returns an object which represents a literal Alloy expression.
expr(lit):: {
// We need to use a special marker field to indicate that this object is an
// expression, otherwise manifest.jsonnet would treat it as an object
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
local river = import './main.libsonnet';
local alloy = import './main.libsonnet';

// The expectations below have to have sorted fields, since Jsonnet won't give
// you the fields back in the original order.
Expand Down Expand Up @@ -27,7 +27,7 @@ local tests = [
{
name: 'Exprs',
input: {
expr_attr: river.expr('prometheus.remote_write.default.receiver'),
expr_attr: alloy.expr('prometheus.remote_write.default.receiver'),
},
expect: |||
expr_attr = prometheus.remote_write.default.receiver
Expand All @@ -36,11 +36,11 @@ local tests = [
{
name: 'Blocks',
input: {
[river.block('labeled_block', 'foobar')]: {
[alloy.block('labeled_block', 'foobar')]: {
attr_1: 15,
attr_2: 30,
},
[river.block('unlabeled_block')]: {
[alloy.block('unlabeled_block')]: {
attr_1: 15,
attr_2: 30,
},
Expand All @@ -59,11 +59,11 @@ local tests = [
{
name: 'Ordered blocks',
input: {
[river.block('labeled_block', 'foobar', index=1)]: {
[alloy.block('labeled_block', 'foobar', index=1)]: {
attr_1: 15,
attr_2: 30,
},
[river.block('unlabeled_block', index=0)]: {
[alloy.block('unlabeled_block', index=0)]: {
attr_1: 15,
attr_2: 30,
},
Expand All @@ -82,10 +82,10 @@ local tests = [
{
name: 'Nested blocks',
input: {
[river.block('outer.block')]: {
[alloy.block('outer.block')]: {
attr_1: 15,
attr_2: 30,
[river.block('inner.block')]: {
[alloy.block('inner.block')]: {
attr_3: 45,
attr_4: 60,
},
Expand All @@ -106,10 +106,10 @@ local tests = [
name: 'Complex example',
input: {
attr_1: 'Hello, world!',
[river.block('some_block', 'foobar')]: {
[alloy.block('some_block', 'foobar')]: {
attr_1: [0, 1, 2, 3],
attr_2: { first_name: 'John', last_name: 'Smith' },
expr: river.expr('env("HOME")'),
expr: alloy.expr('env("HOME")'),
},
},
expect: |||
Expand All @@ -129,13 +129,13 @@ local tests = [
input: {
attr_1: 'Hello, world!',

[river.block('outer_block')]: {
[alloy.block('outer_block')]: {
attr_1: 53,
[river.block('inner_block', 'labeled')]: [
[alloy.block('inner_block', 'labeled')]: [
{ bool: true },
{ bool: false },
],
[river.block('inner_block', 'other_label')]: [
[alloy.block('inner_block', 'other_label')]: [
{ bool: true },
{ bool: false },
],
Expand Down Expand Up @@ -163,7 +163,7 @@ local tests = [
{
name: 'Indented literals',
input: {
attr_1: river.expr('concat([%s])' % river.manifestRiverValue({ hello: 'world' })),
attr_1: alloy.expr('concat([%s])' % alloy.manifestAlloyValue({ hello: 'world' })),
},
expect: |||
attr_1 = concat([{
Expand All @@ -174,7 +174,7 @@ local tests = [
{
name: 'Pruned expressions',
input: std.prune({
expr: river.expr('env("HOME")'),
expr: alloy.expr('env("HOME")'),
}),
expect: |||
expr = env("HOME")
Expand All @@ -183,7 +183,7 @@ local tests = [
];

std.map(function(test) (
assert river.manifestRiver(test.input) == test.expect : (
assert alloy.manifestAlloy(test.input) == test.expect : (
|||
%s FAILED

Expand All @@ -194,7 +194,7 @@ std.map(function(test) (
ACTUAL
======
%s
||| % [test.name, test.expect, river.manifestRiver(test.input)]
||| % [test.name, test.expect, alloy.manifestAlloy(test.input)]
);
'%s: PASS' % test.name
), tests)
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
local utils = import './internal/utils.jsonnet';

// parseField parses a field name from a Jsonnet object and determines if it's
// supposed to be a River attribute or block.
// supposed to be an Alloy attribute or block.
local parseField(name) = (
local parts = std.split(name, ' ');
local numParts = std.length(parts);
Expand All @@ -27,8 +27,8 @@ local parseField(name) = (
)
);

// isRiverExpr returns true if value was constructed with river.expr().
local isRiverExpr(value) = std.isObject(value) && std.length(value) == 1 && utils.exprMarker in value;
// isAlloyExpr returns true if value was constructed with alloy.expr().
local isAlloyExpr(value) = std.isObject(value) && std.length(value) == 1 && utils.exprMarker in value;

// linePadding returns number of spaces to indent a line with given a specific
// indentation level.
Expand All @@ -38,7 +38,7 @@ local manifester(indent=0) = {
local padding = linePadding(indent),
local this = $,

// body manifests a River body to text, manifesting both attributes and
// body manifests an Alloy body to text, manifesting both attributes and
// blocks.
body(value): (
// First we need to look at each public field of the value and parse it as
Expand Down Expand Up @@ -88,11 +88,11 @@ local manifester(indent=0) = {
), parsedFields, '')
),

// value manifests a River value to text.
// value manifests an Alloy value to text.
value(value): (
if value == null then (
'null'
) else if isRiverExpr(value) then (
) else if isAlloyExpr(value) then (
local lines = std.split(value[utils.exprMarker], '\n');

// When injecting literals, each line after the first should have the
Expand Down Expand Up @@ -162,14 +162,14 @@ local manifester(indent=0) = {

{

// manifestRiver returns a pretty-printed River file from the Jsonnet value.
// value must be an object.
manifestRiver(value):: (
assert std.isObject(value) : 'manifestRiver must be called with object';
// manifestAlloy returns a pretty-printed Alloy syntax file from the Jsonnet
// value. value must be an object.
manifestAlloy(value):: (
assert std.isObject(value) : 'manifestAlloy must be called with object';
manifester().body(value)
),

manifestRiverValue(value):: (
manifestAlloyValue(value):: (
manifester().value(value)
),
}
65 changes: 0 additions & 65 deletions operations/river-jsonnet/README.md

This file was deleted.

Loading