Amazon EventBridge Schedulerを簡単に有効化・無効化！（Automationのドキュメント付き）

# はじめに
　定期的な処理をAmazon EventBridge Ruleを使って実行していましたが、スケジューリング機能がAWS EventBridge Schedulerとして登場してきました。今後はどんどんAmazon EventBridge Schedulerを使っていくと思うので、こっちを使うように進めています。

# やりたいこと
　定期処理をAmazon EventBridge Schedulerとして定義し、コストを最小にするためにEC2が起動している間は定期処理を実行、停止している間は定期処理を停止したいです。定期処理＝Lambdaで一定間隔で同期処理を行う等。
　今回は人の手を介さず、自動でAmazon EventBridge Schedulerの有効化、無効化を行います。（EC2の状態に連動する部分は別途、記事を書こうかと思います。）

# AWSマネジメントコンソールでの有効化、無効化
　AWSマネジメントコンソールだとどんな感じになるでしょう・・・
## スケジュール有効化
　対象のスケジュールを選択し、右上の「有効化」をクリックすることで有効化されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129814/ed5efd27-fb24-41bf-e648-83001efb89d2.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129814/b851d981-5a00-aa2b-7c5a-28952404bbaf.png)

## スケジュール無効化
　有効化と同様に対象のスケジュールを選択し、右上の「無効化」をクリックすることで無効化されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129814/1d284a10-294c-c2cc-f03e-56d769939daf.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129814/6f6e2ee0-9a9f-4045-f809-ebd9a965c5a2.png)

すごく簡単にできますね。じゃあ、なんか簡単にできそうな気がしてきます。

# APIの確認
　APIを確認してみます。EventBridge　Ruleだと[EnableRule](https://bridocs.aws.amazon.com/ja_jp/eventbridge/latest/APIReference/API_EnableRule.html)、[DisableRule](https://docs.aws.amazon.com/ja_jp/eventbridge/latest/APIReference/API_DisableRule.html)のような有効化、無効化と簡単なAPIがあったので、同じ感じだろうと思っていました。が、甘かった。。。

↓↓ Amazon EventBridge Scheduler API

https://docs.aws.amazon.com/ja_jp/scheduler/latest/APIReference/Welcome.html

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129814/d2b145d6-9b77-e35f-4689-589eecd9b384.png)

Enable〜、Disable〜がない。。。（2023/2/14時点）
ではでは、次はUpdateですね。[UpdateSchedule](https://docs.aws.amazon.com/ja_jp/scheduler/latest/APIReference/API_UpdateSchedule.html)を見てみると、

>Updates the specified schedule. When you call UpdateSchedule, EventBridge Scheduler uses all values, including empty values, specified in the request and overrides the existing schedule. This is by design. This means that if you do not set an optional field in your request, that field will be set to its system-default value after the update.
>Before calling this operation, we recommend that you call the GetSchedule API operation and make a note of all optional parameters for your UpdateSchedule call.

だそうです。（英語を読めてる雰囲気出して翻訳つかってます。）
UpdateScheduleを呼び出すと、EventBridge スケジューラはリクエストで指定された空の値を含むすべての値を使用し、既存のスケジュールを上書きします。しかも、リクエストでオプションのフィールドを設定しない場合、そのフィールドは更新後にシステムのデフォルト値に設定されますよ、と。
さらに、このオペレーションを呼び出す前に、GetSchedule APIオペレーションを呼び出し、UpdateSchedule呼び出しのすべてのオプション パラメータを書き留めておくことをお勧めします、とのことです。

ということで、
GetSchedule　→ UpdateSchedule
が必要になるとのことです。EventBridge　Ruleのように簡単にできないぞ、そんなことはないでしょ、と疑いはじめてマネジメントコンソールを見てみます。

# AWSマネジメントコンソールの動作確認

　スケジュールの無効化ボタンをクリックした際のリクエストを確認してみます。

## 1つ目のリクエスト

　最初にGETのリクエストが飛んでいます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129814/b26c4808-2955-a412-1cf2-c44aa027448a.png)

レスポンスの内容は以下です。
※一部、マスキングしています。

