Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: event source mapping #103

Merged
merged 6 commits into from
Feb 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ These types of resources supported:
* [Lambda Provisioned Concurrency](https://www.terraform.io/docs/providers/aws/r/lambda_provisioned_concurrency_config.html)
* [Lambda Async Event Configuration](https://www.terraform.io/docs/providers/aws/r/lambda_function_event_invoke_config.html)
* [Lambda Permission](https://www.terraform.io/docs/providers/aws/r/lambda_permission.html)

Not supported, yet:
* [Lambda Event Source Mapping](https://www.terraform.io/docs/providers/aws/r/lambda_event_source_mapping.html)


Expand All @@ -34,7 +32,7 @@ This Terraform module is the part of [serverless.tf framework](https://github.co
- [x] Lambda@Edge
- [x] Conditional creation for many types of resources.
- [x] Control execution of nearly any step in the process - build, package, store package, deploy, update.
- [x] Control nearly all aspects of Lambda resources (provisioned concurrency, VPC, EFS, dead-letter notification, tracing, async events, IAM role, IAM policies, and more).
- [x] Control nearly all aspects of Lambda resources (provisioned concurrency, VPC, EFS, dead-letter notification, tracing, async events, event source mapping, IAM role, IAM policies, and more).
- [x] Support integration with other `serverless.tf` modules like [HTTP API Gateway](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2) (see [examples there](https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2/tree/master/examples/complete-http)).


Expand Down Expand Up @@ -565,6 +563,7 @@ Q4: What does this error mean - `"We currently do not support adding policies fo
* [With VPC](https://github.com/terraform-aws-modules/terraform-aws-lambda/tree/master/examples/with-vpc) - Create Lambda Function with VPC.
* [With EFS](https://github.com/terraform-aws-modules/terraform-aws-lambda/tree/master/examples/with-efs) - Create Lambda Function with Elastic File System attached (Terraform 0.13+ is recommended).
* [Multiple regions](https://github.com/terraform-aws-modules/terraform-aws-lambda/tree/master/examples/multiple-regions) - Create the same Lambda Function in multiple regions with non-conflicting IAM roles and policies.
* [Event Source Mapping](https://github.com/terraform-aws-modules/terraform-aws-lambda/tree/master/examples/event-source-mapping) - Create Lambda Function with event source mapping configuration (SQS, DynamoDB, and Kinesis).


<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
Expand Down Expand Up @@ -629,6 +628,7 @@ Q4: What does this error mean - `"We currently do not support adding policies fo
| docker\_pip\_cache | Whether to mount a shared pip cache folder into docker environment or not | `any` | `null` | no |
| docker\_with\_ssh\_agent | Whether to pass SSH\_AUTH\_SOCK into docker environment or not | `bool` | `false` | no |
| environment\_variables | A map that defines environment variables for the Lambda Function. | `map(string)` | `{}` | no |
| event\_source\_mapping | Map of event source mapping | `any` | `{}` | no |
| file\_system\_arn | The Amazon Resource Name (ARN) of the Amazon EFS Access Point that provides access to the file system. | `string` | `null` | no |
| file\_system\_local\_mount\_path | The path where the function can access the file system, starting with /mnt/. | `string` | `null` | no |
| function\_name | A unique name for your Lambda Function | `string` | `""` | no |
Expand Down Expand Up @@ -689,6 +689,10 @@ Q4: What does this error mean - `"We currently do not support adding policies fo
| lambda\_role\_name | The name of the IAM role created for the Lambda Function |
| local\_filename | The filename of zip archive deployed (if deployment was from local) |
| s3\_object | The map with S3 object data of zip archive deployed (if deployment was from S3) |
| this\_lambda\_event\_source\_mapping\_function\_arn | The the ARN of the Lambda function the event source mapping is sending events to |
| this\_lambda\_event\_source\_mapping\_state | The state of the event source mapping |
| this\_lambda\_event\_source\_mapping\_state\_transition\_reason | The reason the event source mapping is in its current state |
| this\_lambda\_event\_source\_mapping\_uuid | The UUID of the created event source mapping |
| this\_lambda\_function\_arn | The ARN of the Lambda Function |
| this\_lambda\_function\_invoke\_arn | The Invoke ARN of the Lambda Function |
| this\_lambda\_function\_kms\_key\_arn | The ARN for the KMS encryption key of Lambda Function |
Expand Down
16 changes: 16 additions & 0 deletions examples/event-source-mapping/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Event Source Mapping configuration

Configuration in this directory creates Lambda Function with event source mapping configuration for SQS queue, Kinesis stream, and DynamoDB table.

## Usage

To run this example you need to execute:

```bash
$ terraform init
$ terraform plan
$ terraform apply
```

Note that this example may create resources which cost money. Run `terraform destroy` when you don't need these resources.

120 changes: 120 additions & 0 deletions examples/event-source-mapping/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
provider "aws" {
region = "eu-west-1"

# Make it faster by skipping something
skip_get_ec2_platforms = true
skip_metadata_api_check = true
skip_region_validation = true
skip_credentials_validation = true
skip_requesting_account_id = true
}

####################################################
# Lambda Function with event source mapping
####################################################

module "lambda_function" {
source = "../../"

function_name = "${random_pet.this.id}-lambda-event-source-mapping"
handler = "index.lambda_handler"
runtime = "python3.8"

source_path = "${path.module}/../fixtures/python3.8-app1"

event_source_mapping = {
sqs = {
event_source_arn = aws_sqs_queue.this.arn
}
dynamodb = {
event_source_arn = aws_dynamodb_table.this.stream_arn
starting_position = "LATEST"
# This can be created but it won't be updated/removed. To be reviewed in the future.
# destination_config = {
# on_failure = {
# destination_arn = aws_sqs_queue.failure.arn
# }
# }
}
kinesis = {
event_source_arn = aws_kinesis_stream.this.arn
starting_position = "LATEST"
}
}

allowed_triggers = {
sqs = {
principal = "sqs.amazonaws.com"
source_arn = aws_sqs_queue.this.arn
}
dynamodb = {
principal = "dynamodb.amazonaws.com"
source_arn = aws_dynamodb_table.this.stream_arn
}
kinesis = {
principal = "kinesis.amazonaws.com"
source_arn = aws_kinesis_stream.this.arn
}
}

create_current_version_allowed_triggers = false

# Allow failures to be sent to SQS queue
attach_policy_statements = true
policy_statements = {
sqs_failure = {
effect = "Allow",
actions = ["sqs:SendMessage"],
resources = [aws_sqs_queue.failure.arn]
}
}

attach_policies = true
number_of_policies = 3

policies = [
"arn:aws:iam::aws:policy/service-role/AWSLambdaSQSQueueExecutionRole",
"arn:aws:iam::aws:policy/service-role/AWSLambdaDynamoDBExecutionRole",
"arn:aws:iam::aws:policy/service-role/AWSLambdaKinesisExecutionRole",
]
}

##################
# Extra resources
##################

resource "random_pet" "this" {
length = 2
}

resource "aws_sqs_queue" "this" {
name = random_pet.this.id
}

resource "aws_dynamodb_table" "this" {
name = random_pet.this.id
billing_mode = "PAY_PER_REQUEST"
hash_key = "UserId"
range_key = "GameTitle"
stream_view_type = "NEW_AND_OLD_IMAGES"
stream_enabled = true

attribute {
name = "UserId"
type = "S"
}

attribute {
name = "GameTitle"
type = "S"
}
}

resource "aws_kinesis_stream" "this" {
name = random_pet.this.id
shard_count = 1
}

resource "aws_sqs_queue" "failure" {
name = "${random_pet.this.id}-failure"
}
66 changes: 66 additions & 0 deletions examples/event-source-mapping/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Lambda Function
output "this_lambda_function_arn" {
description = "The ARN of the Lambda Function"
value = module.lambda_function.this_lambda_function_arn
}

output "this_lambda_function_invoke_arn" {
description = "The Invoke ARN of the Lambda Function"
value = module.lambda_function.this_lambda_function_invoke_arn
}

output "this_lambda_function_name" {
description = "The name of the Lambda Function"
value = module.lambda_function.this_lambda_function_name
}

output "this_lambda_function_qualified_arn" {
description = "The ARN identifying your Lambda Function Version"
value = module.lambda_function.this_lambda_function_qualified_arn
}

output "this_lambda_function_version" {
description = "Latest published version of Lambda Function"
value = module.lambda_function.this_lambda_function_version
}

output "this_lambda_function_last_modified" {
description = "The date Lambda Function resource was last modified"
value = module.lambda_function.this_lambda_function_last_modified
}

output "this_lambda_function_kms_key_arn" {
description = "The ARN for the KMS encryption key of Lambda Function"
value = module.lambda_function.this_lambda_function_kms_key_arn
}

output "this_lambda_function_source_code_hash" {
description = "Base64-encoded representation of raw SHA-256 sum of the zip file"
value = module.lambda_function.this_lambda_function_source_code_hash
}

output "this_lambda_function_source_code_size" {
description = "The size in bytes of the function .zip file"
value = module.lambda_function.this_lambda_function_source_code_size
}

# Lambda Event Source Mapping
output "this_lambda_event_source_mapping_function_arn" {
description = "The the ARN of the Lambda function the event source mapping is sending events to"
value = module.lambda_function.this_lambda_event_source_mapping_function_arn
}

output "this_lambda_event_source_mapping_state" {
description = "The state of the event source mapping"
value = module.lambda_function.this_lambda_event_source_mapping_state
}

output "this_lambda_event_source_mapping_state_transition_reason" {
description = "The reason the event source mapping is in its current state"
value = module.lambda_function.this_lambda_event_source_mapping_state_transition_reason
}

output "this_lambda_event_source_mapping_uuid" {
description = "The UUID of the created event source mapping"
value = module.lambda_function.this_lambda_event_source_mapping_uuid
}
Empty file.
9 changes: 9 additions & 0 deletions examples/event-source-mapping/versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
terraform {
required_version = ">= 0.12.6"

required_providers {
aws = ">= 3.27"
random = ">= 2"
}
}

32 changes: 31 additions & 1 deletion main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ resource "aws_lambda_permission" "current_version_triggers" {
event_source_token = lookup(each.value, "event_source_token", null)
}

# Error: Error adding new Lambda Permission for destined-tetra-lambda: InvalidParameterValueException: We currently do not support adding policies for $LATEST.
# Error: Error adding new Lambda Permission for lambda: InvalidParameterValueException: We currently do not support adding policies for $LATEST.
resource "aws_lambda_permission" "unqualified_alias_triggers" {
for_each = var.create && var.create_function && !var.create_layer && var.create_unqualified_alias_allowed_triggers ? var.allowed_triggers : {}

Expand All @@ -204,3 +204,33 @@ resource "aws_lambda_permission" "unqualified_alias_triggers" {
source_account = lookup(each.value, "source_account", null)
event_source_token = lookup(each.value, "event_source_token", null)
}

resource "aws_lambda_event_source_mapping" "this" {
for_each = var.create && var.create_function && !var.create_layer && var.create_unqualified_alias_allowed_triggers ? var.event_source_mapping : tomap({})

function_name = aws_lambda_function.this[0].arn

event_source_arn = each.value.event_source_arn

batch_size = lookup(each.value, "batch_size", null)
maximum_batching_window_in_seconds = lookup(each.value, "maximum_batching_window_in_seconds", null)
enabled = lookup(each.value, "enabled", null)
starting_position = lookup(each.value, "starting_position", null)
starting_position_timestamp = lookup(each.value, "starting_position_timestamp", null)
parallelization_factor = lookup(each.value, "parallelization_factor", null)
maximum_retry_attempts = lookup(each.value, "maximum_retry_attempts", null)
maximum_record_age_in_seconds = lookup(each.value, "maximum_record_age_in_seconds", null)
bisect_batch_on_function_error = lookup(each.value, "bisect_batch_on_function_error", null)

/* @todo: fix this
dynamic "destination_config" {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@svenlito There seems to be a bug somewhere related to the editing of destination_config argument of this resource (once created, it won't be removed/updated via this resource). I couldn't figure out the solution, so just disabled this feature for now.

for_each = lookup(each.value, "destination_config", {})

content {
on_failure {
destination_arn = lookup(destination_config.value, "on_failure") #"destination_arn"]
}
}
}
*/
}
21 changes: 21 additions & 0 deletions outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,27 @@ output "this_lambda_layer_version" {
value = element(concat(aws_lambda_layer_version.this.*.version, [""]), 0)
}

# Lambda Event Source Mapping
output "this_lambda_event_source_mapping_function_arn" {
description = "The the ARN of the Lambda function the event source mapping is sending events to"
value = { for k, v in aws_lambda_event_source_mapping.this : k => v.function_arn }
}

output "this_lambda_event_source_mapping_state" {
description = "The state of the event source mapping"
value = { for k, v in aws_lambda_event_source_mapping.this : k => v.state }
}

output "this_lambda_event_source_mapping_state_transition_reason" {
description = "The reason the event source mapping is in its current state"
value = { for k, v in aws_lambda_event_source_mapping.this : k => v.state_transition_reason }
}

output "this_lambda_event_source_mapping_uuid" {
description = "The UUID of the created event source mapping"
value = { for k, v in aws_lambda_event_source_mapping.this : k => v.uuid }
}

# IAM Role
output "lambda_role_arn" {
description = "The ARN of the IAM role created for the Lambda Function"
Expand Down
10 changes: 10 additions & 0 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,16 @@ variable "allowed_triggers" {
default = {}
}

############################################
# Lambda Event Source Mapping
############################################

variable "event_source_mapping" {
description = "Map of event source mapping"
type = any
default = {}
}

#################
# CloudWatch Logs
#################
Expand Down