AWS CLI v2でDynamoDBのハイレベルコマンドを試してみた #reinvent

はじめに

中山(順)です

AWS CLI v2が開発中なのは皆さんご存じでしょうか?

AWS CLI v2 development

今回のre:Inventでも紹介セッションが実施されました。

[レポート] DEV322: What’s New with the AWS CLI #reinvent

その際に、DynamoDBのハイレベルコマンドのデモが行われていました。 AWS CLIのコマンドは基本的にAPIと1:1に対応しています。 ただし、例外的にs3のハイレベルコマンドだけ提供されていました。 これが非常に使い勝手が良く、重宝していました。

v2で登場するDynamoDBも便利そうなのでちょっと使ってみました。

やってみた

今回はAmazon Linux (1)上で実施してみました。

インストール

以下のコマンドでインストールします。

sudo pip install -e git://github.com/aws/aws-cli.git@v2#egg=awscli

バージョンを確認します。

aws --version
aws-cli/2.0.0dev0 Python/2.7.14 Linux/4.14.77-70.59.amzn1.x86_64 botocore/1.12.48

コマンドの確認

DynamoDBのハイレベルコマンドは"ddb"です。ヘルプを確認してみます。

aws ddb help
DDB()                                                                    DDB()



NAME
       ddb -

DESCRIPTION
       High level DynamoDB commands.

       See 'aws help' for descriptions of global parameters.

SYNOPSIS
          aws ddb <Command> [<Arg> ...]

OPTIONS
       None

       See 'aws help' for descriptions of global parameters.

AVAILABLE COMMANDS
       o put

       o select



                                                                         DDB()

"select"と"put"の2つのコマンドが用意されています。

テーブルの作成

まずは検証用のテーブルを作成します。 コマンドはコマンドリファレンスのサンプルを拝借します。

aws dynamodb create-table \
    --table-name MusicCollection \
    --attribute-definitions AttributeName=Artist,AttributeType=S AttributeName=SongTitle,AttributeType=S \
    --key-schema AttributeName=Artist,KeyType=HASH AttributeName=SongTitle,KeyType=RANGE \
    --provisioned-throughput ReadCapacityUnits=1,WriteCapacityUnits=1
{
    "TableDescription": {
        "TableArn": "arn:aws:dynamodb:us-east-1:XXXXXXXXXXXX:table/MusicCollection",
        "AttributeDefinitions": [
            {
                "AttributeName": "Artist",
                "AttributeType": "S"
            },
            {
                "AttributeName": "SongTitle",
                "AttributeType": "S"
            }
        ],
        "ProvisionedThroughput": {
            "NumberOfDecreasesToday": 0,
            "WriteCapacityUnits": 1,
            "ReadCapacityUnits": 1
        },
        "TableSizeBytes": 0,
        "TableName": "MusicCollection",
        "TableStatus": "CREATING",
        "TableId": "8b9c9b82-7a36-4e84-a09c-9d43bb24777a",
        "KeySchema": [
            {
                "KeyType": "HASH",
                "AttributeName": "Artist"
            },
            {
                "KeyType": "RANGE",
                "AttributeName": "SongTitle"
            }
        ],
        "ItemCount": 0,
        "CreationDateTime": "2018-11-30T09:17:43.920000+00:00"
    }
}

実行履歴の取得を有効化

後で実行履歴を確認するため、有効化します。

aws configure set cli_history enabled

書き込み

書き込みは以下のように行います。 詳細はヘルプをご確認ください。

aws ddb put MusicCollection '{Artist: "No One You Know", SongTitle: "Call Me Today", AlbumTitle: "Somewhat Famous"}'
aws ddb put MusicCollection '{Artist: "Obscure Indie Band", SongTitle: "Atlas"}' \
    --condition 'attribute_not_exists(Artist)'

参照

参照は以下のように行います。

全件をスキャンする場合は以下の通りです。

aws ddb select MusicCollection
Count: 2
Items:
- Artist: Obscure Indie Band
  SongTitle: Atlas
- AlbumTitle: Somewhat Famous
  Artist: No One You Know
  SongTitle: Call Me Today
ScannedCount: 2

スキャンした結果の絞り込みは以下のように行います。

aws ddb select MusicCollection --projection 'SongTitle, AlbumTitle' \
    --filter 'Artist = "No One You Know"'
Count: 1
Items:
- AlbumTitle: Somewhat Famous
  SongTitle: Call Me Today
ScannedCount: 2

クエリは以下のように行います。

aws ddb select MusicCollection --projection SongTitle \
    --key-condition 'Artist = "No One You Know"'
Count: 1
Items:
- SongTitle: Call Me Today
ScannedCount: 1

実行履歴の確認

