Listing instance name among other data with aws-cli 1.3.6

c-garcia picture c-garcia · Apr 5, 2014 · Viewed 14.1k times · Source

Using aws-cli 1.3.6 I am trying to get a simple table of my ec2 instances with the Name and state. I have been looking at the --query and JMESpath documentation and I have been able to select the "Value" item of a Map which "Key" item is equal to Name. This is useful to get the instance-name. Therefore, the code below seems to work

aws ec2 describe-instances --output table --query 'Reservations[].Instances[].Tags[?Key==`Name`].Value'

And delivers this:

-------------------
|DescribeInstances|
+-----------------+
|  Name1          |
|  Name2          |
+-----------------+

However, if I want to add the state, things get not as I would have expected. Using

aws ec2 describe-instances --output table --query 'Reservations[].Instances[].[Tags[?Key==`Name`].Value,State.Name]'

Delivers

-------------------
|DescribeInstances|
+-----------------+
|  Name1          |
|  stopped        |
|  Name2          |
|  stopped        |
+-----------------+

instead of a two column table with name and state.

If we turn the output to JSON, we can see that the Tags selection returns a list (one-element list) and that's probably the issue:

[
    [
        [
            "Name1"
        ],
        "stopped"
    ],
    [
        [
            "Name2"
        ],
        "stopped"
    ]
]

I have not been able to turn this list into an scalar by selecting the first element. This, does not work. Returns an empty list as the Name.

aws ec2 describe-instances --output json --query 'Reservations[].Instances[].[Tags[?Key==`Name`].Value[0],State.Name]'

The same as this

aws ec2 describe-instances --output json --query 'Reservations[].Instances[].[Tags[?Key==`Name`].Value[][0],State.Name]'

The only way I have figured out of addressing this is by means of the join function. Since I only expect one element, it is ok but I seems to be a little bit hacky.

aws ec2 describe-instances --output table --query 'Reservations[].Instances[].[join(`,`,Tags[?Key==`Name`].Value),State.Name]'

---------------------------
|    DescribeInstances    |
+-------------+-----------+
|  Name1      |  stopped  |
|  Name2      |  stopped  |
+-------------+-----------+

The question, therefore, is: is there any way of picking the first element of the result of the filter (?Key==XXXX) bearing in mind that suffixing it with [0] seems not to work?

Thanks in advance!

Answer

Steffen Opel picture Steffen Opel · May 3, 2014

The question, therefore, is: is there any way of picking the first element of the result of the filter (?Key==XXXX) bearing in mind that suffixing it with [0] seems not to work?

The way you phrased this question hints towards the solution in fact, namely Pipe Expressions (only available as of version 1.3.7 of the aws-cli though, hence impossible to figure out at question time):

pipe-expression  = expression "|" expression

A pipe expression combines two expressions, separated by the | character. It is similar to a sub-expression with two important distinctions:

  1. Any expression can be used on the right hand side. A sub-expression restricts the type of expression that can be used on the right hand side.
  2. A pipe-expression stops projections on the left hand side for propagating to the right hand side. If the left expression creates a projection, it does not apply to the right hand side.

The emphasized part is key, as shown in the subsequent examples, notably:

If you instead wanted only the first sub list, ["first1", "second1"], you can use a pipe-expression:

foo[*].bar[0] -> ["first1", "first2"]
foo[*].bar | [0] -> ["first1", "second1"]

Solution

Thus, applying a pipe expression yields the desired result:

aws ec2 describe-instances --output table \
  --query 'Reservations[].Instances[].[Tags[?Key==`Name`] | [0].Value, State.Name]'

----------------------------------
|        DescribeInstances       |
+--------------------+-----------+
|  Name1             |  stopped  |
|  Name2             |  stopped  |
+--------------------+-----------+