如何使用 Terraform 模块的输出作为另一个 Terraform 模块的输入?

发布于 2025-01-19 03:01:41 字数 2774 浏览 2 评论 0原文

我正在编写 Terraform 来部署 S3 存储桶和 lambda。需要 S3 存储桶,因为这是存储 zip 对象以准备部署到 lambda 的位置。

我的顶级 main.tf 中有两个模块:

module "s3" {
  count  = var.enable_s3 ? 1 : 0
  source = "./modules/s3"
}

module "lambdas" {
  count     = var.enable_lambdas ? 1 : 0
  source    = "./modules/lambdas"
  bucket_id = module.s3.lambda_bucket_id
}

模块:

main.tfoutputs.tf

resource "aws_s3_bucket" "lambda_bucket" {
  bucket = "lunchboxd-lambdas"

  tags = {
    Owner       = "Terraform",
    Description = "A bucket to hold the lambdas zip"
  }
}

s3

output "lambda_bucket_id" {
  value       = aws_s3_bucket.lambda_bucket.id
  description = "ID of the bucket holding the lambda functions."
}

lambdas 模块:

variables.tf

variable "bucket_id" {}

main.tf

data "archive_file" "lambda_hello_world" {
  type = "zip"

  source_dir  = "${path.module}/hello-world"
  output_path = "${path.module}/hello-world.zip"
}

resource "aws_s3_object" "lambda_hello_world" {
  bucket = var.bucket_id

  key    = "hello-world.zip"
  source = data.archive_file.lambda_hello_world.output_path

  etag = filemd5(data.archive_file.lambda_hello_world.output_path)
}


resource "aws_lambda_function" "hello_world" {
  function_name = "HelloWorld"

  s3_bucket = var.bucket_id
  s3_key    = aws_s3_object.lambda_hello_world.key

  runtime = "nodejs12.x"
  handler = "hello.handler"

  source_code_hash = data.archive_file.lambda_hello_world.output_base64sha256

  role = aws_iam_role.lambda_exec.arn
}

resource "aws_cloudwatch_log_group" "hello_world" {
  name = "/aws/lambda/${aws_lambda_function.hello_world.function_name}"

  retention_in_days = 30
}

resource "aws_iam_role" "lambda_exec" {
  name = "serverless_lambda"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Action = "sts:AssumeRole"
      Effect = "Allow"
      Sid    = ""
      Principal = {
        Service = "lambda.amazonaws.com"
      }
      }
    ]
  })
}

resource "aws_iam_role_policy_attachment" "lambda_policy" {
  role       = aws_iam_role.lambda_exec.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}

当我尝试验证我的 terraform 时,出现以下错误:

╷
│ Error: Unsupported attribute
│ 
│   on main.tf line 36, in module "lambdas":
│   36:   bucket_id = module.s3.aws_s3_bucket.lambda_bucket.id
│     ├────────────────
│     │ module.s3 is a list of object, known only after apply
│ 
│ Can't access attributes on a list of objects. Did you mean to access an attribute for a specific element of the list, or across all elements of the list?
╵

我已遵循文档关于输出和模块组成,但我不确定我做错了什么。感谢所有帮助。

I am writing Terraform to deploy an S3 bucket and a lambda. The S3 bucket is needed as this is where the zip object will be stored ready to deploy to lambda.

I have two modules in my top-level main.tf:

module "s3" {
  count  = var.enable_s3 ? 1 : 0
  source = "./modules/s3"
}

module "lambdas" {
  count     = var.enable_lambdas ? 1 : 0
  source    = "./modules/lambdas"
  bucket_id = module.s3.lambda_bucket_id
}

s3 module:

main.tf

resource "aws_s3_bucket" "lambda_bucket" {
  bucket = "lunchboxd-lambdas"

  tags = {
    Owner       = "Terraform",
    Description = "A bucket to hold the lambdas zip"
  }
}

outputs.tf

output "lambda_bucket_id" {
  value       = aws_s3_bucket.lambda_bucket.id
  description = "ID of the bucket holding the lambda functions."
}

lambdas module:

variables.tf

variable "bucket_id" {}

main.tf

