AWS CLI の query による絞り込み


`aws ec2 describe-うんちゃら` で必要な情報を取得した時のメモ。
主に↓を参照しつつ、Try&Errorの結果。
http://jmespath.readthedocs.org/en/latest/specification.html



### 絞り込み方
コマンドとしては以下の形式で絞り込む。`--query` の条件はシングルクォート`'`でないとエラーとなる。

```bash
$ aws ec2 describe-instances --query '条件'
```

この時、条件として設定する文字列は、以下のような感じで考えるとやり易いかもしれない。

* JSONの階層構造を意識する
* 表示項目を絞り込む
* 表示対象を絞り込む

例えば `aws ec2 describe-instances` の実行結果を見ると、`Reservations` がトップレベルにあるのがわかる。

```json
{
    "Reservations": [
        {
            "OwnerId": "XXXXXXXXXXXX",
            "ReservationId": "r-XXXXXXXX",
            "Groups": [],
            "Instances": [
                {
                    "Monitoring": {
                        "State": "disabled"
:
:
```

なので、単純に `Reservations` 以下を表示させる場合は、

```bash
$ aws ec2 describe-instances --query 'Reservations[]'
```

とすることで、以下のように一階層下からの表示に絞り込める。

```json
[
    {
        "OwnerId": "XXXXXXXXXXXX",
        "ReservationId": "r-XXXXXXXX",
        "Groups": [],
        "Instances": [
            {
                "Monitoring": {
                    "State": "disabled"
                },
:
:
```

さらに下の階層に絞る場合は `.` で繋げれば良い。

```bash
$ aws ec2 describe-instances --query 'Reservations[].Instances[]'
[
    {
        "Monitoring": {
            "State": "disabled"
        },
        "PublicDnsName": null,
        "Platform": "windows",
        "State": {
            "Code": 80,
            "Name": "stopped"
:
:
```


次に、表示対象を絞る場合、`.` で繋げた後に `[]` もしくは `{}` で囲った中に表示対象を記載すれば良い。
`[]` の場合は配列表示、`{}` の場合はハッシュ表示となる。

```bash:配列時
$ aws ec2 describe-instances --query 'Reservations[].Instances[].[InstanceId]'
[
    [
        "i-AAAAAAAA"
    ],
    [
        "i-BBBBBBBB"
    ],
    [
        "i-CCCCCCCC"
    ],
:
:
```

ハッシュ時は任意のKeyを追加する必要がある。指定しないとエラー。

```bash:ハッシュ時
$ aws ec2 describe-instances --query 'Reservations[].Instances[].{ID:InstanceId}'
[
    {
        "ID": "i-AAAAAAAA"
    },
    {
        "ID": "i-BBBBBBBB"
    },
    {
        "ID": "i-CCCCCCCC"
    },:
:
```

ただ、このままだと全てのインスタンスが対象となるので、そこで絞り込みが必要となる。
表示階層を指定している `[]` 内にその配下にある項目に対して条件を **[?項目名==\`値\`]**　という形式で記載する。値をバッククォートで囲うのが要注意。

```bash
$ aws ec2 describe-instances --query 'Reservations[].Instances[?InstanceId==`i-AAAAAAAA`].[InstanceId]'
[
    [
        [
            "i-AAAAAAAA"
        ]
    ],
    [],
    [],
    [],
    [],
:
:
```

しかし、空要素も表示されてしまうため、表示部分の末尾に `[]` を追加することで空要素を非表示にできる。
なぜ、`[]` で良いのかは不明。。。一階層下がることで空は消えるのか？

```bash
$ aws ec2 describe-instances --query 'Reservations[].Instances[?InstanceId==`i-AAAAAAAA `].[InstanceId][]'
[
    [
        "i-AAAAAAAA"
    ]
]
```

基本的には今までの考え方を組み合わせていくのみ。
応用的に色々あるみたいだが、Try&Errorの結果ベースなので説明は無理。。。


### 実行例
以下は簡単なシナリオ想定での例。

#### Tag名からインスタンス情報を取得したい
おそらくは、サーバホスト名=Tag名という設計が多いはず。

```bash
$ aws ec2 describe-instances --query 'Reservations[].Instances[?Tags[?Key==`Name`].Value|[0]==`TAG_NAME`][]|[0]'
```

Tag名からInstanceIdのみ取得する場合。

```bash
aws ec2 describe-instances --query 'Reservations[].Instances[?Tags[?Key==`Name`].Value|[0]==`TAG_NAME`][].[InstanceId][]|[0]'
```


#### インスタンス一覧が見たい
サマリ的な情報を見たいときとか。IPやらタグ名やら状態やら。

```bash
aws ec2 describe-instances --query 'sort_by(Reservations[].Instances[].{InstanceId:InstanceId,Tags:Tags[?Key==`Name`].Value|[0],InstanceType:InstanceType,State:State.Name,Ip:PrivateIpAddress,AZ:Placement.AvailabilityZone,Platform:Platform},&Tags)' --output table                       |
```


#### サブネットの一覧を見たい
どのAZにどんなサブネットがあって、そのIDとかちょっと見たいなぁという時に。

```bash
aws ec2 describe-subnets --query 'Subnets[].{VpcId:VpcId,Cidr:CidrBlock,AZ:AvailabilityZone,SubnetId:SubnetId,Tags:Tags[?Key==`Name`].Value|[0]}' --output table
```

AZ順にソートもできる。

```bash
aws ec2 describe-subnets --query 'sort_by(Subnets[].{VpcId:VpcId,Cidr:CidrBlock,AZ:AvailabilityZone,SubnetId:SubnetId,Tags:Tags[?Key==`Name`].Value|[0]},&AZ)' --output table
```