概要
boto3を使い、CloudWatchEventsでLambda Functionを呼ぶルールを設定した。最初、うまくルールが発動せずハマったことがあるので、注意点もメモっておく。
背景と目的
boto3から、AWSのCloudWatchEventsにルールを設定し、定期的にLambda Functionを実行しようと思ったので、方法を調べ、メモしておく。
詳細
1.boto3のドキュメントで方法を確認
CloudWatchEventsのルールを設定するには、boto3.client("events").put_ruleとboto3.client("events").put_targetsを使う。
また、呼び出し側のLambda関数のpolicyにおいて、CloudWatchEventsから呼び出されることを許可必要がある。ここで、ハマってしまいうまく動かなかった。注意。
2.実装
実装したのは以下。ここでは、ルール名をboto3_test、ターゲットのLambda Functionをfor_testという名前のもの(内容は、ブランク関数。Hello world!を出力するだけ)、入力パラメータはjson文字列とした。
import boto3 # ルールを追加 ret_rule = boto3.client("events").put_rule( Name="boto3_test", Description=u"説明文", ScheduleExpression="cron(* * * * ? *)" ) print json.dumps(ret_rule, indent=4) # ターゲットを追加 ret_target = boto3.client("events").put_targets( Rule="boto3_test", Targets=[ { "Id": "for_test", "Arn": "arn:aws:lambda:リージョン:アカウントID:function:for_test", "Input": json.dumps({}) } ] )
ここで、上記ソースコードを実行すると、エラーなく実行され、マネジメントコンソール上にも、有効なルールとして表示される。しかし、これだけではちゃんと動かない。
put_targetsの説明をじっくり読むと、
To be able to make API calls against the resources that you own, Amazon CloudWatch Events needs the appropriate permissions. For AWS Lambda and Amazon SNS resources, CloudWatch Events relies on resource-based policies.
とある。つまり、Lambda Function側のポリシーを設定してねということ。で、リソースポリシーはどう設定すればいいのかというと、こちらに記述があり、AWS Lambda Permissionの項を参考に、呼び出されるLambda Functionのポリシーを設定。
# Lambdaにパーミッションを追加 ret_lambda = boto3.client("lambda").add_permission( FunctionName='for_test', StatementId='ステートメントID', Action='lambda:InvokeFunction', Principal='events.amazonaws.com', SourceArn='arn:aws:events:リージョン:アカウントID:rule/boto3_test' )
なお、マネジメントコンソールからルールを設定した場合は、裏で勝手にこのパーミッションの設定をやってくれている。なので、動くということだ。
3.動作確認
上記の設定により、ちゃんと指定したルールに沿って、イベントが発生し、Lambda Functionが実行された。
まとめ
boto3を使い、CloudWatchEventsでLambda Functionを呼ぶルールを設定することができた。呼び出し側のLambda Functionのポリシーを適切に設定する必要があることに注意。