【aws-cli】EC2インスタンスを起動停止時刻でフィルタする

`aws-cli`では`ec2 describe-instances`を利用してEC2インスタンスの一覧を取得できます。
ここではインスタンス一覧取得時にインスタンスの起動時刻・停止時刻でフィルタするサンプルとなります。

先に結果を書いてしましますが、インスタンスの開始時刻についてはフィルタするのに問題はないのですが。

停止時刻の方についてはマネージメントコンソールやCLIでAPIを利用してシャットダウンした場合は停止時刻を後から確認できますが、OSからシャットダウンをすると現状、`ec2 describe-instances`で停止時刻を取得する方法はなさそう？

## 利用するaws-cliのバージョン

今回利用しているaws-cliのバージョンについては下記となります

- aws-cli/2.2.22 Python/3.8.8 Windows/10 exe/AMD64 prompt/off

## ec2 describe-instancesのドキュメント

[describe-instances](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/describe-instances.html)

## 起動時刻でフィルタする


[describe-instances](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/describe-instances.html)ドキュメントを確認すると、EC2インスタンスの起動時刻は`LaunchTime`を参照すればよさそうな事がわかります。

また`filters`オプションで`launch-time`フィルタ項目としても提供されている事もわかります。

### filtersオプションでフィルタする

まずは`filters`オプションで提供されている`launch-time`を利用してフィルタしてみます。

`LaunchTime`項目は`yyyy-MM-ddThh:mm:ss+0000`の形式となっている。

現在、起動しているインスタンスで、起動時刻が`2021年1月`となっているインスタンスを取得する場合は下記の用に記載する
※あくまで`2021年1月`に起動なので、`2021年1月以降`ではない点に注意

```PowerShell
# 現在起動していて2021年1月に起動したインスタンスを取得
aws ec2 describe-instances --filters "Name=instance-state-name,Values=running" "Name=launch-time,Values=2021-01*"
```

filtersオプションはワイルドカードが利用できますが、これだけだと`◯月☓日以降`といった細かい条件を指定しての抽出できません。

### queryオプションでフィルタする

もうすこし細かくフィルタしたい場合は、`query`オプションを利用してフィルタします。
下記のようにすると、`2021年1月1日以降`に起動して、現在も起動しているインスタンスの一覧を抽出できます。

```PowerShell
# 2021年1月1日以降に起動して現在も起動しているインスタンスを取得
# queryオプション Instances[?LaunchTime>=`2021-01-01`][] 
# queryオプションで出力する項目をtag-Name,InstanceId,LaunchTime,Stateを指定
aws ec2 describe-instances --filters "Name=instance-state-name,Values=running" --query 'Reservations[].Instances[?LaunchTime>=`2021-01-01`][].{Name:Tags[?Key==`Name`]|[0].Value,InstanceId:InstanceId,LaunchTime:LaunchTime,State:State.Name}'
```

## 停止時刻でフィルタする

[describe-instances](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/describe-instances.html)

`aws-cli`のドキュメントを確認した所、インスタンスを停止した時刻を直接持つ項目はなさそうです。

色々と項目を確認してみると、`StateTransitionReason`にAPIからインスタンスを停止した場合に下記形式で停止時間が表示されるようなので、今回はこれを利用してフィルタしてみます。

`User initiated (yyyy-MM-dd hh:mm:ss GMT)`

※注意点

`StateTransitionReason`項目とは別に`StateReason`という項目が存在し。
これはAPIドキュメントの`StateReason`の値が入っていそうです。

[StateReason](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/APIReference/API_StateReason.html)

APIドキュメントを確認すると

- APIを利用してシャットダウンをした場合は `Client.UserInitiatedShutdown` 
- OSから`shutdown -h`でシャットダウンした場合は　`Client.InstanceInitiatedShutdown`

とシャットダウンの方法によりコードが分けられています。

これはちょっと`StateReason`によって、`StateTransitionReason`の出力形式も別になってきそう？　な気配がするので確認してみます。

`2021年7月現在`実際に試してみると下記のようになります。（`マネージメントコンソール`でも`aws-cli`でも同様でした）

- `Client.UserInitiatedShutdown(APIでシャットダウン)`では`StateTransitionReason`に時刻が表示される。
- `Client.InstanceInitiatedShutdown（OSからシャットダウン）`では`StateTransitionReason`に時刻が表示されない。

![Client.UserInitiatedShutdown](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/597b1f77-d12e-c423-93d5-a401eddffb4b.png)

![Client.InstanceInitiatedShutdown](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/d784397d-3a89-2393-0951-4456522d4315.png)

ここでは試していませんがスポットインスタンスで入札価格をスポット価格が上回って停止した場合はまた別のメッセージが表示されそうですし、AWS基盤障害等で停止した場合は更に別のメッセージが入りそうな気はします。

ですので今回紹介する方法で停止時刻をフィルタできるのは、あくまで、**APIでインスタンスを停止したインスタンスのみ**となりそうです。

この点、注意が必要となります。

```PowerShell
# 2021年1月1日以前に停止して現在も停止しちえるインスタンスを取得（APIを利用して停止したインスタンスのみ）
aws ec2 describe-instances --filters "Name=instance-state-name,Values=stopped" --query 'Reservations[].Instances[?StateTransitionReason<=`User initiated (2021-01-01 00:00:00 GMT)`][].{InstanceId:InstanceId,LaunchTime:LaunchTime,StateTransitionReason:StateTransitionReason,Name:Tags[?Key==`Name`].Value|[0],State:State.Name,Message:StateReason.Message}'
```

## 総評

起動開始時刻は項目として用意されているので容易に取得することができます。

停止時刻はAWS側で項目として用意されていないようなので、複数項目を組み合わせて抽出できるかとも思いましたが。

APIを利用せずにOSからシャットダウンしたケース等では`ec2 describe-instances`では停止時刻を参照できる項目はなさそうに思います。