CloudWatchログアラームの作成が面倒なので、Excelから設定値を読み込んで作成できるようにしてみた。

# はじめに
こんにちは、山田です。
今回は、CloudWatchログアラームをExcelから作成する方法について記載していきます。
よろしくお願いします。
# 概要図
概要図は以下の通りです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1096361/54c80c37-30f4-620f-a821-a86a723978cb.png)
①：Lambdaを用いて、Excelファイルを作成してS3にアップロードします。
②：作成されたExcelファイルをダウンロードします。
③：ダウンロード後、Excelファイルを記入してアップロードします。
④：Lambdaを用いて、Excelファイルを読み込みCloudWatchアラームを作成します。
# エクセルファイル作成用Lmabdaのフローチャート・コード
エクセルファイル作成用Lmabdaのフローチャート・コードはそれぞれ以下になります。
## フローチャート
フローチャートは以下の通りです。
![フローチャート (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1096361/d2c68b3a-f916-b7b7-7589-cf227953d354.png)
## コード
実際のコードは以下の通りです。
```python
import openpyxl
import boto3
import os
from openpyxl import Workbook
from openpyxl.worksheet.datavalidation import DataValidation
from openpyxl.styles import PatternFill, Font, Border, Side

s3 = boto3.resource('s3')
s3_client = boto3.client('s3')
sns_client = boto3.client('sns')
cloudwatch_client = boto3.client('cloudwatch')
logs_client = boto3.client('logs')

os.chdir('/tmp')

book = openpyxl.Workbook()
book_x = book.active
book_x.title = 'ログアラーム'
book_y = book.create_sheet('メトリクスフィルター')

book_sheet = ["ログアラーム","メトリクスフィルター"]
for item in book_sheet:
    sheet = book[item]
    for row in range(1,100):
        for col in range(1,6):
            cell = sheet.cell(row = row, column = col)
            cell.font = openpyxl.styles.Font(name='MeiryoUI')
    
    fill = PatternFill(start_color="1F497D", end_color="1F497D", fill_type = "solid")
    font = Font(bold=True, color="FFFFFF")
    for col in range(1,6):
        cell = sheet.cell(row = 1, column = col)
        cell.fill = fill
        cell.font = font
        
    thin = Side(border_style="thin", color="000000")
    for row in range(1,100):
        for col in range(1,6):
            cell = sheet.cell(row = row, column = col)
            cell.border = Border(left=thin, right=thin, top=thin, bottom=thin)
    
    sheet.column_dimensions['I'].hidden = True


def create_logalarmsheet():

    sheet = book['ログアラーム']

    sheet['A1'] = 'No.'
    sheet['B1'] = 'AlarmName'
    sheet['C1'] = 'Description'
    sheet['D1'] = 'MetricsName'
    sheet['E1'] = 'SNS ARN'
    
    sns=[]

    response=sns_client.list_topics()
    count = 0
    for i in range(len(response['Topics'])):
        sns.append(response['Topics'][i]['TopicArn'])
        count+=1
    count = 0
    while 'nextToken' in response:
        response=sns_client.list_topics(nextToken=response['nextToken'])
        for i in range(len(response['Topics'])):
            sns.append(response['Topics'][i]['TopicArn'])
            count+=1

    for i in range(2,100):
        sheet.cell(row=i,column=4).value = '=メトリクスフィルター!E' + str(i)
    
    for i in range(1,100):
        sheet['D'+str(i)].number_format = '#'
    
    for i in range(len(sns)):
        sheet.cell(row=(i+1),column=9).value = sns[i]
        
    dv = DataValidation(type="list", formula1='I1:I'+str(len(sns)), allow_blank=True)
    dv.add(f"E2:E100")

    sheet.add_data_validation(dv)

def create_metricsfiltersheet():

    sheet = book['メトリクスフィルター']

    sheet['A1'] = 'No.'
    sheet['B1'] = 'LogGroupName'
    sheet['C1'] = 'FilterName'
    sheet['D1'] = 'FilterPattern'
    sheet['E1'] = 'MetricsName'

    loggroup = []

    response=logs_client.describe_log_groups()
    count = 0
    for i in range(len(response['logGroups'])):
        loggroup.append(response['logGroups'][i]['logGroupName'])
        count+=1
    count = 0
    while 'nextToken' in response:
        response=logs_client.describe_log_groups(nextToken=response['nextToken'])
        for i in range(len(response['logGroups'])):
            loggroup.append(response['logGroups'][i]['logGroupName'])
            count+=1
    
    for i in range(len(loggroup)):
        sheet.cell(row=(i+1),column=9).value = loggroup[i]
        
    dv = DataValidation(type="list", formula1='I1:I'+str(len(loggroup)), allow_blank=True)
    dv.add(f"B2:B100")
    
    sheet.add_data_validation(dv)

def lambda_handler(event, context):
    create_logalarmsheet()
    create_metricsfiltersheet()
    book.save('エクセル名.xlsx')
    s3_client.upload_file('エクセル名.xlsx','エクセルファイルをアプロードするS3バケット名', 'エクセル名.xlsx')
```
## Excelファイル
実際に生成されるエクセルファイルの以下の通りです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1096361/4271cc34-56c0-b58e-f81e-fd1fe8a40883.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1096361/d4199592-d662-046b-3ae2-ebbebe476b01.png)
# CloudWAtchアラーム作成用Lmabdaのフローチャート・コード
CloudWAtchアラーム作成用Lmabdaのフローチャート・コードは以下の通りです。
## フローチャート
フローチャートは以下の通りです。
![フローチャート (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1096361/3805128b-ec40-7ce0-9c1e-261593705e5e.png)
## コード
実際のコードは以下の通りです。
```python
import openpyxl
import boto3
import os
import time
from io import BytesIO

s3 = boto3.resource('s3')
s3_client = boto3.client('s3')
sns_client = boto3.client('sns')
cloudwatch_client = boto3.client('cloudwatch')
logs_client = boto3.client('logs')

os.chdir('/tmp')

source_bucket_obj = s3.Bucket('S3バケット名')
source_bucket_obj.download_file('エクセル名.xlsx', 'エクセル名.xlsx')
book = openpyxl.load_workbook('エクセル名.xlsx')
def put_logevent():
    
    s3_resp = s3_client.get_object(Bucket='S3バケット名', Key='エクセル名.xlsx')
    wb = openpyxl.load_workbook(BytesIO(s3_resp['Body'].read()),data_only=True)
    sheet = wb["メトリクスフィルター"]
    
    B = []
    D = []
    
    eng=[B,D]
    
    B_column = len(list(sheet.columns)[2])
    for item in eng:
        count = (eng.index(item)+1)*2
        for i in range(2,B_column+1):
            if sheet.cell(row=i, column=count).value is not None:
                item.append(sheet.cell(row=i, column=count).value)


    for i in range(len(B)):
        res = logs_client.describe_log_streams(
          logGroupName=B[i])
        seq_token=res['logStreams'][0]['uploadSequenceToken']
        response = logs_client.put_log_events(
        logGroupName=B[i],
        logStreamName=res['logStreams'][0]['logStreamName'],
        logEvents=[
            {
            'timestamp': int(time.time()) * 1000,
            'message': D[i]
            },
        ],
        sequenceToken = seq_token
        )

def create_metricsfilter():
        
    sheet = book['メトリクスフィルター']

    B = []
    C = []
    D = []
    E = []
    
    eng=[B,C,D,E]

    B_column = len(list(sheet.columns)[1])
    print(B)
    for item in eng:
        count = eng.index(item)+2
        for i in range(2,B_column+1):
            if sheet.cell(row=i, column=count).value is not None:
                item.append(sheet.cell(row=i, column=count).value)
    
    for i in range(len(B)):
        logs_client.put_metric_filter(
        logGroupName=B[i],
        filterName=C[i],
        filterPattern=D[i],
        metricTransformations=[
            {
                'metricName': E[i],
                'metricNamespace': 'Logs',
                'metricValue': '1',
            },
        ]
        )

def create_logalarm():
    
    sheet = book['ログアラーム']
    sheet2 = book['メトリクスフィルター']
    
    for i in range(2,100):
        sheet['D'+str(i)] = sheet2['E'+str(i)].value
    
    B = []
    C = []
    D = []
    E = []
    
    eng=[B,C,D,E]

    B_column = len(list(sheet.columns)[1])
    for item in eng:
        count = eng.index(item)+2
        for i in range(2,B_column+1):
            if sheet.cell(row=i, column=count).value is not None:
                item.append(sheet.cell(row=i, column=count).value)

    for i in range(len(B)):
      response=cloudwatch_client.put_metric_alarm(
      AlarmName=B[i],
      AlarmDescription=C[i],
      ActionsEnabled=True,
      AlarmActions=[
        E[i],
      ],
      MetricName=D[i],
      Namespace='Logs',
      Statistic='Sum',
      Period=300,
      Unit='Seconds',
      Threshold=1,
      EvaluationPeriods=1,
      ComparisonOperator='GreaterThanOrEqualToThreshold'
      )

def lambda_handler(event, context):    
    create_metricsfilter()
    put_logevent()
    time.sleep(5)
    create_logalarm()
```
# 動作確認
前提条件は以下の通りです。

**・メトリクスが保存されている名前空間は「Logs」
・アラーム通知条件は、5分間の合計値が１以上になった場合**

エクセルファイル作成用Lmabdaを実行します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1096361/868180b1-6a0e-182e-4c27-c1093b5de2cb.png)
エクセルファイルをダウンロードします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1096361/5c22f6e3-7c5b-2b93-c3ef-a302dbc06794.png)
エクセルを記入します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1096361/df372a17-7180-cf05-4220-414bbd2053ae.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1096361/ed1a4b47-0b1e-d81d-05bd-47cd762d307f.png)
エクセルファイルを同じ名前でアップロードします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1096361/f843536e-1344-840c-d1c8-2e04f8a7052b.png)
CloudWAtchアラーム作成用Lmabdaを実行します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1096361/45f9ec35-a8c0-9d97-723c-ca93417d441f.png)
CloudWatchアラームが作成されていることが確認できれば完了。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1096361/5b8a41ff-95cd-e76c-f594-8d121a42a201.png)

# 終わりに
今回はログアラームをExcelより作成する方法について記載しました。
まだまだ改良点はあると思うので、これからも改善していきたいと思います。
また、その他のメトリクスに関してもExcelファイルから作成できるようにしていきたいと思います。
最後まで拝読いただきありがとうございます。