SAMを使用してCloudwatchアラームがアラーム状態になったらSlackに通知が行くようなシステムを構築する

本日はSAMを使い、Cloudwatchアラームが発生した場合Slackにメッセージが送信されるサーバレスアーキテクチャーを構築します。

AWS Serverless Application Model (AWS SAM) は、AWS でサーバーレスアプリケーションを構築するために使用できるオープンソースのフレームワークです。Lambdaだけでなく、SNS,S3、SES、Cloudwatchを使用したサーバレスなシステム構築を簡単に行うことができます。
SAMコマンドを使用し、Cloudformationのスタックのデプロイを行うことでシステムが簡単に構築されます。

環境についてはCloud9を使用してPythonで開発を行います。Cloud9を使用しない場合は、Python、SAMコマンドのインストールが必要です。Cloud9は必要なものが入っているので、私はこちらで開発を行っていきます。

<ol>
<li>Cloud9の環境作成</li>
<li>SAM initで構築を開始する</li>
<li>SARからコードを持ってくる</li>
<li>SAMコマンドでデプロイ</li>
<li>Cloudformation確認</li>
<li>作成されたシステムを確認・テスト</li>
</ol>

### はじめに

今回の開発作業ですが、SAR（レポジトリ）からpythonコードなどを持ってきたのですが、プログラムが古くテストの際にエラーが発生してしまいました。不完全な記事になってしまい申し訳ありません。
ですが、リソースの展開まではうまくいきましたので、SAMコマンドの使い方、SAMの仕組み、SAMを利用したCloudformationスタックの作成、リソースの展開までの流れは紹介できたと思います。

https://blog.denet.co.jp/amazon-cloudwatch-alerts-triggered-by-amazon-sns-from-aws-lamda-to-slack-2/

以上のことを踏まえたうえで記事を読んでいただければ幸いです。
本記事に関してですが、時間があればコードを書き直して、もう一度挑戦しようと思います。その際は記事を更新します。

### １．Cloud9の環境作成

Cloud9の環境は以下の流れで作成できます。

1.Cloud9のサービスコンソールへ移動
2.[Create environment]を選択
3.環境名、パラメータをを設定する
4.[create]をクリック

立ち上がるまで少し時間がかかります。立ち上がってきたら[Open in Cloud9]で開発環境に入りましょう。![スクリーンショット 2023-02-25 121322.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1260979/32ac60b2-5762-4192-e7b6-2854715d043f.png)



### ２．SAM initで構築を開始する

さっそく下記コマンドを打ってSAMを開始していきましょう。
「Choose an AWS Quick Start application template」の選択肢ですが後で編集するのでとりあえず「hello_world」を選択している。


```
ec2-user:~/environment $ sam init

        SAM CLI now collects telemetry to better understand customer needs.

        You can OPT OUT and disable telemetry collection by setting the
        environment variable SAM_CLI_TELEMETRY=0 in your shell.
        Thanks for your help!

        Learn More: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-telemetry.html


You can preselect a particular runtime or package type when using the `sam init` experience.
Call `sam init --help` to learn more.

Which template source would you like to use?
        1 - AWS Quick Start Templates
        2 - Custom Template Location

Choice: 1

Choose an AWS Quick Start application template
        1 - Hello World Example
        2 - Multi-step workflow
        3 - Serverless API
        4 - Scheduled task
        5 - Standalone function
        6 - Data processing
        7 - Infrastructure event management
        8 - Lambda EFS example
        9 - Machine Learning
Template: 1

Use the most popular runtime and package type? (Python and zip) [y/N]: y

Would you like to enable X-Ray tracing on the function(s) in your application?  [y/N]: y
X-Ray will incur an additional cost. View https://aws.amazon.com/xray/pricing/ for more details

Project name [sam-app]: Cloudwatch-alarm-slack

Cloning from https://github.com/aws/aws-sam-cli-app-templates (process may take a moment)

    -----------------------
    Generating application:
    -----------------------
    Name: s3-trigger-sns
    Runtime: python3.9
    Architectures: x86_64
    Dependency Manager: pip
    Application Template: hello-world
    Output Directory: .
    
    Next steps can be found in the README file at ./s3-trigger-sns/README.md
        

    Commands you can use next
    =========================
    [*] Create pipeline: cd s3-trigger-sns && sam pipeline init --bootstrap
    [*] Validate SAM template: sam validate
    [*] Test Function in the Cloud: sam sync --stack-name {stack-name} --watch
    

SAM CLI update available (1.74.0); (1.57.0 installed)
To download: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html

ec2-user:~/environment $ 

```