一覧は以下のように確認できます。 一覧では、コマンドID/時刻/コマンド(パラメーター無し)しか確認できません。

aws history list
414fadc6-f609-40c1-ba04-1c160ddfb7cc  2018-11-30 09:36:56 AM  ddb select                                        0
366e9b1b-1169-4b88-8a51-52b520c7383f  2018-11-30 09:36:47 AM  ddb select                                        0
be1168ca-0f75-4e85-bb3e-661266e7d9b8  2018-11-30 09:36:39 AM  ddb put                                           0
8f2fb791-d6a6-4723-b255-9c4d5a4bc0c8  2018-11-30 09:36:34 AM  ddb put                                           0
d638a10b-6dd8-4e37-8978-ae445616e53c  2018-11-30 09:36:25 AM  dynamodb create-table                             0

各実行履歴の確認は以下のように行います。 コマンドIDを指定して詳細を確認します。 以下の通り、実体はPutItemのAPIをコールしていることがわかります。

aws history show 8f2fb791-d6a6-4723-b255-9c4d5a4bc0c8
AWS CLI command entered
at time: 2018-11-30 09:36:34.182
with AWS CLI version: aws-cli/2.0.0dev0 Python/2.7.14 Linux/4.14.77-70.59.amzn1.x86_64 botocore/1.12.48
with arguments: [u'ddb', u'put', u'MusicCollection', u'{Artist: "No One You Know", SongTitle: "Call Me Today", AlbumTitle: "Somewhat Famous"}']

[0] API call made
at time: 2018-11-30 09:36:34.261
to service: dynamodb
using operation: PutItem
with parameters: {
    "Item": {
        "AlbumTitle": {
            "S": "Somewhat Famous"
        },
        "Artist": {
            "S": "No One You Know"
        },
        "SongTitle": {
            "S": "Call Me Today"
        }
    },
    "ReturnConsumedCapacity": "NONE",
    "TableName": "MusicCollection"
}

[0] HTTP request sent
at time: 2018-11-30 09:36:34.270
to URL: https://dynamodb.us-east-1.amazonaws.com/
with method: POST
with headers: {
    "Authorization": "AWS4-HMAC-SHA256 Credential=XXXXXXXXXXXXXXXXXXXX/20181130/us-east-1/dynamodb/aws4_request, SignedHeaders=content-type;host;x-amz-date;x-amz-security-token;x-amz-target
, Signature=3546...",
    "Content-Length": "189",
    "Content-Type": "application/x-amz-json-1.0",
    "User-Agent": "aws-cli/2.0.0dev0 Python/2.7.14 Linux/4.14.77-70.59.amzn1.x86_64 botocore/1.12.48",
    "X-Amz-Date": "20181130T093634Z",
    "X-Amz-Security-Token": "xxx",
    "X-Amz-Target": "DynamoDB_20120810.PutItem"
}
with body: {
    "Item": {
        "AlbumTitle": {
            "S": "Somewhat Famous"
        },
        "Artist": {
            "S": "No One You Know"
        },
        "SongTitle": {
            "S": "Call Me Today"
        }
    },
    "ReturnConsumedCapacity": "NONE",
    "TableName": "MusicCollection"
}

[0] HTTP response received
at time: 2018-11-30 09:36:34.319
with status code: 200
with headers: {
    "Connection": "keep-alive",
    "Content-Length": "2",
    "Content-Type": "application/x-amz-json-1.0",
    "Date": "Fri, 30 Nov 2018 09:36:34 GMT",
    "Server": "Server",
    "x-amz-crc32": "2745614147",
    "x-amzn-RequestId": "6TDKTJ4PDE2NKEQHBR82NI2RTJVV4KQNSO5AEMVJF66Q9ASUAAJG"
}
with body: {}

[0] HTTP response parsed
at time: 2018-11-30 09:36:34.326
parsed to: {
    "ResponseMetadata": {
        "HTTPHeaders": {
            "connection": "keep-alive",
            "content-length": "2",
            "content-type": "application/x-amz-json-1.0",
            "date": "Fri, 30 Nov 2018 09:36:34 GMT",
            "server": "Server",
            "x-amz-crc32": "2745614147",
            "x-amzn-requestid": "6TDKTJ4PDE2NKEQHBR82NI2RTJVV4KQNSO5AEMVJF66Q9ASUAAJG"
        },
        "HTTPStatusCode": 200,
        "RequestId": "6TDKTJ4PDE2NKEQHBR82NI2RTJVV4KQNSO5AEMVJF66Q9ASUAAJG"
    }
}

AWS CLI command exited
at time: 2018-11-30 09:36:34.329
with return code: 0

スキャンの場合は以下のような感じです。

