Terraform: aws_lambda_function requires archive file to be present to plan/apply

Created on 22 Oct 2018  ยท  4Comments  ยท  Source: hashicorp/terraform

Terraform Version

Terraform v0.11.9

  • provider.archive v1.1.0
  • provider.aws v1.24.0

main.tf

```provider "aws" {
region = "eu-west-1"
}

data "archive_file" "testfile" {
type = "zip"
output_path = "test.zip"

source {
content = "1"
filename = "testfile.txt"
}
}

resource "aws_iam_role" "lambda_test_role" {
name = "lambda-test-role"
assume_role_policy = < {
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": [
"arn:aws:logs:*"
]
}
]
}
EOF
}

resource "aws_lambda_function" "test_lambda" {
#depends_on = ["data.archive_file.testfile"]
filename = "test.zip"
function_name = "testing"
role = "${aws_iam_role.lambda_test_role.arn}"
handler = "test.lambda_handler"
source_code_hash = "${base64sha256(file("test.zip"))}"
runtime = "python2.7"
description = "Testing"
timeout = "60"
memory_size = "128"
}
```

Crash Output

Error: aws_lambda_function.test_lambda: 1 error(s) occurred:

  • aws_lambda_function.test_lambda: file: open test.zip: no such file or directory in:

${base64sha256(file("test.zip"))}

Expected Behavior

I would expect it to create the archive and then do the sha check

Actual Behavior

It crashes on plan

Steps to Reproduce

  1. terraform init
  2. terraform plan

Additional Context

https://github.com/hashicorp/terraform/issues/6513 - this looks similar but I can't get it to work. If I touch test.zip then a plan works, however if I delete the file then the plan fails again. I have tried depends_on but that's not working.

References

  • #6513
config question

Most helpful comment

Hi @itunesnosignup,

Unfortunately the built-in functions are evaluated during early configuration language processing and so are not subject to dependency handling: the file function is for reading files that are statically present as part of the configuration, rather than files that are generated along the way. In addition to that, using file() is not necessarily safe with a binary file since it expects the file contents to be UTF-8 encoded text and so the file contents may become corrupted, producing an incorrect hash. (In the forthcoming 0.12 release of Terraform, this would be an error rather than silent corruption.)

The archive_file data source exports its own output_base64sha256 attribute which provides the hash you need here but also lets Terraform know that it must wait until the archive_file has completed before evaluating it, and does not require conversion of the file contents into an in-memory unicode string as the file function does:

resource "aws_lambda_function" "test_lambda" {
  filename         = "${data.archive_file.testfile.output_path}"
  function_name    = "testing"
  role             = "${aws_iam_role.lambda_test_role.arn}"
  handler          = "test.lambda_handler"
  source_code_hash = "${data.archive_file.testfile.output_base64sha256}"
  runtime          = "python2.7"
  description      = "Testing"
  timeout          = "60"
  memory_size      = "128"
}

Note also that since both filename and source_code_hash are populated with references to the data resource there is no need for the explicit depends_on: Terraform can see that the dependency exists automatically.

All 4 comments

Hi @itunesnosignup,

Unfortunately the built-in functions are evaluated during early configuration language processing and so are not subject to dependency handling: the file function is for reading files that are statically present as part of the configuration, rather than files that are generated along the way. In addition to that, using file() is not necessarily safe with a binary file since it expects the file contents to be UTF-8 encoded text and so the file contents may become corrupted, producing an incorrect hash. (In the forthcoming 0.12 release of Terraform, this would be an error rather than silent corruption.)

The archive_file data source exports its own output_base64sha256 attribute which provides the hash you need here but also lets Terraform know that it must wait until the archive_file has completed before evaluating it, and does not require conversion of the file contents into an in-memory unicode string as the file function does:

resource "aws_lambda_function" "test_lambda" {
  filename         = "${data.archive_file.testfile.output_path}"
  function_name    = "testing"
  role             = "${aws_iam_role.lambda_test_role.arn}"
  handler          = "test.lambda_handler"
  source_code_hash = "${data.archive_file.testfile.output_base64sha256}"
  runtime          = "python2.7"
  description      = "Testing"
  timeout          = "60"
  memory_size      = "128"
}

Note also that since both filename and source_code_hash are populated with references to the data resource there is no need for the explicit depends_on: Terraform can see that the dependency exists automatically.

Just throwing an idea here - it seems to me that for these use cases something akin to a provider would be very beneficial.

A bash script that is called before a resource is created could generate the package needed by the lambda resource.

Hello again!

We didn't hear back from you, so I'm going to close this in the hope that a previous response gave you the information you needed. If not, please do feel free to re-open this and leave another comment with the information my human friends requested above. Thanks!

I'm going to lock this issue because it has been closed for _30 days_ โณ. This helps our maintainers find and focus on the active issues.

If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

larstobi picture larstobi  ยท  3Comments

ketzacoatl picture ketzacoatl  ยท  3Comments

ronnix picture ronnix  ยท  3Comments

c4milo picture c4milo  ยท  3Comments

sprokopiak picture sprokopiak  ยท  3Comments