AWS CLIにhistory機能が追加されました #reinvent

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

西澤です。みんな大好きAWS CLIに地味に嬉しいアップデートがあったのをたまたま見つけたのでご紹介したいと思います。

AWS CLIのリリース情報を確認していたところ、ちょっと気になる記述を見つけました。

  • 1.13.0
    • feature:cli_history: Setting the value of cli_history to enabled in the shared config file enables the CLI to keep history of all commands ran.
    • feature:history list: Lists all of the commands that have been run via the stored history of the CLI.
    • feature:history show: Shows the important events related to running a command that was recorded in the CLI history.

aws-cli/CHANGELOG.rst at develop · aws/aws-cli

きちんとマニュアルも更新されているようです。

AWS CLIのhistory機能を有効化

前提として、AWS CLIのバージョンを1.13.0以上にバージョンアップしておく必要があります。必要に応じてバージョンアップしておきましょう。執筆時点の最新バージョンでは1.14.0になっていました。

$ aws --version
aws-cli/1.14.0 Python/2.7.10 Darwin/16.7.0 botocore/1.8.4

公式ドキュメントの手順の通りに設定を行います。cli_history enabledをプロファイルに設定すると、~/.aws/configファイルに設定が書き込まれるようです。

$ aws configure set cli_history enabled --profile cm-nishizawa
$ cat ~/.aws/config
[default]
output = json
[profile cm-nishizawa]
output = json
region = us-west-2
cli_history = enabled
:::

AWS CLIのhistory記録を呼び出し

それでは、この状態でhistoryがどのように呼び出せるのかを実際に試してみます。まずは、適当なawsコマンドをいくつか実行します。

$ aws ec2 describe-regions
$ aws ec2 describe-availability-zones
$ aws s3 ls s3://aaa

すると、.aws/cli/historyの下に何だかデータが生成されているようです。

$ ls -l ~/.aws/cli/history/
total 104
-rw-r--r--  1 nishizawa.tetsunori  staff  20480 11 30 11:21 history.db
-rw-r--r--  1 nishizawa.tetsunori  staff  32768 11 30 11:21 history.db-shm
-rw-r--r--  1 nishizawa.tetsunori  staff      0 11 30 11:21 history.db-wal
$ find ~/.aws/cli/history -ls -exec file {} \;
19686927        0 drwxr-xr-x    5 nishizawa.tetsunori staff                 170 11 30 10:25 /Users/nishizawa.tetsunori/.aws/cli/history
/Users/nishizawa.tetsunori/.aws/cli/history: directory
19686929       40 -rw-r--r--    1 nishizawa.tetsunori staff               20480 11 30 11:21 /Users/nishizawa.tetsunori/.aws/cli/history/history.db
/Users/nishizawa.tetsunori/.aws/cli/history/history.db: SQLite 3.x database, last written using SQLite version 3016000
19686933       64 -rw-r--r--    1 nishizawa.tetsunori staff               32768 11 30 11:21 /Users/nishizawa.tetsunori/.aws/cli/history/history.db-shm
/Users/nishizawa.tetsunori/.aws/cli/history/history.db-shm: data
19686932        0 -rw-r--r--    1 nishizawa.tetsunori staff                   0 11 30 11:21 /Users/nishizawa.tetsunori/.aws/cli/history/history.db-wal
/Users/nishizawa.tetsunori/.aws/cli/history/history.db-wal: empty

まずは、実行したコマンドの一覧をlistで呼び出してみます。こちらはオプション等は一切無しのようです。

$ aws history list
b251d060-f43a-4124-8803-1b0307c4e292  2017-11-30 11:33:04 AM  s3 ls                                             255
12498f1d-d28f-47b5-8e23-f5a4d6cf8f04  2017-11-30 11:19:30 AM  ec2 describe-availability-zones                   0
3dfb7224-a54f-4513-840b-8c5b4e364b8f  2017-11-30 10:25:48 AM  ec2 describe-regions                              0

それでは、実行結果の詳細をshowで確認してみます。これは想像していたよりずっとしっかりしたhistoryですね。驚きました。

$ aws history show

AWS CLI command entered
at time: 2017-11-30 11:33:04.641
with AWS CLI version: aws-cli/1.14.0 Python/2.7.10 Darwin/16.7.0 botocore/1.8.4
with arguments: [u's3', u'ls', u's3://aaa']

[0] API call made
at time: 2017-11-30 11:33:04.737
to service: s3
using operation: ListObjects
with parameters: {
    "Bucket": "aaa",
    "Delimiter": "/",
    "Prefix": ""
}

