terraform:将模块变量作为对象

时间:2020-05-20 11:35:53

标签: 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.

有什么想法吗?

3 个答案:

答案 0 :(得分:2)

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

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

kubernetes_namespace

我们可以在提供程序实现中看到this block is defined as having MaxItems: 1,只要保持为真(这似乎很可能),您就可以期望variable "namespace" { type = object({ metadata = list(object({ name = string })) }) } 是空列表或单项列表,您可以在本地变量中编写该代码,以方便在模块的其他位置使用:

var.namespace.metadata

以上内容将使locals { namespace_name = var.namespace.metadata[0].name } 引用给定的名称空间名称,或者如果给定的名称空间没有local.namespace_name块,则表达式将失败,因为将没有元素{{1} }。


以上只是获得对名称空间 name 的访问的许多复杂性。如果您希望将来需要使用metadata对象的其他属性,则上述结构可能会很有用,但是如果仅使用名称即可实现,则将其简化为一个直接使用名称空间名称的单个字符串变量:

[0]

...,您可以让呼叫者担心如何获取该名称:

kubernetes_namespace

答案 1 :(得分:1)

您应该能够改为将kubernetes_namespace.this.metadata.0.name传递给模块,并且只需让模块变量采用字符串即可。那应该给您所需的依赖关系链,并且还可以简化一些事情。

因此您模块的inputs.tf应该具有:

variable "namespace" {
  type = string
}

然后您这样称呼它:

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

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

    namespace = kubernetes_namespace.this.metadata.0.name
    workers   = 1
}

答案 2 :(得分:0)

我认为您已经解决了复杂的事情。

var.namespace中已经有了所需的东西,我会用

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

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

    namespace = var.namespace
    workers = 1
}



IF ,您需要设置对模块资源的依赖关系:
https://discuss.hashicorp.com/t/tips-howto-implement-module-depends-on-emulation/2305/2


如果使用Terraform 0.12,则此模式更为简单,因为depends_on可以直接引用Terraform 0.12和更高版本中的变量:

variable "vm_depends_on" {
  type    = any
  default = null
}

resource "azure_virtual_machine" "example" {
  depends_on = [var.vm_depends_on]

  # ...
}

由于此变量仅用于其依赖性而不是其值,因此我将其定义为具有any类型以获得最大的灵活性。然后,该模块的调用者可以使用vm_depends_on,其方式与一流的Depends_on元参数相同:

module "example" {
  source = "..."

  vm_depends_on = [module.fw_core01.firewall]
}