AWSで価格取得してLineBotに送る
やったこと
- AWSの価格を取得して、定期的にLineで配信する
- 言語はPython。
- 概要図は下記
- なお、本記事でぜんぶ網羅して説明できていなくて、上から順にやっても手順漏れまくりなことに注意。ポイントっぽい部分のメモでしかないです。
Lineに投稿される内容
背景
概要
- (1) LambdaでAWSの価格取得する関数を作成
- (2-1) LambdaのLayerでlinebot用のPythonライブラリのLayerを用意した
- Layerというのは、Lambda用のライブラリセット。Lambda本体に同梱しても良いはずだけど、Line送信するライブラリは将来作成した別のBotでも使いそうな気がしたので、Layer化してみた
- (2-2) LambdaからLineに対してメッセージ送信。
- 自分しか使っていないLineBotアカウントからブロードキャスト送信する形とした。(自分のLineのuseridがわかればToでできそうだったけど、自分のLineのuseridがわからなかった・・・。)
(3) これらをまとめるStepFunctionを作成
- このStepFunctionを定期実行するようにした
その他メモ
- 権限は結構ややこしかった。上手な設計や運用方法はまだつかめていない上にたぶん漏れがあるけど、記憶の範囲で記載する。
- Lambdaなどは、設定したIAMロールで動くことになる。このIAMロールにはLambdaを実行するための権限であったり、ログ出力(CloudWatch Logs)に書き込むための権限が必要になる。今回、コスト参照を行っているため、CostExplorer関係の権限を付与した。
- boto3
- ソースとトークン(パスワード的な文字列)の分離
- 権限は結構ややこしかった。上手な設計や運用方法はまだつかめていない上にたぶん漏れがあるけど、記憶の範囲で記載する。
手順
(1)LamndaでAWS価格の取得
- 環境メモ
- 開発時のメモ
- VSCodeなどでローカル開発したほうがやりやすい。その際、boto3のclientは下記のように情報を追加すれば、ローカルからもつながる。
- IAMユーザのシークレットアクセスキーは、IAMユーザ作成時にしか出てこないのでちゃんとメモする。(メモしそこねたらリセットができる)
client = boto3.client('ce', aws_access_key_id='IAMユーザのアクセスキーを入れる', aws_secret_access_key='IAMユーザのシークレットアクセスキーを入れる', region_name='us-east-1' )
from datetime import datetime, timedelta, date import boto3 import json # 今日-start ~ 今日+end日前までのコストを求める def get_cost_for_oneday(client, start, end): # 日付を計算 start_date = date.today() - timedelta(days=start) end_date = date.today() + timedelta(days=end) # API用に文字列にする start_str = start_date.strftime('%Y-%m-%d') end_str = end_date.strftime('%Y-%m-%d') # APIを実行する response = client.get_cost_and_usage( TimePeriod={ 'Start': start_str, 'End': end_str }, Granularity='DAILY', Metrics=[ 'AmortizedCost' ] ) # Metricsの参考。 # https://qiita.com/tamura_CD/items/4a9a412faf379b334986 # responseはdictで、['ResultsByTime']に各日付の情報が入っている ret_list = [] for d in response['ResultsByTime']: tmp = { 'start' : d['TimePeriod']['Start'], 'end' : d['TimePeriod']['End'], 'billing' : d['Total']['AmortizedCost']['Amount'] } ret_list.append(tmp) return ret_list def lambda_handler(event, context): # boto3で接続 client = boto3.client('ce', region_name='us-east-1') # 3日前~今日を取得する ret = get_cost_for_oneday(client, 3,0) return { 'statusCode': 200, 'body': ret }
(2-1)LambdaのLayer(Line送信用ライブラリ)
- ソースが必要なライブラリをzipで固めてアップロードできる。(LambdaからはそのLayerに紐付ける)
- pythonは「pip install hogehoge -t .」のようなコマンドで手元にライブラリを保存して、それをzipで固めればOK。
- ただし、注意点があり、「それをpythonという名前のフォルダで行う必要がある」。
- 参考:PythonモジュールをLambda Layerにアップロードする時のフォルダ構成について - Qiita
(2-2)LambdaのLine送信
from linebot import LineBotApi from linebot.models import TextSendMessage import json import os def lambda_handler(event, context): # ドル円のレート rate = 115 # 各日の文字列を入れる ans_str_list = [] # 新しい順に文字列を作る costdata_list = reversed(event['body']) for d in costdata_list: doller, start, end = d['billing'], d['start'], d['end'] yen = int(float(doller) * rate) tmp = f'{yen}円: 期間[{start}~{end}], (${doller})' ans_str_list.append(tmp) # print(tmp) mes_text = "\n".join(ans_str_list) #print(mes_text) messages = TextSendMessage(text=mes_text) # 環境変数でセットする(Line DevelopersのMessagingAPIのChannel access token (long-lived)) CHANNEL_ACCESS_TOKEN = os.getenv('CHANNEL_ACCESS_TOKEN') line_bot_api = LineBotApi(CHANNEL_ACCESS_TOKEN) # Lineにメッセージを投げる line_bot_api.broadcast(messages) return { 'statusCode': 200, 'body': json.dumps('Hello from Lambda!') }
(2-2)Line developers
正直良くわかっていないけど、いくつかわかったこと。 * Line Developerに登録する。チャンネルを作るとBot用のアカウントが作成されるような形になる。APIからはこのアカウントが操作できる感じ。Bot用アカウントと個人Lineアカウントを友だち状態にしておいて、ブロードキャスト送信するかたちとした。(ピンポイントで送信する方法がよくわからなかったので) * PythonでLine botを作ってみた - Qiita * CHANNEL_ACCESS_TOKEN は、LINE Developers の MessagingAPIの画面の一番したのほうにある、Channel access token(long-lived)の値を使う * Lineのuseridはスルッとは分からないようだった(Lineアプリから見えているものとは別のuseridが内部にあり、APIなどからはそのuseridを使う)。個人のuseridがわかれば、broadcastではなく、ピンポイントなメッセージ送信に切り替えられるのに・・・。
(3)StepFunction
- StepFunctionは、Lambdaを複数つなげたもの。JP1/AJSみたいな感じ。
- 先に動いたLambdaの戻り値を、後続のLambdaが受け取ることができる。
- 今回は、1つ目はAWS価格を返すようにして、2つ目はそれを受け取ってLineに投げる作りとした。2つ目を単体でテスト実行するときは、実行時のパラメータにダミーデータを入れることができる。
- StepFunctionが動くときのロールも注意が必要
- Lambdaを実行する権限があればOKだけど、Lambda(リソース)に対して実行できるかの権限までちゃんと指定しなければいけない。
EventBridgeでの定期実行。