概要

boto3を使い、CloudWatchEventsでLambda Functionを呼ぶルールを設定した。最初、うまくルールが発動せずハマったことがあるので、注意点もメモっておく。


背景と目的

boto3から、AWSのCloudWatchEventsにルールを設定し、定期的にLambda Functionを実行しようと思ったので、方法を調べ、メモしておく。


詳細

1.boto3のドキュメントで方法を確認

CloudWatchEventsのルールを設定するには、boto3.client("events").put_ruleboto3.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のポリシーを適切に設定する必要があることに注意。