Terraform: JSON Path Query doesn't work in terraform - json

I have data like below in json file site24x7IPs.json, and new filter it in terraform:
{
"LocationDetails": [
{
"IPv6_Address_External": "2803:eb80:4000:d::0/64",
"City": "Buenos Aires",
"Place": "Argentina",
"external_ip": "170.78.75.88"
},
{
"IPv6_Address_External": "",
"City": "Buenos Aires",
"Place": "Argentina",
"external_ip": "170.78.75.87"
},
{
"IPv6_Address_External": "",
"City": "Melbourne",
"Place": "Australia",
"external_ip": "103.91.166.0/24"
}
]
}
And terraform code:
locals {
site24x7IPs = jsondecode(file("${path.module}/site24x7IPs.json"))
}
output "site24x7IPs" {
#value = local.site24x7IPs.LocationDetails[*].external_ip # This works
# I'd like to filter the IP from Australia,
value = local.site24x7IPs.LocationDetails[?(#.Place == "Australia")].external_ip
}
Expecting Result:
"103.91.166.0/24"
Output:
value = local.site24x7IPs.LocationDetails[?(#.Place == "Australia")].external_ip
This character is not used within the language.
.LocationDetails[?(#.Place == "Australia")].external_ip is the JSON query syntax, but it doesn't work in Terraform.
Is there a similar way to achieve the filtering goal in Terraform?
Thanks,

This should give you the result:
output "australia_ip_with_quotes" {
value = format("%q",element([for i in local.site24x7IPs.LocationDetails: i.external_ip if i.Place == "Australia"],0))
}
output "australia_ip_without_quotes" {
value = element([for i in local.site24x7IPs.LocationDetails: i.external_ip if i.Place == "Australia"],0)
}
output "list" {
value = [for i in local.site24x7IPs.LocationDetails: i.external_ip if i.Place == "Australia"]
}
Outputs:
australia_ip_with_quotes = "103.91.166.0/24"
australia_ip_without_quotes = 103.91.166.0/24
list = [
"103.91.166.0/24",
]

Related

How to get the All index values in Groovy JSON xpath

Please find the attached Groovy code which I am using to get the particular filed from the response body.
Query 1 :
It is retrieving the results when the I am using the correct Index value like if the data.RenewalDetails[o], will give output as Value 1 and if the data.RenewalDetails[1], output as Value 2.
But in my real case, I will never know about number of blocks in the response, so I want to get all the values that are satisficing the condition, I tried data.RenewalDetails[*] but it is not working. Can you please help ?
Query 2:
Apart from the above condition, I want to add one more filter, where "FamilyCode": "PREMIUM" in the Itemdetails, Can you help on the same ?
def BoundId = new groovy.json.JsonSlurper().parseText('{"data":{"RenewalDetails":[{"ExpiryDetails":{"duration":"xxxxx","destination":"LHR","from":"AUH","value":2,"segments":[{"valudeid":"xxx-xx6262-xxxyyy-1111-11-11-1111"}]},"Itemdetails":[{"BoundId":"Value1","isexpired":true,"FamilyCode":"PREMIUM","availabilityDetails":[{"travelID":"AAA-AB1234-AAABBB-2022-11-10-1111","quota":"X","scale":"XXX","class":"X"}]}]},{"ExpiryDetails":{"duration":"xxxxx","destination":"LHR","from":"AUH","value":2,"segments":[{"valudeid":"xxx-xx6262-xxxyyy-1111-11-11-1111"}]},"Itemdetails":[{"BoundId":"Value2","isexpired":true,"FamilyCode":"PREMIUM","availabilityDetails":[{"travelID":"AAA-AB1234-AAABBB-2022-11-10-1111","quota":"X","scale":"XXX","class":"X"}]}]}]},"warnings":[{"code":"xxxx","detail":"xxxxxxxx","title":"xxxxxxxx"}]}')
.data.RenewalDetails[0].Itemdetails.find { itemDetail ->
itemDetail.availabilityDetails[0].travelID.length() == 33
}?.BoundId
println "Hello " + BoundId
Something like this:
def txt = '''\
{
"data": {
"RenewalDetails": [
{
"ExpiryDetails": {
"duration": "xxxxx",
"destination": "LHR",
"from": "AUH",
"value": 2,
"segments": [
{
"valudeid": "xxx-xx6262-xxxyyy-1111-11-11-1111"
}
]
},
"Itemdetails": [
{
"BoundId": "Value1",
"isexpired": true,
"FamilyCode": "PREMIUM",
"availabilityDetails": [
{
"travelID": "AAA-AB1234-AAABBB-2022-11-10-1111",
"quota": "X",
"scale": "XXX",
"class": "X"
}
]
}
]
},
{
"ExpiryDetails": {
"duration": "xxxxx",
"destination": "LHR",
"from": "AUH",
"value": 2,
"segments": [
{
"valudeid": "xxx-xx6262-xxxyyy-1111-11-11-1111"
}
]
},
"Itemdetails": [
{
"BoundId": "Value2",
"isexpired": true,
"FamilyCode": "PREMIUM",
"availabilityDetails": [
{
"travelID": "AAA-AB1234-AAABBB-2022-11-10-1111",
"quota": "X",
"scale": "XXX",
"class": "X"
}
]
}
]
}
]
},
"warnings": [
{
"code": "xxxx",
"detail": "xxxxxxxx",
"title": "xxxxxxxx"
}
]
}'''
def json = new groovy.json.JsonSlurper().parseText txt
List<String> BoundIds = json.data.RenewalDetails.Itemdetails*.find { itemDetail ->
itemDetail.availabilityDetails[0].travelID.size() == 33 && itemDetail.FamilyCode == 'PREMIUM'
}?.BoundId
assert BoundIds.toString() == '[Value1, Value2]'
Note, that you will get the BoundIds as a List
If you amend your code like this:
def json = new groovy.json.JsonSlurper().parse(prev.getResponseData()
you would be able to access the number of returned items as:
def size = json.data.RenewalDetails.size()
as RenewalDetails represents a List
Just add as many queries you want using Groovy's && operator:
find { itemDetail ->
itemDetail.availabilityDetails[0].travelID.length() == 33 &&
itemDetail.FamilyCode.equals('PREMIUM')
}
More information:
Apache Groovy - Parsing and producing JSON
Apache Groovy: What Is Groovy Used For?

how can I insert variables into json file when using terraform

this is the module folder structure
the json definition file (machine_definition.json)
{
"Comment": "A Hello World example of the Amazon States Language using Pass states",
"StartAt": "Hello",
"States": {
"Hello": {
"Type": "Pass",
"Result": "Hello",
"Next": "World"
},
"World": {
"Type": "${var.test}",
"Result": "World",
"End": true
}
}
}
for example I'm trying to enter var.test in here.
how to make the json file detect my variables?
here is the step function definition
module "step-functions" {
source = "terraform-aws-modules/step-functions/aws"
name = "env-${var.environment}-state-machine"
definition = file("${path.module}/machine_definition.json")
tags = var.tags
service_integrations = {
xray = {
xray = true
}
}
cloudwatch_log_group_name = "env-${var.environment}-state-machine-logGroup"
attach_policies = true
number_of_policies = 2
policies = ["arn:aws:iam::aws:policy/AmazonS3FullAccess", "arn:aws:iam::aws:policy/AWSLambda_FullAccess"]
}
Variables cannot be added to a file that way. In order to achieve what you want, you need to use the templatefile [1] built-in fuction. To achieve this you need a bit of code change:
definition = templatefile("${path.module}/machine_definition.json", {
type = var.test
})
Then, in the JSON file, you need to reference the templated variable (type) like this:
{
"Comment": "A Hello World example of the Amazon States Language using Pass states",
"StartAt": "Hello",
"States": {
"Hello": {
"Type": "Pass",
"Result": "Hello",
"Next": "World"
},
"World": {
"Type": "${type}",
"Result": "World",
"End": true
}
}
}
This should render the file properly.
[1] https://developer.hashicorp.com/terraform/language/functions/templatefile

Groovy script to compare 2 JSON array objects

I am trying to find the best way to compare 2 JSON Array objects using Groovy script.
JSON Obj1 =
{
"PO":
[
{
"OrderNumber": "12345",
"Location": "US",
}
{
"OrderNumber": "11223",
"Location": "US",
}
]
}
JSON Obj2 = {
"ResultPO":
[
{
"OrderNumber": "12345_00001",
"Location": "US",
"Customer": "ABC"
}
{
"OrderNumber": "98765_00002",
"Location": "US",
"Customer": "XYZ"
}
]
}
I need to return the JSON Output as below after finding the obj1 value in obj2 where OrderNumber is key identifier.
{
"ResultPO":
[
{
"OrderNumber": "12345_00001",
"Location": "US",
"Customer": "ABC"
}
]
}
Below is the sample code I have tried using JsonSlurper and findall but not able to get desired outcome.
def builder
def filterJson
filterJson = Obj2.findAll(){ it.OrderNumber.substring(0,4) == Obj1.OrderNumber.text()}
builder = new JsonBuilder(filterJson)
Try this one:
class OrderFilterSpec extends Specification {
def str1 = """{"PO":[
{"OrderNumber": "12345","Location": "US"},
{"OrderNumber": "11223","Location": "US"}
]}"""
def str2 = """{"ResultPO":[
{"OrderNumber": "12345_00001","Location": "US","Customer": "ABC"},
{"OrderNumber": "98765_00002","Location": "US","Customer": "XYZ"}
]}"""
def slurper = new JsonSlurper()
def buildResult(String first, String second) {
def (parsed1, parsed2) = [slurper.parseText(first), slurper.parseText(second)]
def filteredOrders = parsed2.ResultPO.findAll {
it.OrderNumber[0..4] in parsed1.PO.collect { it.OrderNumber }
}
return [ResultPO: filteredOrders]
}
def 'test order filtering'() {
expect:
buildResult(str1, str2) == [ResultPO: [[OrderNumber: '12345_00001', Location: 'US', Customer: 'ABC']]]
}
}

Find specific value in a large json file

I've a simple json array similar to the below. I'd like to find the record that contain a matching value, say for example name == jack.
{
"data": [
{
"Record": {
"attributes": {
"name": "Jack",
"age": "38",
"description": "1234",
}
}
}
]
}
Below python code works but it is very slow. Is there any way to get the results quicker?
with open('records.json') as f:
input_dict = json.load(f)
input_var = input_dict["data"]
for i in input_var:
if i["Record"]["attributes"]["name"] == "Jack":
print(i["Record"]["attributes"])
break

Get Values form Json, using jpath

{
"data": [
{
"id": "52fb62dc-a446-4fbb-9c7e-e75d8c90f6d9",
"name": "abx",
"address": {
"address1": "New Address 1",
"address2": "New Address 2",
"Pin":"800001"
}
},
{
"id": "52fb62dc-a446-4fbb-9c7e-e75d8c90f6d9",
"name": "xyz",
"address": {
"address1": "New Address 1",
"address2": "New Address 2",
"Pin":"800002"
}
},
{
"id": "52fb62dc-a446-4fbb-9c7e-e75d8c90f6d9",
"name": "ijk",
"address": {
"address1": "New Address 1",
"address2": "New Address 2",
"Pin":"800003"
}
}
]
}
Out put json should be like this
[
{
"name": "abx",
"Pin": "800001"
},
{
"name": "xyz",
"Pin": "800002"
},
{
"name": "ijk",
"Pin": "800003"
}
]
From the input json, I want to extract all values using
jpath
Name Path = "data.name"
Pin Path = "data.address.pin"
I need all values, I will create an output json.
If both json and jpath are dynamic then try using the below code, here i have used the same input json and output json in my code block.
$(document).ready(function () {
var outputArr = [];
//Assume that these jpaths are dynamic.
var name = "data.name", pin = "data.address.Pin";
//Assigned input json object to sampleData variable.
$.each(sampleData.data, function (item, value) {
//Replacing 'data.' with empty('') as we are looping through data array.
var nameValue = extractValue(value, name.replace('data.', ''));
var pinValue = extractValue(value, pin.replace('data.', ''));
outputArr.push({ 'name': nameValue, 'Pin': pinValue });
});
//logging into console for testing purpose.
console.log(outputArr);
--to do with outputArr --
//Recursive function that returns the required value from the json
function extractValue(value, jPathKey) {
if (jPathKey.split(".").length > 1) {
//Here use of replace function is must as we need to get the object with the mentioned jPathKey to loop further.
return extractValue(value[jPathKey.replace('.', '$').split('$')[0]], jPathKey.replace('.', '$').split('$')[1])
}
else {
return value[jPathKey];
}
}
});
Note: Here only thing that need to take care is the case of jpath should match with case of input json