print from json with a given condition in terraform - terraform

I'm into the terraform world recently and learning based on the requirements. I've a question on printing the values with a given condition
json file:
{
"team1" : [
{
"engg_name" : "Alex",
"guid" : 1001,
"scope" : "QA"
},
{
"engg_name" : "Trex",
"guid" : 1002,
"scope" : "QA"
},
{
"engg_name" : "Jessica",
"guid" : 1003,
"scope" : "QA"
},
{
"engg_name" : "Tom",
"guid" : 1004,
"scope" : "DEV"
}
],
"team2" : [
{
"engg_name" : "Roger",
"guid" : 2001,
"scope" : "DEV"
},
{
"engg_name" : "Jhonny",
"guid" : 2002,
"scope" : "DEV"
}
]
}
What I'm trying:
print the engg whose scope is DEV from the json file
locals {
teams = jsondecode(file("${path.module}/teams_info.json"))
engg_with_scope_dev = flatten([for i in local.teams : i.teams if keys(local.teams).scope == "DEV"])
}
Error:
engg_with_scope_dev = flatten([for i in local.teams : i.teams if keys(local.teams).scope == "DEV"])
|----------------
| local.teams is object with 2 attributes
This value does not have any attributes.
Can someone suggest me what's the right way to just print based on the condition?
output must be as following:
engg_with_scope_dev = ["Tom", "Roger", "Jhonny"]

You need an embedded for loop for this:
locals {
teams = jsondecode(file("${path.module}/teams_info.json"))
engg_with_scope_dev = flatten([for team in local.teams : [
for engineer in team : engineer.engg_name if engineer.scope == "DEV"
]])
}
Other solution would be to use a concatenation of the lists with ellipsis operator:
locals {
teams = jsondecode(file("${path.module}/teams_info.json"))
engg_with_scope_dev = ([
for engineer in concat(values(local.teams)...) : engineer.engg_name if engineer.scope == "DEV"
])
}
But also, a simple flatten with values would work as well:
locals {
teams = jsondecode(file("${path.module}/teams_info.json"))
engg_with_scope_dev = ([
for engineer in flatten(values(local.teams)) : engineer.engg_name if engineer.scope == "DEV"
])
}

Related

json file in terraform

I have a JSON file with the following and trying to list the shapes ex: "t3-nano, t3-micro, t3-small, t2.medium, t3-2xlarge, r6g-medium".
json file = info.json
{
"t3-nano" : {
"service_name" : "t3",
"existing" : 100
},
"t3-micro" : {
"service_name" : "t3",
"existing" : 1
},
"t3-small" : {
"service_name" : "t3",
"existing" : 2
},
"t2.medium" : {
"service_name" : "t2",
"existing" : 0
},
"t3-2xlarge" : {
"service_name" : "t3-2",
"existing" : 5
},
"r6g-medium" : {
"service_name" : "r6g.medium",
"existing" : 10
}
}
I tried the following
locals {
service_name = flatten([for i in local.info : i[*].service_name])
shapes = flatten([for i in local.info : i[*].index])
}
and it got failed
Error: Unsupported attribute
This object does not have an attribute named "index".
I was expecting to print shapes = [t3-nano, t3-micro, t3-small, t2.medium, t3-2xlarge, r6g-medium]. Can someone help if there is a way to just list the shapes?
The flatten function and for expression are both unnecessary here. The function keys already has the functionality and return value that you want to achieve:
shapes = keys(local.info)
and that will assign the requested value.

Nested loop based on json response in Terraform for multiple resource target

Array:
regions = [
{name: "region1"},
{name: "region2"},
{name: "region3"},
{name: "region4"},
{name: "region5"},
{name: "region6"}]
Json:
{
"region1" : ["cluster1"],
"region2" : [],
"region3" : ["cluster1"],
"region4" : ["cluster1","cluster2"]
}
resource "type" "name" {
count = length(regionLength)
name = "region-name/cluster-name"
}
I need resource created with such name output like this
region1/cluster1
region2
region3/cluster1
region4/cluster1
region4/cluster2
Can we achieve this too:
Final = []
For r , cs in arr:
for oc in regions:
if r == oc.name:
for c in cs:
oc[‘cluster’] = r-c
Final.push(oc)
Thanks in advance.
You can achieve that as folllows:
variable "regions" {
default = {
"region1" : ["cluster1"],
"region2" : [],
"region3" : ["cluster1"],
"region4" : ["cluster1","cluster2"]
}
}
locals {
region_list = flatten([for region, clusters in var.regions:
[ for cluster in coalescelist(clusters, [""]):
"${region}/${cluster}"
]
])
}
which gives:
region_list = [
"region1/cluster1",
"region2/",
"region3/cluster1",
"region4/cluster1",
"region4/cluster2",
]

Terraform: nested for loop from yaml

