4 min read | by Jordi Prats
To be able to deploy a lambda function there are several pieces that need to be deployed:
First we are going to create the IAM role that's going to use out lambda function. We'll have to take into account that the call will come form the lambda service so the IAM role needs to be set accordingly:
data "aws_iam_policy_document" "lambda_assume_role_policy_doc" {
statement {
actions = ["sts:AssumeRole"]
effect = "Allow"
principals {
type = "Service"
identifiers = [ "lambda.amazonaws.com" ]
}
}
}
resource "aws_iam_role" "example_lambda" {
name = "${var.appname}-packer-cleanup-lambda"
path = "/cl/app/${var.appname}/"
assume_role_policy = data.aws_iam_policy_document.lambda_assume_role_policy_doc.json
force_detach_policies = true
}
resource "aws_iam_policy" "example_ec2_operations" {
name = "${var.appname}-packer-cleanup-ec2-operations-policy"
policy = jsonencode({
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ec2:*",
],
"Resource": [
"*",
]
}
]
})
}
resource "aws_iam_role_policy_attachment" "attach_iam_policy_to_iam_role" {
count = try(var.config.example, false) ? 1 : 0
role = aws_iam_role.example_lambda.name
policy_arn = aws_iam_policy.example_ec2_operations.arn
}
To trigger this function we are going to use a CloudWatch event that's going to be triggered everyday at midnight (UTC):
resource "aws_cloudwatch_event_rule" "every_day" {
name = "every-day"
description = "Fires every day at 8:00 UTC"
schedule_expression = "cron(0 0 * * ? *)"
}
resource "aws_cloudwatch_event_target" "example_lambda_every_five_minutes" {
rule = aws_cloudwatch_event_rule.every_day.name
arn = aws_lambda_function.example_lambda.arn
}
resource "aws_lambda_permission" "allow_cloudwatch_to_call_example_lambda" {
statement_id = "AllowExecutionFromCloudWatch"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.example_lambda.function_name
principal = "events.amazonaws.com"
source_arn = aws_cloudwatch_event_rule.every_day.arn
}
To use a simple example for a lambda we are going to use the following python code that will just return a list of instance-id and it's state. We'll need the name of the function and it's file name:
def lambda_handler(event, context):
ret_val = []
try:
ec2 = boto3.client('ec2', region_name='eu-west-1')
response = ec2.describe_instances(Filters=instance_filter)
for reservation in response['Reservations']:
for instance in reservation["Instances"]:
ret_val.append({'instance_id': instance["InstanceId"], 'state': instance["State"]["Name"]})
except:
pass
return ret_val
Let's assume we have the code on a folder witting our terraform code called lambda/simple_example. We are going to name our file handler. The name of the handler (handler option) is going to be the file name and the name of the function we want to call. So, for this example it's going to be handler.lambda_handler
Then, we are going to tell terraform to generate a zip file on lambda/simple_example.zip (notice how it is outside of the code itself)
To finally, put all the pieces together with the aws_lambda_function resource:
data "archive_file" "zip_example" {
type = "zip"
source_dir = "${path.module}/lambda/simple_example/"
output_path = "${path.module}/lambda/simple_example.zip"
}
resource "aws_lambda_function" "example_lambda" {
filename = data.archive_file.zip_example.output_path
source_code_hash = data.archive_file.zip_example.output_base64sha256
role = aws_iam_role.example_lambda.arn
function_name = "example_lambda_fx"
handler = "handler.lambda_handler"
runtime = "python3.8"
timeout = "600"
reserved_concurrent_executions = 1
}
We can now wait for the trigger to execute it, or use the console to test the function: We can find it clicking on the function and then on the Test tab there is a Test button
Posted on 05/05/2022