Openstack:使用额外磁盘对多个实例进行 Terraform - for_each 列表(对象)

问题描述 投票:0回答:2

我目前正在尝试使用 Terraform 在 Openstack 下创建多个实例。之后我想附上更多。但我对最后一点没有任何进展。 有人知道我该如何解决吗?

variable "instances" {
  description = "The Instances to be deployed"
  type = map(object({
    name             = string
    image            = string
    flavor           = string
    volume_size      = number
    security_groups  = list(string)
    network          = string
    keypair_name     = string
    floating_ip_pool = string
    tags             = list(string)
    additional_disks = list(object({
      disk        = string
      volume_size = number
    }))
  }))
}

instances = {
  "Websrv01" = {
    name             = "websrv01"
    image            = "Ubuntu 22.04"
    flavor           = "SCS-2V-4-20s"
    volume_size      = 20
    security_groups  = ["default"]
    network          = "test-intern"
    keypair_name     = "ssh-pub"
    floating_ip_pool = "public"
    tags             = ["general", "webserver"]
    additional_disks = []
  },
  "dbsrv01" = {
    name             = "dbsrv01"
    image            = "Ubuntu 22.04"
    flavor           = "SCS-2V-4-20s"
    volume_size      = 20
    security_groups  = ["default"]
    network          = "test-intern"
    keypair_name     = "ssh-pub"
    floating_ip_pool = "public"
    tags             = ["general", "dbserver"]
    additional_disks = [
      { disk = "db_data", volume_size = 30 },
      { disk = "db_log", volume_size = 10 }
    ]
  }
}