data "archive_file" "lambda_hello_world" {
  type = "zip"

  source_dir  = "${path.module}/hello-world"
  output_path = "${path.module}/hello-world.zip"
}

resource "aws_s3_object" "lambda_hello_world" {
  bucket = var.bucket_id

  key    = "hello-world.zip"
  source = data.archive_file.lambda_hello_world.output_path

  etag = filemd5(data.archive_file.lambda_hello_world.output_path)
}


resource "aws_lambda_function" "hello_world" {
  function_name = "HelloWorld"

  s3_bucket = var.bucket_id
  s3_key    = aws_s3_object.lambda_hello_world.key

  runtime = "nodejs12.x"
  handler = "hello.handler"

  source_code_hash = data.archive_file.lambda_hello_world.output_base64sha256

  role = aws_iam_role.lambda_exec.arn
}

resource "aws_cloudwatch_log_group" "hello_world" {
  name = "/aws/lambda/${aws_lambda_function.hello_world.function_name}"

  retention_in_days = 30
}

resource "aws_iam_role" "lambda_exec" {
  name = "serverless_lambda"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Action = "sts:AssumeRole"
      Effect = "Allow"
      Sid    = ""
      Principal = {
        Service = "lambda.amazonaws.com"
      }
      }
    ]
  })
}

resource "aws_iam_role_policy_attachment" "lambda_policy" {
  role       = aws_iam_role.lambda_exec.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}

When I try to validate my terraform I am getting the following error:

╷
│ Error: Unsupported attribute
│ 
│   on main.tf line 36, in module "lambdas":
│   36:   bucket_id = module.s3.aws_s3_bucket.lambda_bucket.id
│     ├────────────────
│     │ module.s3 is a list of object, known only after apply
│ 
│ Can't access attributes on a list of objects. Did you mean to access an attribute for a specific element of the list, or across all elements of the list?
╵

I have followed the documentation on Outputs and module composition but I am unsure what I am doing wrong. All help appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

猥︴琐丶欲为 2025-01-26 03:01:41

您的模块“ s3”块具有 /code> meta-argument 因此,参考实例在此处适用。

具体来说,module.s3是对象列表,而不仅仅是一个对象(如错误消息中的暗示),因此当您参考它时,您需要指定您的列表的哪个元素想参考。

在您的情况下,您只有零或一个模块的实例,因此模块。S3将是零或一个元素的列表。因此,您需要向Terraform解释,如果模块的零元素为零元素。

如果buck_id> buck_id变量可以接受module“ lambdas”在没有桶时为null,那么编写此内容的一种方法是使用 一个函数如果它具有一个元素,则将列表转换为单个值或null(如果没有元素):

  bucket_id = one(module.s3.aws_s3_bucket[*].lambda_bucket.id)

此表达式首先使用 splat操作员[*] 将对象列表转换为id值的列表,然后使用一个转换为单个字符串或null。

如果您需要buck_id在没有实例module.s3的情况下具有其他值在这种情况下填充此变量。做什么将取决于您需要的翻译规则;您可以在此处使用任何Terraform语言表达式或功能来做出动态决定。

Your module "s3" block has the count meta-argument and so the documentation under Referring to instances applies here.

Specifically, module.s3 is a list of objects rather than just a single object (as hinted in the error message) and so when you refer to it you need to specify which of the elements of that list you want to refer to.

In your case you only have zero or one instances of the module, and so module.s3 would be a list of either zero or one elements. You'll therefore need to explain to Terraform what should happen if there are zero elements of module.s3 but one instance of module.lambdas.

If it's acceptable for the bucket_id variable in module "lambdas" to be null when there is no bucket, one way to write this would be to use the one function to convert the list into either a single value if it has one element or to null if it has no elements:

  bucket_id = one(module.s3.aws_s3_bucket[*].lambda_bucket.id)

This expression first uses the splat operator [*] to translate from the list of objects to a list of just the id values, and then uses one to translate to either a single string or to a null.

If you need bucket_id to have some other value in the case where there are no instances of module.s3 then you'll need to specify some other logic here to describe how to populate this variable in that case. Exactly what to do will depend on the translation rule you need; you can use any Terraform language expression or function to make a dynamic decision here.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文