[0] HTTP request sent
at time: 2017-11-30 11:33:04.741
to URL: https://s3.us-west-2.amazonaws.com/aaa?delimiter=%2F&prefix=&encoding-type=url
with method: GET
with headers: {
    "Authorization": "AWS4-HMAC-SHA256 Credential=AKIAIJXL3QINBH3K6ZRQ/20171130/us-west-2/s3/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=a7ca6d2ff43691172122f0276155c383bfc29974a6539b917e17ad5006f67e4b",
    "User-Agent": "aws-cli/1.14.0 Python/2.7.10 Darwin/16.7.0 botocore/1.8.4",
    "X-Amz-Content-SHA256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
    "X-Amz-Date": "20171130T023304Z"
}
with body: There is no associated body

[0] HTTP response received
at time: 2017-11-30 11:33:05.339
with status code: 301
with headers: {
    "content-type": "application/xml",
    "date": "Thu, 30 Nov 2017 02:33:04 GMT",
    "server": "AmazonS3",
    "transfer-encoding": "chunked",
    "x-amz-bucket-region": "us-east-1",
    "x-amz-id-2": "bfoj0yn02Xo1i6xyh9CPAR2NSWx8GnyzJEMQOayklBeTqosnelNqqxTmnj9BVFSIw8Cc3GUOjtc=",
    "x-amz-request-id": "8A4FD0E466EE0EC0"
}
with body: <?xml version="1.0" ?>
<Error>
    <Code>PermanentRedirect</Code>
    <Message>The bucket you are attempting to access must be addressed using the specified endpoint. Please send all future requests to this endpoint.</Message>
    <Bucket>aaa</Bucket>
    <Endpoint>s3.amazonaws.com</Endpoint>
    <RequestId>8A4FD0E466EE0EC0</RequestId>
    <HostId>bfoj0yn02Xo1i6xyh9CPAR2NSWx8GnyzJEMQOayklBeTqosnelNqqxTmnj9BVFSIw8Cc3GUOjtc=</HostId>
</Error>


[0] HTTP response parsed
at time: 2017-11-30 11:33:05.340
parsed to: {
    "Error": {
        "Bucket": "aaa",
        "Code": "PermanentRedirect",
        "Endpoint": "s3.amazonaws.com",
        "Message": "The bucket you are attempting to access must be addressed using the specified endpoint. Please send all future requests to this endpoint."
    },
    "ResponseMetadata": {
        "HTTPHeaders": {
            "content-type": "application/xml",
            "date": "Thu, 30 Nov 2017 02:33:04 GMT",
            "server": "AmazonS3",
            "transfer-encoding": "chunked",
            "x-amz-bucket-region": "us-east-1",
            "x-amz-id-2": "bfoj0yn02Xo1i6xyh9CPAR2NSWx8GnyzJEMQOayklBeTqosnelNqqxTmnj9BVFSIw8Cc3GUOjtc=",
            "x-amz-request-id": "8A4FD0E466EE0EC0"
        },
        "HTTPStatusCode": 301,
        "HostId": "bfoj0yn02Xo1i6xyh9CPAR2NSWx8GnyzJEMQOayklBeTqosnelNqqxTmnj9BVFSIw8Cc3GUOjtc=",
        "RequestId": "8A4FD0E466EE0EC0"
    }
}

[0] HTTP request sent
at time: 2017-11-30 11:33:05.341
to URL: https://s3.amazonaws.com/aaa?delimiter=%2F&prefix=&encoding-type=url
with method: GET
with headers: {
    "Authorization": "AWS4-HMAC-SHA256 Credential=AKIAIJXL3QINBH3K6ZRQ/20171130/us-east-1/s3/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=e34f6754a9dee759701c16c1b47e6075170c29ed0a7d719a38fdfc29eb4967a4",
    "User-Agent": "aws-cli/1.14.0 Python/2.7.10 Darwin/16.7.0 botocore/1.8.4",
    "X-Amz-Content-SHA256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
    "X-Amz-Date": "20171130T023305Z"
}
with body: There is no associated body

[0] HTTP response received
at time: 2017-11-30 11:33:06.128
with status code: 403
with headers: {
    "content-type": "application/xml",
    "date": "Thu, 30 Nov 2017 02:33:05 GMT",
    "server": "AmazonS3",
    "transfer-encoding": "chunked",
    "x-amz-bucket-region": "us-east-1",
    "x-amz-id-2": "/EcZryxvUzKXr2531heCtMizP93m0c9bMfbNSJS0KXI1NlvXDUcfn9DjXI58GyACWlowNCI7tm0=",
    "x-amz-request-id": "063C9B92E28B3BAB"
}
with body: <?xml version="1.0" ?>
<Error>
    <Code>AccessDenied</Code>
    <Message>Access Denied</Message>
    <RequestId>063C9B92E28B3BAB</RequestId>
    <HostId>/EcZryxvUzKXr2531heCtMizP93m0c9bMfbNSJS0KXI1NlvXDUcfn9DjXI58GyACWlowNCI7tm0=</HostId>
