Amazon Connect ユーザーのステータスを決められた時間に一括でオフラインにする

Amazon Connect ユーザーの管理をされている方、一度は思ったことあるはずです。「オフラインにするの忘れる人多すぎ…」と。
今回はそんな方のために、決まった時間（終業時間など）になったらエージェントのステータスをオフラインにします。

## 最初にまとめ
- [PutUserStatus API](https://docs.aws.amazon.com/ja_jp/connect/latest/APIReference/API_PutUserStatus.html)を使います
- Linux のCronやEventBridge などを使って決まった時間にこのAPIで「Offline」というステータスをPutしてあげます
- 様々やり方がありますが[AWS CLI](https://docs.aws.amazon.com/goto/aws-cli/connect-2017-08-08/PutUserStatus) で行う方法と[AWS SDK Python(boto3)](https://docs.aws.amazon.com/goto/boto3/connect-2017-08-08/PutUserStatus)で行う方法を紹介します

## （没案）EventBridge Scheduler でPutUserStatus API を直接叩く
EventBridge のスケジューラという機能を使うと、Cron/Rate形式でAWS API を叩く指定が出来ます。
Amazon EventBridge のスケジュール から「スケジュールを作成」で新しいジョブを作成します。![スクリーンショット 2023-07-04 202916.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3484427/fad2a2f0-32fe-7761-f861-2648fc1c6bff.png)

cron形式で毎日18時にAPI を叩く場合はこんな感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3484427/71e08f71-2a21-8d6b-0932-d5e4a256453e.png)

すべてのAPI からAmazon Connect を選択。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3484427/2ca4529d-c837-d3a3-9aeb-50864348f598.png)

PutUserStatusを選択して、パラメーターをJson形式で指定します。

```json:parameter
{
  "AgentStatusId": "[OfflineのステータスID]", ### list-agent-statuses CLI で事前に取得
  "InstanceId": "[connectインスタンスのARN]", ### Connectコンソールで確認
  "UserId": "[対象ユーザーのID]"              ### list-users CLI で事前に取得
}
```

![スクリーンショット 2023-07-04 203648.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3484427/d98d96d3-bbf2-57b9-d951-7cf4e015577f.png)

アクセス許可で指定するIAMロールは別途作成する必要があります。（自動では作成されない）
今回コールするAPIのアクセス権限を持った、Principal（信頼されたエンティティ）が`scheduler.amazonaws.com`のIAMロールを作成してください。
![スクリーンショット 2023-07-04 204639.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3484427/c00e2057-9751-e8de-db35-2b5142c60432.png)

最後の画面で「スケジュールを作成」すれば完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3484427/d56540a7-ae44-c978-0128-189e6064d4c8.png)

### なぜ没になったのか
シンプルに、Jsonパラメーターの`UserId`がStringである必要があり、List形式で複数指定することが出来ませんでした…
これではユーザーの人数分スケジュールを作成する必要があり、現実的ではなかった…
5人くらいなら、ありかも。

## EC2 にスクリプトを置いてcrondで叩く
AWS CLI を使ってお一人お一人に対して丁寧にOfflineステータスを置いていくスタイルです。脳筋ですが一番シンプル。ただ超ナンセンスですのでお勧めはしません。
```bash:AgentOffline.sh
#!/bin/bash

aws connect put-user-status --instance-id arn:aws:connect:ap-northeast-1:766*********:instance/********* --user-id [対象ユーザーのID 1] --agent-status-id [OfflineのステータスID]

aws connect put-user-status --instance-id arn:aws:connect:ap-northeast-1:766*********:instance/********* --user-id [対象ユーザーのID 2] --agent-status-id [OfflineのステータスID]

aws connect put-user-status --instance-id arn:aws:connect:ap-northeast-1:766*********:instance/********* --user-id [対象ユーザーのID 3] --agent-status-id [OfflineのステータスID]

aws connect put-user-status --instance-id arn:aws:connect:ap-northeast-1:766*********:instance/********* --user-id [対象ユーザーのID 4] --agent-status-id [OfflineのステータスID]

・
・
・ 

```
余談ですがAmazon Linux 2023 にはcrontab がインストールされていないので自分で入れる必要があります。
https://jainsaket-1994.medium.com/installing-crontab-on-amazon-linux-2023-ec2-98cf2708b171

## AWS SDK Python(boto3)を使ってAPI を叩くLambdaをEventBridge Scheduler で実行
同じくPutUserStatus API をboto3で呼び出します。パラメーターなどはドキュメントを確認してください。
https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/connect/client/put_user_status.html

今回サンプルコードを用意しようと思ったのですが、Pythonの知識が赤ちゃんレベルの僕には難しかった…
ChatGPTさんに聞きながら色々試したのですがギブアップ。実際ちゃんと動作しない（OfflineステータスのユーザーにOfflineステータスをPutするな！と怒られてしまう）のですが一応貼っておきます。どなたかアドバイスをください…

本当は、①全てのユーザー状態を取得②そこからAvailableのユーザーをフィルタして③そいつらにOfflineステータスをPutする　をやりたかった…

:::note warn
以下のコードはChatGPTを使って生成したコードを元にしています。
:::

```python:lambda_function.py
import boto3
import json
import os

connect = boto3.client("connect")

def lambda_handler(event, context):
    instance_id = os.environ['INSTANCE_ID']
    agent_status_id = os.environ['OFFLINE_ID']
    agent_list = get_agent_list(instance_id)

    for agent in agent_list:
        set_agent_state_to_offline(instance_id, agent,agent_status_id)

    return {
        "statusCode": 200,
        "body": json.dumps(f"{len(agent_list)} agents set to offline")
    }

def get_agent_list(instance_id):
    response = connect.list_users(InstanceId=instance_id)
    return response["UserSummaryList"]

def set_agent_state_to_offline(instance_id, agent,agent_status_id):
    connect.put_user_status(
        InstanceId=instance_id,
        UserId=agent["Id"],
        AgentStatusId=agent_status_id
    )
```

あとはEventBridge Scheduler で 没案と同じようにLambda Invoke を設定すればOKです。
Lambda実行ロールにAmazon Connect 実行のためのIAMポリシー（Amazon Connect Full Accessなど）を付与するのを忘れないでください。