我目前正在尝试使用 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
}
这个问题或多或少与此处提出和回答的问题相似。尽管如此,我想让你轻松一点。
如果您想迭代 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
属性中拉出。
我已经尝试使用 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 格式的动态清单,并将其与标签分组。有什么简单的方法可以做到这一点吗?