Search code examples
jsonamazon-web-servicesansiblejmespath

JSON query for finding the newest snapshot for host and device?


I am trying to find the newest snapshot for a device and host in AWS with the aws ec2 command. I am getting the following output from aws ec2 describe-snapshots.

As you can see I can have several snapshots for the same host (see Tags with Keys hostname and devicename) and device. The start time differs.

{
"Snapshots": [
    {
        "Description": "My desc.",
        "Encrypted": false,
        "VolumeId": "vol-aaa",
        "State": "completed",
        "VolumeSize": 8,
        "StartTime": "2018-02-02T19:27:56.000Z",
        "Progress": "100%",
        "OwnerId": "5674567",
        "SnapshotId": "snap-xxx"
    },  
    {
        "Description": "host1.domain.com - sdc",
        "Tags": [
            {
                "Value": "SNAP1",
                "Key": "Name"
            },
            {
                "Value": "sdc",
                "Key": "devicename"
            },
            {
                "Value": "host1.domain.com",
                "Key": "hostname"
            }
        ],
        "Encrypted": false,
        "VolumeId": "vol-xxx",
        "State": "completed",
        "VolumeSize": 140,
        "StartTime": "2018-09-21T08:39:58.000Z",
        "Progress": "100%",
        "OwnerId": "345634563456",
        "SnapshotId": "snap-xxx"
    },  
    {
        "Description": "host1.domain.com - sdc",
        "Tags": [
            {
                "Value": "SNAP2",
                "Key": "Name"
            },
            {
                "Value": "sdc",
                "Key": "devicename"
            },
            {
                "Value": "host1.domain.com",
                "Key": "hostname"
            }
        ],
        "Encrypted": false,
        "VolumeId": "vol-xxx",
        "State": "completed",
        "VolumeSize": 140,
        "StartTime": "2018-09-22T08:39:58.000Z",
        "Progress": "100%",
        "OwnerId": "345634563456",
        "SnapshotId": "snap-xxx"
    }
}

How would I query this JSON in Ansible to get the newest snapshot for the hostname and device? I don't do this often so struggle with the query syntax.

Until now I have the following.

 - shell: "aws ec2 describe-snapshots"
   register: snap
   delegate_to: localhost

 - debug:
     msg: "{{ snap.stdout | from_json | json_query(query) }}"
   vars:
     query: "Snapshots[].Tags[?Key=='hostname'].Value"

But how do I select all snapshot elements where Tags.Value is equal to a certain value where Key is "hostname"? And how do I then select the newest from the list I get?


Solution

  • According to the fine manual, JMESPath supports nested bracket specifier expressions:

      vars:
        snap: |
          {
            "Snapshots": [
              {"Id": "aaa", "Tags": [{"Key": "hostname", "Value": "alpha"}]},
              {"Id": "bbb", "Tags": [{"Key": "hostname", "Value": "beta"}]}
            ]
          }
        jq: "Snapshots[? Tags[? Key=='hostname' && Value=='alpha']].Id"
      tasks:
      - debug:
          msg: "{{ snap | from_json | json_query(jq) }}"
    

    As for the "for a certain host" part, that vars: query: is subject to jinja2 interpolation just like every other ansible string, thus:

    vars:
      query: ... [? Value=='{{ the_hostname }}' ] ...
    

    Just be careful to ensure the value is correctly escaped -- which likely won't be a problem with a hostname, but I mean in general.

    Then, as for the "newest from the list" part, ISO8601 has the very pleasing side benefit of sorting lexigraphically, so:

      vars:
        jq: "Snapshots[? Tags[? Key=='hostname' && Value=='alpha']]"
      tasks:
      - debug:
          msg: "{{ snap | from_json | json_query(jq) | sort(attribute='StartTime', reverse=True) }}"