首页 > 解决方案 > terraform:模块变量作为对象

问题描述

这是我的模块片段:

inputs.tf

variable "namespace" {
    type = object({
        metadata = object({
            name = string
        })
    })
}

main.tf

resource "helm_release" "spark" {
    name       = "spark"
    repository = "https://charts.bitnami.com/bitnami" 
    chart      = "spark"
    version    = "1.2.21"
    namespace  = var.namespace.metadata.name
}

如您所见,我正在尝试访问以前创建kubernetes_namespace的 .

进入我的环境工作区:

resource "kubernetes_namespace" "this" {
    metadata {
        name = var.namespace
    }
}

module "spark" {
    source = "../modules/spark"

    namespace = kubernetes_namespace.this
    workers = 1
}

当我尝试制定计划时,我收到了这条消息:

➜  development terraform plan | xclip -selection clipboard

Error: Invalid value for module argument

  on main.tf line 14, in module "spark":
  14:     namespace = kubernetes_namespace.this

The given value is not suitable for child module variable "namespace" defined
at ../modules/spark/inputs.tf:1,1-21: attribute "metadata": object required.

有任何想法吗?

标签: terraform

解决方案


该错误报告您分配给namespace变量的值与其类型约束不兼容。

metadata属性kubernetes_namespace似乎被定义为对象列表而不是单个对象,因此这里的自动类型转换是不可能的。您可以在此处进行的一种方法是更改​​变量的类型以匹配资源类型架构,如下所示:

variable "namespace" {
    type = object({
        metadata = list(object({
            name = string
        }))
    })
}

我们可以在提供程序实现中看到,该块被定义为具有MaxItems: 1,因此只要它仍然正确(这似乎很可能),您就可以期望var.namespace.metadata它是一个空列表或单项列表,您可以在本地编写变量以便在模块的其他地方更容易使用:

locals {
  namespace_name = var.namespace.metadata[0].name
}

以上将local.namespace_name引用给定的命名空间名称,或者如果给定的命名空间没有metadata块,则表达式将失败,因为在这种情况下将没有元素[0]


以上只是为了访问命名空间名称而变得非常复杂。如果您希望将来需要使用对象的其他属性,则上述结构可能很有用kubernetes_namespace,但如果您可以仅使用名称,那么将其简化为单个字符串变量可能会有所帮助命名空间名称直接:

variable "namespace_name" {
  type = string
}

...您可以让调用者担心如何获取该名称:

resource "kubernetes_namespace" "this" {
    metadata {
        name = var.namespace
    }
}

module "spark" {
    source = "../modules/spark"

    namespace_name = kubernetes_namespace.this.metadata.name
    workers        = 1
}

推荐阅读