AWS Support との思い出をいつまでもとっておけるようにしました。

## AWS Support みなさん使っていますか？
わたしの好きなサービスのひとつが AWS Support なのは皆さんご存知だとは思います。
試験に出ますよ。

さて。
この AWS Support を使って問い合わせたもの(起票したもの)は、起票後12か月間は使えるとのこと。
https://aws.amazon.com/jp/premiumsupport/faqs/
>**Q: ケース履歴の保存期間はどれほどですか?**
>
>サポートケースの履歴は、作成後12ヵ月間ご利用いただけます。

ということは、起票から12か月経過すると、 AWS Support との思い出がなくなってしまう！？
軽微な質問や超重要な障害への問い合わせも全部なくなってしまうの！？

それは、なんだか嫌だな、って。
と、弊社の複数のつよつよエンジニアーズから同じタイミングで話をもらったので、
ものは試しと、AWS Support との思い出を取っておけるようにしてみました。

## レシピ
### 登場人物
- AWS Support
 - ~~AWS Support との思い出~~ サポートケース
- AWS Lambda
 - Python 3.x で Lambda 関数を作ります
 - IAM Roleは適宜つけてくださいね。
 - Amazon CloudWatch Logs の書き込み系と Amazon DynamoDB の読み書き系を付与しています。
- Amazon DynamoDB
 - 思い出を取っておく場所(SupportCasesテーブル)
 - 育んでいる最中の思い出を取っておく場所(notResolvedCasesテーブル)

###  構成図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548623/bc250729-fe60-d7d7-77d7-54b117f56792.png)
※ AWS Support のシンプルアイコンが見当たらなかったのでForumsアイコンで代用しています。

### Amazon CloudWatch Events
今回は10日に1度取り込むので以下のような設定にしました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548623/01a9d739-7b8a-3d5d-26c7-20d4dedd6599.png)

後述の Lambda 関数を作ってから設定してくださいね。

完成した Amazon CloudWatch Events はこんな感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548623/2b2bdfcc-1e86-ae8d-98ac-0657575bb069.png)


### Amazon DynamoDB のテーブル
#### SupportCasesテーブル(思い出を取っておく場所＝解決済状態のサポートケース)

| キー名       |     設定     |
|:------------|:-------------|
| case_id     | プライマリキー |
| timeCreated | ソートキー    |


#### notResolvedCasesテーブル(育んでいる最中の思い出を取っておく場所＝未解決状態のサポートケース)

| キー名       |     設定     |
|:------------|:-------------|
| case_id     | プライマリキー |
| timeCreated | ソートキー    |

### AWS Lambda の Lambda関数
エラーハンドリングはやっていないので、あくまでご参考・・・

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

dynamodb = boto3.resource('dynamodb')
s_table = dynamodb.Table('SupportCases')
n_table = dynamodb.Table('notResolvedCases')

# AWS Support の エンドポイントは米国東部(us-east-1)
support = boto3.client('support', 'us-east-1')

# 10日に1度動くために実行時点から10日前の0時0分とする。
now = datetime.datetime.now()
lastUpdate = '{0:%Y}-{0:%m}-{0:%d}T00:00:00.000Z'.format(now - datetime.timedelta(days=10))

def lambda_handler(event, context):
    # 前回見た際に、resolved になっていないものがあったかを確認
    notResolvedIds = getNotResolvedIds()
    
    # resolved になっていなかったものがあれば更新する
    if len(notResolvedIds) >= 1:
        upDateNotReslvedIds(notResolvedIds)
        
    # 前回取得から今回までの間の追加・更新分を取得
    supportCases = describeSupportCases()
    
    # あれば更新する
    if len(supportCases) >= 1:
        addSupportCases(supportCases)
        
    return

def getNotResolvedIds():
    # notResolvedCases テーブルから resolved になっていない
    # サポートケースの caseId を取得する
    case_ids=[]
    response = n_table.scan()
    for i in response['Items']:
        case_ids.append(i['case_id'])
    
    return case_ids

def upDateNotReslvedIds(notResolvedIds):
    # case_idを指定して resolved にいなかったサポートケースを取得する
    
    response=support.describe_cases(
        caseIdList=notResolvedIds,
        includeResolvedCases=True,
        language='ja'
    )

    for i in response['cases']:
        # resolved になっていなかったサポートケースの情報を更新する
        response = s_table.put_item(
            Item={
                'case_id': i['caseId'],
                'display_id': i['displayId'],
                'subject': i['subject'],
                'serviceCode': i['serviceCode'],
                'categoryCode': i['categoryCode'],
                'severityCode': i['severityCode'],
                'timeCreated': i['timeCreated'],
                'status': i['status'],
                'communications': i['recentCommunications']['communications']
            }
        )

        # 更新時に resolvedになっていたら、notResolvedCasesテーブルから情報を消す
        if i['status'] == "resolved":
            response = n_table.delete_item(
                Key={
                    'case_id': i['caseId'],
                    'timeCreated': i['timeCreated']
                }
            )

def describeSupportCases():
    # 指定日(例：10日前)から実行時点までのサポートケースを取得する
    response = support.describe_cases(
        afterTime=lastUpdate,
        includeResolvedCases=True,
        language='ja'
    )
    
    return response

def addSupportCases(supportCases):
    # 取得したサポートケースを SupportCases テーブルに格納する
    for i in supportCases['cases']:
        response = s_table.put_item(
            Item={
                'case_id': i['caseId'],
                'display_id': i['displayId'],
                'subject': i['subject'],
                'serviceCode': i['serviceCode'],
                'categoryCode': i['categoryCode'],
                'severityCode': i['severityCode'],
                'timeCreated': i['timeCreated'],
                'status': i['status'],
                'communications': i['recentCommunications']['communications']

            }
        )
        # status が resolved 以外だったら notResolvedCases テーブルに記録する
        if i['status'] != "resolved":
            response = n_table.put_item(
            Item={
                'case_id': i['caseId'],
                'timeCreated': i['timeCreated'],
                'status': i['status'],
            }
        )
```

### これが動くとどうなるのか
かんたんにまとめると以下の通り。。

1. Amazon CloudWatch Events が発火する
2. AWS Lambda が動き出し、Lambda 関数を実行
 3. notResolvedCases テーブルに情報があるか確認
 4. ある場合は、そのサポートケースのIDをもとに情報を取得
 5. 取得した情報を SupportCases テーブルへ更新
 6. そのサポートケースのステータスが resolved(解決済み)になっていたら notResolvedCases テーブルから削除
 7. 実行時の10日前から実行時までの期間を指定して、 AWS Support からサポートケースの情報を取得する。
 8. 取得したサポートケースの情報を SupportCases テーブルに格納する
 9. その際、サポートケースのステータスが resolved(解決済み)になって**いない**場合には、notResolvedCases テーブルに情報を書き込む

おしまい。


## まとめ
12か月程度しか記憶しておけない AWS Support との思い出をこのように保存しておくことで、
今後は、以下の例のような表示方法でいつまでも楽しむことができます。

- Amazon QuickSight
- Amazon CloudSearch
- Amazon API Gateway + AWS Lambda + Amazon S3 によるWebUIでの表示