```json
{
    "Arn": "arn:aws:scheduler:ap-northeast-1:XXXXXXXXXXXX:schedule/default/execute-sync",
    "CreationDate": 1.676300282709E9,
    "Description": "",
    "EndDate": null,
    "FlexibleTimeWindow": {
        "MaximumWindowInMinutes": null,
        "Mode": "OFF"
    },
    "GroupName": "default",
    "KmsKeyArn": null,
    "LastModificationDate": 1.676384549268E9,
    "Name": "execute-sync",
    "ScheduleExpression": "cron(*/5 * * * ? *)",
    "ScheduleExpressionTimezone": "Asia/Tokyo",
    "StartDate": null,
    "State": "ENABLED",
    "Target": {
        "Arn": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:data-sync",
        "DeadLetterConfig": null,
        "EcsParameters": null,
        "EventBridgeParameters": null,
        "Input": "{}",
        "KinesisParameters": null,
        "RetryPolicy": {
            "MaximumEventAgeInSeconds": 86400,
            "MaximumRetryAttempts": 3
        },
        "RoleArn": "arn:aws:iam::XXXXXXXXXXXX:role/service-role/Amazon_EventBridge_Scheduler_LAMBDA_XXXXXXXXXXXX",
        "SageMakerPipelineParameters": null,
        "SqsParameters": null
    }
}
```

## 2つ目のリクエスト

　次のリクエストを見てみます。PUTのリクエストが飛んでいます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129814/143beb4e-6b4a-6acc-9e7f-75151c04fac2.png)

ペイロードは以下です。
※一部、マスキングしています。

```json
{
  "GroupName": "default",
  "ScheduleExpression": "cron(*/5 * * * ? *)",
  "Target": {
    "Arn": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:data-sync",
    "RoleArn": "arn:aws:iam::XXXXXXXXXXXX:role/service-role/Amazon_EventBridge_Scheduler_LAMBDA_XXXXXXXXXXXX",
    "RetryPolicy": {
      "MaximumEventAgeInSeconds": 86400,
      "MaximumRetryAttempts": 3
    },
    "Input": "{}"
  },
  "State": "DISABLED",
  "FlexibleTimeWindow": { "Mode": "OFF" },
  "Description": "",
  "ScheduleExpressionTimezone": "Asia/Tokyo",
  "ClientToken": "b77b6823-472e-49b2-a605-8d50c81e36b9"
}
```

疑いながら見てみましたが、そんなことありました。
GetSchedule　→ UpdateSchedule
をやっていました。これをやるしかありません。

# AWS Systems Manager Automationを使う
　Lambdaで関数を作って、行うこともできますが、面倒なので作りたくありません。なるべくメンテしたくない。。。
というわけで、[AWS Systems Manager Automation](https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/systems-manager-automation.html)を使います。

## ドキュメント確認

　もしかして、Amazon EventBridge Schedulerのドキュメントが提供されているんじゃない？と思って見てみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129814/3c2a5396-7141-60f5-9134-0e033512648f.png)

残念。ありません。Ruleはありますね。
仕方ありません。ドキュメント作っちゃいます。

## Amazon EventBridge Scheduler有効化・無効化ドキュメント

　こんな感じです。使ってみてください。

