-
Notifications
You must be signed in to change notification settings - Fork 9.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
depends_on should should defer interpolation #22036
Comments
Hi @mutt13y, The various functions with We generally recommend against using Terraform to generate temporary artifacts locally, since that isn't really what it is for. We offer the facilities to do so because we're pragmatic and want to enable users to do some things that are slightly outside of Terraform's scope when needed, but the experience when doing so won't necessarily be smooth. If generating the zip file as part of the |
Hi @apparentlymart, Stuart |
Provisioners in general are a sort of "last resort" feature for doing small fixups after an object is created that don't otherwise fit into Terraform's declarative model. For example, in some environments it's impractical to customize machine images so that compute instances can immediately start their work on boot, and so provisioners can fill that gap by allowing last-moment initialization to happen on the remote host. As an example for Where possible though, Terraform prefers to think of infrastructure objects as a sort of "appliance" that just starts immediately doing its job as soon as it's created. For managed services that sort of behavior tends to come for free. For services you deploy yourself into a generic virtual machine that will generally require a custom machine image and a feature like EC2's They can also be used for things that I might claim Terraform shouldn't be used for, such as generating artifacts for deployment, because that's just the nature of general features like that. The Terraform team is generally pragmatic about folks using these features to get things done even if it wasn't something the feature was intended for, but that doesn't mean that these unintended uses will come without friction. Another feature in Terraform that exists to be pragmatic about this sort of unintended use case is the I think it would still be better to separate artifact creation from provisioning though, because that has other benefits: you can build and test those artifacts using a CI system as is normally done for code to be deployed, and you can keep a historical tail of older artifacts to roll back to in the event of a problem, etc. There's a more specific suggestion for one way to set this up in the guide Serverless Applications with AWS Lambda and API Gateway. Even if your use-case doesn't include an API portion, the part about deploying the lambda function could still be relevant/useful. |
I would also like to see this kind of behaviour added. We currently use the null_resource and local-exec provisioner to copy some files from a GCS bucket to the local machine. The content of these files which are being copied are used in a later step to create some kubernetes secrets. Although we specify that the kubernetes secret resource is dependent on the local-exec command, it doesn't wait for the local-exec to finish. This results in an error that the file to create the kubernetes secret resource does not exist. We don't necessarily create artifacts during the Terraform run, but we are very reliant on certain remote files which need to be pulled in during the run. |
I ended up writing a Makefile, you could use concourse as a better alternative. I do end up wondering what the actual use case for the local-exec is if we cant control when it runs. |
Well as I read the above comment it is only intended for small fixes, not for actual resource creation. We looked at using Vault, but it currently is overkill to set up and maintain a whole client/server application just for our secrets. |
There's going to be a lot of people wanting this use case when working with lambda, exactly as the OP is doing. The original request:
seems pretty fair and straightforward to me. ED: Although, I notice
I have no idea what "Used to trigger updates" is supposed to mean but my terraform does apply without it. ED: also for the OP's use case https://www.terraform.io/docs/providers/archive/d/archive_file.html would be better |
I personally think that the expectation that developers should run additional build steps, in an infrastructure repository, besides The syntax of |
I managed to make this work with an empty zip file. |
I'd like to add an example use case to this old issue for posterity sake. We have a reusable module for deploying Lambda functions that can take either a list of source files, a directory of source files, or an S3 bucket and key to download the prepackaged source files. The module uses It works, but the source_code_hash variable is the trickiest part due to the issue at hand. Snippet: locals {
package = "${path.module}/package.zip"
}
data "archive_file" "dir" {
count = var.source_dir != null ? 1 : 0
type = "zip"
source_dir = var.source_dir
output_path = local.package
}
data "archive_file" "files" {
count = length(var.source_files) > 0 ? 1 : 0
type = "zip"
output_path = local.package
dynamic "source" {
for_each = toset(var.source_files)
content {
content = file(source.value)
filename = basename(source.value)
}
}
}
data "external" "download_package" {
count = var.download_package ? 1 : 0
program = [
"aws", "s3api", "get-object", "--bucket=${var.package_s3_bucket}", "--key=${var.package_s3_key}", local.package,
# The query is used to provide external with a string only JSON output which it requires to work.
"--query={LastModified:LastModified}", "--output=json",
]
}
data "local_file" "package" {
depends_on = [
data.archive_file.dir,
data.archive_file.files,
data.external.download_package,
]
filename = var.local_package != null ? var.local_package : local.package
}
resource "aws_lambda_function" "this" {
depends_on = [
data.local_file.package,
]
filename = data.local_file.package.filename
source_code_hash = var.ignore_source_code_changes ? null : filebase64sha256(data.local_file.package.filename)
...
} The above works IF the package zip has already been generated and needs no update, but does not work otherwise. The workaround below is sort of working, but causes the lambda to redeploy with every plan. resource "aws_lambda_function" "this" {
depends_on = [
data.local_file.package,
]
filename = data.local_file.package.filename
source_code_hash = var.ignore_source_code_changes ? null : base64sha256(data.local_file.package.content_base64)
...
} |
Hi @zachwhaley! Thanks for sharing that use-case and partial workaround. I think the reason your workaround causes the configuration to be non-converging is because The result is therefore syntactically valid (it's a base64-encoded SHA256 hash) but it's not semantically valid: it's a hash of the wrong source content, so it can never match. Terraform doesn't currently have a function for generating a SHA256 hash of some binary data given as a base64 string, so I don't have a suggestion about how to adapt what you described here to make it work, but just wanted to note that the workaround here is failing for a reason other than what this issue is proposing. The Your comment here makes me realize that the The |
Returning to this much later: I notice that my Resources (which includes "data resources", declared by Functions like Skipping expression evaluation until all dependencies have been resolved would amount to planning and applying only one resource at a time, because we cannot plan changes for a resource without evaluating its configuration. Therefore I don't think the direct request of this issue is viable, but the following adaptation of the original example should get the desired result using the resource "null_resource" "lambda" {
provisioner "local-exec" {
command = "cd lambda; zip -u git_hook.zip git_hook.py"
}
}
data "local_file" "lambda" {
filename = "lambda/git_hook.zip"
depends_on = [null_resource.lambda]
}
resource "aws_lambda_function" "git_hook" {
filename = "lambda/git_hook.zip"
function_name = "git_hook_sqs"
role = aws_iam_role.iam_for_lambda.arn
handler = "lambda_handler"
source_code_hash = data.local_file.lambda.content_base64sha256
runtime = "python3.7"
environment {
variables = {
foo = "bar"
}
}
} The direct dependency between Those who are interested in creating |
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. |
Current Terraform Version
Use-cases
interpolation functions should not run until the depended_on resource has completed.
Because that resource may change the environment.
Attempted Solutions
This immediately fails with
Call to function "filebase64sha256" failed: no file exists at lambda/git_hook.zip
Proposal
depends_on should be transitive
current plan
should be
References
The text was updated successfully, but these errors were encountered: