I have some condition, if it is satisfied I've to create a massive object and merge it into the other one (at least that's how I understand jsonnet
works in general):
local something_something = true;
local tst = {
n1: {
a: "10.172.52.0/22",
b: "10.172.56.0/22",
},
n2: {
c: "10.172.60.0/22",
},
};
{
aws_route: {
public: {
route_table_id: '${aws_route_table.public.id}',
destination_cidr_block: '0.0.0.0/0',
gateway_id: '${aws_internet_gateway.tst.id}',
}
} + (
if something_something then {
['nat_%s' % zone]: {
route_table_id: '${aws_route_table.nat_%s.id}' % zone,
destination_cidr_block: '0.0.0.0/0',
nat_gateway_id: '${aws_nat_gateway.ngw_%s.id}' % zone,
}
for zone in std.objectFields(tst.n1)
} else {})
+ (
if something_something then {
['nat_%s' % zone]: {
route_table_id: '${aws_route_table.nat_%s.id}' % zone,
destination_cidr_block: '0.0.0.0/0',
nat_gateway_id: '${aws_nat_gateway.ngw_%s.id}' % zone,
}
for zone in std.objectFields(tst.n2)
} else {})
}
This yields the desired result:
$ ./jsonnet tst.jsonnet
{
"aws_route": {
"nat_a": {
"destination_cidr_block": "0.0.0.0/0",
"nat_gateway_id": "${aws_nat_gateway.ngw_a.id}",
"route_table_id": "${aws_route_table.nat_a.id}"
},
"nat_b": {
"destination_cidr_block": "0.0.0.0/0",
"nat_gateway_id": "${aws_nat_gateway.ngw_b.id}",
"route_table_id": "${aws_route_table.nat_b.id}"
},
"nat_c": {
"destination_cidr_block": "0.0.0.0/0",
"nat_gateway_id": "${aws_nat_gateway.ngw_c.id}",
"route_table_id": "${aws_route_table.nat_c.id}"
},
"public": {
"destination_cidr_block": "0.0.0.0/0",
"gateway_id": "${aws_internet_gateway.tst.id}",
"route_table_id": "${aws_route_table.public.id}"
}
}
}
This works, but there's a lot of boilerplate, namely I have to use exactly the same if-then-else
over and over again... What I'm dreaming of is to have one if-then-else
and be able to set my massive object in one go, something along the lines:
{
aws_route: {
public: {
route_table_id: '${aws_route_table.public.id}',
destination_cidr_block: '0.0.0.0/0',
gateway_id: '${aws_internet_gateway.tst.id}',
}
} + (
if something_something then {
['nat_%s' % zone]: {
route_table_id: '${aws_route_table.nat_%s.id}' % zone,
destination_cidr_block: '0.0.0.0/0',
nat_gateway_id: '${aws_nat_gateway.ngw_%s.id}' % zone,
}
for zone in std.objectFields(tst.n1),
['nat_%s' % zone]: {
route_table_id: '${aws_route_table.nat_%s.id}' % zone,
destination_cidr_block: '0.0.0.0/0',
nat_gateway_id: '${aws_nat_gateway.ngw_%s.id}' % zone,
}
for zone in std.objectFields(tst.n2)
} else {})
}
Sadly this is not supported:
STATIC ERROR: tst.jsonnet:26:41: expected for, if or "}" after for clause, got: ","
Does my take make sense in jsonnet
in general, are there better ways to achieve the same?
You can aggregate both comprehensions inside the if-then-else clause, the below code implements it:
local something_something = true;
local tst = {
n1: {
a: '10.172.52.0/22',
b: '10.172.56.0/22',
},
n2: {
c: '10.172.60.0/22',
},
};
{
aws_route: {
public: {
route_table_id: '${aws_route_table.public.id}',
destination_cidr_block: '0.0.0.0/0',
gateway_id: '${aws_internet_gateway.tst.id}',
},
} + (
// Aggregate (merge actually) both comprehensions, i.e. this construct:
// if cond then {obj} + {obj} else {}
// where obj are the below comprehensions
if something_something then {
['nat_%s' % zone]: {
route_table_id: '${aws_route_table.nat_%s.id}' % zone,
destination_cidr_block: '0.0.0.0/0',
nat_gateway_id: '${aws_nat_gateway.ngw_%s.id}' % zone,
}
for zone in std.objectFields(tst.n1)
} + {
['nat_%s' % zone]: {
route_table_id: '${aws_route_table.nat_%s.id}' % zone,
destination_cidr_block: '0.0.0.0/0',
nat_gateway_id: '${aws_nat_gateway.ngw_%s.id}' % zone,
}
for zone in std.objectFields(tst.n2)
}
else {}
),
}
After the above fix, generalize to loop inside nested zones
object
local something_something = true;
local tst = {
n1: {
a: '10.172.52.0/22',
b: '10.172.56.0/22',
},
n2: {
c: '10.172.60.0/22',
},
};
// Loop over nested zones object to manifest nat blocks
local aws_nat(cond, zones) = (
if cond then {
['nat_%s' % zone]: {
route_table_id: '${aws_route_table.nat_%s.id}' % zone,
destination_cidr_block: '0.0.0.0/0',
nat_gateway_id: '${aws_nat_gateway.ngw_%s.id}' % zone,
}
for entry in std.objectFields(zones)
for zone in std.objectFields(zones[entry])
} else {}
);
{
aws_route: {
public: {
route_table_id: '${aws_route_table.public.id}',
destination_cidr_block: '0.0.0.0/0',
gateway_id: '${aws_internet_gateway.tst.id}',
},
} + aws_nat(something_something, tst),
}