#概要
AWSの学習の中で,CloudFormationを使ってみたくなったので使ってみました。
目標:
Lambda関数をスケジュール起動させて,LINEで通知を送るサーバーレスのBOTをCloudFormationでデプロイします。
今回は1分おきに「slimeはkawaii。」「dragonはkakkoii。」「ghostはkowai。」のメッセージいずれかをランダムでLINEにpush通知するアプリケーションを作ります。
※通知する内容はDynamoDBから取得します。
下のようなネットワーク図になります。
図中のAWSサービスをCloudFormationテンプレートにまとめます。
#CloudFormationのテンプレート
CloudFormationのテンプレートです。
リソースはAWS Lambda,Amazon DynamoDB,Amazon CloudWatchです。
また今回はテンプレートの中でLambdaとCloudWatchそれぞれのIAMロールも作るようにしました。
AWSTemplateFormatVersion: 2010-09-09
Description: Line_Push_bot
Parameters:
pushFunctionName:
Type: String
Default: PushFunction
Description: pushFunction
dynamoDBTableName:
Type: String
Default: sampleContents
pushFuncStoredS3BucketName:
Type: String
Description: "pushFunction Stored S3 Bucket"
S3KeyName:
Type: String
Default: "lambda_function.zip"
pushFuncHandlerName:
Type: String
Default: lambda_function.lambda_handler
pushFuncIAMPolicyName:
Type: String
Default: PushFuncIAM
lineUserID:
Type: String
lineChannelAccessToken:
Type: String
Resources:
pushFunc:
Type: 'AWS::Lambda::Function'
Properties:
FunctionName: !Ref 'pushFunctionName'
Code:
S3Bucket: !Ref 'pushFuncStoredS3BucketName'
S3Key: !Ref 'S3KeyName'
Description: "push lambda template"
Handler: !Ref 'pushFuncHandlerName'
Role: !GetAtt
- LambdaExecutionRole
- Arn
Runtime: python3.6
Environment:
Variables:
'uid': !Ref 'lineUserID'
'LINE_CHANNEL_ACCESS_TOKEN': !Ref 'lineChannelAccessToken'
LambdaExecutionRole:
Type: 'AWS::IAM::Role'
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- 'sts:AssumeRole'
Policies:
- PolicyName: !Ref 'pushFuncIAMPolicyName'
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- 'dynamodb:GetItem'
Resource: !Sub 'arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${dynamoDBTableName}'
- Effect: Allow
Action:
- 'logs:CreateLogStream'
- 'logs:PutLogEvents'
- 'logs:CreateLogGroup'
Resource: '*'
PushLambdaScheduleEvent:
Type: AWS::Events::Rule
Properties:
Description: 'schedule event for pushFunction'
ScheduleExpression: 'rate(1 minute)'
State: ENABLED
Targets:
- Arn: !GetAtt pushFunc.Arn
Id: TargetFunctionV1
PushLambdaInvokePermission:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:InvokeFunction
FunctionName: !Ref pushFunctionName
Principal: events.amazonaws.com
SourceArn: !GetAtt PushLambdaScheduleEvent.Arn
sampleTable:
Type: 'AWS::DynamoDB::Table'
Properties:
TableName: !Ref dynamoDBTableName
AttributeDefinitions:
- AttributeName: type
AttributeType: S
KeySchema:
- AttributeName: type
KeyType: HASH
ProvisionedThroughput:
ReadCapacityUnits: 5
WriteCapacityUnits: 5
Lambdaのコードは下のようになります。
import urllib.request, urllib.parse
import boto3
import json
import os
import random
dynamodb = boto3.resource("dynamodb")
table = dynamodb.Table('sampleContents')
def lambda_handler(event, context):
types = ["dragon", "slime", "ghost"]
type = random.choice(types)
try:
response = table.get_item(
Key = {
'type': type
}
)
msg = response['Item']['characteristic']
except:
msg = "まだいません"
pushmsg = "{0}は{1}。".format(type, msg)
url = 'https://api.line.me/v2/bot/message/push'
body = {
"to": os.environ['uid'],
"messages": [
{
"type": "text",
"text": pushmsg
}
]
}
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + os.environ['LINE_CHANNEL_ACCESS_TOKEN']
}
req = urllib.request.Request(url, data=json.dumps(body).encode('utf-8'), method='POST', headers=headers)
with urllib.request.urlopen(req) as res:
pass
return {'statusCode': 200, 'body': '{}'}
#手順
上に記述したコードを使ってデプロイする手順を追って説明します。
-
LINE MessagingAPIを利用できるようにします。
未登録の場合はLINE Developersに登録しましょう。
以下記載のURLにしたがって,プロバイダーとチャネルを作成します。
プロバイダーのプランはフリーではなくDveloper Trialです(Push Messageを利用するため)。
↓詳しくはLINE Developersのドキュメントを参照してください。↓
[Messaging APIを利用するには]https://developers.line.biz/ja/docs/messaging-api/getting-started/
このとき,アクセストークン(ロングターム)とYour user IDを控えておきます。 -
1で作成したチャネルの基本設定の中にあるQRコードを読み取り,お友達追加をしてください。
-
lambda_function.py
をlambda_function.zip
という名前でzip圧縮し,S3バケットにアップロードします。
この時のS3バケット名を控えておきます。
S3バケットを作成するリージョンとCloudFormationでスタックを作成するリージョンは一致させてください。
例えばap-northeast-1にスタックを作成する場合は,ap-northeast-1にS3バケットを作成してください。 -
CFnTemplate.yaml
を基にしてスタックを作成します。
下図を参考にしてアクセストークン(ロングターム),Your user ID,S3バケット名を各パラメーターの値へ入れていきます。
手順通りに進めた場合,デフォルトで入力されている項目は特に変更する必要はありません。
※スタックの作成完了後は1分おきにLINEが届きますのでご注意ください。
#動作確認
-
LINEを確認します。
「・・・はまだいません。」とメッセージが届くはずです。
・・・の部分は slime, dragon, ghostのいずれかです。
例えば「slimeはkawaii。」のような「・・・は***。」というメッセージがpush通知されることが今回の目標ですが,まだDynamoDBのテーブルに該当の要素がないため,pushFuncがこのようなメッセージを生成して通知しています。 -
DynamoDBへ要素を追加します。
「・・・は***。」という形のメッセージをLINEにpush通知するために,DynamoDBのテーブルへ要素を追加します。
sampleContentsという名前のテーブルができているので,以下のようにします。
type | characteristic |
---|---|
slime | kawaii |
dragon | kakkoii |
ghost | kowai |
上のように要素をDBに追加することで,LINEに「・・・は***。」とpushされます。
・・・はtype,***はcharacteristicが対応します。
#削除方法
-
CloudFormationのスタックを削除します。
-
次に
lambda_function.py
がアップロードされているS3バケットを削除します。 -
最後にLINE Developersにログインし,チャネル,プロバイダーの順に削除します。