canonical / terraform-provider-maas

Terraform MAAS provider
Mozilla Public License 2.0
64 stars 45 forks source link

cannot have resource_machine and resource_instance deploy in parallel #12

Closed jeff-hillman closed 2 years ago

jeff-hillman commented 2 years ago

Ubuntu focal (18.04) latest terraform-provider-maas snap install go 1.18.3 snap installed terraform 1.2.2

Using the config:

provider "maas" {
  api_version = "2.0"
  api_key     = "37sMeRpnfT4QvRAWLJ:9SrMeuJAW2NkN8kzJX:QqwWEKKSZGJkbzDM3tdFJvhyHcMcGmKg"
  api_url     = "http://192.168.101.10:5240/MAAS"
}
resource "maas_machine" "edge-3" {
  power_type = "virsh"
  power_parameters = {
    power_address = "qemu+ssh://jeff@192.168.101.1/system",
    power_pass = "******",
    power_id = "microk8s-2"
  }
  pxe_mac_address = "52:54:00:f4:6e:20"
}
resource "maas_instance" "random_nodes" {
  count = 1
  deploy_params {
    distro_series = "focal"
  }
}

Results in the machine being created but the instance error out due the there being no nodes available:

m$ terraform apply

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:

  # maas_instance.random_nodes[0] will be created
  + resource "maas_instance" "random_nodes" {
      + cpu_count    = (known after apply)
      + fqdn         = (known after apply)
      + hostname     = (known after apply)
      + id           = (known after apply)
      + ip_addresses = (known after apply)
      + memory       = (known after apply)
      + pool         = (known after apply)
      + tags         = (known after apply)
      + zone         = (known after apply)

      + deploy_params {
          + distro_series = "focal"
        }
    }

  # maas_machine.edge-3 will be created
  + resource "maas_machine" "edge-3" {
      + architecture     = "amd64/generic"
      + domain           = (known after apply)
      + hostname         = (known after apply)
      + id               = (known after apply)
      + min_hwe_kernel   = (known after apply)
      + pool             = (known after apply)
      + power_parameters = (sensitive value)
      + power_type       = "virsh"
      + pxe_mac_address  = "52:54:00:f4:6e:20"
      + zone             = (known after apply)
    }

Plan: 2 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

