1
votes

I'm trying to create a Terraform module that will build my JS lambdas, zip them and deploy them. This however proves to be problematic

resource "null_resource" "build_lambda" {
  count = length(var.lambdas)

  provisioner "local-exec" {
    command = "mkdir tmp"
    working_dir = path.root
  }

  provisioner "local-exec" {
    command = var.lambdas[count.index].code.build_command
    working_dir = var.lambdas[count.index].code.working_dir
  }
}

data "archive_file" "lambda_zip" {
  count = length(var.lambdas)
  type        = "zip"
  source_dir = var.lambdas[count.index].code.working_dir
  output_path = "${path.root}/tmp/${count.index}.zip"

  depends_on = [
    null_resource.build_lambda
  ]
}

/*******************************************************
* Lambda definition
*******************************************************/
resource "aws_lambda_function" "lambda" {
  count = length(var.lambdas)
  filename = data.archive_file.lambda_zip[count.index].output_path
  source_code_hash = filebase64sha256(data.archive_file.lambda_zip[count.index].output_path)
  function_name = "${var.application_name}-${var.lambdas[count.index].name}"
  description = var.lambdas[count.index].description

  handler = var.lambdas[count.index].handler
  runtime = var.lambdas[count.index].runtime
  role = aws_iam_role.iam_for_lambda.arn
  memory_size = var.lambdas[count.index].memory_size

  depends_on = [aws_iam_role_policy_attachment.lambda_logs, aws_cloudwatch_log_group.log_group, data.archive_file.lambda_zip]
}

The property source_code_hash = filebase64sha256(data.archive_file.lambda_zip[count.index].output_path) , although technically not obligatory, is necessary, or the existing lambda will never get overriden as Terraform will think that it is still the same version of lambda and will skip the deployment altogether. Unfortunately it looks like the method filebase64sha256 is evaluated before the creation of any resource. This means that there is no zip for the hash calculation and so I get the error

Error: Error in function call

  on modules\api-gateway-lambda\main.tf line 35, in resource "aws_lambda_function" "lambda":
  35:   source_code_hash = filebase64sha256(data.archive_file.lambda_zip[count.index].output_path)
    |----------------
    | count.index is 0
    | data.archive_file.lambda_zip is tuple with 1 element

Call to function "filebase64sha256" failed: no file exists at tmp\0.zip.

If i manually place a zip in the right location, I can see that the whole thing starts working and the zip eventually gets overriden by a new one, but the hash in this case must come from the previous zip. What is the right way to execute the whole thing in the right order?

1

1 Answers

3
votes

The archive_file data source has its own output_base64sha256 attribute which can give you that same result without asking Terraform to read a file that doesn't exist yet:

  source_code_hash = data.archive_file.lambda_zip[count.index].output_base64sha256

The data source will populate this at the same time it creates the file, and because your lambda function depends on the data source it will therefore always be available before the lambda function configuration is evaluated.