Reputation: 307
I have some (redacted) JSON at the bottom of this post, a result of running ec2-describe-instances in AWS. The sample JSON has 2 arrays, however this could be larger. I have used jq before but I am having trouble pulling out values that are deeply nested in the JSON. In particular, I am interested in:
Summarised, I want a JSON array I can iterate over that will give me an InstanceID, tags on that instance and a single volume. You will notice that each instance has 3 volumes attached (could be more, or less). I'd like to be able to iterate over each one individually. The end result I am hoping would look something like this:
[
{
"InstanceId": "i-11111111",
"DeviceName": "/dev/sda1",
"VolumeId": "vol-1111111a",
"TAG1": "VALUE1",
"TAG2": "VALUE2"
},
{
"InstanceId": "i-11111111",
"DeviceName": "xvdf",
"VolumeId": "vol-1111111b",
"TAG1": "VALUE1",
"TAG2": "VALUE2"
},
{
"InstanceId": "i-11111111",
"DeviceName": "xvdg",
"VolumeId": "vol-1111111c",
"TAG1": "VALUE1",
"TAG2": "VALUE2"
},
{
"InstanceId": "i-22222222",
"DeviceName": "/dev/sda1",
"VolumeId": "vol-2222222a",
"TAG1": "VALUE1",
"TAG2": "VALUE2"
},
{
"InstanceId": "i-22222222",
"DeviceName": "/dev/sdb",
"VolumeId": "vol-2222222b",
"TAG1": "VALUE1",
"TAG2": "VALUE2"
},
{
"InstanceId": "i-22222222",
"DeviceName": "/dev/sdc",
"VolumeId": "vol-2222222c",
"TAG1": "VALUE1",
"TAG2": "VALUE2"
}
]
This is similar to another question I have posted here on stackoverflow. I have tried so many different combinations but cannot get this to work. Any help is really appreciated.
Here's the JSON:
{
"Reservations": [
{
"OwnerId": "xx",
"ReservationId": "xx",
"Groups": [],
"Instances": [
{
"Monitoring": {
"State": "xx"
},
"PublicDnsName": "",
"Platform": "xx",
"State": {
"Code": xx,
"Name": "xx"
},
"EbsOptimized": xx,
"LaunchTime": "xx",
"PrivateIpAddress": "xx",
"ProductCodes": [],
"VpcId": "xx",
"StateTransitionReason": "",
"InstanceId": "i-11111111",
"ImageId": "xx",
"PrivateDnsName": "xx",
"KeyName": "xx",
"SecurityGroups": [
{
"GroupName": "xx",
"GroupId": "xx"
},
{
"GroupName": "xx",
"GroupId": "xx"
}
],
"ClientToken": "xx",
"SubnetId": "xx",
"InstanceType": "xx",
"NetworkInterfaces": [
{
"Status": "xx",
"MacAddress": "xx",
"SourceDestCheck": xx,
"VpcId": "xx",
"Description": "xx",
"NetworkInterfaceId": "xx",
"PrivateIpAddresses": [
{
"PrivateDnsName": "xx",
"Primary": xx,
"PrivateIpAddress": "xx"
}
],
"PrivateDnsName": "xx",
"Attachment": {
"Status": "xx",
"DeviceIndex": xx,
"DeleteOnTermination": xx,
"AttachmentId": "xx",
"AttachTime": "xx"
},
"Groups": [
{
"GroupName": "xx",
"GroupId": "xx"
},
{
"GroupName": "xx",
"GroupId": "xx"
}
],
"SubnetId": "xx",
"OwnerId": "xx",
"PrivateIpAddress": "xx"
}
],
"SourceDestCheck": xx,
"Placement": {
"Tenancy": "xx",
"GroupName": "xx",
"AvailabilityZone": "xx"
},
"Hypervisor": "xx",
"BlockDeviceMappings": [
{
"DeviceName": "/dev/sda1",
"Ebs": {
"Status": "attached",
"DeleteOnTermination": xx,
"VolumeId": "vol-1111111a",
"AttachTime": "xx"
}
},
{
"DeviceName": "xvdf",
"Ebs": {
"Status": "attached",
"DeleteOnTermination": xx,
"VolumeId": "vol-1111111b",
"AttachTime": "xx"
}
},
{
"DeviceName": "xvdg",
"Ebs": {
"Status": "attached",
"DeleteOnTermination": xx,
"VolumeId": "vol-11111111c",
"AttachTime": "xx"
}
}
],
"Architecture": "xx",
"RootDeviceType": "xx",
"RootDeviceName": "xx",
"VirtualizationType": "hvm",
"Tags": [
{
"Value": "TAG1",
"Key": "VALUE1"
},
{
"Value": "TAG2",
"Key": "VALUE2"
},
{
"Value": "TAG3",
"Key": "VALUE3"
},
{
"Value": "TAG4",
"Key": "VALUE4"
},
{
"Value": "TAG5",
"Key": "VALUE5"
},
{
"Value": "TAG6",
"Key": "Value6"
}
],
"AmiLaunchIndex": xx
}
]
},
{
"OwnerId": "xx",
"ReservationId": "xx",
"Groups": [],
"Instances": [
{
"Monitoring": {
"State": "xx"
},
"PublicDnsName": "",
"Platform": "xx",
"State": {
"Code": xx,
"Name": "xx"
},
"EbsOptimized": xx,
"LaunchTime": "xx",
"PrivateIpAddress": "xx",
"ProductCodes": [],
"VpcId": "xx",
"StateTransitionReason": "",
"InstanceId": "i-22222222",
"ImageId": "xx",
"PrivateDnsName": "xx",
"KeyName": "xx",
"SecurityGroups": [
{
"GroupName": "xx",
"GroupId": "xx"
},
{
"GroupName": "xx",
"GroupId": "xx"
}
],
"ClientToken": "xx",
"SubnetId": "xx",
"InstanceType": "xx",
"NetworkInterfaces": [
{
"Status": "xx",
"MacAddress": "xx",
"SourceDestCheck": xx,
"VpcId": "xx",
"Description": "xx",
"NetworkInterfaceId": "xx",
"PrivateIpAddresses": [
{
"PrivateDnsName": "xx",
"Primary": xx,
"PrivateIpAddress": "xx"
}
],
"PrivateDnsName": "xx",
"Attachment": {
"Status": "xx",
"DeviceIndex": xx,
"DeleteOnTermination": xx,
"AttachmentId": "xx",
"AttachTime": "xx"
},
"Groups": [
{
"GroupName": "xx",
"GroupId": "xx"
},
{
"GroupName": "xx",
"GroupId": "xx"
}
],
"SubnetId": "xx",
"OwnerId": "xx",
"PrivateIpAddress": "xx"
}
],
"SourceDestCheck": xx,
"Placement": {
"Tenancy": "xx",
"GroupName": "xx",
"AvailabilityZone": "xx"
},
"Hypervisor": "xx",
"BlockDeviceMappings": [
{
"DeviceName": "/dev/sda1",
"Ebs": {
"Status": "attached",
"DeleteOnTermination": xx,
"VolumeId": "vol-2222222a",
"AttachTime": "xx"
}
},
{
"DeviceName": "/dev/sdb",
"Ebs": {
"Status": "attached",
"DeleteOnTermination": xx,
"VolumeId": "vol-2222222b",
"AttachTime": "xx"
}
},
{
"DeviceName": "/dev/sdc",
"Ebs": {
"Status": "attached",
"DeleteOnTermination": xx,
"VolumeId": "vol-2222222c",
"AttachTime": "xx"
}
}
],
"Architecture": "xx",
"RootDeviceType": "xx",
"RootDeviceName": "xx",
"VirtualizationType": "hvm",
"Tags": [
{
"Value": "TAG1",
"Key": "VALUE1"
},
{
"Value": "TAG2",
"Key": "VALUE2"
},
{
"Value": "TAG3",
"Key": "VALUE3"
},
{
"Value": "TAG4",
"Key": "VALUE4"
},
{
"Value": "TAG5",
"Key": "VALUE5"
},
{
"Value": "TAG6",
"Key": "Value6"
}
],
"AmiLaunchIndex": xx
}
]
}
]
Edit: an example of something I have tried (this one is not trying to get the tags for simplicities sake:
jq -r '.Reservations.Instances | map(({ InstanceId } + (.BlockDeviceMappings | add) + (.BlockDeviceMappings.Ebs | Add))| { InstanceId, DeviceName, VolumeId })' <(echo "$json_array_windows")
jq: error: Add/0 is not defined at <top-level>, line 1:
.Reservations.Instances | map(({ InstanceId } + (.BlockDeviceMappings | add) + (.BlockDeviceMappings.Ebs | Add))| { InstanceId, DeviceName, VolumeId })
jq: 1 compile error
Upvotes: 2
Views: 1206
Reputation: 116640
The following jq filter produces a stream of JSON objects as requested. If you really need a JSON array, then simply wrap the entire expression in square brackets.
.Reservations[] | .Instances[]
| { InstanceId }
+ (.BlockDeviceMappings[]
| { DeviceName,
"VolumeId": .Ebs.VolumeId } )
+ (.Tags
| { "TAG1": ( map( select(.Value == "TAG1"))[] | .Key),
"TAG2": ( map( select(.Value == "TAG2"))[] | .Key) } )
Here is the output (once the input JSON has been corrected):
{
"InstanceId": "i-11111111",
"DeviceName": "/dev/sda1",
"VolumeId": "vol-1111111a",
"TAG1": "VALUE1",
"TAG2": "VALUE2"
}
{
"InstanceId": "i-11111111",
"DeviceName": "xvdf",
"VolumeId": "vol-1111111b",
"TAG1": "VALUE1",
"TAG2": "VALUE2"
}
{
"InstanceId": "i-11111111",
"DeviceName": "xvdg",
"VolumeId": "vol-11111111c",
"TAG1": "VALUE1",
"TAG2": "VALUE2"
}
{
"InstanceId": "i-22222222",
"DeviceName": "/dev/sda1",
"VolumeId": "vol-2222222a",
"TAG1": "VALUE1",
"TAG2": "VALUE2"
}
{
"InstanceId": "i-22222222",
"DeviceName": "/dev/sdb",
"VolumeId": "vol-2222222b",
"TAG1": "VALUE1",
"TAG2": "VALUE2"
}
{
"InstanceId": "i-22222222",
"DeviceName": "/dev/sdc",
"VolumeId": "vol-2222222c",
"TAG1": "VALUE1",
"TAG2": "VALUE2"
}
Upvotes: 4