代码之家  ›  专栏  ›  技术社区  ›  Jambla

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

  •  0
  • Jambla  · 技术社区  · 3 年前

    我正在编写Terraform来部署一个S3桶和一个lambda。需要S3存储桶,因为这是存储zip对象的地方,可以部署到lambda。

    我的顶层主模块中有两个模块。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模块:

    主要的tf

    resource "aws_s3_bucket" "lambda_bucket" {
      bucket = "lunchboxd-lambdas"
    
      tags = {
        Owner       = "Terraform",
        Description = "A bucket to hold the lambdas zip"
      }
    }
    

    产出。tf

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

    lambdas模块:

    变量。tf

    variable "bucket_id" {}
    

    主要的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"
    }
    
    

    当我尝试验证我的地形时,我得到了以下错误:

    ╷
    │ 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?
    ╵
    

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

    1 回复  |  直到 3 年前
        1
  •  2
  •   Martin Atkins    3 年前

    你的 module "s3" 布洛克 the count meta-argument 因此,下面的文档 Referring to instances 适用于这里。

    明确地 module.s3 是一个对象列表,而不仅仅是一个对象(如错误消息中所暗示的),因此当您引用它时,需要指定要引用该列表中的哪些元素。

    在您的情况下,您只有零个或一个模块实例,依此类推 单元s3 将是一个包含零个或一个元素的列表。因此,你需要向Terraform解释,如果地球上没有元素,会发生什么 单元s3 但有一个例子 module.lambdas .

    如果这是可以接受的 bucket_id 可变的 module "lambdas" 要在没有bucket时为null,一种写入方法是使用 the one function 将列表转换为单个值(如果它有一个元素)或 null 如果没有任何元素:

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

    这个表达首先使用 the splat operator [*] 将对象列表转换为仅包含 id 值,然后使用 转换为单个字符串或null。

    如果你需要 桶号 在没有 单元s3 然后需要在这里指定一些其他逻辑来描述在这种情况下如何填充这个变量。具体做什么取决于你需要的翻译规则;您可以使用任何地形语言表达式或函数在此处做出动态决策。