Terraform DigitalOcean for_each with projects and DNS records

Viewed 143

I want to create multiple servers on DigitalOcean, put them inside a project and create a DNS record for each server created.

I have the following main.tf file under the root:

module "ubuntu-server" {
    source = "./modules/server"

    for_each = var.servers

    name           =       each.value.name
    region         =       each.value.region
}

module "terraform-project" {
    source = "./modules/project" 

    project_name   =       var.project_name
    resources      =       module.ubuntu-server.droplet_urn
}

module "server-record" {
    source = "./modules/record"

    domain_name    =       var.domain_name
    name           =       module.ubuntu-server[*].droplet_name
    value          =       module.ubuntu-server[*].droplet_ip_address
}

The server module (./modules/server) contains the following main file:

resource "digitalocean_droplet" "server" {
    name    = var.name
    region  = var.region 
}

The project module (./modules/project):

resource "digitalocean_project" "terraform_project" {
  name        = var.project_name
  resources   = var.resources
}

The record module (./modules/record):

data "digitalocean_domain" "server" {
  name = var.domain_name
}

resource "digitalocean_record" "www" {
  domain    = data.digitalocean_domain.server.id
  type      = "A"
  name      = var.name
  value     = var.value
}

The ./modules/server has the following outputs:

output "droplet_ip_address" {
  value = digitalocean_droplet.server.ipv4_address
}

output "droplet_name" {
  value = digitalocean_droplet.server.name
}

output "droplet_urn" {
   value = [
     for row in digitalocean_droplet.server.urn : row.urn
   ]
}

The variables file looks as follows:

domain_name     =       "my_domain.com"
project_name    =       "project_name"
servers = {
    server1 = {
        name  = "server1",
        region = "region1",

    },
    server2 = {
        name  = "server2",
        region = "region2",
    } 
}

Issue 1

The first issue is that the project can only be created once while multiple resources (servers) must be assigned to it (see the doc here. Therefore I created an output in the ./modules/server as follows:

output "droplet_urn" {
  value = [
    for row in digitalocean_droplet.server.urn : row.urn
  ]
}

I was assuming this provided me with a list of urn's so I could assign that list to the resources attribute in the project section. but I get the following error (in the server modules output):

│ A value of type string cannot be used as the collection in a 'for' expression.

Issue 2

The other issue is that the server-record needs to be created for each server. I'm getting the following error:

│ Error: Unsupported attribute
│ 
│   on main.tf line 28, in module "server-record":
│   28:     name           =       module.ubuntu-server[*].droplet_name
│ 
│ This object does not have an attribute named "droplet_name".
╵
╷
│ Error: Unsupported attribute
│ 
│   on main.tf line 29, in module "server-record":
│   29:     value          =       module.ubuntu-server[*].droplet_ip_address
│ 
│ This object does not have an attribute named "droplet_ip_address".
1 Answers

Since you are using for_each to create your modules, you should do:

name           =      values(module.ubuntu-server)[*].droplet_name
value          =      values(module.ubuntu-server)[*].droplet_ip_address

Your digitalocean_droplet.server is only one instance, as you are not using any count nor for_each. Thus you can't iterate over it.

Related