Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AWS CLI and JMESPath filter and select on nested properties

I want to use the CLI tool, to retrieve the distribution-id of a CloudFront distribution with a specific cname/alias.

This is what I came up with:

aws cloudfront list-distributions --query "DistributionList.Items[?Aliases.Items!='null']|DistributionList.Items[?contains(Aliases.Items,'cname.cdn.mycompany.com') == 'true'].{Id:Id}"

I'm not an expert at JMESPath, and I don't understand why my query doesn't return a result. A distribution with the specified domain as alias exists.

like image 745
Jeroen Jacobs Avatar asked Feb 23 '16 09:02

Jeroen Jacobs


2 Answers

You're very close! A few things though:

  • null is not 'null'
  • After the pipe you'll be working with the results of the first expression
  • like null, true is not a string (== true is also redundant)

jmespath.org Has a live editor that you can use to test out expressions. Here's a simplified json we can use to test this case:

{
    "DistributionList": {
        "Items": [
            {
                "Id": "foo",
                "Aliases": {
                    "Quantity": 1,
                    "Items": [
                        "cname.cdn.mycompany.com"
                    ]
                }
            },
            {
                "Id": "bar",
                "Aliases": {
                    "Quantity": 1,
                    "Items": [
                        "cname.cdn.othercompany.com"
                    ]
                }
            },
            {
                "Id": "baz",
                "Aliases": {
                    "Quantity": 0
                }
            }
        ]
    }
}

Let's start with the first part of the expression. The only fix you need is taking the quotes off null:

DistributionList.Items[?Aliases.Items!=null]

Which will successfully filter out elements without Items under Alias. Here is what you would get back if you stopped here, and what you'll have to work with after the pipe:

[
  {
    "Id": "foo",
    "Aliases": {
      "Quantity": 1,
      "Items": [
        "cname.cdn.mycompany.com"
      ]
    }
  },
  {
    "Id": "bar",
    "Aliases": {
      "Quantity": 1,
      "Items": [
        "cname.cdn.othercompany.com"
      ]
    }
  }
]

Note that there is no DistributionList.Items anymore.

So now we want to filter for a specific CNAME. Lets leave out the tautology == true.

[?contains(Aliases.Items, 'cname.cdn.mycompany.com')]

So the full expression now is:

DistributionList.Items[?Aliases.Items!=null] | [?contains(Aliases.Items, 'cname.cdn.mycompany.com')]

And your result is the successfully filtered list:

[
  {
    "Id": "foo",
    "Aliases": {
      "Quantity": 1,
      "Items": [
        "cname.cdn.mycompany.com"
      ]
    }
  }
]

Now if you want the Id's of the matching elements, just add .Id to that last expression. If you know there will only be one, you can just select that element with another pipe and [0].

DistributionList.Items[?Aliases.Items!=null] | [?contains(Aliases.Items, 'cname.cdn.mycompany.com')].Id | [0]

And you get the Id you want!

"foo"
like image 157
Jordon Phillips Avatar answered Oct 20 '22 14:10

Jordon Phillips


To add, I found it out without the pipe.

aws cloudfront list-distributions --query "DistributionList.Items[?contains(Aliases.Items, 'cname.cdn.mycompany.com')].Id" --output text

like image 24
devopsmarine Avatar answered Oct 20 '22 16:10

devopsmarine