SystemsManagerChangeCalendarでssmAutomationランブックの実行を制御する

# SystemsManagerChangeCalendarとは
SystemsManagerの機能の一つで、カレンダー内の特定の日付・時間に「イベント」を挿入することで、そのイベント間のアクションの実行を制御を行える機能です。

例えば、「毎日定時にSystems Manager Automation ランブックからEC2インスタンスを停止させているが、この日だけは停止させたくない」といった場合に、対象日にイベントを設定しておくことでインスタンスを停止させないということができます。

更にEventBridgeとも連携できるため、柔軟にイベントの管理が行えます。

以下公式ドキュメントです。
> AWS Systems Manager の一機能である Change Calendar では、指定したアクション (Systems Manager Automation ランブックなど) が AWS アカウント で実行できるまたはできない日付と時刻の範囲を設定できます。Change Calendar では、このような範囲はイベントと呼ばれます。Change Calendar エントリを作成すると、ChangeCalendar タイプの Systems Manager のドキュメントが作成されます。

https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/systems-manager-change-calendar.html

## 使ってみる
実際に使ってみます。
以下の構成のようなイメージで作成します。
![構成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675893/302fa935-b465-61e0-7f5f-9a7697685fdf.png)


### Systems Manager Automation ランブックの設定
まず、ChangeCalendarで実行管理するサンプルのメンテナンスウィンドウを作成します。
実行するタスクは「AWS-RestartEC2Instance」、実行時間は15分毎としています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675893/b550d8d9-77a7-af5a-d9a3-bca7150d004a.png)

しばらく放置して正しく実行されていることを確認します。
![image_04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675893/c46d4840-d7d8-c816-7077-ee125b5f4897.png)


### カレンダーの作成
次にカレンダーを作成します。

最近の発表でカレンダーをインポートして作成することができるというアップデートがありましたので、こちらを利用します。

https://aws.amazon.com/jp/about-aws/whats-new/2021/09/aws-systems-calender-third-party-imports/

適当なイベントをGoogleカレンダーに入れ、エクスポートします。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675893/7a16de6d-2db3-7afa-3d6d-1eea15551d0e.png" width=70%>


※後にインポートしてわかったのですが、**Googleカレンダーの設定が日本標準時だとうまくインポートできません。**なので、Googleカレンダーの設定を協定世界時に直してからエクスポートしてください。
↓日本標準時で15:30~16:30のイベントを入れたカレンダーをインポートすると以下のように表示されます。
![image_03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675893/95e74390-3a72-097f-7568-1d35eed995ff.png)



その後、マネージドコンソールのインポートから先ほどエクスポートした.ics形式のカレンダーをインポートします。
カレンダータイプはそれぞれ

- デフォルトで開く：イベントがある場合、タスクを実行しない。
- デフォルトで閉じる：イベントがある場合のみタスクを実行する。


となります。
![image_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675893/63cfbe9d-7236-3e2a-e4af-9b46eccc85a2.png)

作成すると以下のようにカレンダーが表示されます。
![image_05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675893/7064361f-b54d-618d-7afa-0e458aa01959.png)


### タスクにカレンダーの状態確認ステップを追加
タスクのステップにカレンダーの状態を確認するステップを挟みます。

「ドキュメント」から「AWS-RestartEC2Instance」を選択し、クローンの作成を押下します。
![image_07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675893/34911b57-6b2c-0139-f5a5-6000327358dc.png)

次にドキュメントエディタから以下のように編集し「オートメーションを作成する」を押します。
![image_08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675893/2e752df2-7b23-0c46-d250-8213b61e218a.png)



※AccountID,CalendarNameは置換して下さい。

<details><summary>Copy-AWS-RestartEC2Instance</summary><div>

```json:Copy-AWS-RestartEC2Instance
{
	"description": "Restart EC2 instances(s)",
	"schemaVersion": "0.3",
	"assumeRole": "{{ AutomationAssumeRole }}",
	"parameters": {
	  "InstanceId": {
	    "type": "StringList",
	    "description": "(Required) EC2 Instance(s) to restart"
	  },
	  "AutomationAssumeRole": {
	    "type": "String",
	    "description": "(Optional) The ARN of the role that allows Automation to perform the actions on your behalf.",
	    "default": ""
	  }
	},
	"mainSteps": [
	  {
	    "name": "checkChangeCalendarOpen",
	    "action": "aws:assertAwsResourceProperty",
	    "inputs": {
	      "Service": "ssm",
	      "Api": "GetCalendarState",
	      "CalendarNames": [
		"arn:aws:ssm:ap-northeast-1:<AccountID:document/<CalendarName>"
	      ],
	      "PropertySelector": "$.State",
	      "DesiredValues": [
		"OPEN"
	      ]
	    },
	    "nextStep": "stopInstances"
	  },
	  {
	    "name": "stopInstances",
	    "action": "aws:changeInstanceState",
	    "inputs": {
	      "InstanceIds": "{{ InstanceId }}",
	      "DesiredState": "stopped"
	    }
	  },
	  {
	    "name": "startInstances",
	    "action": "aws:changeInstanceState",
	    "inputs": {
	      "InstanceIds": "{{ InstanceId }}",
	      "DesiredState": "running"
	    }
	  }
	]
      }
```

</div></details>

参考：

https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/systems-manager-change-calendar-automations.html

作成が完了したら「メンテナンスウィンドウ」からドキュメント「AWS-RestartEC2Instance」を「Copy-AWS-RestartEC2Instance」に変更します。
![image_09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675893/4d15a767-3e0f-c1c3-3095-2bef7d1ddc1b.png)

### 実行確認
イベントが予定されている時間のみ、実行が行われていないか確認します。
対象時間の実行履歴を見てみると...
![image_10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675893/4878cb60-f7f5-2a69-b356-70972e3bba17.png)

ChangeCalendarから「OPEN」が返ってきていない為、失敗となっています！

イベントの時間が過ぎると、成功に戻りました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675893/86052775-69ae-56c6-7825-4a1479c887af.png)


# まとめ
ChangeCalendarでssmAutomationランブックの実行制御を行えることを確認しました。これにより、Cronなどで表現しきれない急なイベントが発生しても、カレンダーにイベントを入れるだけで実行の調整が行えます。
今回はCalendarからOPENが返ってこない場合はエラーという単純な制御でしたが、作りこみ次第でよりいい感じにできると思います。
機会があれば試してみたいです。