I made it my mission to figure out how to get instances that were missing a tag through AWS CLI instead of using external tools like jq or python.

Nate Fox, AWS Solutions Architect

Using Amazon Web Services Command Line Interface to Find Instances without a ‘Name’ Tag

Many times I’ve needed to find AWS EC2 instances without a certain tag. Usually its the Name tag but other tags come up from time to time (we use a tag of Owner quite a bit here). After coming across this Reddit post and this Stack Overflow question, I made it my mission to figure out how to get instances that were missing a tag through AWS CLI instead of using external tools like jq or python.

The --Query Parameter, JMESPath and filtering

JMESPath is the ‘engine’ behind the --query parameter in AWS CLI. In its most basic form, it’ll help you filter out or traverse JSON. AWS has some nice documentation on how to use it at a basic level. In this post, we will focus on the filter ability of JMESPath.

Using the bracket and question mark will trigger the JMESPath filter: [? ... ]

For example, many people have wanted to get the instance Name tag along with the InstanceId. This is achieved by using the filter for the Tags → Key=='Name':

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

While this is useful, we’re looking to do the actual opposite. First, we’ll want to dive down into each instance:

aws ec2 describe-instances \
 --query 'Reservations[].Instances[]'

This will spit out each of the instances. We want to create a filter on each of these where the Name tag doesn’t exist. A tag that exists would look like:

aws ec2 describe-instances \
 --query 'Reservations[].Instances[?Tags[?Key != `Name`]]'

The problem with this filter is that as we loop through the Tags array, we’ll most likely hit an instance that has more than one tag. That instance will register true because the first tag may have "Key:" "SomeTag" (but the second could be "Key:" "Name"). So we want to look for the object with the Name key but with no Value (aka null).

First, lets get the Value from the Name tag:

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

Now we can use JMESPath’s not_null() function to filter for ones that exist:

aws ec2 describe-instances \
 --query 'Reservations[].Instances[?not_null(Tags[?Key == `Name`].Value)]'

The problem is that this still captures anything with a Name tag. So we negate it. IE: anything that isn’t not_null aka not not null 🙂

aws ec2 describe-instances \
 --query 'Reservations[].Instances[?!not_null(Tags[?Key == `Name`].Value)]'

Which will return something like the following:

[
    [
        {
            "Monitoring": {
                "State": "disabled"
            }, 
            "PublicDnsName": "", 
            "RootDeviceType": "ebs"
            ...
        }
    ], 
    [], 
    [], 
    [], 
    [], 
    [], 
    [], 
    [
        {
            "Monitoring": {
                "State": "disabled"
            }, 
            "PublicDnsName": "", 
            "RootDeviceType": "ebs"
            ...
        }
    ], 
    []
]

We don’t want to have these empty arrays, so we’ll flatten the instance object with a pipe:

aws ec2 describe-instances \
  --query 'Reservations[].Instances[?!not_null(Tags[?Key == `Name`].Value)] | []'

And thats it! If you’d like a few more examples of some common uses, here you go:

Display InstanceId of instances which have no Name tag:

aws ec2 describe-instances \
  --output text \
  --query 'Reservations[].Instances[?!not_null(Tags[?Key == `Name`].Value)] | [].[InstanceId]'

 

Display InstanceId of running instances which have no Owner tag:

aws ec2 describe-instances \
  --output text \
  --filters Name=instance-state-name,Values=running \
  --query 'Reservations[].Instances[?!not_null(Tags[?Key == `Owner`].Value)] | [].[InstanceId]'

 

Display VolumeId and Size of volumes which have no Name tag:

aws ec2 describe-volumes \
 --output text \
 --query 'Volumes[?!not_null(Tags[?Key == `Name`].Value)] | [].[VolumeId,Size]'

 

Display SnapshotId and StartTime of my snapshots which have no CreatedBy tag:

aws ec2 describe-snapshots \
 --output text \
 --owner-ids self \
 --query 'Snapshots[?!not_null(Tags[?Key == `CreatedBy`].Value)] | [].[SnapshotId,StartTime]'

 

Onica

About Onica

Onica is one of the largest and fastest-growing Amazon Web Services (AWS) Premier Consulting Partners in the world, helping companies enable, operate, and innovate on the cloud. From migration strategy to operational excellence and immersive transformation, Onica is a full spectrum AWS integrator.