Skip to content

Commit 2cac06b

Browse files
authored
Lamdba Component Update (#1115)
1 parent 4a3a99e commit 2cac06b

File tree

8 files changed

+449
-192
lines changed

8 files changed

+449
-192
lines changed

modules/lambda/README.md

Lines changed: 147 additions & 97 deletions
Large diffs are not rendered by default.

modules/lambda/main.tf

Lines changed: 71 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,22 @@
11
locals {
2-
enabled = module.this.enabled
3-
iam_policy_enabled = local.enabled && (try(length(var.iam_policy), 0) > 0 || var.policy_json != null)
4-
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
2+
enabled = module.this.enabled
3+
var_iam_policy_enabled = local.enabled && (try(length(var.iam_policy), 0) > 0 || var.policy_json != null)
4+
iam_policy_enabled = local.enabled && local.var_iam_policy_enabled
55

6-
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)
7-
function_name = coalesce(var.function_name, module.label.id)
6+
s3_bucket_name = var.s3_bucket_name != null ? var.s3_bucket_name : one(module.s3_bucket[*].outputs.bucket_id)
87

9-
cicd_s3_key_format = var.cicd_s3_key_format != null ? var.cicd_s3_key_format : "stage/${module.this.stage}/lambda/${local.function_name}/%s"
10-
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")))
8+
function_name = coalesce(var.function_name, module.this.id)
9+
10+
var_policy_json = local.var_iam_policy_enabled ? [var.policy_json] : []
11+
12+
lambda_files = fileset("${path.module}/lambdas/${var.zip.input_dir == null ? "" : var.zip.input_dir}", "*")
13+
file_content_map = var.zip.enabled ? [
14+
for f in local.lambda_files : filebase64sha256("${path.module}/lambdas/${coalesce(var.zip.input_dir, var.name)}/${f}")
15+
] : []
16+
output_zip_file = local.enabled && var.zip.enabled ? "${path.module}/lambdas/${random_pet.zip_recreator[0].id}.zip" : null
1117

18+
cicd_s3_key_format = var.cicd_s3_key_format != null ? var.cicd_s3_key_format : "stage/${module.this.stage}/lambda/${local.function_name}/%s"
19+
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"))
1220
}
1321

