From f403e71adf6dff6e08512c8a6e7be5361750ff87 Mon Sep 17 00:00:00 2001 From: Rafael Felix Correa Date: Mon, 4 Feb 2019 15:41:51 +0100 Subject: [PATCH 1/3] Support for scheduled lambda runs through Cloudwatch Events rule this patch allow provisioning cloudwatch event rules from within the module. for now only scheduled execution is supported. --- README.md | 12 ++++++++ cloudwatch.tf | 21 +++++++++++++ outputs.tf | 5 +++ tests/cloudwatch-event-trigger/lambda.py | 2 ++ tests/cloudwatch-event-trigger/main.tf | 39 ++++++++++++++++++++++++ variables.tf | 12 ++++++++ 6 files changed, 91 insertions(+) create mode 100644 cloudwatch.tf create mode 100644 tests/cloudwatch-event-trigger/lambda.py create mode 100644 tests/cloudwatch-event-trigger/main.tf diff --git a/README.md b/README.md index 3ed1d52..238bd60 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,15 @@ module "lambda" { subnet_ids = ["${aws_subnet.test.id}"] security_group_ids = ["${aws_security_group.test.id}"] } + + // Trigger from a Cloudwatch Events rule. + attach_cloudwatch_rule_config = true + cloudwatch_rule_config { + name = "scheduled-run" + enabled = true // set this to false if you want to have the trigger declared but disabled + description = "Run my lambda every day at 8pm" + schedule_expression = "cron(0 20 * * ? *)" + } } ``` @@ -68,11 +77,13 @@ function name unique per region, for example by setting | Name | Description | Type | Default | Required | |------|-------------|:----:|:-----:|:-----:| +| attach\_cloudwatch\_rule\_config | Set this to true if using the cloudwatch_rule_config variable | string | `false` | no | | attach\_dead\_letter\_config | Set this to true if using the dead_letter_config variable | string | `"false"` | no | | attach\_policy | Set this to true if using the policy variable | string | `"false"` | no | | attach\_vpc\_config | Set this to true if using the vpc_config variable | string | `"false"` | no | | build\_command | The command that creates the Lambda package zip file | string | `"python build.py '$filename' '$runtime' '$source'"` | no | | build\_paths | The files or directories used by the build command, to trigger new Lambda package builds whenever build scripts change | list | `` | no | +| cloudwatch\_rule\_config | Cloudwatch Rule for the Lambda function | map | `` | no | | dead\_letter\_config | Dead letter configuration for the Lambda function | map | `` | no | | description | Description of what your Lambda function does | string | `"Managed by Terraform"` | no | | enable\_cloudwatch\_logs | Set this to false to disable logging your Lambda output to CloudWatch Logs | string | `"true"` | no | @@ -94,6 +105,7 @@ function name unique per region, for example by setting | Name | Description | |------|-------------| +| cloudwatch\_rule\_arn | The ARN of the Cloudwatch rule | | function\_arn | The ARN of the Lambda function | | function\_name | The name of the Lambda function | | function\_qualified\_arn | The qualified ARN of the Lambda function | diff --git a/cloudwatch.tf b/cloudwatch.tf new file mode 100644 index 0000000..204c42a --- /dev/null +++ b/cloudwatch.tf @@ -0,0 +1,21 @@ +resource "aws_lambda_permission" "cloudwatch_trigger" { + count = "${var.attach_cloudwatch_rule_config ? 1 : 0}" + statement_id = "AllowExecutionFromCloudWatch" + action = "${lookup(var.cloudwatch_rule_config, "enabled", true) ? "lambda:InvokeFunction" : "lambda:DisableInvokeFunction"}" + function_name = "${element(concat(aws_lambda_function.lambda.*.function_name, aws_lambda_function.lambda_with_dl.*.function_name, aws_lambda_function.lambda_with_vpc.*.function_name, aws_lambda_function.lambda_with_dl_and_vpc.*.function_name), 0)}" + principal = "events.amazonaws.com" + source_arn = "${aws_cloudwatch_event_rule.rule.arn}" +} +resource "aws_cloudwatch_event_rule" "rule" { + count = "${var.attach_cloudwatch_rule_config ? 1 : 0}" + name = "${var.cloudwatch_rule_config["name"]}" + description = "${var.cloudwatch_rule_config["description"]}" + schedule_expression = "${var.cloudwatch_rule_config["schedule_expression"]}" +} + +resource "aws_cloudwatch_event_target" "target" { + count = "${var.attach_cloudwatch_rule_config ? 1 : 0}" + target_id = "${element(concat(aws_lambda_function.lambda.*.function_name, aws_lambda_function.lambda_with_dl.*.function_name, aws_lambda_function.lambda_with_vpc.*.function_name, aws_lambda_function.lambda_with_dl_and_vpc.*.function_name), 0)}" + rule = "${aws_cloudwatch_event_rule.rule.name}" + arn = "${element(concat(aws_lambda_function.lambda.*.arn, aws_lambda_function.lambda_with_dl.*.arn, aws_lambda_function.lambda_with_vpc.*.arn, aws_lambda_function.lambda_with_dl_and_vpc.*.arn), 0)}" +} \ No newline at end of file diff --git a/outputs.tf b/outputs.tf index 7602f3e..1124cde 100644 --- a/outputs.tf +++ b/outputs.tf @@ -22,3 +22,8 @@ output "role_name" { description = "The name of the IAM role created for the Lambda function" value = "${aws_iam_role.lambda.name}" } + +output "cloudwatch_rule_arn" { + description = "The ARN of the Cloudwatch rule" + value = "${element(concat(aws_cloudwatch_event_rule.rule.*.arn), 0)}" +} \ No newline at end of file diff --git a/tests/cloudwatch-event-trigger/lambda.py b/tests/cloudwatch-event-trigger/lambda.py new file mode 100644 index 0000000..7a16f44 --- /dev/null +++ b/tests/cloudwatch-event-trigger/lambda.py @@ -0,0 +1,2 @@ +def lambda_handler(event, context): + return 'test passed' diff --git a/tests/cloudwatch-event-trigger/main.tf b/tests/cloudwatch-event-trigger/main.tf new file mode 100644 index 0000000..820e8c9 --- /dev/null +++ b/tests/cloudwatch-event-trigger/main.tf @@ -0,0 +1,39 @@ +terraform { + backend "local" { + path = "terraform.tfstate" + } +} + +provider "aws" { + region = "eu-west-1" +} + +resource "random_id" "name" { + byte_length = 6 + prefix = "terraform-aws-lambda-scheduled-" +} + +module "lambda" { + source = "../../" + + function_name = "${random_id.name.hex}" + description = "Test cloudwatch rule trigger in terraform-aws-lambda" + handler = "lambda.lambda_handler" + runtime = "python3.6" + timeout = 30 + + source_path = "${path.module}/lambda.py" + + attach_cloudwatch_rule_config = true + + cloudwatch_rule_config { + name = "scheduled-run" + # enabled = false + description = "Test scheduled lambda run" + schedule_expression = "cron(0 20 * * ? *)" + } +} + +output "cloudwatchrule_arn" { + value = "${module.lambda.cloudwatch_rule_arn}" +} diff --git a/variables.tf b/variables.tf index c22af6c..314eb43 100644 --- a/variables.tf +++ b/variables.tf @@ -84,6 +84,18 @@ variable "attach_vpc_config" { default = false } +variable "cloudwatch_rule_config" { + description = "Cloudwatch Rule for the Lambda function" + type = "map" + default = {} +} + +variable "attach_cloudwatch_rule_config" { + description = "Set this to true if using the cloudwatch_rule_config variable" + type = "string" + default = false +} + variable "tags" { description = "A mapping of tags" type = "map" From e0771904076096ddf009744c5fc2d2aa7907d5d6 Mon Sep 17 00:00:00 2001 From: Rafael Felix Correa Date: Mon, 4 Feb 2019 16:08:50 +0100 Subject: [PATCH 2/3] cloudwatch output can be empty (since its optional) --- outputs.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/outputs.tf b/outputs.tf index 1124cde..a3694d1 100644 --- a/outputs.tf +++ b/outputs.tf @@ -25,5 +25,5 @@ output "role_name" { output "cloudwatch_rule_arn" { description = "The ARN of the Cloudwatch rule" - value = "${element(concat(aws_cloudwatch_event_rule.rule.*.arn), 0)}" + value = "${element(concat(aws_cloudwatch_event_rule.rule.*.arn, list("")), 0)}" } \ No newline at end of file From 744a9a9f8edb31182f0166a64b1508bb41f6d5bd Mon Sep 17 00:00:00 2001 From: Rafael Felix Correa Date: Mon, 11 Mar 2019 15:27:45 +0100 Subject: [PATCH 3/3] Added support for custom input in cloudwatch event target --- README.md | 1 + cloudwatch.tf | 3 ++- tests/cloudwatch-event-trigger/main.tf | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 238bd60..a6152b0 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,7 @@ module "lambda" { enabled = true // set this to false if you want to have the trigger declared but disabled description = "Run my lambda every day at 8pm" schedule_expression = "cron(0 20 * * ? *)" + input = "{\"key\": \"value\"}" } } ``` diff --git a/cloudwatch.tf b/cloudwatch.tf index 204c42a..b2c6af2 100644 --- a/cloudwatch.tf +++ b/cloudwatch.tf @@ -17,5 +17,6 @@ resource "aws_cloudwatch_event_target" "target" { count = "${var.attach_cloudwatch_rule_config ? 1 : 0}" target_id = "${element(concat(aws_lambda_function.lambda.*.function_name, aws_lambda_function.lambda_with_dl.*.function_name, aws_lambda_function.lambda_with_vpc.*.function_name, aws_lambda_function.lambda_with_dl_and_vpc.*.function_name), 0)}" rule = "${aws_cloudwatch_event_rule.rule.name}" + input = "${lookup(var.cloudwatch_rule_config, "input", "")}" arn = "${element(concat(aws_lambda_function.lambda.*.arn, aws_lambda_function.lambda_with_dl.*.arn, aws_lambda_function.lambda_with_vpc.*.arn, aws_lambda_function.lambda_with_dl_and_vpc.*.arn), 0)}" -} \ No newline at end of file +} diff --git a/tests/cloudwatch-event-trigger/main.tf b/tests/cloudwatch-event-trigger/main.tf index 820e8c9..4820604 100644 --- a/tests/cloudwatch-event-trigger/main.tf +++ b/tests/cloudwatch-event-trigger/main.tf @@ -31,6 +31,7 @@ module "lambda" { # enabled = false description = "Test scheduled lambda run" schedule_expression = "cron(0 20 * * ? *)" + input = "{\"key\": \"value\"}" } }