terraform - 如何在属性中使用变量

terraform - how to use variables inside attributes

我不确定这样做是否正确,但我想使用变量作为属性。

例如,我有一个根据用户输入而变化的变量:os_name = ubuntu

我想像下面这样使用这个变量名,

resource "aws_instance" "workerNode" {
  ..................
  ami = data.aws_ami.${var.os_name}.image_id
  ..................
}

以下是数据块的例子,

data "aws_ami" "suse" {
    count  = "${var.os_name == "suse" ? 1 : 0}"
    owners = ["amazon"]
    most_recent = true
    filter {
        name = "name"
        values = ["suse-sles-${var.os_version}-sp*-v????????-hvm-ssd-x86_64"]
    }
}    

结果如下,

  "architecture" = "x86_64"
  "hypervisor" = "xen"
  "id" = "ami-0d3905203a039e3b0"
  "image_id" = "ami-0d3905203a039e3b0"

但是 terraform 不允许我这样做。有什么方法可以做到这一点,或者我必须更改工作流程?

您可以通过使用 for_each 指定您的 AMI 来使其工作,从而获得您可以通过密钥访问的 map

我的 data.aws_ami.myamis 看起来像这样:

data "aws_ami" "myamis" {
  for_each = toset(["suse", "ubuntu"])

  most_recent = true
  owners      = ["amazon"]

  filter {
    name = "name"
    values = ["${each.value}*"]
  }
}

出于测试目的,我定义了一个变量 foo,如下所示:

variable "foo" {
  type    = string
  default = "suse"
}

现在我可以像这样访问 AMI:

$ tf console
> data.aws_ami.myamis[var.foo].image_id
"ami-0ea50c090ba6e85c5"

您可以调整它以满足您对 os_nameos_version 的需要。

我已经通过条件表达式解决了这个问题。

我不确定这是否是一种标准的做事方式,但它对我有用。

我尝试用嵌套条件表达式模拟 if/elif/else。

output "name" {
    value = "${ var.os_name == "ubuntu" ? data.aws_ami.ubuntu[0].image_id : (var.os_name == "redhat" ? data.aws_ami.redhat[0].image_id : (var.os_name == "centos" ? data.aws_ami.suse[0].image_id : data.aws_ami.suse[0].image_id ))}"
}

在不适合使用 for_each 将所有实例收集到单个资源下的情况下(这会隐含地使该资源显示为对象映射),您可以明确地获得类似的结果写一个 local value 表达式来构造一个等价的映射:

locals {
  amis = {
    suse   = data.aws_ami.suse
    ubuntu = data.aws_ami.ubuntu
  }
}

那你可以参考local.amis["ubuntu"]local.amis["suse"](如果需要可以用变量替换元素键。


话虽如此,对于您的情况似乎确实存在一种可能的不同方法,只需要一个 data 块就可以到达那里:

locals {
  os_ami_queries = {
    suse = {
      owners = ["amazon"]
      filters = {
        name = ["suse-sles-${var.os_version}-sp*-v????????-hvm-ssd-x86_64"]
      }
    }
    ubuntu = {
      owners = ["amazon"]
      filters = {
        name = ["ubuntu-${var.os_version}-something-something"]
      }
    }
  }
  ami_query = local.os_ami_queries[var.os_name]
}

data "aws_ami" "selected" {
  owners = local.ami_query.owners

  dynamic "filter" {
    for_each = local.ami_query.filters
    content {
      name   = filter.key
      values = filter.value
    }
  }
}

这种不同的排列在 data "aws_ami" 查找之前 OS 选择 ,因此它可以使用与任何 OS 相关联的设置由调用者选择。 AMI id 将位于 data.aws_ami.selected.id.

话虽如此,这种方法的缺点是非常间接并使用 dynamic 块,因此我会权衡替代方案的可读性以选择主观上似乎最容易遵循的方案对于不熟悉此配置的人。没有一个单一的答案,因为在某种程度上这是一个品味问题,所以如果你在团队环境中工作,这可能是与同事讨论的事情,看看哪种方法最适合权衡,比如你期望多长时间添加和删​​除受支持的操作系统与更改结果使用方式的详细信息。