I am trying to run nested for loop on terraform.
I have the following Yaml file:
Employees:
- Department:
- Dev:
- name: "danielf"
role: developer
details:
email : danielf#example.com
firstname : daniel
lastname : folsik
- name: "johnb"
role: developer
details:
email : johnb#example.com
firstname : john
lastname : belk
- Ops:
- name: "benol"
role: devops
details:
email : benol#example.com
firstname : ben
lastname : olkin
- name: "pauld"
role: devops
details:
email : pauld#example.com
firstname : paul
lastname : dempler
I am using locals to get the yaml data:
locals {
ou_config = yamldecode(file("employees.yaml"))
}
I want to run into the list of objects on "Dev" and "Ops" lists using for_each.
for example, I want to run on the "Dev" list to get the following list of objects in the first iteration:
[
{
key = "email"
value = "danielf#example.com"
},
{
key = "firstname"
value = "daniel"
},
{
key = "lastname"
value = "folskin"
}
]
The next run on the for_each will be:
[
{
key = "email"
value = "johnb#example.com"
},
{
key = "firstname"
value = "john"
},
{
key = "lastname"
value = "belk"
}
]
etc.
How can I do it on terraform?
If I understand correctly, all you are trying to extract is the details portion of that yaml file ...
Here is what I would do to get all:
locals {
ou_config = yamldecode(file("employees.yaml"))
expanded_names = flatten([
for e in local.ou_config.Employees : [
for d in e.Department : [
for key, person in d : [
for key, value in person : [
value.details
]
]
]
]
])
}
output "test" {
value = local.expanded_names
}
And if we want to filter we add an if key == "Dev"
locals {
ou_config = yamldecode(file("employees.yaml"))
expanded_names = flatten([
for e in local.ou_config.Employees : [
for d in e.Department : [
for key, person in d : [
for key, value in person : [
value.details
]
] if key == "Dev"
]
]
])
}
output "test" {
value = local.expanded_names
}
A terraform plan on that will look like:
Changes to Outputs:
+ test = [
+ {
+ email = "danielf#example.com"
+ firstname = "daniel"
+ lastname = "folsik"
},
+ {
+ email = "johnb#example.com"
+ firstname = "john"
+ lastname = "belk"
},
]
That format should be easier to loop in the final resource than the key value you suggested

Parse and modify JSON

I've a JSON with next structure and data:
[ {
"id" : 716612,
"type" : "ad",
"stats" : [ {
"day" : "2020-06-01",
"impressions" : 1956,
"clicks" : 1,
"reach" : 1782
},
{
"day" : "2020-06-13",
"spent" : "73.32",
"reach" : 1059
} ]
}, {
"id" : 414290,
"type" : "campaign",
"stats" : [ {
"day" : "2020-05-21",
"effective_cost_per_click" : "31.200",
"effective_cost_per_mille" : "108.337"
},
{
"day" : "2020-05-17",
"impressions" : 1,
"reach" : 1,
"ctr" : "0.000",
"uniq_views_count" : 1
} ]
} ]
I need to map id and type from top level with data inside stats to get result like this:
[ {
"id" : 716612,
"type" : "ad",
"day" : "2020-06-01",
"impressions" : 1956,
"clicks" : 1,
"reach" : 1782
},
{
"id" : 716612,
"type" : "ad",
"day" : "2020-06-13",
"spent" : "73.32",
"reach" : 1059
},
...
I tried with:
def json = new JsonSlurper().parseText(text)
def result = json.collectMany{ a ->
a["stats"].collectMany{ b ->
b.collect{
[id: a.id,
type: a.type
]
}
}
}
But it returns only id and type fields without stats. I thought that I'm looping through stat and just adding needed fields from above. I guess I don't get the difference between collectMany and collect?
You were close 😁
You want to collect the stat plus the id and type, so you need:
def result = json.collectMany { a ->
a.stats.collect { b ->
[ id: a.id, type: a.type ] + b
}
}

terraform output map value from lists of maps

I want to get a specific map element from a lists of maps in Terraform's output.
For example, how would I access account in properties.json for each map item
and print a list as output conditionally for type also.
I tried for loops and splat expressions as below but it does not return exact value.
It seems that the props below is also a list.
output "resources_by_name" {
description = "Resource name of all machine type resources from a vRA deployment"
value = [
for props in deployment.deploy[*].resources.*.properties_json:
jsondecode(props).account
if jsondecode(props).type == "vsphere"
]
}
I am not sure how to use nested for loops or access map items within the lists.
properties.json
[
[
{
"id" = "b5336bf7-07fb-4026-aa3d-479bd974ca45"
"name" = "test1"
"properties_json" = "{"account":"test0","constraints":"anothertest4"}"
"type" = "vsphere"
},
{
"id" = "67a3380b-8008-4f9c-9c13-2a1a935d5820"
"name" = "test2"
"properties_json" = "{"account":"test1","constraints":"anothertest3"}"
"type" = "gcp"
},
],
[
{
"id" = "eeddd127-cba2-4b34-a2d7-e56dda5d2974"
"name" = "test3"
"properties_json" = "{"account":"test2","constraints":"anothertest2"}"
"type" = "aws"
},
{
"id" = "81de1857-c0c9-4c9e-8fbd-d8a1da64fa3c"
"name" = "test4"
"properties_json" = "{"account":"test3","constraints":"anothertest1"}"
"type" = "az"
},
],
]
Here is working example. I had to fill out the blanks missing from your question, thus you may need to modify it to suit your needs:
locals {
properties = [
[
{
"id" = "b5336bf7-07fb-4026-aa3d-479bd974ca45"
"name" = "test1"
"properties_json" = "{\"account\":\"test0\",\"constraints\":\"anothertest4\"}"
"type" = "vsphere"
},
{
"id" = "67a3380b-8008-4f9c-9c13-2a1a935d5820"
"name" = "test2"
"properties_json" = "{\"account\":\"test1\",\"constraints\":\"anothertest3\"}"
"type" = "gcp"
},
],
[
{
"id" = "eeddd127-cba2-4b34-a2d7-e56dda5d2974"
"name" = "test3"
"properties_json" = "{\"account\":\"test2\",\"constraints\":\"anothertest2\"}"
"type" = "aws"
},
{
"id" = "81de1857-c0c9-4c9e-8fbd-d8a1da64fa3c"
"name" = "test4"
"properties_json" = "{\"account\":\"test3\",\"constraints\":\"anothertest1\"}"
"type" = "az"
},
],
]
}
output "resources_by_name" {
value = [for props in flatten(local.properties):
jsondecode(props.properties_json).account
if props.type == "vsphere"
]
}
Outcome:
resources_by_name = [
"test0",
]

Resources