resource "openstack_compute_instance_v2" "instances" {
  for_each = var.instances

  name            = each.value.name
  flavor_id       = data.openstack_compute_flavor_v2.flavor[each.key].id
  key_pair        = each.value.keypair_name
  security_groups = each.value.security_groups

  ## Boot Disk
  block_device {
    uuid                  = data.openstack_images_image_v2.image[each.key].id
    source_type           = "image"
    volume_size           = each.value.volume_size
    boot_index            = 0
    destination_type      = "volume"
    delete_on_termination = true
  }
 
  lifecycle {
    prevent_destroy = true

  network {
    name = each.value.network
  }

  tags = each.value.tags
}

## Get floating IP if needed
resource "openstack_networking_floatingip_v2" "floating_ip" {
  for_each = { for k, v in var.instances : k => v if v.floating_ip_pool != "" }

  pool = each.value.floating_ip_pool
}

## Associate floating ip to Instances
resource "openstack_compute_floatingip_associate_v2" "associate" {
  for_each = openstack_networking_floatingip_v2.floating_ip

  instance_id = openstack_compute_instance_v2.instances[each.key].id
  floating_ip = each.value.address
}

## Additional Disks
resource "openstack_blockstorage_volume_v3" "additional_disks" {
  for_each = {
    for instance, disks in var.instances : instance => disks.additional_disks
    if length(disks.additional_disks) > 0
  }

  name                 = "${each.key}-${each.value[0].disk}"
  size                 = each.value[0].volume_size
  enable_online_resize = true
}

## Attach additional disks to instances
resource "openstack_compute_volume_attach_v2" "attach_additional_disks" {
  for_each = {
    for instance, disks in var.instances : instance => disks.additional_disks
    if length(disks.additional_disks) > 0
  }

  instance_id = openstack_compute_instance_v2.instances[each.key].id
  volume_id   = openstack_blockstorage_volume_v3.additional_disks[each.key].id
}

这里只考虑第一个硬盘。 我尝试循环列表中的真相,但 [*] 失败了。

问候 艾迪

使用单次添加磁盘即可工作:

resource "openstack_blockstorage_volume_v3" "additional_disks" {
  for_each = {
    for instance, disks in var.instances : instance => disks.additional_disks
    if length(disks.additional_disks) > 0
  }

  name                 = "${each.key}-${each.value[0].disk}"
  size                 = each.value[0].volume_size
  enable_online_resize = true
}

resource "openstack_compute_volume_attach_v2" "attach_additional_disks" {
  for_each = {
    for instance, disks in var.instances : instance => disks.additional_disks
    if length(disks.additional_disks) > 0
  }

  instance_id = openstack_compute_instance_v2.instances[each.key].id
  volume_id   = openstack_blockstorage_volume_v3.additional_disks[each.key].id
}
terraform openstack
2个回答
0
投票

这个问题或多或少与此处提出和回答的问题相似。尽管如此,我想让你轻松一点。

如果您想迭代 json 对象中的多个对象并与父对象具有适当的相关性,建议使用

flatten
函数并提取您感兴趣的相关字段以进行进一步迭代。

下面

locals
var 的作用完全相同::

locals {
  additional_disks = flatten([
    for instance_key, instance in var.instances : [
      for index in range(length(instance.additional_disks)) : {
        local_disk_index = index % length(instance.additional_disks)
        instance_key     = instance_key
        disk_key         = format("%s-%s", instance_key, instance.additional_disks[index % length(instance.additional_disks)].disk)
        disk_values      = instance.additional_disks[index % length(instance.additional_disks)]
      }
    ]
  ])
}

我们使用

instance_key
lookup
实例构建一个对象列表,然后将
disk
键和值与其关联。

上面的

local.additional_disks
可以像下面一样使用来配置资源。

## Additional Disks    
resource "openstack_blockstorage_volume_v3" "additional_disks" {
  for_each = {
    for disk in local.additional_disks: disk.disk_key => disk
  }     
      
  name                 = each.value.disk_values.disk
  size                 = each.value.disk_values.volume_size
  enable_online_resize = true
}

## Attach additional disks to instances
resource "openstack_compute_volume_attach_v2" "attach_additional_disks" {   
        
  for_each = {
    for disk in local.additional_disks: disk.disk_key => disk
  } 
  
  instance_id = openstack_compute_instance_v2.instances[each.value.instance_key].id
  volume_id   = openstack_blockstorage_volume_v3.additional_disks[each.key].id
} 

并且

terraform plan
给出以下输出 ::

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

...blah-blah..
# openstack_blockstorage_volume_v3.additional_disks["dbsrv01-db_data"] will be created
  + resource "openstack_blockstorage_volume_v3" "additional_disks" {
      + attachment           = (known after apply)
      + availability_zone    = (known after apply)
      + enable_online_resize = true
      + id                   = (known after apply)
      + metadata             = (known after apply)
      + name                 = "db_data"
      + region               = (known after apply)
      + size                 = 30
      + volume_type          = (known after apply)
    }

  # openstack_blockstorage_volume_v3.additional_disks["dbsrv01-db_log"] will be created
  + resource "openstack_blockstorage_volume_v3" "additional_disks" {
      + attachment           = (known after apply)
      + availability_zone    = (known after apply)
      + enable_online_resize = true
      + id                   = (known after apply)
      + metadata             = (known after apply)
      + name                 = "db_log"
      + region               = (known after apply)
      + size                 = 10
      + volume_type          = (known after apply)
    }
...blah-blah..
 # openstack_compute_volume_attach_v2.attach_additional_disks["dbsrv01-db_data"] will be created
  + resource "openstack_compute_volume_attach_v2" "attach_additional_disks" {
      + device      = (known after apply)
      + id          = (known after apply)
      + instance_id = (known after apply)
      + region      = (known after apply)
      + volume_id   = (known after apply)
    }

  # openstack_compute_volume_attach_v2.attach_additional_disks["dbsrv01-db_log"] will be created
  + resource "openstack_compute_volume_attach_v2" "attach_additional_disks" {
      + device      = (known after apply)
      + id          = (known after apply)
      + instance_id = (known after apply)
      + region      = (known after apply)
      + volume_id   = (known after apply)
    }

另一个未经询问的建议,我看到你直接在资源上硬编码

enable_online_resize
。这不是一个好主意,通过将其硬编码为
additional_disks
来将其从
true
属性中拉出。


0
投票

我已经尝试使用 ChatGPT 来解决它。他已经走上了正确的道路。但没有向当地人提出解决方案。已在 for_each 循环中使用 flatten 尝试过。 我还不熟悉 flatten 和 locals。 现在,在 ChatGPT 建议转换为地图(对象)之后,我用更简单的表示法稍微改变了解决方案。

这就是我的解决方案现在的样子:

variable "instances" {
  description = "The Instances to be deployed"
  type = map(object({
    name             = string
    image            = string
    flavor           = string
    volume_size      = number
    security_groups  = list(string)
    network          = string
    keypair_name     = string
    floating_ip_pool = string
    tags             = list(string)
    additional_disks = map(object({
      volume_size = number
    }))
  }))
}

instances = {
  "Websrv01" = {
    name             = "websrv01"
    image            = "Ubuntu 22.04"
    flavor           = "SCS-2V-4-20s"
    volume_size      = 20
    security_groups  = ["default"]
    network          = "test-intern"
    keypair_name     = "ssh_general"
    floating_ip_pool = "public"
    tags             = ["general", "webserver"]
    additional_disks = {}
  },
  "Websrv02" = {
    name             = "websrv02"
    image            = "Ubuntu 22.04"
    flavor           = "SCS-2V-4-20s"
    volume_size      = 20
    security_groups  = ["default"]
    network          = "test-intern"
    keypair_name     = "ssh_general"
    floating_ip_pool = "public"
    tags             = ["general", "webserver"]
    additional_disks = {}
  },
  "dbsrv01" = {
    name             = "dbsrv01"
    image            = "Ubuntu 22.04"
    flavor           = "SCS-2V-4-20s"
    volume_size      = 20
    security_groups  = ["default"]
    network          = "test-intern"
    keypair_name     = "ssh_general"
    floating_ip_pool = "public"
    tags             = ["general", "dbserver"]
    additional_disks = {
      db_data = { volume_size = 30 },
      db_log  = { volume_size = 10 }
    }
  }
}

## Create Additional Disks for Instances  
resource "openstack_blockstorage_volume_v3" "additional_disks" {
  for_each = {
    for disk in local.additional_disks : "${disk.instance_key}-${disk.disk_name}" => disk
  }

  name                 = each.key
  size                 = each.value.disk_values.volume_size
  enable_online_resize = true
}

## Attach additional disks to instances
resource "openstack_compute_volume_attach_v2" "attach_additional_disks" {
  for_each = {
    for disk in local.additional_disks : "${disk.instance_key}-${disk.disk_name}" => disk
  }

  instance_id = openstack_compute_instance_v2.instances[each.value.instance_key].id
  volume_id   = openstack_blockstorage_volume_v3.additional_disks[each.key].id
}

我还将使用enable_online_resize来实现该提示。

还有一个问题。我想在多个环境中使用该代码,因此从它创建一个模块肯定有意义吗? 那我现在就尝试一下。

最后,我想为 Ansible 生成 INI 格式的动态清单,并将其与标签分组。有什么简单的方法可以做到这一点吗?

© www.soinside.com 2019 - 2024. All rights reserved.