</Error>


[0] HTTP response parsed
at time: 2017-11-30 11:33:06.128
parsed to: {
    "Error": {
        "Code": "AccessDenied",
        "Message": "Access Denied"
    },
parsed to: {
    "Error": {
        "Code": "AccessDenied",
        "Message": "Access Denied"
    },
    "ResponseMetadata": {
        "HTTPHeaders": {
            "content-type": "application/xml",
            "date": "Thu, 30 Nov 2017 02:33:05 GMT",
            "server": "AmazonS3",
            "transfer-encoding": "chunked",
            "x-amz-bucket-region": "us-east-1",
            "x-amz-id-2": "/EcZryxvUzKXr2531heCtMizP93m0c9bMfbNSJS0KXI1NlvXDUcfn9DjXI58GyACWlowNCI7tm0=",
            "x-amz-request-id": "063C9B92E28B3BAB"
        },
        "HTTPStatusCode": 403,
        "HostId": "/EcZryxvUzKXr2531heCtMizP93m0c9bMfbNSJS0KXI1NlvXDUcfn9DjXI58GyACWlowNCI7tm0=",
        "RequestId": "063C9B92E28B3BAB"
    }
}

AWS CLI command exited
at time: 2017-11-30 11:33:06.132
with return code: 255

直近ではなく以前の結果をhistoryから取得したい場合には、listで確認したcommand_idを引数に渡せばOKです。

$ aws history show 3dfb7224-a54f-4513-840b-8c5b4e364b8f

AWS CLI command entered
at time: 2017-11-30 10:25:48.199
with AWS CLI version: aws-cli/1.14.0 Python/2.7.10 Darwin/16.7.0 botocore/1.8.4
with arguments: [u'ec2', u'describe-regions']

[0] API call made
at time: 2017-11-30 10:25:48.595
to service: ec2
using operation: DescribeRegions
with parameters: {}

[0] HTTP request sent
at time: 2017-11-30 10:25:48.601
to URL: https://ec2.us-west-2.amazonaws.com/
with method: POST
with headers: {
    "Authorization": "AWS4-HMAC-SHA256 Credential=AKIAIJXL3QINBH3K6ZRQ/20171130/us-west-2/ec2/aws4_request, SignedHeaders=content-type;host;x-amz-date, Signature=216c2166cf23288084d453911462408895182bacb337077064c89041ad7b659a",
    "Content-Length": "41",
    "Content-Type": "application/x-www-form-urlencoded; charset=utf-8",
    "User-Agent": "aws-cli/1.14.0 Python/2.7.10 Darwin/16.7.0 botocore/1.8.4",
    "X-Amz-Date": "20171130T012548Z"
}
with body: Action=DescribeRegions&Version=2016-11-15

[0] HTTP response received
at time: 2017-11-30 10:25:49.199
with status code: 200
with headers: {
    "content-type": "text/xml;charset=UTF-8",
    "date": "Thu, 30 Nov 2017 01:25:47 GMT",
    "server": "AmazonEC2",
    "transfer-encoding": "chunked",
    "vary": "Accept-Encoding"
}
with body: <?xml version="1.0" ?>
<DescribeRegionsResponse xmlns="http://ec2.amazonaws.com/doc/2016-11-15/">
    <requestId>e60926d0-b5b2-4e8d-82ff-0e759b0beff7</requestId>
    <regionInfo>
        <item>
            <regionName>ap-south-1</regionName>
            <regionEndpoint>ec2.ap-south-1.amazonaws.com</regionEndpoint>
        </item>
        <item>
            <regionName>eu-west-2</regionName>
            <regionEndpoint>ec2.eu-west-2.amazonaws.com</regionEndpoint>
        </item>
        <item>
            <regionName>eu-west-1</regionName>
            <regionEndpoint>ec2.eu-west-1.amazonaws.com</regionEndpoint>
        </item>
        <item>
            <regionName>ap-northeast-2</regionName>
            <regionEndpoint>ec2.ap-northeast-2.amazonaws.com</regionEndpoint>
        </item>
        <item>
            <regionName>ap-northeast-1</regionName>
            <regionEndpoint>ec2.ap-northeast-1.amazonaws.com</regionEndpoint>
        </item>
        <item>
            <regionName>sa-east-1</regionName>
            <regionEndpoint>ec2.sa-east-1.amazonaws.com</regionEndpoint>
        </item>
        <item>
            <regionName>ca-central-1</regionName>
            <regionEndpoint>ec2.ca-central-1.amazonaws.com</regionEndpoint>
        </item>
        <item>
            <regionName>ap-southeast-1</regionName>
            <regionEndpoint>ec2.ap-southeast-1.amazonaws.com</regionEndpoint>
        </item>
        <item>
            <regionName>ap-southeast-2</regionName>
            <regionEndpoint>ec2.ap-southeast-2.amazonaws.com</regionEndpoint>
        </item>
        <item>
            <regionName>eu-central-1</regionName>
            <regionEndpoint>ec2.eu-central-1.amazonaws.com</regionEndpoint>
        </item>
        <item>
            <regionName>us-east-1</regionName>
            <regionEndpoint>ec2.us-east-1.amazonaws.com</regionEndpoint>
        </item>
        <item>
            <regionName>us-east-2</regionName>
            <regionEndpoint>ec2.us-east-2.amazonaws.com</regionEndpoint>
        </item>
        <item>
            <regionName>us-west-1</regionName>
            <regionEndpoint>ec2.us-west-1.amazonaws.com</regionEndpoint>
        </item>
        <item>
            <regionName>us-west-2</regionName>
            <regionEndpoint>ec2.us-west-2.amazonaws.com</regionEndpoint>
        </item>
    </regionInfo>
</DescribeRegionsResponse>


[0] HTTP response parsed
at time: 2017-11-30 10:25:49.200
parsed to: {
    "Regions": [
        {
            "Endpoint": "ec2.ap-south-1.amazonaws.com",
            "RegionName": "ap-south-1"
        },
        {
            "Endpoint": "ec2.eu-west-2.amazonaws.com",
            "RegionName": "eu-west-2"
        },
        {
            "Endpoint": "ec2.eu-west-1.amazonaws.com",
            "RegionName": "eu-west-1"
        },
        {
            "Endpoint": "ec2.ap-northeast-2.amazonaws.com",
            "RegionName": "ap-northeast-2"
        },
        {
            "Endpoint": "ec2.ap-northeast-1.amazonaws.com",
            "RegionName": "ap-northeast-1"
        },
        {
            "Endpoint": "ec2.sa-east-1.amazonaws.com",
            "RegionName": "sa-east-1"
        },
        {
            "Endpoint": "ec2.ca-central-1.amazonaws.com",
            "RegionName": "ca-central-1"
        },
        {
            "Endpoint": "ec2.ap-southeast-1.amazonaws.com",
            "RegionName": "ap-southeast-1"
        },
        {
            "Endpoint": "ec2.ap-southeast-2.amazonaws.com",
            "RegionName": "ap-southeast-2"
        },
        {
            "Endpoint": "ec2.eu-central-1.amazonaws.com",
            "RegionName": "eu-central-1"
        },
        {
            "Endpoint": "ec2.us-east-1.amazonaws.com",
            "RegionName": "us-east-1"
        },
        {
            "Endpoint": "ec2.us-east-2.amazonaws.com",
            "RegionName": "us-east-2"
        },
        {
            "Endpoint": "ec2.us-west-1.amazonaws.com",
            "RegionName": "us-west-1"
        },
        {
            "Endpoint": "ec2.us-west-2.amazonaws.com",
            "RegionName": "us-west-2"
        }
    ],
    "ResponseMetadata": {
        "HTTPHeaders": {
            "content-type": "text/xml;charset=UTF-8",
            "date": "Thu, 30 Nov 2017 01:25:47 GMT",
            "server": "AmazonEC2",
            "transfer-encoding": "chunked",
            "vary": "Accept-Encoding"
        },
        "HTTPStatusCode": 200,
        "RequestId": "e60926d0-b5b2-4e8d-82ff-0e759b0beff7"
    }
}

AWS CLI command exited
at time: 2017-11-30 10:25:49.204
with return code: 0

まとめ

事前に設定を有効にしておく必要がありますが、重要なシステムを対象とする作業においては、どのようなコマンドを実行し、どのような結果が返ってきたのかを確認できるのは嬉しいですね。re:Inventで盛り上がっている中ですが、今後もAWSの細かいアップデートもしっかり拾ってお伝えしていきたいと思います。

どこかの誰かのお役に立てば嬉しいです。