how.wtf

AWS CLI query examples

· Thomas Taylor

While some users may prefer to pipe AWS CLI JSON output to jq for parsing, it is possible to leverage the --query functionality that’s built-in.

Commonly, users deal with large JSON outputs when executing AWS CLI commands in their environments. To mitigate the process, JMESPath, a powerful filtering language, can specify resource properties, create lists, search output, etc.

AWS CLI Output

For reference, the AWS CLI documentation lists JSON document outputs. The commands listed below use aws ec2 describe-images, but any combination of the examples can be used for other services and properties.

1aws ec2 describe-images \
2    --region us-east-1 \
3    --image-ids ami-1234567890EXAMPLE

Output (provided by AWS):

 1{
 2    "Images": [
 3        {
 4            "VirtualizationType": "hvm",
 5            "Description": "Provided by Red Hat, Inc.",
 6            "PlatformDetails": "Red Hat Enterprise Linux",
 7            "EnaSupport": true,
 8            "Hypervisor": "xen",
 9            "State": "available",
10            "SriovNetSupport": "simple",
11            "ImageId": "ami-1234567890EXAMPLE",
12            "UsageOperation": "RunInstances:0010",
13            "BlockDeviceMappings": [
14                {
15                    "DeviceName": "/dev/sda1",
16                    "Ebs": {
17                        "SnapshotId": "snap-111222333444aaabb",
18                        "DeleteOnTermination": true,
19                        "VolumeType": "gp2",
20                        "VolumeSize": 10,
21                        "Encrypted": false
22                    }
23                }
24            ],
25            "Architecture": "x86_64",
26            "ImageLocation": "123456789012/RHEL-8.0.0_HVM-20190618-x86_64-1-Hourly2-GP2",
27            "RootDeviceType": "ebs",
28            "OwnerId": "123456789012",
29            "RootDeviceName": "/dev/sda1",
30            "CreationDate": "2019-05-10T13:17:12.000Z",
31            "Public": true,
32            "ImageType": "machine",
33            "Name": "RHEL-8.0.0_HVM-20190618-x86_64-1-Hourly2-GP2"
34        }
35    ]
36}

Please note Images is a top-level list-type element in the JSON document.

Examples

Warning: The AWS describe-images commands outputs a large JSON document. The JMESPath list slicing (Images[:3]) feature is leveraged to truncate the results. If the full output is desired, use Images[] instead.

Listing Outputs

List the ImageId of the first 3 images owned by Amazon:

1$ aws ec2 describe-images \
2  --owner amazon \
3  --query "Images[:3].ImageId"
4[
5    "aki-04206613",
6    "aki-0a4aa863",
7    "aki-12f0127b"
8]

Note: Images[:3].ImageId outputs the property into a single list. If a list for each image is desired, use Images[:3].[ImageId]. As shown in the next example, it’s useful for listing multiple properties.

List the ImageId and OwnerId of the first 3 images owned by Amazon:

 1$ aws ec2 describe-images \
 2  --owner amazon \
 3  --query "Images[:3].[ImageId,OwnerId]"
 4[
 5    [
 6        "aki-04206613",
 7        "137112412989"
 8    ],
 9    [
10        "aki-0a4aa863",
11        "470254534024"
12    ],
13    [
14        "aki-12f0127b",
15        "470254534024"
16    ]
17]

List the ImageId and OwnerId of the first 3 images owned by Amazon in a list of JSON objects:

If desired, the output values can be nested in a hash object using JMESPath’s hash multi-selection feature.

 1$ aws ec2 describe-images \
 2  --owner amazon \
 3  --query "Images[:3].{image:ImageId,owner:OwnerId}"
 4[
 5    {
 6        "image": "aki-04206613",
 7        "owner": "137112412989"
 8    },
 9    {
10        "image": "aki-0a4aa863",
11        "owner": "470254534024"
12    },
13    {
14        "image": "aki-12f0127b",
15        "owner": "470254534024"
16    }
17]

Filter Projection & Pipe Expressions

List the ImageId of the first 3 images that are owned by Amazon’s OwnerId of 137112412989:

JMESPath provides two features needed to accomplish this query:

  1. Filter Projection
  2. Pipe Expressions
1$ aws ec2 describe-images \
2  --owner amazon \
3  --query "Images[?OwnerId=='137112412989'] | [:3].ImageId"
4[
5    "aki-04206613",
6    "aki-499ccb20",
7    "aki-5c21674b"
8]

The combination of a filter projection, Images[?OwnerId=='137112412989'], and a pipe expression, | [:3].ImageId satisfies the requirement.

Here’s the Python code representing the filter projection operation:

1result = []
2for image in inputData['Images']:
3  if image['OwnerId'] == '137112412989'
4    result.append(image)
5return result