aws history show 366e9b1b-1169-4b88-8a51-52b520c7383f
AWS CLI command entered
at time: 2018-11-30 09:36:47.567
with AWS CLI version: aws-cli/2.0.0dev0 Python/2.7.14 Linux/4.14.77-70.59.amzn1.x86_64 botocore/1.12.48
with arguments: [u'ddb', u'select', u'MusicCollection']

[0] API call made
at time: 2018-11-30 09:36:47.648
to service: dynamodb
using operation: Scan
with parameters: {
    "ConsistentRead": true,
    "ReturnConsumedCapacity": "NONE",
    "TableName": "MusicCollection"
}

[0] HTTP request sent
at time: 2018-11-30 09:36:47.653
to URL: https://dynamodb.us-east-1.amazonaws.com/
with method: POST
with headers: {
    "Authorization": "AWS4-HMAC-SHA256 Credential=XXXXXXXXXXXXXXXXXXXX/20181130/us-east-1/dynamodb/aws4_request, SignedHeaders=content-type;host;x-amz-date;x-amz-security-token;x-amz-target
, Signature=7803...",
    "Content-Length": "90",
    "Content-Type": "application/x-amz-json-1.0",
    "User-Agent": "aws-cli/2.0.0dev0 Python/2.7.14 Linux/4.14.77-70.59.amzn1.x86_64 botocore/1.12.48",
    "X-Amz-Date": "20181130T093647Z",
    "X-Amz-Security-Token": "xxxx",
    "X-Amz-Target": "DynamoDB_20120810.Scan"
}
with body: {
    "ConsistentRead": true,
    "ReturnConsumedCapacity": "NONE",
    "TableName": "MusicCollection"
}

[0] HTTP response received
at time: 2018-11-30 09:36:47.714
with status code: 200
with headers: {
    "Connection": "keep-alive",
    "Content-Length": "208",
    "Content-Type": "application/x-amz-json-1.0",
    "Date": "Fri, 30 Nov 2018 09:36:47 GMT",
    "Server": "Server",
    "x-amz-crc32": "2411811827",
    "x-amzn-RequestId": "4FKMC96OQFABKRJAO5OBAS2Q4RVV4KQNSO5AEMVJF66Q9ASUAAJG"
}
with body: {
    "Count": 2,
    "Items": [
        {
            "Artist": {
                "S": "Obscure Indie Band"
            },
            "SongTitle": {
                "S": "Atlas"
            }
        },
        {
            "AlbumTitle": {
                "S": "Somewhat Famous"
            },
            "Artist": {
                "S": "No One You Know"
            },
            "SongTitle": {
                "S": "Call Me Today"
            }
        }
    ],
    "ScannedCount": 2
}

[0] HTTP response parsed
at time: 2018-11-30 09:36:47.717
parsed to: {
    "Count": 2,
    "Items": [
        {
            "Artist": {
                "S": "Obscure Indie Band"
            },
            "SongTitle": {
                "S": "Atlas"
            }
        },
        {
            "AlbumTitle": {
                "S": "Somewhat Famous"
            },
            "Artist": {
                "S": "No One You Know"
            },
            "SongTitle": {
                "S": "Call Me Today"
            }
        }
    ],
    "ResponseMetadata": {
        "HTTPHeaders": {
            "connection": "keep-alive",
            "content-length": "208",
            "content-type": "application/x-amz-json-1.0",
            "date": "Fri, 30 Nov 2018 09:36:47 GMT",
            "server": "Server",
            "x-amz-crc32": "2411811827",
            "x-amzn-requestid": "4FKMC96OQFABKRJAO5OBAS2Q4RVV4KQNSO5AEMVJF66Q9ASUAAJG"
        },
        "HTTPStatusCode": 200,
        "RequestId": "4FKMC96OQFABKRJAO5OBAS2Q4RVV4KQNSO5AEMVJF66Q9ASUAAJG"
    },
    "ScannedCount": 2
}

AWS CLI command exited
at time: 2018-11-30 09:36:47.724
with return code: 0

クエリの結果は以下のような感じです。

aws history show eef26433-d3de-49f8-8409-3f4e6b943647
AWS CLI command entered
at time: 2018-11-30 10:00:50.420
with AWS CLI version: aws-cli/2.0.0dev0 Python/2.7.14 Linux/4.14.77-70.59.amzn1.x86_64 botocore/1.12.48
with arguments: [u'ddb', u'select', u'MusicCollection', u'--projection', u'SongTitle', u'--key-condition', u'Artist = "No One You Know"']