1422
data "aws_ssm_parameter" "cicd_ssm_param" {
@@ -17,25 +25,15 @@ data "aws_ssm_parameter" "cicd_ssm_param" {
1725
name = var.cicd_ssm_param_name
1826
}
1927

20-
module "label" {
21-
source = "cloudposse/label/null"
22-
version = "0.25.0"
23-
24-
attributes = [var.function_name]
25-
26-
context = module.this.context
27-
}
28-
2928
module "iam_policy" {
3029
count = local.iam_policy_enabled ? 1 : 0
3130
source = "cloudposse/iam-policy/aws"
3231
version = "1.0.1"
3332

3433
iam_policy_enabled = true
3534
iam_policy = var.iam_policy
36-
iam_source_policy_documents = var.policy_json != null ? [var.policy_json] : []
37-
38-
context = module.this.context
35+
iam_source_policy_documents = local.var_policy_json != null ? local.var_policy_json : []
36+
context = module.this.context
3937
}
4038

4139
resource "aws_iam_role_policy_attachment" "default" {
@@ -46,15 +44,27 @@ resource "aws_iam_role_policy_attachment" "default" {
4644
}
4745

4846
data "archive_file" "lambdazip" {
49-
count = var.zip.enabled ? 1 : 0
50-
type = "zip"
51-
output_path = "${path.module}/lambdas/${var.zip.output}"
47+
count = local.enabled && var.zip.enabled ? 1 : 0
48+
type = "zip"
49+
50+
output_path = local.output_zip_file
5251
source_dir = "${path.module}/lambdas/${var.zip.input_dir}"
52+
53+
depends_on = [random_pet.zip_recreator]
54+
}
55+
56+
resource "random_pet" "zip_recreator" {
57+
count = local.enabled && var.zip.enabled ? 1 : 0
58+
59+
prefix = coalesce(module.this.name, "lambda")
60+
keepers = {
61+
file_content = join(",", local.file_content_map)
62+
}
5363
}
5464

5565
module "lambda" {
5666
source = "cloudposse/lambda-function/aws"
57-
version = "0.4.1"
67+
version = "0.6.1"
5868

5969
function_name = local.function_name
6070
description = var.description
@@ -63,37 +73,47 @@ module "lambda" {
6373
image_uri = var.image_uri
6474
image_config = var.image_config
6575

66-
filename = var.filename
67-
s3_bucket = local.s3_full_bucket_name
76+
filename = var.zip.enabled ? coalesce(data.archive_file.lambdazip[0].output_path, var.filename) : var.filename
77+
s3_bucket = local.s3_bucket_name
6878
s3_key = local.s3_key
6979
s3_object_version = var.s3_object_version
7080

71-
architectures = var.architectures
72-
cloudwatch_event_rules = var.cloudwatch_event_rules
73-
cloudwatch_lambda_insights_enabled = var.cloudwatch_lambda_insights_enabled
74-
cloudwatch_logs_retention_in_days = var.cloudwatch_logs_retention_in_days
75-
cloudwatch_logs_kms_key_arn = var.cloudwatch_logs_kms_key_arn
76-
cloudwatch_log_subscription_filters = var.cloudwatch_log_subscription_filters
77-
ignore_external_function_updates = var.ignore_external_function_updates
78-
event_source_mappings = var.event_source_mappings
79-
kms_key_arn = var.kms_key_arn
80-
lambda_at_edge_enabled = var.lambda_at_edge_enabled
81-
layers = var.layers
82-
memory_size = var.memory_size
83-
package_type = var.package_type
84-
permissions_boundary = var.permissions_boundary
85-
publish = var.publish
86-
reserved_concurrent_executions = var.reserved_concurrent_executions
87-
runtime = var.runtime
88-
sns_subscriptions = var.sns_subscriptions
89-
source_code_hash = var.source_code_hash
90-
ssm_parameter_names = var.ssm_parameter_names
91-
timeout = var.timeout
92-
tracing_config_mode = var.tracing_config_mode
93-
vpc_config = var.vpc_config
94-
custom_iam_policy_arns = var.custom_iam_policy_arns
95-
dead_letter_config_target_arn = var.dead_letter_config_target_arn
96-
iam_policy_description = var.iam_policy_description
81+
architectures = var.architectures
82+
cloudwatch_lambda_insights_enabled = var.cloudwatch_lambda_insights_enabled
83+
cloudwatch_logs_retention_in_days = var.cloudwatch_logs_retention_in_days
84+
cloudwatch_logs_kms_key_arn = var.cloudwatch_logs_kms_key_arn
85+
kms_key_arn = var.kms_key_arn
86+
lambda_at_edge_enabled = var.lambda_at_edge_enabled
87+
layers = var.layers
88+
memory_size = var.memory_size
89+
package_type = var.package_type
90+
permissions_boundary = var.permissions_boundary
91+
publish = var.publish
92+
reserved_concurrent_executions = var.reserved_concurrent_executions
93+
runtime = var.runtime
94+
source_code_hash = var.source_code_hash
95+
ssm_parameter_names = var.ssm_parameter_names
96+
timeout = var.timeout
97+
tracing_config_mode = var.tracing_config_mode
98+
vpc_config = var.vpc_config
99+
custom_iam_policy_arns = var.custom_iam_policy_arns
100+
dead_letter_config_target_arn = var.dead_letter_config_target_arn
101+
iam_policy_description = var.iam_policy_description
97102

98103
context = module.this.context
99104
}
105+
106+
resource "aws_lambda_function_url" "lambda_url" {
107+
count = var.function_url_enabled ? 1 : 0
108+
function_name = module.lambda.function_name
109+
authorization_type = "AWS_IAM"
110+
111+
cors {
112+
allow_credentials = true
113+
allow_origins = ["*"]
114+
allow_methods = ["*"]
115+
allow_headers = ["date", "keep-alive"]
116+
expose_headers = ["keep-alive", "date"]
117+
max_age = 86400
118+
}
119+
}

modules/lambda/remote-state.tf

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
module "s3_bucket" {
2+
count = local.enabled && var.s3_bucket_component != null ? 1 : 0
3+
4+
source = "cloudposse/stack-config/yaml//modules/remote-state"
5+
version = "1.5.0"
6+
7+
component = var.s3_bucket_component.component
8+
9+
tenant = var.s3_bucket_component.tenant
10+
environment = var.s3_bucket_component.environment
11+
stage = var.s3_bucket_component.stage
12+
13+
context = module.this.context
14+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
module "cloudwatch_event_rules_label" {
2+
for_each = var.cloudwatch_event_rules
3+
4+
source = "cloudposse/label/null"
5+
version = "0.25.0"
6+
attributes = [each.key]
7+
8+
context = module.this.context
9+
}
10+
11+
resource "aws_cloudwatch_event_rule" "event_rules" {
12+
for_each = var.cloudwatch_event_rules
13+
14+
name = module.cloudwatch_event_rules_label[each.key].id
15+
16+
description = each.value.description
17+
event_bus_name = each.value.event_bus_name
18+
event_pattern = each.value.event_pattern
19+
is_enabled = each.value.is_enabled
20+
name_prefix = each.value.name_prefix
21+
role_arn = each.value.role_arn
22+
schedule_expression = each.value.schedule_expression
23+
24+
tags = module.cloudwatch_event_rules_label[each.key].tags
25+
}
26+
27+
resource "aws_cloudwatch_event_target" "sns" {
28+
for_each = var.cloudwatch_event_rules
29+
30+
rule = aws_cloudwatch_event_rule.event_rules[each.key].name
31+
target_id = "ScheduleExpression"
32+
arn = module.lambda.arn
33+
}
34+
35+
resource "aws_lambda_permission" "allow_cloudwatch_to_call_lambda" {
36+
for_each = var.cloudwatch_event_rules
37+
38+
statement_id = format("%s-%s", "AllowExecutionFromCloudWatch", each.key)
39+
action = "lambda:InvokeFunction"
40+
function_name = module.lambda.function_name
41+
principal = "events.amazonaws.com"
42+
source_arn = aws_cloudwatch_event_rule.event_rules[each.key].arn
43+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
variable "s3_notifications" {
2+
type = map(object({
3+
bucket_name = optional(string)
4+
bucket_component = optional(object({
5+
component = string
6+
environment = optional(string)
7+
tenant = optional(string)
8+
stage = optional(string)
9+
}))
10+
events = optional(list(string))
11+
filter_prefix = optional(string)
12+
filter_suffix = optional(string)
13+
source_account = optional(string)
14+
}))
15+
description = "A map of S3 bucket notifications to trigger the Lambda function"
16+
default = {}
17+
}
18+
19+
module "s3_bucket_notifications_component" {
20+
for_each = { for k, v in var.s3_notifications : k => v if v.bucket_component != null }
21+
22+
source = "cloudposse/stack-config/yaml//modules/remote-state"
23+
version = "1.5.0"
24+
25+
component = each.value.bucket_component.component
26+
27+
tenant = each.value.bucket_component.tenant
28+
environment = each.value.bucket_component.environment
29+
stage = each.value.bucket_component.stage
30+
31+
context = module.this.context
32+
}
33+
34+
resource "aws_lambda_permission" "s3_notification" {
35+
for_each = var.s3_notifications
36+
37+
statement_id = "AllowS3Invoke"
38+
action = "lambda:InvokeFunction"
39+
function_name = module.lambda.function_name
40+
principal = "s3.amazonaws.com"
41+
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)
42+
source_account = each.value.source_account
43+
}
44+
45+
resource "aws_s3_bucket_notification" "s3_notifications" {
46+
for_each = var.s3_notifications
47+
48+
depends_on = [aws_lambda_permission.s3_notification]
49+
50+
bucket = each.value.bucket_component == null ? each.value.bucket_name : module.s3_bucket_notifications_component[each.key].outputs.bucket_id
51+
52+
lambda_function {
53+
lambda_function_arn = module.lambda.arn
54+
events = each.value.events == null ? ["s3:ObjectCreated:*"] : each.value.events
55+
filter_prefix = each.value.filter_prefix
56+
filter_suffix = each.value.filter_suffix
57+
}
58+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
variable "sqs_notifications" {
2+
type = map(object({
3+
sqs_arn = optional(string)
4+
sqs_component = optional(object({
5+
component = string
6+
environment = optional(string)
7+
tenant = optional(string)
8+
stage = optional(string)
9+
}))
10+
batch_size = optional(number)
11+
source_account = optional(string)
12+
on_failure_arn = optional(string)
13+
maximum_concurrency = optional(number)
14+
}))
15+
description = "A map of SQS queue notifications to trigger the Lambda function"
16+
default = {}
17+
}
18+
19+
module "sqs_queue" {
20+
for_each = { for k, v in var.sqs_notifications : k => v if v.sqs_component != null }
21+
22+
source = "cloudposse/stack-config/yaml//modules/remote-state"
23+
version = "1.5.0"
24+
25+
component = each.value.sqs_component.component
26+
27+
tenant = each.value.sqs_component.tenant
28+
environment = each.value.sqs_component.environment
29+
stage = each.value.sqs_component.stage
30+
31+
context = module.this.context
32+
}
33+
34+
module "sqs_iam_policy" {
35+
for_each = var.sqs_notifications
36+
37+
source = "cloudposse/iam-policy/aws"
38+
version = "1.0.1"
39+
40+
iam_policy_enabled = true
41+
iam_policy = {
42+
version = "2012-10-17"
43+
statements = [
44+
{
45+
effect = "Allow"
46+
actions = ["sqs:ReceiveMessage", "sqs:DeleteMessage", "sqs:GetQueueAttributes"]
47+
resources = each.value.sqs_arn != null ? [each.value.sqs_arn.sqs_arn] : [module.sqs_queue[each.key].outputs.sqs_queue.queue_arn]
48+
},
49+
]
50+
}
51+
context = module.this.context
52+
}
53+
54+
resource "aws_iam_role_policy_attachment" "sqs_default" {
55+
for_each = var.sqs_notifications
56+
57+
role = module.lambda.role_name
58+
policy_arn = module.sqs_iam_policy[each.key].policy_arn
59+
}
60+
61+
resource "aws_lambda_event_source_mapping" "event_source_mapping" {
62+
for_each = var.sqs_notifications
63+
64+
event_source_arn = each.value.sqs_arn != null ? [each.value.sqs_arn.sqs_arn] : module.sqs_queue[each.key].outputs.sqs_queue.queue_arn
65+
function_name = module.lambda.function_name
66+
batch_size = each.value.batch_size == null ? 1 : each.value.batch_size
67+
68+
scaling_config {
69+
maximum_concurrency = each.value.maximum_concurrency
70+
}
71+
dynamic "destination_config" {
72+
for_each = { for k, v in each.value : k => v if k == "on_failure_arn" && v != null }
73+
content {
74+
on_failure {
75+
destination_arn = destination_config.value
76+
}
77+
}
78+
}
79+
80+
depends_on = [aws_iam_role_policy_attachment.sqs_default]
81+
}

0 commit comments

Comments
 (0)