完了すると下記のようにフォルダが作成されます。
これで準備は完了です。

![スクリーンショット 2023-02-25 122159.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1260979/5a6e03e0-5842-e756-327e-b76579e54d32.png)

events・・・テストの際に使うイベント
hello_world・・・Lambdaのコード（Choose an AWS Quick Start application templateでhello_worldを選択したのでこの名前になっている）
test・・・テストで使用するもの一式が入っている
template.yaml・・・SAMテンプレートファイル


今回はhello_worldの関数とSAMテンプレートを今回の目的のものに変更してCloudformationをデプロイします。
どのように変更するのかは次の章で記述していきます。


### ３．SARからコードを持ってくる

AWS Serverless Application Repository（SAR） は、サーバーレスアプリケーション用のマネージド型リポジトリです。
pythonコードやテンプレートファイルを入手できます。

![スクリーンショット 2023-02-25 124341.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1260979/83fc9ffa-ebf0-b050-1017-275f8138a144.png)

目的のものを検索していきます。

![スクリーンショット 2023-02-25 180140.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1260979/ed39431a-4049-5426-a031-e0750f938387.png)

「cloudwatch-alarm-to-slack-python3」を選択します。選択するとLambdaのページへ移動します。
下記のテンプレートにyamlファイル用のコードが記述されてあります。これをCloud9のtemplate.yamlへ記述します。

![スクリーンショット 2023-02-25 180407.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1260979/c767a211-3f35-0023-0879-3041ba73ebdc.png)

次はpythonのコードですが、上の画像の[ソースコードURL]からソースコードが格納されてあるgithubのページに移動できます。
下記の[Lambda_function.py]を選択して[Raw]をクリックしURLをコピーします。

![タイトルなし.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1260979/54278192-8ab4-824e-66f0-540949a1fac8.jpeg)

Rawをコピーしてwgetコマンドでファイルをプルしていきます。コマンドを実行するとファイルが作成されます。app.py(とりあえず作成したhello_world用のpythonファイル)はいらないので削除します。次はデプロイをしていくのですが、template.yamlのlambdaのHandlerが実行するファイルの関数を指していることを確認します。

```
Resources:
  cloudwatchalarmtoslackpython3:
    Type: AWS::Serverless::Function
    Properties:
      Handler: lambda_function.lambda_handler
      Runtime: python3.9
```




### ４．SAMコマンドでデプロイ

まずはビルドを行ってきます。

```
ec2-user:~/environment/s3-trigger-sns $ sam build --use-container
Starting Build inside a container
The resource AWS::Serverless::Function 'cloudwatchalarmtoslackpython3' has specified S3 location for CodeUri. It will not be built and SAM CLI does not support invoking it locally.

Build Succeeded

Built Artifacts  : .aws-sam/build
Built Template   : .aws-sam/build/template.yaml

Commands you can use next
=========================
[*] Validate SAM template: sam validate
[*] Invoke Function: sam local invoke
[*] Test Function in the Cloud: sam sync --stack-name {stack-name} --watch
[*] Deploy: sam deploy --guided
        
ec2-user:~/environment/s3-trigger-sns $ 
```

