0

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?

Tony Stark
  • 2,318
  • 1
  • 22
  • 41
  • 1
    Just as a "for your future reference," [jmespath](https://stackoverflow.com/questions/tagged/jmespath) is a **much** better SO tag than the more generic `json-query` one, since that syntax has a specific name where other people could have weighed in faster (or even with a more accurate answer, for all I know) – mdaniel Sep 22 '18 at 19:49

1 Answers1

2

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) }}"
mdaniel
  • 31,240
  • 5
  • 55
  • 58
  • After sorting I'd have to use the keyword `first` for the newest, right? – Tony Stark Sep 22 '18 at 20:47
  • Yes (err, the first filter). You could also use jmespath to sort and reverse, then use [0] to select the first element: http://jmespath.org/specification.html#reverse – james.haggerty Sep 23 '18 at 01:16