Accessing list element in terraform output - json

I have following code in terraform state file( pasted just part of state file which I consider relevant for this question), which is result of running terraform code pasted below as well:
"mode": "managed",
"type": "azurerm_vpn_gateway",
"name": "azure_vpngw",
"provider": "provider[\"registry.terraform.io/hashicorp/azurerm\"].azure_clusters",
"instances": [
{
"schema_version": 0,
"attributes": {
"bgp_settings": [
{
"asn": 65515,
"bgp_peering_address": "",
"instance_0_bgp_peering_address": [
{
"custom_ips": [
"169.254.21.1"
],
"default_ips": [
"10.255.176.12"
],
"ip_configuration_id": "Instance0",
"tunnel_ips": [
"10.255.176.4",
"20.184.79.231"
]
Relevant terraform code:
resource "azurerm_vpn_gateway" "azure_vpngw" {
provider = azurerm.azure_clusters
name = "azure_vpngw"
location = azurerm_resource_group.azure_networking.location
resource_group_name = azurerm_resource_group.azure_networking.name
virtual_hub_id = azurerm_virtual_hub.azure_hub.id
bgp_settings {
asn = 65515
peer_weight = 50
instance_0_bgp_peering_address {
custom_ips = ["169.254.21.1"]
}
instance_1_bgp_peering_address {
custom_ips = ["169.254.22.1"]
}
}
}
And I need to accesss last element in tunnel_ips list, so 20.184.79.231.
I have been trying diff things like
azurerm_vpn_gateway.azure_vpngw.bgp_settings[0].instance_0_bgp_peering_address[0].tunnel_ips[0][1]
but it did not work. So, issue is in last part - tunnel_ips[0][1] I believe. If anybody has idea, it would be very wellcome.

Since your code is not a valid TF code, I modified it to actually be such, and this is how you can access your ip:
locals {
t = <<EOL
{
"mode": "managed",
"type": "azurerm_vpn_gateway",
"name": "azure_vpngw",
"provider": "provider[azure_clusters",
"instances": [{
"schema_version": 0,
"attributes": {
"bgp_settings": [{
"asn": 65515,
"bgp_peering_address": "",
"instance_0_bgp_peering_address": [{
"custom_ips": [
"169.254.21.1"
],
"default_ips": [
"10.255.176.12"
],
"ip_configuration_id": "Instance0",
"tunnel_ips": [
"10.255.176.4",
"20.184.79.231"
]
}]
}]
}
}]
}
EOL
v = jsondecode(local.t)
}
output "test" {
value = local.v["instances"][0]["attributes"]["bgp_settings"][0]["instance_0_bgp_peering_address"][0]["tunnel_ips"][1]
}
gives:
test = "20.184.79.231"

I figure it out. So, to fetch IP and use it in another resource definition I did:
ip_address = sort(azurerm_vpn_gateway.azure_vpngw.bgp_settings[0].instance_0_bgp_peering_address[0].tunnel_ips)[1]

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?

jmespath :select json object element based on other (array) element in the object

I have this JSON
{
"srv_config": [{
"name": "db1",
"servers": ["srv1", "srv2"],
"prop": [{"source":"aa"},"destination":"bb"},{"source":"cc"},"destination":"cc"},]
}, {
"name": "db2",
"servers": ["srv2", "srv2"],
"prop": [{"source":"dd"},"destination":"dd"},{"source":"ee"},"destination":"ee"},]
}
]
}
I try to build a JMESPath expression to select the prop application in each object in the main array, but based on the existence of a string in the servers element.
To select all props, I can do:
*.props [*]
But how do I add condition that says "select only if srv1 is in servers list"?
You can use the contains function in order to filter based on a array containing something.
Given the query:
*[?contains(servers, `srv1`)].prop | [][]
This gives us:
[
{
"source": "aa",
"destination": "bb"
},
{
"source": "cc",
"destination": "cc"
}
]
Please mind that I am also using a bit of flattening here.
All this run towards a corrected version of you JSON:
{
"srv_config":[
{
"name":"db1",
"servers":[
"srv1",
"srv2"
],
"prop":[
{
"source":"aa",
"destination":"bb"
},
{
"source":"cc",
"destination":"cc"
}
]
},
{
"name":"db2",
"servers":[
"srv2",
"srv2"
],
"prop":[
{
"source":"dd",
"destination":"dd"
},
{
"source":"ee",
"destination":"ee"
}
]
}
]
}

react native json image

I want to print out JSON images as a variable.
This is my local JSON file (JsonData.json):
{
"appetizer": [
{
"num": "appetizer1",
"name": "salad",
"condition": [ "1", "2" ],
"image": "./appetizer/salad.png"
},
{
"num": "appetizer2",
"name": "soup",
"condition": [ "2", "3" ],
"image": "./appetizer/soup.png"
},
…
],
"main": [
{
"num": "main1",
"name": "beef",
"condition": [ "1" ],
"image": "./main/beef.png"
},
{
"num": "main2",
"name": "fish",
"condition": [ "2", "3" ],
"image": "./main/fish.png"
},
…
]
}
I filtered the name when condition="2". (salad,soup,fish)
This is the code for filtering name:
const newArray1 = [...JsonData["apptizer"], ...JsonData["main"]];
const JsonResult = newArray1.filter(item => {
if(item.condition.indexOf("2") !== -1) return item.name;
});
AND I want to get the image when condition="2".
How can I get them? And How can I print out them?
Do I have to use base64? If so, Can you tell me how to use it?
I saw the explanation, but I can't understand it.
And I imported JSON file this way (I've been correctly using it):
var JsonData = require('./JsonData.json');
You can use below code:
let mainObject = JSON.parse(JSON.stringify(data))
let allKeys = Object.keys(mainObject)
let finalObject = []
allKeys.map((value, index) => {
let array = mainObject[value]
array.map((aryObject, aryIndex) => {
let condition = aryObject['condition']
if (condition.includes('2')) {
finalObject.push(aryObject)
}
})
})
alert(JSON.stringify(finalObject))
You can import data in top of screen:
import { data } from './data';
You can add below text in data.js:
export const data = {
"appetizer": [
{
"num": "appetizer1",
"name": "salad",
"condition": ["1"],
"image": "./appetizer/salad.png"
},
{
"num": "appetizer2222",
"name": "soup",
"condition": ["2", "3"],
"image": "./appetizer/soup.png"
},
],
"main": [
{
"num": "main1",
"name": "beef",
"condition": ["1"],
"image": "./main/beef.png"
},
{
"num": "main2",
"name": "fish",
"condition": ["21", "3"],
"image": "./main/fish.png"
},
]
}
You can use Object#values to get the arrays corresponding to appetizer and main and then Array#flat to extract the nested objects into a transformed array. Then use the Array#filter (which you are already using) to filter out only the required objects based on your condition and then Array#map to get the name and image values out of every filtered object into an array of objects.
Please consider following snippts
const jsonData = {"appetizer":[{"num":"appetizer1","name":"salad","condition":["1","2"],"image":"./appetizer/salad.png"},{"num":"appetizer2","name":"soup","condition":["2","3"],"image":"./appetizer/soup.png"}],"main":[{"num":"main1","name":"beef","condition":["1"],"image":"./main/beef.png"},{"num":"main2","name":"fish","condition":["2","3"],"image":"./main/fish.png"}]};
const filteredValues = Object.values(jsonData)
.flat()
.filter(o => o.condition.includes('2'))
.map(({name, image}) => ({ name, image }));
console.log(filteredValues);
The output of the above code will be an array of objects having the following structure
[{
"name": SOME_NAME,
"image": SOME_PATH
},
{
"name": SOME_NAME,
"image": SOME_PATH
},
...
]
You can use the above array to retrieve your image path and display it accordingly.
I think you shouldn't be worried about base64 as images are stored locally and path will be sufficient to display the image.
Hope this will help!!!
Side Note: You can avoid the Array#flat part as you are already doing it manually [...JsonData["apptizer"], ...JsonData["main"]] but flat will be handy in case there are more keys in jsonData that need to be considered.

Dwg comparison through design automation

I would like to know if it is possible, and if yes, how can I achieve dwg comparison through the design automation? I there a way to create a comparison activity accepting 2 dwg in input, and post a boolean as output?
Yes you can create an activity accepting two drawings.
Following activity JSON uses an in-built compare and output the result diff drawing.
Sample Activity Json
{
"HostApplication": "",
"RequiredEngineVersion": "23.0",
"Parameters": {
"InputParameters": [
{
"Name": "HostDwg",
"LocalFileName": "$(HostDwg)"
},
{
"Name": "ToCompareWith",
"LocalFileName": "ToCompareWith.dwg"
}
],
"OutputParameters": [
{
"Name": "Result",
"LocalFileName": "output.dwg"
}
]
},
"Instruction": {
"CommandLineParameters": null,
"Script": "COMPAREINPLACE\nON\n-COMPARE\n\nToCompareWith.dwg\n_SAVEAS\n\noutput.dwg\n"
},
"Id": "FPDCompare"
}
Workitem Json
{
"Arguments": {
"InputArguments": [
{
"Resource": "https://madhukar-fda.s3.us-west-2.amazonaws.com/Kitchens1.dwg",
"Name": "HostDwg"
},
{
"Resource": "https://madhukar-fda.s3.us-west-2.amazonaws.com/Kitchens2.dwg",
"Name": "ToCompareWith"
}
],
"OutputArguments": [
{
"Name": "Result",
"HttpVerb": "POST"
}
]
},
"ActivityId": "FPDCompare"
}
If you are using your own custom compare logic, you can output the
results to txt file or json file.
Activity Json
{
"HostApplication": "",
"RequiredEngineVersion": "23.0",
"Parameters": {
"InputParameters": [
{
"Name": "HostDwg",
"LocalFileName": "$(HostDwg)"
},
{
"Name": "ToCompareWith",
"LocalFileName": "ToCompareWith.dwg"
}
],
"OutputParameters": [
{
"Name": "Result",
"LocalFileName": "output.txt"
}
]
},
"Instruction": {
"CommandLineParameters": null,
"Script": "ISDWGSIMILAR\nToCompareWith.dwg\n"
},
"AppPackages":["Compare"],
"Version": 1,
"Id": "Compare"
}
Workitem Json
{
"Arguments": {
"InputArguments": [
{
"Resource":"https://madhukar-fda.s3.us-west-2.amazonaws.com/Kitchens.dwg",
"Name": "HostDwg"
},
{
"Resource":"https://madhukar-fda.s3.us-west-2.amazonaws.com/Kitchens1.dwg",
"Name": "ToCompareWith"
}
],
"OutputArguments": [
{
"Name": "Result",
"HttpVerb": "POST"
}
]
},
"ActivityId": "Compare"
}
Note: In the script argument - "ISDWGSIMILAR" is a custom command where you will process two drawings, the first one will be current and second one is the drawing to which you are willing compare [ToCompareWith]
Custom NET Command
[CommandMethod("FDACOMMANDS", "ISDWGSIMILAR", CommandFlags.Transparent)]
public static void CompareDrawing()
{
var doc = Application.DocumentManager.MdiActiveDocument;
var db = doc.Database;
var ed = doc.Editor;
var promptResult = ed.GetString("Select Drawing To Compare With");
if (promptResult.Status != PromptStatus.OK) return;
var drawingToCompareWith = promptResult.StringResult;
ed = Application.DocumentManager.MdiActiveDocument.Editor;
using (OpenCloseTransaction o = new OpenCloseTransaction())
{
/*
{
Here your logic code to compare two drawings
}
*/
/*output.txt / json is pushed to your cloud storage as provided in workitem json*/
using (var writer = File.CreateText("output.txt"))
{
if (b != null) /*b value is result of your compare*/
{
writer.WriteLine("TRUE Drawings are same");
}
else writer.WriteLine("FALSE Drawings aren't same");
}
}
}

Set next step for the waterfall dialogue in Microsoft BotBuilder NodeJS SDK

I am using Microsoft Bot Framework for my facebook messenger bot. I want to load the dialog data from json files instead of hard coding in the js file. I would like to configure the next step in the dialog, based on result from the "current" step, which is part of the json file configuration, something like this.
{
"name": "welcome",
"type": "waterfall",
"steps": [
{
"id": 0,
"data": [
{
"type": "text",
"value": "Hey, It's nice to meet you."
},
{
"type": "quickReplies",
"value": "What do you want to do next?",
"options": [
{
"text": "some option 1",
"value": "option1"
},
{
"text": "some option 2",
"value": "option2"
}
]
}
],
"next": [
{
"result": "option1",
"action": "goto step 2"
},
{
"result": "option2",
"action": "goto step 5"
}
]
}
]
}
I would like to process all the incoming messages and respond with correct dialog or correct step in the dialog for the user.
I am trying something like this;
handleMessage = function (session) {
var step = session.dialogData["BotBuilder.Data.WaterfallStep"] || 0;
// check response data from previou step and identify the next step.
// set the waterfall step id
session.dialogData["BotBuilder.Data.WaterfallStep"] = 2;
session.send("Hello");
}
var bot = new builder.UniversalBot(connector, function (session) {
handleMessage(session);
})
.set('storage',tableStorage);
With this code, I am always getting step as zero for session.dialogData["BotBuilder.Data.WaterfallStep"] even after setting this to a different number.
Also, as soon as I set the waterfall step number, all other state data that is stored in my table storage for this conversation is gone.
Storage data before setting waterfall step:
{
"BotBuilder.Data.SessionState": {
"callstack": [
{
"id": "*:/",
"state": {
"BotBuilder.Data.WaterfallStep": 0
}
},
{
"id": "*:welcome",
"state": {
"BotBuilder.Data.WaterfallStep": 1
}
},
{
"id": "BotBuilder:prompt-text",
"state": {
"options": {
"prompt": {
"type": "message",
"agent": "botbuilder",
"source": "facebook",
"address": {
"id": "mid.$cAAAlr-0LRH9niO21L1hV6hs83GuJ",
"channelId": "facebook",
"user": {
"id": "XXXX",
"name": "XXXX"
},
"conversation": {
"isGroup": false,
"id": "XX"
},
"bot": {
"id": "XXX",
"name": "XXX"
},
"serviceUrl": "https://facebook.botframework.com"
},
"text": "what do you want to next"
//ignored for simplicity
},
"promptAfterAction": true,
"libraryNamespace": "*"
},
"turns": 0,
"lastTurn": 1517594116372,
"isReprompt": false
}
}
],
"lastAccess": 1517594112740,
"version": 0
}
}
After I set the waterfall step:
{
"BotBuilder.Data.SessionState": {
"callstack": [
{
"id": "*:/",
"state": {
"BotBuilder.Data.WaterfallStep": 2
}
}
],
"lastAccess": 1517602122416,
"version": 0
}
}
Interestingly the step number is saved to the database (but in session state) but my "session" variable do not have this value anywhere. Also, even after configuring custom state service, the serviceUrl is still https://facebook.botframework.com which I thought is the default state service used if there is no state service set for the bot.
Per your code, as your bot actually contains only one waterfall step: handleMessage(session);, which raised your issue. You can consider to create multiple dialogs from json configration instead of complex waterfall steps.
Here is my quick test, for your information:
const json = `
[{
"name": "welcome",
"type": "waterfall",
"steps": [
{
"id": 0,
"data": [
{
"type": "text",
"value": "Hey, It's nice to meet you."
},
{
"type": "quickReplies",
"value": "What do you want to do next?",
"options": [
{
"text": "some option 1",
"value": "option1"
},
{
"text": "some option 2",
"value": "option2"
}
]
}
],
"next": [
{
"result": "option1",
"action": "dialog2"
},
{
"result": "option2",
"action": "dialog3"
}
]
}
]
},{
"name":"dialog2",
"type": "waterfall",
"steps": [
{
"data": [
{
"type": "text",
"value": "Hey, this is dialig2."
}]
}
]
},{
"name":"dialog3",
"type": "waterfall",
"steps": [
{
"data": [
{
"type": "text",
"value": "Hey, this is dialig3."
}]
}
]
}]
`;
const generateSignleStep = (step) => {
return (session, args, next) => {
step.forEach(sentence => {
switch (sentence.type) {
case 'quickReplies':
let choices = sentence.options.map(item => {
return item.value
});
let card = new builder.ThumbnailCard(session)
.text(sentence.value)
.buttons(sentence.options.map(choice => new builder.CardAction.imBack(session, choice.value, choice.text)))
let message = new builder.Message(session).addAttachment(card);
builder.Prompts.choice(session, message, choices);
break;
case 'text':
default:
session.send(sentence.value)
break;
}
})
}
}
const generatenextAction = (actions) => {
return (session, args, next) => {
const response = args.response;
actions.map(action => {
if (action.result == response.entity) {
session.beginDialog(action.action);
}
})
}
}
const generateWaterfallSteps = (steps) => {
let waterfall = [];
steps.forEach(step => {
waterfall.push(generateSignleStep(step.data));
if (step.next) {
waterfall.push(generatenextAction(step.next));
}
});
return waterfall;
}
var bot = new builder.UniversalBot(connector);
const jsonobj = JSON.parse(json);
jsonobj.forEach(dialog => {
bot.dialog(dialog.name, generateWaterfallSteps(dialog.steps))
.triggerAction({
matches: new RegExp(dialog.name, "g")
})
});
The result is: