awscliのquery利用方法まとめ(主にqueryオプションとTips)

queryオプションを主にaws cliの使い方をメモしておきます。随時更新予定です。

queryオプション

queryオプションはaws cliの結果をフィルタ、整形できるオプションです。書式は jq とか使ったことあるなら馴染みあるはずJMESPathです。

JMESPath Specification — JMESPath

--query (string)

       A JMESPath query to use in filtering the response data.



query指定無しだと

例えばAMIの一覧を出す以下のコマンド、人の目にもJSONParser無しのスクリプトにも優しくないです。少し前まではここで jq の出番だったのですが、今はqueryオプションで対応しています。

$ aws ec2 describe-images --owners self 
{
    "Images": [
            {
            "VirtualizationType": "hvm",
            ...
            ...



基本の使い方

出力形式を知る

クエリするにはクエリ対象のスキーマを知らないといけません。とりあえずコマンド打って確認するのもいいですが、AWSの公式サイトにも纏まっています。使いたいコマンドのOutput項目を確認します。

ec2 — AWS CLI 1.32.12 Command Reference

例えば上で挙げた aws ec2 describe-images コマンドなら以下のように出力例と、

{
    "Images": [
        {
            "VirtualizationType": "paravirtual",
            "Name": "My server",
            "Hypervisor": "xen",
            "ImageId": "ami-5731123e",
            "RootDeviceType": "ebs",
            "State": "available",
            "BlockDeviceMappings": [
                {
 ...
 ...
}

項目毎の説明も記載されています。

Images -> (list)

Information about one or more images. (structure)

Describes an image. Architecture -> (string)

The architecture of the image. ....



queryを使ってみる

実際に動かしてみます。[] で囲まれていることからも、上の説明からもわかるように Images という list の中に。その Architecture が連想配列で子要素に入っています。

{
    "Images": [
            {
            "VirtualizationType": "hvm",
            ...
            ...

上で内容を 連想配列の VirtualizationType の項目を取ってみます。Images配列の一つ目の項目から VirtualizationType のキーの値を取得するクエリは 'Images[0].VirtualizationType となります。

$ aws ec2 describe-images --owners self --query  'Images[0].VirtualizationType'
"hvm"

配列の添え字は [0:4] のような範囲指定から [*] または [] で全部取得などもできます。

$ aws ec2 describe-images --owners self --query  'Images[0:4].VirtualizationType'
[
    "hvm",
    "paravirtual",
    "hvm",
    "hvm"
]

[] の中にワイルドカードや数字の代わりに条件式を入れることもできます。先頭に? を付けてることで条件式になります。

これで条件式が真の項目に絞って取得することができます。条件式の値は「``」で囲むのがポイント。

$ aws ec2 describe-images --owners self --query  'Images[?VirtualizationType == `paravirtual`]'
[
    {
        "VirtualizationType": "paravirtual",
        ...
        ...

複数条件でANDやOR取りたい場合は、二つ目の条件前には ? は不要です。

$ aws ec2 describe-images --owners self --query  'Images[?VirtualizationType == `paravirtual` && Name == `ami-a`]'

連想配列部分をマッピングしなおすことも可能です。後書く関数との連携で使います。

$ aws ec2 describe-images --owners self --query  'Images[*].{v:VirtualizationType,n:Name}'
[
    {
        "n": "ami-name1",
        "v": "hvm"
    },
    {
        "n": "ami-name2",
        "v": "paravirtual"
    },
    ...
    ...
]




関数(Functions)

関数の一覧はこちらのサイトで確認できます。ここでは自分が使ったものメモしていきます。

関数使う際に型を意識して利用する必要があります。よくあるのは引数の型がstringなのに 1234 みたいに入力して怒られるパターンです。 後述のto_stringしたり "1234" のように " で囲んで利用します。

number (integers and double-precision floating-point format in JSON)
string
boolean (true or false)
array (an ordered, sequence of values)
object (an unordered collection of key value pairs)
null



contains

例えば DeleteFlag というタグを設定したAMIを一覧を取得するとします。このようなクエリでいけます。

aws ec2 describe-images --owners self --query  'Images[?Tags[?Key == `DeleteFlag`]]'

DeleteFalg以外にもFlagがあって Flag という文字列を含むKeyをタグに設定してあるAMIを取得したい場合、contains を使うとうまくいきます。

$ aws ec2 describe-images --owners self --query  'Images[?Tags[?contains(Key,`Flag`)]]'

「Proj1」という文字がタグに含まれている一覧ならこんな感じ。

$ aws ec2 describe-images --owners self --query  'Images[*].Tags[?contains(`Proj1`,Value)]'



join

$glue に指定した文字で配列を結合します。

string join(string $glue, array[string] $stringsarray)

配列を引数に取るのでこんな実行例があります。

インスタンスIDを # 区切りで出力

$ aws ec2 describe-instances --query 'join(`%`,Reservations[].Instances[].InstanceId)'

EC2のインスタンスIDと紐付いている複数のEBSを , 結合、テーブル形式で出力。

$ aws ec2 describe-instances --query 'Reservations[].Instances[0:10].{ID:InstanceId,EBS:join(`,`,BlockDeviceMappings[].DeviceName)}' --output table
--------------------------------------------------------------------------
|                            DescribeInstances                           |
+------------------------------------------------+-----------------------+
|                       EBS                      |          ID           |
+------------------------------------------------+-----------------------+
|  /dev/xvda                                    |  i-1234abcd           |
|  /dev/sda1,/dev/sdf                            |  i-abcd1234           |
|  /dev/sda1,/dev/sdf,/dev/sdg,/dev/sdh,/dev/sdi |  i-5678efgh           |
....



starts_withとends_with

接頭辞と接尾辞判定に使います。

boolean starts_with(string $subject, string $prefix)
boolean ends_with(string $subject, string $suffix)

絞り込みに使うと便利です。

aws ec2 describe-images --owners self --query  'Images[?starts_with(Name,`dev-`)]'
aws ec2 describe-images --owners self --query  'Images[?ends_with(Name,`"20170907"`)]'



to_string

普通のtoStringです。文字列に変換できます。

$ aws ec2 describe-images --owners self --query  'Images[*].BlockDeviceMappings[*].Ebs.VolumeSize'
[
    [
        80
    ],
...
$ aws ec2 describe-images --owners self --query  'Images[*].BlockDeviceMappings[*].Ebs.to_string(VolumeSize)' 
[
    [
        "80"
    ],
...



sort_by

特定のフィールドなどで柔軟にsortします。

sort_by(array elements, expression->number|expression->string expr)

例えばCloudWatchのデータを取ってきたら順番がバラバラでした。

$ aws cloudwatch get-metric-statistics --namespace AWS/EBS --metric-name VolumeQueueLength --period 60 --statistics Average --query 'sort_by(Datapoints[*],&Timestamp)' --output table --start-time 2017-09-01T10:00:00Z --end-time 2017-09-01T10:30:00Z --dimensions Name=VolumeId,Value=vol-abcd1234

--------------------------------------------------------
|                  GetMetricStatistics                 |
+--------------------+------------------------+--------+
|       Average      |       Timestamp        | Unit   |
+--------------------+------------------------+--------+
|  0.000833333333333 |  2017-09-01T10:00:00Z  |  Count |
|  1.9456            |  2017-09-01T10:05:00Z  |  Count |
|  0.000533333333333 |  2017-09-01T10:20:00Z  |  Count |
|  0.0141            |  2017-09-01T10:25:00Z  |  Count |
|  0.672766666667    |  2017-09-01T10:10:00Z  |  Count |
|  0.000133333333333 |  2017-09-01T10:15:00Z  |  Count |
+--------------------+------------------------+--------+

sort_byでTimestampのフィールドを使ってsortしてみました。

$ aws cloudwatch get-metric-statistics --namespace AWS/EBS --metric-name VolumeQueueLength --period 60 --statistics Average --query 'Datapoints[*]' --output table --start-time 2017-09-01T10:00:00Z --end-time 2017-09-01T10:30:00Z --dimensions Name=VolumeId,Value=vol-abcd1234
--------------------------------------------------------
|                  GetMetricStatistics                 |
+--------------------+------------------------+--------+
|       Average      |       Timestamp        | Unit   |
+--------------------+------------------------+--------+
|  0.000833333333333 |  2017-09-01T10:00:00Z  |  Count |
|  1.9456            |  2017-09-01T10:05:00Z  |  Count |
|  0.672766666667    |  2017-09-01T10:10:00Z  |  Count |
|  0.000133333333333 |  2017-09-01T10:15:00Z  |  Count |
|  0.000533333333333 |  2017-09-01T10:20:00Z  |  Count |
|  0.0141            |  2017-09-01T10:25:00Z  |  Count |
+--------------------+------------------------+--------+

パイプ使った書き方例はこちら。

$ aws cloudwatch get-metric-statistics --namespace AWS/EBS --metric-name VolumeQueueLength --period 60 --statistics Average --query 'Datapoints[*] | sort_by(@,&Timestamp)' --output table --start-time 2017-09-01T10:00:00Z --end-time 2017-09-01T10:30:00Z --dimensions Name=VolumeId,Value=vol-abcd1234



length

特定の項目の件数(count)を調べたい時はlengthを使います。

$ aws rds describe-db-instances  --query 'length(DBInstances[?DBInstanceIdentifier==`your-rds-name`])'

Tips

JMESPATH文法を手軽に試したい

オンラインでJMESPATH試せます。

JMESPath Tutorial — JMESPath



「EC2のインスタンスID」→「TagのName」を取得
$ aws ec2 describe-tags --query 'Tags[?ResourceId == `i-abcd1234` && Key == `Name`].Value' --output text



「TagのName」→「EC2のインスタンスID」を取得
$ aws ec2 describe-tags --query 'Tags[?ResourceType == `instance` && Key == `Name`  && Value == `host_name`].ResourceId' --output text

starts_withやcontainsと一緒に使っても便利です。最後に連想配列にマップすると列で結果を出力できます。

$ aws ec2 describe-tags --query 'Tags[?ResourceType == `instance` && Key == `Name`  && starts_with(Value,`dev-`)].{R:ResourceId}' --output text
i-abcd1234
i-efgh5678
...
特定のプロジェクトのインスタンス名一覧(どちらもタグから取得)
aws ec2 describe-instances --query 'Reservations[].Instances[?Tags[?Key == `Project` && Value == `AAAA`]].Tags[][?Key == `Name`].Value' --out text



Athenaでユーザごとのクエリ利用状況を取得したい

yomon.hatenablog.com



ELBを命名規則を元に抽出

命名規則からprefixとsufixを元に抽出。

aws elb describe-load-balancers --query 'LoadBalancerDescriptions[?starts_with(LoadBalancerName,`dev`) && ends_with(LoadBalancerName,`front`)].LoadBalancerName'
EC2とRDSのReserved Instancesの一覧情報

RIの一覧情報

aws ec2 describe-reserved-instances --query 'ReservedInstances[*] | sort_by(@,&Start)[*].{aState:State,bRIID:ReservedInstancesId,cAZ:AvailabilityZone,dType:InstanceType,eCount:InstanceCount,fStart:Start,gEnd:End}' --output table
aws rds describe-reserved-db-instances --query 'ReservedDBInstances[*] |  sort_by(@,&StartTime)[*].{aState:State,bReservedDBInstanceId:ReservedDBInstanceId,dMultiAZ:MultiAZ,cDBInstanceClass:DBInstanceClass,eStartTime:StartTime,fProductDescription:ProductDescription}' --output table



関連するAMIのSnapshot一覧

名前が 「 dev- 」始まりのAMIに紐付いたスナップショットの一覧取得

$ aws ec2 describe-images --owners self --query  'Images[?starts_with(Name,`dev-`)].{ID:ImageId,Name:Name,EBS:join(`,`,BlockDeviceMappings[*].Ebs.SnapshotId),VolumeSize:join(`,`,BlockDeviceMappings[*].Ebs.to_string(VolumeSize))}'



CloudFormationのOutput

CloudFormationのスタックデプロイ後にOutputsを取得。

$ aws cloudformation describe-stacks --stack-name your-stack-name --query "Stacks[0].Outputs" --output table
--------------------------------------------------------------------------------------------------------------
|                                               DescribeStacks                                               |
+---------------------------+------------+-------------------------------------------------------------------+
|        Description        | OutputKey  |                            OutputValue                            |
+---------------------------+------------+-------------------------------------------------------------------+
|  URL of your API endpoint |  ApiUrl    |  https://abcdefg.execute-api.ap-northeast-1.amazonaws.com/dev  |
+---------------------------+------------+-------------------------------------------------------------------+




IAMのCredential Reportをデコードして出力

IAMの認証情報レポートを見る方法。

AWS アカウント の認証情報レポートの取得 - AWS Identity and Access Management

# IAMのレポート出力を開始
$ aws iam generate-credential-report
{
    "State": "STARTED",
    "Description": "No report exists. Starting a new report generation task"
}

# IAMのレポート出力が完了
$ aws iam generate-credential-report
{
    "State": "COMPLETE"
}

# レポートはBase64でエンコードされている
$ aws iam get-credential-report
{
    "Content": "BASE64encoded.....xOL0E=",
    "ReportFormat": "text/csv",
    "GeneratedTime": "2019-02-02T00:14:13Z"
}

# base64コマンドでデコード
$ aws iam get-credential-report --query 'Content' --output text | base64 -d
user,arn,user_creation_time,password_enabled,password_last_used,password_last_changed,password_next_rotation,mfa_active,access_key_1_active,access_key_1_last_rotated,access_key_1_last_used_date,access_key_1_last_used_region,access_key_1_last_used_service,access_key_2_active,access_key_2_last_rotated,access_key_2_last_used_date,access_key_2_last_used_region,access_key_2_last_used_service,cert_1_active,cert_1_last_rotated,cert_2_active,cert_2_last_rotated
<root_account>,arn:aws:iamーーー以下省略



EC2のコンソール画面

EC2のコンソール画面はAWSコンソールから結構面倒ですし、grep等の処理するにも面倒ですがコマンドで取得できます。

コマンドラインでEC2のコンソール画面テキスト(システムログ)を取得してgrep分析 - YOMON8.NET



EC2で自身が所属しているVPC IDの取得

$ vpcid=$(aws ec2 describe-instances --query "Reservations[].Instances[?InstanceId == \`$(curl -s 169.254.169.254/2021-01-03/meta-data/instance-id)\`].VpcId" --output text)

$ echo $vpcid
vpc-xxxxx
Bashとの連携

通常の出力でもJSONのパーサーとかあれば使えます。でもBashとの連携となると少し加工した方が使いやすいです。

$ aws ec2 describe-instances --query 'Reservations[].Instances[].InstanceId'
[
    "i-abcd1234",
    "i-efgf5678",
    "i-ijklmn9",
....

--output text を付けるとタブ区切りで出力されます。これでも結構使えます。

$ aws ec2 describe-instances --query 'Reservations[].Instances[].InstanceId' --output text
i-abcd1234  i-efgh5678  i-ijklmn9...

更に少し工夫してダミーの連想配列マップしてからtext形式で出力とやると縦に並びます。これで連携しやすうなりまs。

$ aws ec2 describe-instances --query 'Reservations[].Instances[].{i:InstanceId}' --output text
i-abcd1234
i-efgh5678
i-ijklmn9
...



Debug

Debugオプションあるので動きを詳しく追いたい場合は使えます。結果はエラー出力に出てきます。

aws ec2 describe-tags --debug  2> debuglog.txt
TagのNameがXXXから始まるSubnet一覧
aws ec2 describe-subnets --query 'Subnets[?Tags[?Key == `Name` && starts_with(Value,`Common`)]]'