```yaml:ChangeStateEventBridgeScheduler.yaml
description: |-
  Document name -  ChangeStateEventBridgeScheduler

  ## What does this document do?
  The ChangeStateEventBridgeScheduler Automation document state the scheduler in EventBridgeScheduler

  ## Input Parameters
  * SchedulerName: (Required) Name of the EventBridge scheduler.
  * State: (Required) ENABLED or DISABLED.
  * AutomationAssumeRole: (Optional) The Amazon Resource Name (ARN) of the role that allows SSM Automation to perform the actions on your behalf.

  ## Output parameters
  None
schemaVersion: '0.3'
assumeRole: '{{AutomationAssumeRole}}'
parameters:
  SchedulerName:
    type: String
    description: (Required) Name of the EventBridge scheduler
  State:
    type: String
    description: (Required) ENABLED or DISABLED
    allowedValues:
      - ENABLED
      - DISABLED
  AutomationAssumeRole:
    type: String
    description: (Optional) The Amazon Resource Name (ARN) of the role that allows SSM Automation to perform the actions on your behalf.
    default: ''
    allowedPattern: '^arn:aws(-cn|-us-gov)?:iam::\d{12}:role\/[\w+=,.@_\/-]+|^$'
mainSteps:
  - name: GetEventBridgeScheduler
    action: 'aws:executeAwsApi'
    inputs:
      Service: scheduler
      Api: get_schedule
      Name: '{{SchedulerName}}'
    outputs:
      - Name: Arn
        Selector: $.Arn
        Type: String
      - Name: Description
        Selector: $.Description
        Type: String
      - Name: FlexibleTimeWindow
        Selector: $.FlexibleTimeWindow
        Type: StringMap
      - Name: GroupName
        Selector: $.GroupName
        Type: String
      - Name: Name
        Selector: $.Name
        Type: String
      - Name: ScheduleExpression
        Selector: $.ScheduleExpression
        Type: String
      - Name: ScheduleExpressionTimezone
        Selector: $.ScheduleExpressionTimezone
        Type: String
      - Name: Target
        Selector: $.Target
        Type: StringMap
    description: Get a scheduler in EventBridge
  - name: ChangeStateEventBridgeScheduler
    action: 'aws:executeAwsApi'
    inputs:
      Service: scheduler
      Api: update_schedule
      Description: '{{ GetEventBridgeScheduler.Description }}'
      FlexibleTimeWindow: '{{ GetEventBridgeScheduler.FlexibleTimeWindow }}'
      GroupName: '{{ GetEventBridgeScheduler.GroupName }}'
      Name: '{{ GetEventBridgeScheduler.Name }}'
      ScheduleExpression: '{{ GetEventBridgeScheduler.ScheduleExpression }}'
      ScheduleExpressionTimezone: '{{ GetEventBridgeScheduler.ScheduleExpressionTimezone }}'
      State: '{{State}}'
      Target: '{{ GetEventBridgeScheduler.Target }}'
    description: Change a scheduler in EventBridge

```

## ドキュメントの動作確認

### ドキュメントの作成

AWS Systems Manager Automationのページで「ドキュメントの作成」をクリックします。
　
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129814/144691be-9714-5be1-81f2-37a38b1b8c10.png)

　次にドキュメントの名前を入力します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129814/532059c6-6537-0c18-3f79-d2e0d36f1b05.png)

　「エディタ」タブを選択し、「編集」をクリックします。その後、ドキュメント内容を貼り付けます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129814/f1abe188-bdaa-3a9d-f709-e0a7a399999c.png)

　最後に「オートメーションを作成する」をクリックし、作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129814/32c06718-991f-4ce6-caaf-f4716013595a.png)

　以上、作成完了です。

### 実行してみる（有効化してみる）
　
　AWS Systems Manager Automationのページで先程作成したドキュメントを選択し、「オートメーションを実行する」をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129814/8be48c97-bb90-6310-8163-84ff9fe5a12f.png)

　入力パラメータのSchedulerName、Stateを設定し、実行します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129814/cb4c46bb-6463-ec4b-adf0-e6c6e7094a31.png)

＜実行前（スケジュールの状態）＞
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129814/39d76bd4-04d9-3e29-f021-93f44307814b.png)

＜実行後（オートメーションの結果）＞
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129814/f9d07f39-f589-c7d7-7e38-8a9953af91c6.png)

＜実行後（スケジュールの状態）＞
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129814/a5dc03da-d87e-8e06-ecfe-eb02020e732e.png)

無事、有効化することができました。


# まとめ
　AWS Systems Manager Automationを使うことで人の手を介さず、Amazon EventBridge Schedulerの有効化、無効化することをできることがわかりました。単純に考えるとLambdaを作ったりしないといけませんが、Automationで対応することができました。まだ、ドキュメントが提供されていませんが、載せてあるサンプルを使うことで実現できますので、使ってみてください。


# おまけ
## ドキュメント作成でひっかかった部分
　「ステップ1で取得したデータをステップ2でどうやって使えるの？」とパッとやり方がわかりませんでした。各ステップで取得したデータの受け渡しは以下に記載があります。ここを参考に作成しました。

https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/automation-action-outputs-inputs.html