Skip to content

Commit

Permalink
Lamdba Component Update (#1115)
Browse files Browse the repository at this point in the history
  • Loading branch information
Benbentwo authored Sep 19, 2024
1 parent 4a3a99e commit 2cac06b
Show file tree
Hide file tree
Showing 8 changed files with 449 additions and 192 deletions.
244 changes: 147 additions & 97 deletions modules/lambda/README.md

Large diffs are not rendered by default.

122 changes: 71 additions & 51 deletions modules/lambda/main.tf
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
locals {
enabled = module.this.enabled
iam_policy_enabled = local.enabled && (try(length(var.iam_policy), 0) > 0 || var.policy_json != null)
s3_bucket_computed_name = var.s3_bucket_name != null ? format("%s-%s-%s-%s-%s", module.this.namespace, module.this.tenant, module.this.environment, module.this.stage, var.s3_bucket_name) : null
enabled = module.this.enabled
var_iam_policy_enabled = local.enabled && (try(length(var.iam_policy), 0) > 0 || var.policy_json != null)
iam_policy_enabled = local.enabled && local.var_iam_policy_enabled

s3_full_bucket_name = coalesce(var.s3_full_bucket_name, local.s3_bucket_computed_name, "none") == "none" ? null : coalesce(var.s3_full_bucket_name, local.s3_bucket_computed_name)
function_name = coalesce(var.function_name, module.label.id)
s3_bucket_name = var.s3_bucket_name != null ? var.s3_bucket_name : one(module.s3_bucket[*].outputs.bucket_id)

cicd_s3_key_format = var.cicd_s3_key_format != null ? var.cicd_s3_key_format : "stage/${module.this.stage}/lambda/${local.function_name}/%s"
s3_key = var.s3_bucket_name == null ? null : (var.s3_key != null ? var.s3_key : format(local.cicd_s3_key_format, coalesce(one(data.aws_ssm_parameter.cicd_ssm_param[*].value), "example")))
function_name = coalesce(var.function_name, module.this.id)

var_policy_json = local.var_iam_policy_enabled ? [var.policy_json] : []

lambda_files = fileset("${path.module}/lambdas/${var.zip.input_dir == null ? "" : var.zip.input_dir}", "*")
file_content_map = var.zip.enabled ? [
for f in local.lambda_files : filebase64sha256("${path.module}/lambdas/${coalesce(var.zip.input_dir, var.name)}/${f}")
] : []
output_zip_file = local.enabled && var.zip.enabled ? "${path.module}/lambdas/${random_pet.zip_recreator[0].id}.zip" : null

cicd_s3_key_format = var.cicd_s3_key_format != null ? var.cicd_s3_key_format : "stage/${module.this.stage}/lambda/${local.function_name}/%s"
s3_key = var.s3_key != null ? var.s3_key : format(local.cicd_s3_key_format, coalesce(one(data.aws_ssm_parameter.cicd_ssm_param[*].value), "example"))
}
data "aws_ssm_parameter" "cicd_ssm_param" {
Expand All @@ -17,25 +25,15 @@ data "aws_ssm_parameter" "cicd_ssm_param" {
name = var.cicd_ssm_param_name
}

module "label" {
source = "cloudposse/label/null"
version = "0.25.0"

attributes = [var.function_name]

context = module.this.context
}

module "iam_policy" {
count = local.iam_policy_enabled ? 1 : 0
source = "cloudposse/iam-policy/aws"
version = "1.0.1"

iam_policy_enabled = true
iam_policy = var.iam_policy
iam_source_policy_documents = var.policy_json != null ? [var.policy_json] : []

context = module.this.context
iam_source_policy_documents = local.var_policy_json != null ? local.var_policy_json : []
context = module.this.context
}

resource "aws_iam_role_policy_attachment" "default" {
Expand All @@ -46,15 +44,27 @@ resource "aws_iam_role_policy_attachment" "default" {
}

data "archive_file" "lambdazip" {
count = var.zip.enabled ? 1 : 0
type = "zip"
output_path = "${path.module}/lambdas/${var.zip.output}"
count = local.enabled && var.zip.enabled ? 1 : 0
type = "zip"

output_path = local.output_zip_file
source_dir = "${path.module}/lambdas/${var.zip.input_dir}"

depends_on = [random_pet.zip_recreator]
}

resource "random_pet" "zip_recreator" {
count = local.enabled && var.zip.enabled ? 1 : 0

prefix = coalesce(module.this.name, "lambda")
keepers = {
file_content = join(",", local.file_content_map)
}
}

module "lambda" {
source = "cloudposse/lambda-function/aws"
version = "0.4.1"
version = "0.6.1"

function_name = local.function_name
description = var.description
Expand All @@ -63,37 +73,47 @@ module "lambda" {
image_uri = var.image_uri
image_config = var.image_config

filename = var.filename
s3_bucket = local.s3_full_bucket_name
filename = var.zip.enabled ? coalesce(data.archive_file.lambdazip[0].output_path, var.filename) : var.filename
s3_bucket = local.s3_bucket_name
s3_key = local.s3_key
s3_object_version = var.s3_object_version

architectures = var.architectures
cloudwatch_event_rules = var.cloudwatch_event_rules
cloudwatch_lambda_insights_enabled = var.cloudwatch_lambda_insights_enabled
cloudwatch_logs_retention_in_days = var.cloudwatch_logs_retention_in_days
cloudwatch_logs_kms_key_arn = var.cloudwatch_logs_kms_key_arn
cloudwatch_log_subscription_filters = var.cloudwatch_log_subscription_filters
ignore_external_function_updates = var.ignore_external_function_updates
event_source_mappings = var.event_source_mappings
kms_key_arn = var.kms_key_arn
lambda_at_edge_enabled = var.lambda_at_edge_enabled
layers = var.layers
memory_size = var.memory_size
package_type = var.package_type
permissions_boundary = var.permissions_boundary
publish = var.publish
reserved_concurrent_executions = var.reserved_concurrent_executions
runtime = var.runtime
sns_subscriptions = var.sns_subscriptions
source_code_hash = var.source_code_hash
ssm_parameter_names = var.ssm_parameter_names
timeout = var.timeout
tracing_config_mode = var.tracing_config_mode
vpc_config = var.vpc_config
custom_iam_policy_arns = var.custom_iam_policy_arns
dead_letter_config_target_arn = var.dead_letter_config_target_arn
iam_policy_description = var.iam_policy_description
architectures = var.architectures
cloudwatch_lambda_insights_enabled = var.cloudwatch_lambda_insights_enabled
cloudwatch_logs_retention_in_days = var.cloudwatch_logs_retention_in_days
cloudwatch_logs_kms_key_arn = var.cloudwatch_logs_kms_key_arn
kms_key_arn = var.kms_key_arn
lambda_at_edge_enabled = var.lambda_at_edge_enabled
layers = var.layers
memory_size = var.memory_size
package_type = var.package_type
permissions_boundary = var.permissions_boundary
publish = var.publish
reserved_concurrent_executions = var.reserved_concurrent_executions
runtime = var.runtime
source_code_hash = var.source_code_hash
ssm_parameter_names = var.ssm_parameter_names
timeout = var.timeout
tracing_config_mode = var.tracing_config_mode
vpc_config = var.vpc_config
custom_iam_policy_arns = var.custom_iam_policy_arns
dead_letter_config_target_arn = var.dead_letter_config_target_arn
iam_policy_description = var.iam_policy_description

context = module.this.context
}

resource "aws_lambda_function_url" "lambda_url" {
count = var.function_url_enabled ? 1 : 0
function_name = module.lambda.function_name
authorization_type = "AWS_IAM"

cors {
allow_credentials = true
allow_origins = ["*"]
allow_methods = ["*"]
allow_headers = ["date", "keep-alive"]
expose_headers = ["keep-alive", "date"]
max_age = 86400
}
}
14 changes: 14 additions & 0 deletions modules/lambda/remote-state.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module "s3_bucket" {
count = local.enabled && var.s3_bucket_component != null ? 1 : 0

source = "cloudposse/stack-config/yaml//modules/remote-state"
version = "1.5.0"

component = var.s3_bucket_component.component

tenant = var.s3_bucket_component.tenant
environment = var.s3_bucket_component.environment
stage = var.s3_bucket_component.stage

context = module.this.context
}
43 changes: 43 additions & 0 deletions modules/lambda/triggers_cloudwatch_event_rules.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
module "cloudwatch_event_rules_label" {
for_each = var.cloudwatch_event_rules

source = "cloudposse/label/null"
version = "0.25.0"
attributes = [each.key]

context = module.this.context
}

resource "aws_cloudwatch_event_rule" "event_rules" {
for_each = var.cloudwatch_event_rules

name = module.cloudwatch_event_rules_label[each.key].id

description = each.value.description
event_bus_name = each.value.event_bus_name
event_pattern = each.value.event_pattern
is_enabled = each.value.is_enabled
name_prefix = each.value.name_prefix
role_arn = each.value.role_arn
schedule_expression = each.value.schedule_expression

tags = module.cloudwatch_event_rules_label[each.key].tags
}

resource "aws_cloudwatch_event_target" "sns" {
for_each = var.cloudwatch_event_rules

rule = aws_cloudwatch_event_rule.event_rules[each.key].name
target_id = "ScheduleExpression"
arn = module.lambda.arn
}

resource "aws_lambda_permission" "allow_cloudwatch_to_call_lambda" {
for_each = var.cloudwatch_event_rules

statement_id = format("%s-%s", "AllowExecutionFromCloudWatch", each.key)
action = "lambda:InvokeFunction"
function_name = module.lambda.function_name
principal = "events.amazonaws.com"
source_arn = aws_cloudwatch_event_rule.event_rules[each.key].arn
}
58 changes: 58 additions & 0 deletions modules/lambda/triggers_s3_notifications.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
variable "s3_notifications" {
type = map(object({
bucket_name = optional(string)
bucket_component = optional(object({
component = string
environment = optional(string)
tenant = optional(string)
stage = optional(string)
}))
events = optional(list(string))
filter_prefix = optional(string)
filter_suffix = optional(string)
source_account = optional(string)
}))
description = "A map of S3 bucket notifications to trigger the Lambda function"
default = {}
}

module "s3_bucket_notifications_component" {
for_each = { for k, v in var.s3_notifications : k => v if v.bucket_component != null }

source = "cloudposse/stack-config/yaml//modules/remote-state"
version = "1.5.0"

component = each.value.bucket_component.component

tenant = each.value.bucket_component.tenant
environment = each.value.bucket_component.environment
stage = each.value.bucket_component.stage

context = module.this.context
}

resource "aws_lambda_permission" "s3_notification" {
for_each = var.s3_notifications

statement_id = "AllowS3Invoke"
action = "lambda:InvokeFunction"
function_name = module.lambda.function_name
principal = "s3.amazonaws.com"
source_arn = format("arn:aws:s3:::%s", each.value.bucket_component == null ? each.value.bucket_name : module.s3_bucket_notifications_component[each.key].outputs.bucket_id)
source_account = each.value.source_account
}

resource "aws_s3_bucket_notification" "s3_notifications" {
for_each = var.s3_notifications

depends_on = [aws_lambda_permission.s3_notification]

bucket = each.value.bucket_component == null ? each.value.bucket_name : module.s3_bucket_notifications_component[each.key].outputs.bucket_id

lambda_function {
lambda_function_arn = module.lambda.arn
events = each.value.events == null ? ["s3:ObjectCreated:*"] : each.value.events
filter_prefix = each.value.filter_prefix
filter_suffix = each.value.filter_suffix
}
}
81 changes: 81 additions & 0 deletions modules/lambda/triggers_sqs_queue.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
variable "sqs_notifications" {
type = map(object({
sqs_arn = optional(string)
sqs_component = optional(object({
component = string
environment = optional(string)
tenant = optional(string)
stage = optional(string)
}))
batch_size = optional(number)
source_account = optional(string)
on_failure_arn = optional(string)
maximum_concurrency = optional(number)
}))
description = "A map of SQS queue notifications to trigger the Lambda function"
default = {}
}

module "sqs_queue" {
for_each = { for k, v in var.sqs_notifications : k => v if v.sqs_component != null }

source = "cloudposse/stack-config/yaml//modules/remote-state"
version = "1.5.0"

component = each.value.sqs_component.component

tenant = each.value.sqs_component.tenant
environment = each.value.sqs_component.environment
stage = each.value.sqs_component.stage

context = module.this.context
}

module "sqs_iam_policy" {
for_each = var.sqs_notifications

source = "cloudposse/iam-policy/aws"
version = "1.0.1"

iam_policy_enabled = true
iam_policy = {
version = "2012-10-17"
statements = [
{
effect = "Allow"
actions = ["sqs:ReceiveMessage", "sqs:DeleteMessage", "sqs:GetQueueAttributes"]
resources = each.value.sqs_arn != null ? [each.value.sqs_arn.sqs_arn] : [module.sqs_queue[each.key].outputs.sqs_queue.queue_arn]
},
]
}
context = module.this.context
}

resource "aws_iam_role_policy_attachment" "sqs_default" {
for_each = var.sqs_notifications

role = module.lambda.role_name
policy_arn = module.sqs_iam_policy[each.key].policy_arn
}

resource "aws_lambda_event_source_mapping" "event_source_mapping" {
for_each = var.sqs_notifications

event_source_arn = each.value.sqs_arn != null ? [each.value.sqs_arn.sqs_arn] : module.sqs_queue[each.key].outputs.sqs_queue.queue_arn
function_name = module.lambda.function_name
batch_size = each.value.batch_size == null ? 1 : each.value.batch_size

scaling_config {
maximum_concurrency = each.value.maximum_concurrency
}
dynamic "destination_config" {
for_each = { for k, v in each.value : k => v if k == "on_failure_arn" && v != null }
content {
on_failure {
destination_arn = destination_config.value
}
}
}

depends_on = [aws_iam_role_policy_attachment.sqs_default]
}
Loading

0 comments on commit 2cac06b

Please sign in to comment.