8
votes

I am trying to create an AWS lambda Function using terraform. My terraform directory looks like

  • terraform
    • iam-policies
      • main.tf
    • lambda
      • files/
      • main.tf
    • main.tf

I have my lambda function stored inside /terraform/lambda/files/lambda_function.py.

Whenever I terraform apply, I have a "null_resource" that executes some commands in local machine that will zip the python file

variable "pythonfile" {
  description = "lambda function python filename"
  type        = "string"
}

resource "null_resource" "lambda_preconditions" {
  triggers {
    always_run = "${uuid()}"
  }
  provisioner "local-exec" {
    command = "rm -rf ${path.module}/files/zips"
  }
  provisioner "local-exec" {
    command = "mkdir -p ${path.module}/files/zips"
  }
  provisioner "local-exec" {
    command = "cp -R ${path.module}/files/${var.pythonfile} ${path.module}/files/zips/lambda_function.py"
  }
  provisioner "local-exec" {
    command = "cd ${path.module}/files/zips && zip -r lambda.zip ."
  }
}

My "aws_lambda_function" resource looks like this.

resource "aws_lambda_function" "lambda_function" {
  filename         = "${path.module}/files/zips/lambda.zip"
  function_name    = "${format("%s-%s-%s-lambda-function", var.name, var.environment, var.function_name)}"
  role             = "${aws_iam_role.iam_for_lambda.arn}"
  handler          = "lambda_function.lambda_handler"
  source_code_hash = "${base64sha256(format("%s/files/zips/lambda.zip", path.module))}", length(path.cwd) + 1, -1)}")}"
  runtime          = "${var.function_runtime}"
  timeout          = "${var.function_timeout}"
  memory_size      = "${var.function_memory}"

  environment {
    variables = {
      region      = "${var.region}"
      name        = "${var.name}"
      environment = "${var.environment}"
    }
  }

  vpc_config {
    subnet_ids         = ["${var.subnet_ids}"]
    security_group_ids = ["${aws_security_group.lambda_sg.id}"]
  }

  depends_on = [
    "null_resource.lambda_preconditions"
  ]
}

Problem: Whenever I change the lambda_function.py file and terraform apply again, everything works fine but the actual code in the lambda function do not change. Also if I delete all the terraform state files and apply again, the new change is propagated without any problem.

What could be the possible reason for this?

1
Can you precise "everything works fine but the actual code in the lambda function do not change"? Because it seems like everything is not working fine here (at least, not what you expect). What is the output of terraform apply when you make a change to lambda_function.py? Does it creates a new zip? Does it update lambda_function resource?norbjd
@norbjd whenever I fresh terraform apply, it creates the zip file and uploads the code to lambda without any errors. But when I change the code in the lambda_function.py and terraform apply, the expected result would be an update in the function code in the Lambda console. But actually, the change in the lambda_function.py is not propagated to the lambda function. There is no error in second attempt.Manoj Acharya
Is the zip with updated code created by the second terraform apply?norbjd
@norbjd yes, the second apply creates the updated zip but somehow the code in Lambda isn't changed. I checked the zip also has updated code in it.Manoj Acharya
By the way, the source_code_hash syntax is wrong (not the same number of closing parentheses/brackets as opening). After the first apply, what is its computed value? If after the second apply the source_code_hash is the same, that's why the lambda is not updated (because other computed arguments are the same).norbjd

1 Answers

7
votes

Instead of using null_resource, I used the archive_file data source that creates the zip file automatically if new changes are detected. Next I took a reference from the archive_file data in the lambda resource source_code_hash attribute.

archive_file data source

data "archive_file" "lambda_zip" {
  type        = "zip"
  output_path = "${path.module}/files/zips/lambda.zip"

  source {
    content  = "${file("${path.module}/files/ebs_cleanup_lambda.py")}"
    filename = "lambda_function.py"
  }
}

The lambda resource

resource "aws_lambda_function" "lambda_function" {
  filename         = "${path.module}/files/zips/lambda.zip"
  function_name    = "${format("%s-%s-%s-lambda-function", var.name, var.environment, var.function_name)}"
  role             = "${aws_iam_role.iam_for_lambda.arn}"
  handler          = "lambda_function.lambda_handler"
  source_code_hash = "${data.archive_file.lambda_zip.output_base64sha256}"
  runtime          = "${var.function_runtime}"
  timeout          = "${var.function_timeout}"
  memory_size      = "${var.function_memory}"

  environment {
    variables = {
      region      = "${var.region}"
      name        = "${var.name}"
      environment = "${var.environment}"
    }
  }

  vpc_config {
    subnet_ids         = ["${var.subnet_ids}"]
    security_group_ids = ["${aws_security_group.lambda_sg.id}"]
  }
}