そしてデプロイを行っていきます。
SARからとってきた今回のtemplate.yamlのコードは下記のパラメータを入力する必要があり、
deployする前に事前に作成して準備をしておいてください。
・KeyIdParameter（KMSのKeyID）
・slackChannelParameter(Slackのチャンネルの名前)
・kmsEncryptedHookUrlParameter（HookUrl/すぐ作成できますがサイトから作成しておく必要があります。）


```
ec2-user:~/environment/Cloudwatch-alarm-slack $ sam deploy --guided --capabilities CAPABILITY_IAM CAPABILITY_AUTO_EXPAND

Configuring SAM deploy
======================

        Looking for config file [samconfig.toml] :  Found
        Reading default arguments  :  Success

        Setting default arguments for 'sam deploy'
        =========================================
        Stack Name []: dev-sam-cloudwatch-slack
        AWS Region [ap-northeast-1]: 
        Parameter KeyIdParameter []: 
        Parameter slackChannelParameter []: 
        Parameter kmsEncryptedHookUrlParameter []: 
        #Shows you resources changes to be deployed and require a 'Y' to initiate deploy
        Confirm changes before deploy [Y/n]: y
        #SAM needs permission to be able to create roles to connect to the resources in your template
        Allow SAM CLI IAM role creation [Y/n]: y
        #Preserves the state of previously provisioned resources when an operation fails
        Disable rollback [Y/n]: y
        Save arguments to configuration file [Y/n]: y
        SAM configuration file [samconfig.toml]: 
        SAM configuration environment [default]: 

        Looking for resources needed for deployment:
        Creating the required resources...
        Successfully created!
```


### 5．Cloudformation確認

CloudformationおよびLambda、SNSが展開されていることが確認できました。

![タイトルなし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1260979/7bcf8333-f7a8-4057-9623-ba4363fd11ef.png)


### ６．作成されたシステムを確認・テスト

それでは、Cloudwatchアラームが発生したらSlackに通知が届くのかテストを行っていきます。
今回は適当にCloud9のインスタンスのCPU使用率が80%を超えた場合にアラーム状態になるアラームを作成しました。アラームのSNS設定は今回作成したLambdaを呼び出すSNSトピックを設定します。

![スクリーンショット 2023-02-26 224033.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1260979/7ee6f05b-ac2f-5ecb-dff9-171358dd6a76.png)


下記コマンドを実行し、アラーム状態にします。
```
aws cloudwatch set-alarm-state --alarm-name "dev-sam-Cloud9instance-CPUUtilization > 80" --state-value ALARM --state-reason "alarmtest"
```

Slackに通知がいかず、Lambdaのログを確認したところ下記のエラーが発生しました。
解決方法を探しましたが見つからず以下のサイトによると今回使用したSARのプログラムが古かったため、うまくいかなかったようです。

https://blog.denet.co.jp/amazon-cloudwatch-alerts-triggered-by-amazon-sns-from-aws-lamda-to-slack-2/
```
[ERROR] InvalidCiphertextException: An error occurred (InvalidCiphertextException) when calling the Decrypt operation: 
Traceback (most recent call last):
  File "/var/lang/lib/python3.9/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1030, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1007, in _find_and_load
  File "<frozen importlib._bootstrap>", line 986, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 680, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 850, in exec_module
  File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
  File "/var/task/lambda_function.py", line 62, in <module>
    HOOK_URL = "https://" + boto3.client('kms').decrypt(CiphertextBlob=b64decode(ENCRYPTED_HOOK_URL))['Plaintext'].decode('utf-8')
  File "/var/runtime/botocore/client.py", line 391, in _api_call
    return self._make_api_call(operation_name, kwargs)
  File "/var/runtime/botocore/client.py", line 719, in _make_api_call
    raise error_class(parsed_response, operation_name)
```
解決策が見つからなかったため本記事は以上にしようと思います。
時間があればLambdaのコードとテンプレートファイルのコードを書き換えて、再度デプロイしようと思います。
最後はうまくいきませんでしたが、リソースの展開までうまくいきましたのでSAMを利用した開発の流れは紹介できたと思います。
本記事は以上になります。ありがとうございました。