AWS Command Line Interface (CLI) の出力を `--query` で制御し、パイプラインで活用する

![job_tobisyoku.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/486518/bdb20f63-1055-136c-19c4-425689b6a65d.png)

これを

```
% aws organizations describe-organization
{
    "Organization": {
        "MasterAccountEmail": "master-account@your-organization-example.com",
        "MasterAccountArn": "arn:aws:organizations::111111111111:account/o-xxxxxxxxxx/111111111111",
        "MasterAccountId": "111111111111",
        "Id": "o-xxxxxxxxxx",
        "AvailablePolicyTypes": [
            {
                "Status": "ENABLED",
                "Type": "SERVICE_CONTROL_POLICY"
            }
        ],
        "FeatureSet": "ALL",
        "Arn": "arn:aws:organizations::111111111111:organization/o-xxxxxxxxxx"
    }
}
```


[こう](https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-usage-output.html#cli-usage-output-filter) する話です

```
% aws organizations describe-organization --query 'Organization.MasterAccountEmail' --output text
master-account@your-organization-example.com
```

そしてたとえばこのように応用する

```
% aws ec2 describe-regions --query 'Regions[].{Name:RegionName}' --output text | xargs -I{} aws ec2 describe-availability-zones --region {} --query 'AvailabilityZones[].{c1:RegionName,c2:ZoneName,c3:State}' --output text
eu-north-1      eu-north-1a     available
eu-north-1      eu-north-1b     available
eu-north-1      eu-north-1c     available
ap-south-1      ap-south-1a     available
ap-south-1      ap-south-1b     available
...（省略）
```

* ※全リージョン全AZを列挙

なぜ awscli の `--query` オプションにこだわるのか。まず、  **JSON 解析をわざわざ他のツールに依存したくないから** です。  
[jq](https://stedolan.github.io/jq/tutorial/) はイマイチだし、[JSON](https://en.wikipedia.org/wiki/JSON) なんだから JavaScript で書くのが一番自然な気はするとはいえ、Node.js で実際やってみるとこれはこれで面倒に感じてしまう。  

最初の `describe-organization` を JavaScript でやるとしたらこんなかんじでしょうか  

```
% aws organizations describe-organization | node -e "
  const data = [];
  process.stdin
    .on('readable', () => {
      let chunk;
      while ((chunk = process.stdin.read()) !== null) {
        data.push( chunk );
      }
    } )
    .on('end', () => {
      process.stdout.write( JSON.parse( data.join( '' ) ).Organization.MasterAccountEmail );
    } );
"
```

https://nodejs.org/api/process.html#process_process_stdin

[readline](https://nodejs.org/api/readline.html) だとこのような感じか

```
% aws organizations describe-organization | node -e "
  const data = [];
  require( 'readline' )
    .createInterface( { input: process.stdin } )
    .on( 'line', ( l ) => {
      data.push( l );
    } )
    .on( 'close', () => {
      process.stdout.write( JSON.parse( data.join( '' ) ).Organization.MasterAccountEmail );
    } );
"
```

やはり `--query` パラメタでやった方が楽な気がします。メリットは次のような感じでしょうか  

* 他ツール非依存
* パラメタを考案する必要はあるが、比較的低負担で見通しがよい
* `--output text` との組み合わせで以降の処理にもパイプで繋げやすい
* ※場合によっては `--filters` も有用

そもそもこういった出力制御というのは、本質的に頑張りたい処理ではないので、極力最小化させたいわけです  
最小化すれば、小さな処理を組み合わせた複雑なこともより書きやすくなります  

[organizations](https://docs.aws.amazon.com/cli/latest/reference/organizations/index.html) でも  

```
aws organizations list-accounts --query 'Accounts[].{Id:Id,Name:Name}' --output text | while read a; do printf "$a\n"; aws organizations list-tags-for-resource --resource-id "`echo $a | awk '{print $1}'`" --query 'Tags[].{Key:Key,Value:Value}' --output table; done
```

* ※全メンバーアカウントのタグを列挙
* ※マスターアカウントで動作します

工夫次第で様々に活用できますが、リージョンやアカウントを横断した組織統制系のオペレーションなども、わざわざブラウザに行くまでもなく、このようにささっと CLI でやりますと、楽しいですよ。