[0] API call made
at time: 2018-11-30 10:00:50.497
to service: dynamodb
using operation: Query
with parameters: {
    "ConsistentRead": true,
    "ExpressionAttributeNames": {
        "#n0": "SongTitle",
        "#n1": "Artist"
    },
    "ExpressionAttributeValues": {
        ":n2": {
            "S": "No One You Know"
        }
    },
    "KeyConditionExpression": "#n1 = :n2",
    "ProjectionExpression": "#n0",
    "ReturnConsumedCapacity": "NONE",
    "TableName": "MusicCollection"
}

[0] HTTP request sent
at time: 2018-11-30 10:00:50.502
to URL: https://dynamodb.us-east-1.amazonaws.com/
with method: POST
with headers: {
    "Authorization": "AWS4-HMAC-SHA256 Credential=XXXXXXXXXXXXXXXXXXXX/20181130/us-east-1/dynamodb/aws4_request, SignedHeaders=content-type;host;x-amz-date;x-amz-security-token;x-amz-target, Signature=caa3...",
    "Content-Length": "291",
    "Content-Type": "application/x-amz-json-1.0",
    "User-Agent": "aws-cli/2.0.0dev0 Python/2.7.14 Linux/4.14.77-70.59.amzn1.x86_64 botocore/1.12.48",
    "X-Amz-Date": "20181130T100050Z",
    "X-Amz-Security-Token": "xxxx",
    "X-Amz-Target": "DynamoDB_20120810.Query"
}
with body: {
    "ConsistentRead": true,
    "ExpressionAttributeNames": {
        "#n0": "SongTitle",
        "#n1": "Artist"
    },
    "ExpressionAttributeValues": {
        ":n2": {
            "S": "No One You Know"
        }
    },
    "KeyConditionExpression": "#n1 = :n2",
    "ProjectionExpression": "#n0",
    "ReturnConsumedCapacity": "NONE",
    "TableName": "MusicCollection"
}

[0] HTTP response received
at time: 2018-11-30 10:00:50.542
with status code: 200
with headers: {
    "Connection": "keep-alive",
    "Content-Length": "74",
    "Content-Type": "application/x-amz-json-1.0",
    "Date": "Fri, 30 Nov 2018 10:00:50 GMT",
    "Server": "Server",
    "x-amz-crc32": "2190602160",
    "x-amzn-RequestId": "H3RUHQC8FHOKBFM8KGRIN1FNR7VV4KQNSO5AEMVJF66Q9ASUAAJG"
}
with body: {
    "Count": 1,
    "Items": [
        {
            "SongTitle": {
                "S": "Call Me Today"
            }
        }
    ],
    "ScannedCount": 1
}

[0] HTTP response parsed
at time: 2018-11-30 10:00:50.546
parsed to: {
    "Count": 1,
    "Items": [
        {
            "SongTitle": {
                "S": "Call Me Today"
            }
        }
    ],
    "ResponseMetadata": {
        "HTTPHeaders": {
            "connection": "keep-alive",
            "content-length": "74",
            "content-type": "application/x-amz-json-1.0",
            "date": "Fri, 30 Nov 2018 10:00:50 GMT",
            "server": "Server",
            "x-amz-crc32": "2190602160",
            "x-amzn-requestid": "H3RUHQC8FHOKBFM8KGRIN1FNR7VV4KQNSO5AEMVJF66Q9ASUAAJG"
        },
        "HTTPStatusCode": 200,
        "RequestId": "H3RUHQC8FHOKBFM8KGRIN1FNR7VV4KQNSO5AEMVJF66Q9ASUAAJG"
    },
    "ScannedCount": 1
}

AWS CLI command exited
at time: 2018-11-30 10:00:50.552
with return code: 0

AWS CLI (v1)の時はどうだったか?

以下のようにコマンドを実行する必要があり、v2のハイレベルコマンドが気軽にDynamoDBのデータ操作ができるようになっていることがわかると思います。 先ほどの実行履歴の"[0] HTTP request sent"の"with body"部分でAPIコール時のパラメーターを確認できます。

aws dynamodb put-item \
    --table-name MusicCollection \
    --item file://item.json \
    --return-consumed-capacity TOTAL
aws dynamodb scan \
    --table-name MusicCollection \
    --filter-expression "Artist = :a" \
    --projection-expression "#ST, #AT" \
    --expression-attribute-names file://expression-attribute-names.json \
    --expression-attribute-values file://expression-attribute-values.json
aws dynamodb query \
    --table-name MusicCollection \
    --projection-expression "SongTitle" \
    --key-condition-expression "Artist = :v1" \
    --expression-attribute-values file://expression-attributes.json

まとめ

DynamoDBのデータ操作をCLIで気軽に行いたいとき、これまではコマンドの実行が少々面倒できたがハイレベルコマンドを利用することで簡単に操作できるようになりました。 機会があれば試してみましょう。

現場からは以上です。