In my occasional series on waiting for things, I setup a BASH function to wait for AWS CloudFront invalidations. I mentioned it would be possible to invalid and wait in the same function, but was feeling lazy and left it to the reader. Well, I’ve gotten tired of the two step process, so I’m being industrious so I can be lazy.

How to kick off invalidations from the command line? It’s very straight forward:

1
aws cloudfront create-invalidation --distribution-id ID --paths '/something'

The path can be a simple file path, i.e. “/privacy.html”, or a space separated list “/privacy.html /faq.html”. As with the GUI, the path can be a wildcard “/images/*” and you invalidate the whole site with “/*”.

First, let’s setup an invalidation function:

1
2
3
invalidate-cf() {
    echo aws cloudfront create-invalidation --distribution-id $1 --path ${2:-'/*'}
}

This takes two arguments, the ID of the distribution and the path. If the path is omitted, I use BASH’s Parameter Substitution to default to invaliding the whole site with “/*”, which is more often than not what I want.

1
2
invalidate-cf EXXXXXXXXXXXXX /oops.html
invalidate-cf EXXXXXXXXXXXXX # the whole site.

Now let’s combine it with waiting. For that you’ll need my previous notification function and Growl or terminal-notifier as documented in the now classic post Is the Server Up Yet?.

The trick to our invalidate and wait function is that we need the ID of the invalidation and to get we have to capture and parse the output of our new invalidate-cf function. Fortunately, the output from a function is no different than the output of a command and we can capture it with $().

As I said we also need to parse the output. The create-invalidation command spews out some JSON which include the invalidation ID. We don’t actually have to parse the JSON, we can cheat and just grep and AWK out the ID. The JSON output looks like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
    "Invalidation": {
        "Status": "InProgress",
        "InvalidationBatch": {
            "Paths": {
                "Items": [
                    "/*"
                ],
                "Quantity": 1
            },
            "CallerReference": "cli-1468981569-510844"
        },
        "Id": "IYYYYYYYYYYYY",
        "CreateTime": "2016-07-20T02:26:10.612Z"
    },
    "Location": "https://cloudfront.amazonaws.com/2016-01-28/distribution/EXXXXXXXXXXXXX/invalidation/IYYYYYYYYYYYY"
}

I use grep for Id and then use awk to puck out the value. There are 27 other ways you could to this, but this one is mine. Put together in a function it looks like:

1
2
3
4
invalidate-cf-and-wait() {
    id=$(invalidate-cf $1 $2 | egrep Id | awk -F'"' '{ print $4}' )
    echo "Waiting for invalidation $id"
    aws cloudfront wait invalidation-completed --id $id --distribution-id $1 && notify "Invalidation $id completed";

Which make it as simple as:

1
2
invalidate-cf-and-wait /bad.html
Waiting for invalidation IYYYYYYYYYYYY

Sometimes you have to work to be lazy, but now I’m done working…

Comments