maas_instance.random_nodes[0]: Creating...
maas_machine.edge-3: Creating...
maas_machine.edge-3: Still creating... [10s elapsed]
maas_machine.edge-3: Still creating... [20s elapsed]
maas_machine.edge-3: Still creating... [30s elapsed]
maas_machine.edge-3: Still creating... [40s elapsed]
maas_machine.edge-3: Still creating... [50s elapsed]
maas_machine.edge-3: Still creating... [1m0s elapsed]
maas_machine.edge-3: Still creating... [1m10s elapsed]
maas_machine.edge-3: Still creating... [1m20s elapsed]
maas_machine.edge-3: Still creating... [1m30s elapsed]
maas_machine.edge-3: Still creating... [1m40s elapsed]
maas_machine.edge-3: Still creating... [1m50s elapsed]
maas_machine.edge-3: Still creating... [2m0s elapsed]
maas_machine.edge-3: Creation complete after 2m3s [id=qeckyx]
╷
│ Error: ServerError: 409 Conflict (No machine available.)
│ 
│   with maas_instance.random_nodes[0],
│   on 02-instance.tf line 1, in resource "maas_instance" "random_nodes":
│    1: resource "maas_instance" "random_nodes" {
│ 

Immediately re-running the same config creates the machine as expected. Presumably because it is now in a Ready state whereas it was not in a Ready state immediately after the machine created...

jeff-hillman commented 2 years ago

Adding -parallelism=1 to the above config works, but that would require predicting the number of machines ahead of time and would slow down any other infra resources to be deployed.

cpg1111 commented 2 years ago

Hi @jeff-hillman, so the issue here is that the maas_instance resource should depend on the resource created by maas_machine or a data resource referencing an existing machine. Easiest way to tell Terraform of this dependency is using a value from the maas_machine resource in the maas_instance, this will have Terraform create the machine before the instance.

An example of this would be:

resource "maas_machine" "edge3" {
    architecture = "amd64/generic"
    power_type = "virsh"
    pxe_mac_address = "52:54:00:f4:6e:20"
}

resource "maas_instance" "a_node" {
    hostname = maas_machine.edge3.hostname
}

In the case of an instance resource representing multiple machines maas_machine.edge3.pool or maas_machine.edge3.zone should work instead of hostname.

I'm keeping this issue open as the provider should do this implicitly with machines and instances, but currently it does not. Though, this should be a valid workaround.

jeff-hillman commented 2 years ago

@cpg1111 thanks for the suggestion, however this still didn't work. I tried several combinations of the hostname under allocate_params (maas_machine.microk8s-2.hostname, microk8s-2.maas and just microk8s-2) and all give the error of:

│ Error: ServerError: 409 Conflict (No available machine matches constraints: [('name', ['microk8s-2'])] (resolved to "name=microk8s-2"))
│ 
│   with maas_instance.random_nodes[0],
│   on config.tf line 16, in resource "maas_instance" "random_nodes":
│   16: resource "maas_instance" "random_nodes" {

Here's my config:

provider "maas" {
  api_version = "2.0"
  api_key     = "37sMeRpnfT4QvRAWLJ:9SrMeuJAW2NkN8kzJX:QqwWEKKSZGJkbzDM3tdFJvhyHcMcGmKg"
  api_url     = "http://192.168.101.10:5240/MAAS"
}
resource "maas_machine" "microk8s-2" {
  power_type = "virsh"
  hostname = "microk8s-2"
  power_parameters = {
    power_address = "qemu+ssh://jeff@192.168.101.1/system",
    power_pass = "*******",
    power_id = "microk8s-2"
  }
  pxe_mac_address = "52:54:00:f4:6e:20"
}
resource "maas_instance" "random_nodes" {
  count = 1
  deploy_params {
    distro_series = "focal"
  }
  allocate_params {
    hostname = "microk8s-2"
  }
}
cpg1111 commented 2 years ago

@jeff-hillman you can't use the hardcoded value for this, you must use Terraform's variables. If you notice in my example above, I use maas_machine.edge3.hostname instead of its actual value. This tells Terraform 1. that maas_machine.edge3 needs to exist in order to create maas_instance.a_node and 2. That the instance should have the same hostname (which MAAS will then use that machine to deploy to).

gustavosr98 commented 2 years ago

HI @cpg1111, thanks We got passed that with the customer using explicit dependencies with depends_on

Still we are having issues with applying any terraform template. Getting the following error

│ Error: json: cannot unmarshal object into Go struct field VLAN.boot_interface.discovered.subnet.vlan.relay_vlan of type int

We get the error with this template

resource "maas_machine" "Dell1" {
  power_type = "ipmi"
  power_parameters = {
    power_address = "10.127.4.50"
    power_user    = "root"
    power_pass    = "<HIDDEN>"
  }
  pxe_mac_address = "<HIDDEN>"
}

resource "maas_machine" "Dell2" {
  power_type = "ipmi"
  power_parameters = {
    power_address = "10.127.4.51"
    power_user    = "root"
    power_pass    = "<HIDDEN>"
  }
  pxe_mac_address = "<HIDDEN>"

}

resource "maas_instance" "Dell1" {
  deploy_params {
    distro_series = "rhel/7"
  }
  allocate_params {
    hostname = "Dell1.local"
  }
  depends_on = [ maas_machine.Dell1 ]
}

resource "maas_instance" "Dell2" {
  deploy_params {
    distro_series = "rhel/7"
  }
  allocate_params {
    hostname = "Dell2.local"
  }
  depends_on = [ maas_machine.Dell2 ]
}

Same error shows even in simple templates with just one instance. After already having a machine in "Ready" state and vlans configured through GUI.

resource "maas_instance" "sf_test_1" {
  allocate_params {
      #hostname = "open-crane"
  }

  deploy_params {
    distro_series = "focal"
  }
}

These are the networking configs we have on maas: https://pastebin.canonical.com/p/z4sMTWVJwb/

cpg1111 commented 2 years ago

Hmm seems the model and the object returned do not follow the same schema. Can you please create a separate issue so we may track these separately?

cpg1111 commented 2 years ago

Closing this issue as using references of maas_machine in maas_instance is the official way to create dependencies in Terraform and we have a separate issue tracking the json marshaling issue.