我正在尝试使用 Terragrunt 部署 AWS Lambda 函数,而不附加 zip 包。目标是使用基本配置创建功能并直接通过 Terragrunt 进行管理。
我尝试在 _common/lambdas.yml 中设置
create_package: false
,但 Terragrunt 抛出错误 Could not located source_path "null"。我尝试使用带有 local_existing_package: "./dummy.zip" 和ignore_source_code_hash: true 的虚拟包,但错误仍然存在。
这是我的配置:
第一次尝试,_common/lambdas.yml:
- function_name: test-function
create_package: false
description: "test-function"
handler: "lambda_handler"
runtime: "python3.9"
memory_size: 128
第二次尝试,_common/lambdas.yml:
- function_name: test-function
create_package: false
local_existing_package: "./dummy.zip"
ignore_source_code_hash: true
description: "test-function"
handler: "lambda_handler"
runtime: "python3.9"
memory_size: 128
terragrunt 初始化:
$ terragrunt init
10:05:37.299 INFO Downloading Terraform configurations from git::ssh://[email protected]/terraform-aws-modules/terraform-aws-lambda.git?ref=v7.10.0 into ./.terragrunt-cache/Is4Dzy3Iy9H51bjZPDSOxArR0SA/aFgDcKCtTXEYjkO24zjTsyaNIuc
10:05:38.244 STDOUT terraform: Initializing the backend...
10:05:38.351 STDOUT terraform:
10:05:38.351 STDOUT terraform: Successfully configured the backend "s3"! Terraform will automatically
10:05:38.351 STDOUT terraform: use this backend unless the backend configuration changes.
10:05:38.448 STDOUT terraform: Initializing modules...
10:05:38.464 STDOUT terraform: - wrapper in ..
10:05:38.476 STDOUT terraform: Initializing provider plugins...
10:05:38.476 STDOUT terraform: - Finding hashicorp/aws versions matching ">= 5.32.0"...
10:05:38.500 STDOUT terraform: - Finding hashicorp/external versions matching ">= 1.0.0"...
10:05:38.508 STDOUT terraform: - Finding hashicorp/local versions matching ">= 1.0.0"...
10:05:38.517 STDOUT terraform: - Finding hashicorp/null versions matching ">= 2.0.0"...
10:05:38.550 STDOUT terraform: - Installing hashicorp/external v2.3.4...
10:05:38.733 STDOUT terraform: - Installed hashicorp/external v2.3.4 (signed by HashiCorp)
10:05:38.752 STDOUT terraform: - Installing hashicorp/local v2.5.2...
10:05:38.934 STDOUT terraform: - Installed hashicorp/local v2.5.2 (signed by HashiCorp)
10:05:38.953 STDOUT terraform: - Installing hashicorp/null v3.2.3...
10:05:39.138 STDOUT terraform: - Installed hashicorp/null v3.2.3 (signed by HashiCorp)
10:05:39.157 STDOUT terraform: - Installing hashicorp/aws v5.75.0...
10:05:44.145 STDOUT terraform: - Installed hashicorp/aws v5.75.0 (signed by HashiCorp)
10:05:44.145 STDOUT terraform: Terraform has created a lock file .terraform.lock.hcl to record the provider
10:05:44.145 STDOUT terraform: selections it made above. Include this file in your version control repository
10:05:44.145 STDOUT terraform: so that Terraform can guarantee to make the same selections by default when
10:05:44.145 STDOUT terraform: you run "terraform init" in the future.
10:05:44.146 STDOUT terraform: Terraform has been successfully initialized!
10:05:44.146 STDOUT terraform:
10:05:44.146 STDOUT terraform: You may now begin working with Terraform. Try running "terraform plan" to see
10:05:44.146 STDOUT terraform: any changes that are required for your infrastructure. All Terraform commands
10:05:44.146 STDOUT terraform: should now work.
10:05:44.146 STDOUT terraform: If you ever set or change modules or backend configuration for Terraform,
10:05:44.146 STDOUT terraform: rerun this command to reinitialize your working directory. If you forget, other
10:05:44.146 STDOUT terraform: commands will detect it and remind you to do so if necessary.
terragrunt 计划(两次尝试底部的错误消息相同):
$ terragrunt plan
10:05:53.568 STDOUT terraform: module.wrapper["function-name"].data.external.archive_prepare[0]: Reading...
10:05:54.466 STDOUT terraform: module.wrapper["function-name"].data.aws_caller_identity.current: Reading...
10:05:54.467 STDOUT terraform: module.wrapper["function-name"].data.aws_region.current: Reading...
10:05:54.467 STDOUT terraform: module.wrapper["function-name"].data.aws_iam_policy_document.assume_role[0]: Reading...
10:05:54.468 STDOUT terraform: module.wrapper["function-name"].data.aws_partition.current: Reading...
10:05:54.469 STDOUT terraform: module.wrapper["function-name"].data.aws_region.current: Read complete after 0s [id=us-east-1]
10:05:54.470 STDOUT terraform: module.wrapper["function-name"].data.aws_partition.current: Read complete after 0s [id=aws]
10:05:54.470 STDOUT terraform: module.wrapper["function-name"].data.aws_iam_policy_document.assume_role[0]: Read complete after 0s [id=2690255455]
10:05:54.470 STDOUT terraform: module.wrapper["function-name"].data.aws_caller_identity.current: Read complete after 0s [id=0***055]
10:05:54.609 STDOUT terraform: Terraform used the selected providers to generate the following execution
10:05:54.609 STDOUT terraform: plan. Resource actions are indicated with the following symbols:
10:05:54.609 STDOUT terraform: + create
10:05:54.609 STDOUT terraform: <= read (data resources)
10:05:54.609 STDOUT terraform: Terraform planned the following actions, but then encountered a problem:
10:05:54.609 STDOUT terraform: # module.wrapper["function-name"].data.aws_iam_policy_document.logs[0] will be read during apply
10:05:54.609 STDOUT terraform: # (config refers to values not yet known)
10:05:54.609 STDOUT terraform: <= data "aws_iam_policy_document" "logs" {
10:05:54.609 STDOUT terraform: + id = (known after apply)
10:05:54.609 STDOUT terraform: + json = (known after apply)
10:05:54.609 STDOUT terraform: + minified_json = (known after apply)
10:05:54.609 STDOUT terraform: + statement {
10:05:54.609 STDOUT terraform: + actions = [
10:05:54.609 STDOUT terraform: + "logs:CreateLogGroup",
10:05:54.609 STDOUT terraform: + "logs:CreateLogStream",
10:05:54.609 STDOUT terraform: + "logs:PutLogEvents",
10:05:54.609 STDOUT terraform: ]
10:05:54.609 STDOUT terraform: + effect = "Allow"
10:05:54.609 STDOUT terraform: + resources = (known after apply)
10:05:54.609 STDOUT terraform: }
10:05:54.609 STDOUT terraform: }
10:05:54.609 STDOUT terraform: # module.wrapper["function-name"].aws_cloudwatch_log_group.lambda[0] will be created
10:05:54.609 STDOUT terraform: + resource "aws_cloudwatch_log_group" "lambda" {
10:05:54.609 STDOUT terraform: + arn = (known after apply)
10:05:54.609 STDOUT terraform: + id = (known after apply)
10:05:54.609 STDOUT terraform: + log_group_class = (known after apply)
10:05:54.609 STDOUT terraform: + name = "/aws/lambda/function-name"
10:05:54.609 STDOUT terraform: + name_prefix = (known after apply)
10:05:54.609 STDOUT terraform: + retention_in_days = 0
10:05:54.609 STDOUT terraform: + skip_destroy = false
10:05:54.609 STDOUT terraform: + tags = {
10:05:54.609 STDOUT terraform:
10:05:54.609 STDOUT terraform: }
10:05:54.609 STDOUT terraform: }
10:05:54.609 STDOUT terraform: # module.wrapper["function-name"].aws_iam_policy.logs[0] will be created
10:05:54.610 STDOUT terraform: + resource "aws_iam_policy" "logs" {
10:05:54.610 STDOUT terraform: + arn = (known after apply)
10:05:54.610 STDOUT terraform: + attachment_count = (known after apply)
10:05:54.610 STDOUT terraform: + id = (known after apply)
10:05:54.610 STDOUT terraform: + name = "function-name-logs"
10:05:54.610 STDOUT terraform: + name_prefix = (known after apply)
10:05:54.610 STDOUT terraform: + path = "/"
10:05:54.610 STDOUT terraform: + policy = (known after apply)
10:05:54.610 STDOUT terraform: + policy_id = (known after apply)
10:05:54.610 STDOUT terraform: + tags = {
10:05:54.610 STDOUT terraform:
10:05:54.610 STDOUT terraform: }
10:05:54.610 STDOUT terraform: }
10:05:54.610 STDOUT terraform: # module.wrapper["function-name"].aws_iam_role.lambda[0] will be created
10:05:54.610 STDOUT terraform: + resource "aws_iam_role" "lambda" {
10:05:54.610 STDOUT terraform: + arn = (known after apply)
10:05:54.610 STDOUT terraform: + assume_role_policy = jsonencode(
10:05:54.610 STDOUT terraform: {
10:05:54.610 STDOUT terraform: + Statement = [
10:05:54.610 STDOUT terraform: + {
10:05:54.610 STDOUT terraform: + Action = "sts:AssumeRole"
10:05:54.610 STDOUT terraform: + Effect = "Allow"
10:05:54.610 STDOUT terraform: + Principal = {
10:05:54.610 STDOUT terraform: + Service = "lambda.amazonaws.com"
10:05:54.610 STDOUT terraform: }
10:05:54.610 STDOUT terraform: },
10:05:54.610 STDOUT terraform: ]
10:05:54.610 STDOUT terraform: + Version = "2012-10-17"
10:05:54.610 STDOUT terraform: }
10:05:54.610 STDOUT terraform: )
10:05:54.610 STDOUT terraform: + create_date = (known after apply)
10:05:54.610 STDOUT terraform: + force_detach_policies = true
10:05:54.610 STDOUT terraform: + id = (known after apply)
10:05:54.610 STDOUT terraform: + managed_policy_arns = (known after apply)
10:05:54.610 STDOUT terraform: + max_session_duration = 3600
10:05:54.610 STDOUT terraform: + name = "function-name"
10:05:54.610 STDOUT terraform: + name_prefix = (known after apply)
10:05:54.610 STDOUT terraform: + path = "/"
10:05:54.610 STDOUT terraform: + tags = {
10:05:54.610 STDOUT terraform:
10:05:54.611 STDOUT terraform: }
10:05:54.611 STDOUT terraform: + unique_id = (known after apply)
10:05:54.611 STDOUT terraform: }
10:05:54.611 STDOUT terraform: # module.wrapper["function-name"].aws_iam_role_policy_attachment.logs[0] will be created
10:05:54.611 STDOUT terraform: + resource "aws_iam_role_policy_attachment" "logs" {
10:05:54.611 STDOUT terraform: + id = (known after apply)
10:05:54.611 STDOUT terraform: + policy_arn = (known after apply)
10:05:54.611 STDOUT terraform: + role = "function-name"
10:05:54.611 STDOUT terraform: }
10:05:54.611 STDOUT terraform: Plan: 4 to add, 0 to change, 0 to destroy.
10:05:54.611 STDOUT terraform:
10:05:54.611 STDERR terraform: ╷
10:05:54.611 STDERR terraform: │ Error: External Program Execution Failed
10:05:54.611 STDERR terraform: │
10:05:54.611 STDERR terraform: │ with module.wrapper["function-name"].data.external.archive_prepare[0],
10:05:54.611 STDERR terraform: │ on ../package.tf line 10, in data "external" "archive_prepare":
10:05:54.611 STDERR terraform: │ 10: program = [local.python, "${path.module}/package.py", "prepare"]
10:05:54.611 STDERR terraform: │
10:05:54.611 STDERR terraform: │ The data source received an unexpected error while attempting to execute
10:05:54.611 STDERR terraform: │ the program.
10:05:54.611 STDERR terraform: │
10:05:54.611 STDERR terraform: │ Program: /usr/bin/python3
10:05:54.611 STDERR terraform: │ Error Message: Could not locate source_path "null". Paths are relative to
10:05:54.611 STDERR terraform: │ directory where `terraform plan` is being run
10:05:54.611 STDERR terraform: │ ("./.terragrunt-cache/Is4Dzy3Iy9H51bjZPDSOxArR0SA/aFgDcKCtTXEYjkO24zjTsyaNIuc/wrappers")
10:05:54.611 STDERR terraform: │
10:05:54.611 STDERR terraform: │ State: exit status 1
10:05:54.611 STDERR terraform: ╵
10:05:54.708 ERROR terraform invocation failed in ./.terragrunt-cache/Is4Dzy3Iy9H51bjZPDSOxArR0SA/aFgDcKCtTXEYjkO24zjTsyaNIuc/wrappers stderr=
╷
│ Error: External Program Execution Failed
│
│ with module.wrapper["function-name
"].data.external.archive_prepare[0],
│ on ../package.tf line 10, in data "external" "archive_prepare":
│ 10: program = [local.python, "${path.module}/package.py", "prepare"]
│
│ The data source received an unexpected error while attempting to execute
│ the program.
│
│ Program: /usr/bin/python3
│ Error Message: Could not locate source_path "null". Paths are relative to
│ directory where `terraform plan` is being run
│ ("./.terragrunt-cache/Is4Dzy3Iy9H51bjZPDSOxArR0SA/aFgDcKCtTXEYjkO24zjTsyaNIuc/wrappers")
│
│ State: exit status 1
╵
10:05:54.709 ERROR 1 error occurred:
* [./.terragrunt-cache/Is4Dzy3Iy9H51bjZPDSOxArR0SA/aFgDcKCtTXEYjkO24zjTsyaNIuc/wrappers] exit status 1
terragrunt.hcl 用于 lambda:(我有用于提供程序等的 root terragrunt)
include "root" {
path = find_in_parent_folders()
expose = true
}
include "lambda" {
path = find_in_parent_folders("modules/lambda.hcl")
expose = true
}
locals {
# Load the Lambda configurations from _common/lambdas.yaml
def = merge(
yamldecode(
file(find_in_parent_folders("_common/lambdas.yaml", "{}")),
)
)
# Set the `all_lambdas` list directly from the loaded `def` variable
all_lambdas = "${local.def.commonlambdas}"
# Construct the Lambda functions map with convention-based naming
lambdas = try({
for lambda in "${local.all_lambdas}":
"${include.root.locals.convention-naming}-${lambda.function_name}" => merge(
{ function_name = "${include.root.locals.convention-naming}-${lambda.function_name}"
#Source_path = lambda.source_path
},
try("${lambda.options}", {})
)
}, {})
}
inputs = {
# Default tags and other inputs shared across Lambdas
defaults = {
tags = "${include.root.locals.default_tags}"
}
# Lambda items to be processed
items = "${local.lambdas}"
}
terragrunt.hcl(根):
locals {
default_yaml_path = find_in_parent_folders("empty.yaml")
def = merge(
{
enable_secrets = true
},
yamldecode(
file(find_in_parent_folders("tier.yaml", local.default_yaml_path)),
),
yamldecode(
file(find_in_parent_folders("env.yaml", local.default_yaml_path)),
),
yamldecode(
file(find_in_parent_folders("regional.yaml", local.default_yaml_path)),
),
yamldecode(
file(find_in_parent_folders("_common/common.yaml", local.default_yaml_path)),
),
yamldecode(
file("${get_terragrunt_dir()}/deploy.yaml"),
)
)
default_tags = merge(local.def.default_tags,
{ "provider_account" : local.def.provider_account,
"Env" : local.def.env, "Environment" : local.def.env,
"Rgn": local.def.rgn , "Tier" : local.def.tier })
convention-naming = "c9-${local.def.env}-${local.def.rgn}"
}
generate "provider" {
path = "provider.tf"
if_exists = "overwrite_terragrunt"
contents = <<EOF
provider "aws" {
assume_role {
role_arn = "arn:aws:iam::${local.def.account_id}:role/Admin"
}
region = "${local.def.region}"
}
EOF
}
remote_state {
backend = "s3"
generate = {
path = "backend.tf"
if_exists = "overwrite_terragrunt"
}
config = {
bucket = "c9-${local.def.tier}-terragrunt"
key = "${path_relative_to_include()}/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "c9-${local.def.tier}-terragrunt-lock-table"
acl = "bucket-owner-full-control"
role_arn = "arn:aws:iam::${local.def.account_id}:role/Admin"
}
}
inputs = merge(
yamldecode(
file(find_in_parent_folders("tier.yaml", local.default_yaml_path)),
),
yamldecode(
file(find_in_parent_folders("env.yaml", local.default_yaml_path)),
),
yamldecode(
file(find_in_parent_folders("regional.yaml", local.default_yaml_path)),
),
yamldecode(
file(find_in_parent_folders("_common/common.yaml", local.default_yaml_path)),
),
yamldecode(
file("${get_terragrunt_dir()}/deploy.yaml"),
)
文件树/结构:
repo
├── terragrunt.hcl
├── _common
│ └── lambdas.yaml
└── dev
└── dev4
└── use1
└── lambda
├── dummy.zip
├── deploy.yaml
└── terragrunt.hcl
deploy.yaml 为空,所有函数都将位于 _common/lambdas.yaml 中。此设置是公司创建/迁移资源的方式,因此我无法更改它。
我相信您遇到这个问题是因为 archive_prepare 步骤,尝试找到用于打包的 source_path,即使您试图绕过它。 因此 AWS Lambda 模块 common/lambdas.yaml 中的 archive_prepare 进程需要 source_path 变量。 因此,您要么提供一个 source_path,Terraform 会尝试将其打包到一个 zip 文件中,要么直接提供一个文件名来指向您的 dummy.zip:
- function_name: test-function
create_package: false
filename: "./dummy.zip" # Point to the dummy package
ignore_source_code_hash: true
description: "test-function"
handler: "lambda_handler"
runtime: "python3.9"
memory_size: 128