zxcSora
zxcSora

Reputation: 55

Terraform, dynamic attach multiple disk to 1 vps

My problem is that I can't dynamically connect the created disks to the vps. The google_compute_disk_attach module cannot be used Here is my code What is the correct way in this situation?

resource "google_compute_instance" "vps" {
  name                = var.server_name
  description         = var.server_description
  machine_type        = var.server_type
  zone                = var.server_datacenter
  deletion_protection = var.server_delete_protection
  labels              = var.server_labels
  metadata            = var.server_metadata
  tags                = var.server_tags

  boot_disk {
    auto_delete = false
    initialize_params {
      size   = var.boot_volume_size
      type   = var.boot_volume_type
      image  = var.boot_volume_image
      labels = var.boot_volume_labels
    }
  }
  dynamic "attached_disk" {
    for_each = { for vol in var.volumes : vol.volume_name => vol }
    content {
      source = element(var.volumes[*].volume_name, 0)
    }
  }

  network_interface {
    subnetwork = var.server_network

    access_config {
      nat_ip = google_compute_address.static_ip.address
    }
  }

resource "google_compute_disk" "volume" {
  for_each = { for vol in var.volumes : vol.volume_name => vol }
  name     = each.value.volume_name
  type     = each.value.volume_type
  size     = each.value.volume_size
  zone     = var.server_datacenter
  labels   = each.value.volume_labels
}

volumes variables

  volumes = [{
    volume_name = "v3-postgres-saga-import-test-storage"
    volume_size = "40"
    volume_type = "pd-ssd"
    volume_labels = {
      environment = "production"
      project     = "v3"
      type        = "storage"
    }
    }, {
    volume_name = "volume-vpstest2"
    volume_size = "20"
    volume_type = "pd-ssd"
    volume_labels = {
      environment = "production"
      project     = "v2"
      type        = "storage"
    }
  }]

if do something like that - error

source = google_compute_disk.volume[*].self_link

This object does not have an attribute named "self_link".

Upvotes: 1

Views: 704

Answers (2)

Mazlum Tosun
Mazlum Tosun

Reputation: 6572

You can also use the volume variable directly as map instead of Array :

variables.tf file :

variable "volumes" {
  default = {
     postgres_saga = {
       volume_name   = "v3-postgres-saga-import-test-storage"
       volume_size   = "40"
       volume_type   = "pd-ssd"
       volume_labels = {
         environment = "production"
         project     = "v3"
         type        = "storage"
       }
    },
    volume_vpstest2 = {
      volume_name   = "volume-vpstest2"
      volume_size   = "20"
      volume_type   = "pd-ssd"
      volume_labels = {
        environment = "production"
        project     = "v2"
        type        = "storage"
      }
    }
  }
}

Instead of variable, you can also use a local variable from json configuration. Example of structure of Terraform module :

project
  module
      main.tf
      locals.tf
      resource
          volumes.json

volumes.json file

{
  "volumes": {
      "postgres_saga" : {
         "volume_name"   : "v3-postgres-saga-import-test-storage"
         "volume_size"   : "40"
         "volume_type"   : "pd-ssd"
         "volume_labels" : {
           "environment" : "production"
           "project"     : "v3"
           "type"        : "storage"
         }
      },
      "volume_vpstest2" : {
        "volume_name"   : "volume-vpstest2"
        "volume_size"   : "20"
        "volume_type"   : "pd-ssd"
        "volume_labels" : {
          "environment" : "production"
          "project"     : "v2"
          "type"        : "storage"
        }
      }
   }
}

locals.tf file

locals {
  tables = jsondecode(file("${path.module}/resource/volumes.json"))["volumes"]
}

main.tf file :

resource "google_compute_instance" "vps" {
  name                = var.server_name
  description         = var.server_description
  machine_type        = var.server_type
  zone                = var.server_datacenter
  deletion_protection = var.server_delete_protection
  labels              = var.server_labels
  metadata            = var.server_metadata
  tags                = var.server_tags

  boot_disk {
    auto_delete = false
    initialize_params {
      size   = var.boot_volume_size
      type   = var.boot_volume_type
      image  = var.boot_volume_image
      labels = var.boot_volume_labels
    }
  }

  dynamic "attached_disk" {
    for_each = [
      var.volumes
      # local.volumes
    ]
    content {
      source = attached_disk.value["volume_name"]
    }
  }

  network_interface {
    subnetwork = var.server_network

    access_config {
      nat_ip = google_compute_address.static_ip.address
    }
  }
}

resource "google_compute_disk" "volume" {
  for_each = var.volumes
  # local.volumes
  name     = each.value["volume_name"]
  type     = each.value["volume_type"]
  size     = each.value["volume_size"]
  zone     = var.server_datacenter
  labels   = each.value["volume_labels"]
}

With a map, you can directly use foreach without any transformation on google_compute_disk/volume resource.

You can also use this map in a dynamic bloc.

Upvotes: 0

Marcin
Marcin

Reputation: 238169

Since you've used for_each in google_compute_disk.volume, it will be a map, not a list. Thus you can list all self_link as follows:

source = values(google_compute_disk.volume)[*].self_link

Upvotes: 1

Related Questions