How to for_each through a list(objects) in Terraform 0.12

后端 未结 4 462
别那么骄傲
别那么骄傲 2021-02-03 23:24

I need to deploy a list of GCP compute instances. How do I loop for_each through the "vms" in a list of objects like this:

    "gcp_zone": &q         


        
相关标签:
4条回答
  • 2021-02-03 23:54

    Using the for_each block is pretty new and there's not too much documentation. Some of the best info comes from their announcement blog post: https://www.hashicorp.com/blog/hashicorp-terraform-0-12-preview-for-and-for-each/

    Also make sure to check out the Dynamic Blocks section of their documentation: https://www.terraform.io/docs/configuration/expressions.html#dynamic-blocks

    From what your example looks like you need to have a set of values for each instance that is created so you'll have a map of maps:

    Below is an example I created using Terraform 0.12.12:

    variable "hostnames" {
        default = {
            "one" = {
                "name" = "one",
                "machine" = "n1-standard-1",
                "os" = "projects/coreos-cloud/global/images/coreos-stable-2247-5-0-v20191016",
                "zone" = "us-central1-a"
            },
            "two" = {
                "name" = "two",
                "machine" = "n1-standard-2",
                "os" = "projects/centos-cloud/global/images/centos-8-v20191018",
                "zone" = "us-central1-b"
            }
        }
    }
    
    resource "google_compute_instance" "default" {
        for_each = var.hostnames
        name         = each.value.name
        machine_type = each.value.machine
        zone         = each.value.zone
    
        boot_disk {
            initialize_params {
                image = each.value.os
            }
        }
    
        scratch_disk {
        }
    
        network_interface {
            network = "default"
        }
    }
    

    Terraform plan output:

    Terraform will perform the following actions:
    
      # google_compute_instance.default["one"] will be created
      + resource "google_compute_instance" "default" {
          + can_ip_forward       = false
          + cpu_platform         = (known after apply)
          + deletion_protection  = false
          + guest_accelerator    = (known after apply)
          + id                   = (known after apply)
          + instance_id          = (known after apply)
          + label_fingerprint    = (known after apply)
          + machine_type         = "n1-standard-1"
          + metadata_fingerprint = (known after apply)
          + name                 = "one"
          + project              = (known after apply)
          + self_link            = (known after apply)
          + tags_fingerprint     = (known after apply)
          + zone                 = "us-central1-a"
    
          + boot_disk {
              + auto_delete                = true
              + device_name                = (known after apply)
              + disk_encryption_key_sha256 = (known after apply)
              + kms_key_self_link          = (known after apply)
              + mode                       = "READ_WRITE"
              + source                     = (known after apply)
    
              + initialize_params {
                  + image  = "projects/coreos-cloud/global/images/coreos-stable-2247-5-0-v20191016"
                  + labels = (known after apply)
                  + size   = (known after apply)
                  + type   = (known after apply)
                }
            }
    
          + network_interface {
              + address            = (known after apply)
              + name               = (known after apply)
              + network            = "default"
              + network_ip         = (known after apply)
              + subnetwork         = (known after apply)
              + subnetwork_project = (known after apply)
            }
    
          + scheduling {
              + automatic_restart   = (known after apply)
              + on_host_maintenance = (known after apply)
              + preemptible         = (known after apply)
    
              + node_affinities {
                  + key      = (known after apply)
                  + operator = (known after apply)
                  + values   = (known after apply)
                }
            }
    
          + scratch_disk {
              + interface = "SCSI"
            }
        }
    
      # google_compute_instance.default["two"] will be created
      + resource "google_compute_instance" "default" {
          + can_ip_forward       = false
          + cpu_platform         = (known after apply)
          + deletion_protection  = false
          + guest_accelerator    = (known after apply)
          + id                   = (known after apply)
          + instance_id          = (known after apply)
          + label_fingerprint    = (known after apply)
          + machine_type         = "n1-standard-2"
          + metadata_fingerprint = (known after apply)
          + name                 = "two"
          + project              = (known after apply)
          + self_link            = (known after apply)
          + tags_fingerprint     = (known after apply)
          + zone                 = "us-central1-b"
    
          + boot_disk {
              + auto_delete                = true
              + device_name                = (known after apply)
              + disk_encryption_key_sha256 = (known after apply)
              + kms_key_self_link          = (known after apply)
              + mode                       = "READ_WRITE"
              + source                     = (known after apply)
    
              + initialize_params {
                  + image  = "projects/centos-cloud/global/images/centos-8-v20191018"
                  + labels = (known after apply)
                  + size   = (known after apply)
                  + type   = (known after apply)
                }
            }
    
          + network_interface {
              + address            = (known after apply)
              + name               = (known after apply)
              + network            = "default"
              + network_ip         = (known after apply)
              + subnetwork         = (known after apply)
              + subnetwork_project = (known after apply)
            }
    
          + scheduling {
              + automatic_restart   = (known after apply)
              + on_host_maintenance = (known after apply)
              + preemptible         = (known after apply)
    
              + node_affinities {
                  + key      = (known after apply)
                  + operator = (known after apply)
                  + values   = (known after apply)
                }
            }
    
          + scratch_disk {
              + interface = "SCSI"
            }
        }
    
    Plan: 2 to add, 0 to change, 0 to destroy.
    
    0 讨论(0)
  • 2021-02-04 00:03

    Seem's like I found what to do. If you pass not the maps of maps but the list of maps you can use such code

    resource "google_compute_instance" "node" {
        for_each = {for vm in var.vms:  vm.hostname => vm}
    
        name         = "${each.value.hostname}"
        machine_type = "custom-${each.value.cpu}-${each.value.ram*1024}"
        zone         = "${var.gcp_zone}"
    
        boot_disk {
            initialize_params {
            image = "${var.image_name}"
            size = "${each.value.hdd}"
            }
        }
    
        network_interface {
            network = "${var.network}"
        }
    
        metadata = {
            env_id = "${var.env_id}"
            service_types = "${join(",",each.value.service_types)}"
      }
    }
    

    It will create actual number of instance and when you remove for example middle one of three(if you create three:)), terraform will remove what we asked.

    0 讨论(0)
  • 2021-02-04 00:10

    From Terraform 0.12, you can use the for_each with modules like the following:

    modules/google_compute_instance/variables.tf

    variable "hosts" {
        type = map(object({
            hostname        = string
            cpu             = number
            ram             = number
            hdd             = number
            log_drive       = number
            template        = string 
            service_types   = list(string)
          }))
        }
    

    modules/google_compute_instance/main.tf

    resource "google_compute_instance" "gcp_instance" {
      for_each = var.hosts
    
      hostname      = each.value.repository_name
      cpu           = each.value.cpu
      ram           = each.value.ram
      hdd           = each.value.hdd
      log_drive     = each.value.log_drive
      template      = each.value.template
      service_types = each.value.service_types
    }
    

    servers.tf

    module "gcp_instances" {
        source = ./modules/google_compute_instance"
    
        hosts = {
            "test1-srfe" = {
                hostname        = "test1-srfe",
                cpu             = 1,
                ram             = 4,
                hdd             = 15,
                log_drive       = 300,
                template        = "Template-New",
                service_types   = ["sql", "db01", "db02"]
            },
            "test1-second" = {
                hostname        = "test1-second",
                cpu             = 1,
                ram             = 4,
                hdd             = 15,
                log_drive       = 300,
                template        = "APPs-Template",
                service_types   = ["configs"]
            },
        }
    }
    

    Of course, you can add as many variables as needed and use them in the module.

    0 讨论(0)
  • 2021-02-04 00:18

    You can do the following:

    for_each = toset(keys({for i, r in var.vms:  i => r}))
    cpu = var.vms[each.value]["cpu"]
    

    Assuming you had the following:

    variable "vms" {
        type = list(object({
            hostname        = string
            cpu             = number
            ram             = number
            hdd             = number
            log_drive       = number
            template        = string 
            service_types   = list(string)
        }))
        default = [
            {
                cpu: 1
                ...
            }
        ]
    }
    
    0 讨论(0)
提交回复
热议问题