毎日AWS利用料金をLineに送信する仕組みづくり
扱う技術:
--SAM
--Lambda
--LineAPI
--AWSCostExplo
なにをするのか
AWSの利用料金を毎朝8時にラインにて通知できるようにする。
(利用料金を毎日確認したいが毎日コンソールを開くわけではないので、利用料金を簡単に確認できるようにしたいというのが理由)
リポジトリ
全体構成
prerequizite
AWS CLI
AWS SAM
|-- have already installed
SAMで基本設定。
今回は ランタイムはpythonで、管理方法はzip形式とする。
sam init
Which template source would you like to use?
choice: 1 - AWS Quick Start Templates
Choose an AWS Quick Start application template
Template: 1 - Hello World Example
Which runtime would you like to use?
Runtime: 9 - python3.9
What package type would you like to use?
Package type: 1 - Zip
Project name [sam-app]:hoge
これで基本的な設定ファイルが生成される。このテンプレートをそのままデプロイするとApiGateWayをトリガーとするLambdaが一つ生成される。
これをいじって上の構成のSAMの枠内にあるeventCloudWatchをトリガーにしたLambdaにする。
使用するリソースについての設定はtemplate.yaml内に記述されている。
このtemplate.yamlファイルの記述方法について詳しくはこちらの記事を参考に。
template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
sam-app
Sample SAM Template for sam-app
Globals:
Function:
Timeout: 30
Parameters:
LineToken:
Type: String
Default: xxx
MyLineId:
Type: String
Default: xxx
Globals:
Function:
Handler: app.lambda_handler
Runtime: python3.9
Environment:
Variables:
TZ: Asia/Tokyo
REGION: ap-northeast-1
LINE_TOKEN: !Ref LineToken
MY_LINE_ID: !Ref MyLineId
Resources:
InitialResponseFunction:
Type: AWS::Serverless::Function
Properties:
Role: !GetAtt BillingNotiferIamRole.Arn
Timeout: 300
CodeUri: initial_handler/
Events:
CronAt8oclock:
Type: Schedule
Properties:
Schedule: 'cron(0 12 * * ? *)'
Name: InformBillingTrigger
Description: test schedule
Enabled: false
BillingNotiferIamRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: "sts:AssumeRole"
Policies:
-
PolicyName: "billig_notifer_lambda"
PolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: "Allow"
Action: "logs:*"
Resource: "*"
こんな感じで設定する。
ここで気をつけるのは環境変数のxxxの部分は自分で埋めること。
あとはそのまま使えば大丈夫である
基本は下のgithubレポジトリを見て貰えばいいが、
実際のコード
少し解説すると
この関数で、Cost Exprorerにアクセスしてデータを取ってきていて。
TimePeriodでいつからいつまでのコストをとってくるのかを定義する。
今回はその月はじめ1日からその日までのコストを取得したいから
その日の月+01日を開始日、関数実行時の日終了日に設定している。
Granularityではどの幅でデータを取得するかを定義していて、今回はMontlyにしているのでその月毎にデータをフェッチできる。ここをDailyにすると開始日から終了日までのコストが1日ごとに取得できる。詳しくはこのドキュメント参照
def get_montlycost(head_of_month, today):
billing_client = boto3.client('ce')
response = billing_client.get_cost_and_usage(
TimePeriod={
'Start': head_of_month,
'End': today },
Granularity='MONTHLY',
Metrics=[ 'UnblendedCost',],
GroupBy= [
{ 'Type':'DIMENSION', 'Key':'SERVICE' }
],
)
cost_with_services = response["ResultsByTime"][0]["Groups"]
return cost_with_services
いい感じにその日までのコストと、サービスが取得できたので、それをLine APIを使用して送っていく。
Line APIを使用したデータの送信
今回使用するのはユーザーにデータを送るだけの処理なのでMessageing APIを使用する。
こんな感じのBotが作れたら下にスクロールしてトークンを控えておく。
またBasicSettingにあるYour user ID も控えておこう。これがLINE_TOKENとMY_LINE_IDになる。
LineAPIではBotを使用してメッセージをユーザーに送ることができて、送ることができるメッセージのタイプは
参考資料
テキストメッセージ
スタンプメッセージ
画像メッセージ
動画メッセージ
音声メッセージ
位置情報メッセージ
イメージマップメッセージ
テンプレートメッセージ
Flex Message
である。それで今回使うのはFlex messageのほう。テンプレートメッセージはユーザーとのインタラクションが生じるときに用いられる。
一方的に送る場合はFlex Messageの方を使う。
このシュミレータを使うことで色々テストできる。
flex messageを送るときには
typeをflexに
altTextに何か文字列を入れる必要があり、
contentsのなかにシミュレーターでつくったものをそのまま突っ込めばいい。
{
"type": "flex",
"altText": "alternative text",
"contents": {
"type": "carousel",
"contents": []
}
}
今回はコンポーネントがAWSのその月に使ったサービスによって変動するため、contentsの量が可変的なので、そのままシミュレータで作ったものを突っ込むのではなく、分解して
Blocks/frame.json
{
"type": "flex",
"altText": "alternative text",
"contents": {
"type": "carousel",
"contents": []
}
}
このcontents: []の中にBlock/component.json(幾つになるかわからない)をpushしていくようなコードを書いた。
Block/component.json
{
"type": "bubble",
"size": "nano",
"header": {
"type": "box",
"layout": "vertical",
"contents": [
{
"type": "text",
"text": "0.079 USD",
"color": "#ffffff",
"align": "start",
"size": "md",
"gravity": "center"
},
{
"type": "text",
"text": "20%",
"color": "#ffffff",
"align": "start",
"size": "xs",
"gravity": "center",
"margin": "lg"
},
{
"type": "box",
"layout": "vertical",
"contents": [
{
"type": "box",
"layout": "vertical",
"contents": [
{
"type": "filler"
}
],
"width": "20%",
"backgroundColor": "#0D8186",
"height": "6px"
}
],
"backgroundColor": "#9FD8E36E",
"height": "6px",
"margin": "sm"
}
],
"backgroundColor": "#27ACB2",
"paddingTop": "19px",
"paddingAll": "12px",
"paddingBottom": "16px"
},
"body": {
"type": "box",
"layout": "vertical",
"contents": [
{
"type": "box",
"layout": "horizontal",
"contents": [
{
"type": "text",
"text": "Amazon Relational Database Service",
"color": "#8C8C8C",
"size": "sm",
"wrap": true
}
],
"flex": 1
}
],
"spacing": "md",
"paddingAll": "12px"
},
"styles": {
"footer": {
"separator": false
}
}
}
この送る形ができたらhttps postリクエストにより、実際に送ってみる。
そうするとこんな感じのメッセージを受け取ることができた。
おしまい。
送信時にはこれを参照すると良い。
Discussion