It returns:

 1[
 2    {
 3        "ImageId": "aki-04206613",
 4        "OwnerId": "137112412989",
 5        "..."
 6    },
 7    {
 8        "ImageId": "aki-499ccb20",
 9        "OwnerId": "137112412989",
10        "..."
11    },
12    {
13        "ImageId": "aki-5c21674b",
14        "OwnerId": "137112412989",
15        "..."
16    },
17    "...",
18    "...",
19    "..."
20]

Then, grab the first three using the pipe expression:

| [:3]

 1[
 2    {
 3        "ImageId": "aki-04206613",
 4        "OwnerId": "137112412989",
 5        "..."
 6    },
 7    {
 8        "ImageId": "aki-499ccb20",
 9        "OwnerId": "137112412989",
10        "..."
11    },
12    {
13        "ImageId": "aki-5c21674b",
14        "OwnerId": "137112412989",
15        "..."
16    }
17]

Then, add the specific ImageId property:

| [:3].ImageId

1[
2    "aki-04206613",
3    "aki-499ccb20",
4    "aki-5c21674b"
5]

Function Expressions

JMESPath supports function expressions:

List the Id and CreationDate of the first 3 images that are owned by Amazon whose PlatformDetails contain the string ‘Linux’ in sorted order by CreationDate:

Step #1: Use the contains function and grab the first 3 results:

 1$ aws ec2 describe-images \
 2  --owner amazon \
 3  --query "Images[?contains(PlatformDetails, 'Linux')] | [:3]"
 4[
 5    {
 6        "CreationDate": "2016-09-28T21:31:10.000Z",
 7        "ImageId": "aki-04206613",
 8        "PlatformDetails": "Linux/UNIX",
 9        "..."
10    },
11    {
12        "CreationDate": "2009-12-15T18:44:15.000Z",
13        "ImageId": "aki-0a4aa863",
14        "PlatformDetails": "Linux/UNIX",
15        "..."
16    },
17    {
18        "CreationDate": "",
19        "ImageId": "aki-12f0127b",
20        "PlatformDetails": "Linux/UNIX",
21        "..."
22    }
23]

This filters the top-level Images for all objects with Linux in their PlatformDetails value.

Step #2: Sort by CreationDate:

1$ aws ec2 describe-images \
2  --owner amazon \
3  --query "Images[?contains(PlatformDetails, 'Linux')] | [:3] | sort_by(@, &CreationDate)[].{CreationDate:CreationDate,Id:ImageId}"

The sort_by function requires an input similar to this:

1KeyNameHere: [
2    {
3        "key1": "val1",
4        "key2": "val2"
5    }
6]

If results were ordered by the key2 field, the query would be: sort_by(KeyNameHere, &key2)

Similarly, the input to the sort_by function in the example was:

 1[
 2    {
 3        "CreationDate": "2016-09-28T21:31:10.000Z",
 4        "ImageId": "aki-04206613",
 5        "PlatformDetails": "Linux/UNIX",
 6        "..."
 7    },
 8    { "..." },
 9    { "..." }
10]

There is not a top-level key present. In this case, the character @ is used to represent the list that is being passed. Additionally, the key that is being sorted on must begin with an &.

After the sort_by function, the list is “retrieved” [] and the result is formatted to a customized JSON output.

 1[
 2    {
 3        "CreationDate": "",
 4        "Id": "aki-12f0127b"
 5    },
 6    {
 7        "CreationDate": "2009-12-15T18:44:15.000Z",
 8        "Id": "aki-0a4aa863"
 9    },
10    {
11        "CreationDate": "2016-09-28T21:31:10.000Z",
12        "Id": "aki-04206613"
13    }
14]

The first object contains a null CreationDate value. Luckily, it can be removed from the output using the not_null function.

 1$ aws ec2 describe-images \
 2  --owner amazon \
 3  --query "Images[?contains(PlatformDetails, 'Linux')] | [:4] | @[?not_null(CreationDate)] | sort_by(@, &CreationDate)[].{CreationDate:CreationDate,Id:ImageId}"
 4[
 5    {
 6        "CreationDate": "2009-12-15T18:44:15.000Z",
 7        "Id": "aki-0a4aa863"
 8    },
 9    {
10        "CreationDate": "2010-09-28T03:52:22.000Z",
11        "Id": "aki-1c669375"
12    },
13    {
14        "CreationDate": "2016-09-28T21:31:10.000Z",
15        "Id": "aki-04206613"
16    }
17]

Lastly, a common scenario is to filter based on environment variables:

Retrieve a cloudformation export by name and store the value

1$ export_name=$(aws cloudformation list-exports \
2    --query "Exports[?Name=='$ENV_VAR'].Value" \
3    --output text)
4$ echo $export_name
5value_here

The environment variable was used by wrapping with single quotes!

#aws   #aws-cli  

Reply to this post by email ↪