canonical / terraform-provider-maas

Terraform MAAS provider
Mozilla Public License 2.0
60 stars 43 forks source link

Fails to create a vlan and a subnet in a single plan with DHCP_ON #53

Open gboutry opened 1 year ago

gboutry commented 1 year ago

Terraform Version

$ terraform -v
Terraform v1.4.2
on linux_amd64
+ provider registry.terraform.io/maas/maas v1.1.0

Affected Resource(s)

Please list the resources as a list, for example:

Terraform Configuration Files

data "maas_fabric" "my_fabric" {
  name = "fabric-4"
}
resource "maas_space" "my_space" {
  name = "my-space"
}

resource "maas_vlan" "vlan1000" {
  fabric = data.maas_fabric.my_fabric.id
  vid    = 1000
  name   = "vlan-1000"
  space  = maas_space.my_space.name
  dhcp_on = true
}

resource "maas_subnet" "my_subnet" {
  cidr       = "10.244.0.0/24"
  fabric     = data.maas_fabric.my_fabric.id
  vlan       = maas_vlan.vlan1000.id
  name       = "my-subnet"
  gateway_ip = "10.244.0.1"
  dns_servers = [
    "8.8.8.8",
    "8.8.4.4"
  ]
  ip_ranges {
    type     = "dynamic"
    start_ip = "10.244.0.200"
    end_ip   = "10.244.0.254"
  }
}

Expected Behavior

Terraform's apply succeeds on the first run.

Actual Behavior

The plan fails with the following error:

│ Error: ServerError: 400 Bad Request ({"dhcp_on": ["dhcp can only be turned on when a dynamic IP range is defined."]})
│ 
│   with maas_vlan.vlan1000,
│   on main.tf line 59, in resource "maas_vlan" "vlan1000":
│   59: resource "maas_vlan" "vlan1000" {
│ 

If I set dchp_on = false, on the first apply, then to true on the second, it works.

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  # maas_vlan.vlan1000 will be updated in-place
  ~ resource "maas_vlan" "vlan1000" {
      ~ dhcp_on = false -> true
        id      = "5010"
        name    = "vlan-1000"
        # (4 unchanged attributes hidden)
    }

Steps to Reproduce

Please list the steps required to reproduce the issue, for example:

  1. terraform apply
sparkiegeek commented 1 year ago

Let's figure out if we can express the dependencies properly so that we first create the VLAN without DHCP, then create a subnet with IP ranges, then finally go back and turn on DHCP for the VLAN.

skatsaounis commented 9 months ago

I was thinking a solution that involves the development of a new resource named e.g. maas_vlan_dhcp and the removal of field dhcp_on from maas_vlan. While the ip_ranges field of the new resource is not going to be used in any HTTP call to MAAS it is enough to capture the dependency. Special care will be made to check that the given ranges are of type dynamic. The same can be achieved if we let the dependency come through depends_on meta-argument but could complicate things with deletion.

In the below snippet I have included a demonstration of the new resource.

NOTES:

  1. A quick implementation of a data source of rack controllers is required. Initially, it could return basic information, such as system_id and services enabled.
  2. This approach is not taking into consideration the existing embedded ip_ranges inside a maas_subnet. A complete solution will do one of the two things:
    • Remove the maas_subnet embedded ip_ranges field and keep only the separated resource maas_subnet_ip_range. Breaking change but cleaner
    • Define an optional field subnets := list(subnet_ids) to define dependencies either through it or through ip_ranges to the new resource maas_vlan_dhcp.

Opinions?

data "maas_vlan" "vlan" {
    fabric = "fabric-0"
    vid    = 100
}

data "maas_vlan" "relay_vlan" {
    fabric = "fabric-0"
    vid    = 0
}

data "maas_rack_controller" "controller_primary" {
    name = "maas-dev-1"
}

data "maas_rack_controller" "controller_secondary" {
    name = "maas-dev-2"
}

resource "maas_subnet" "subnet_1" {
  fabric = data.maas_fabric.fabric.id
  vlan   = data.maas_vlan.id
  name   = "test_subnet"

  cidr        = "10.77.77.0/24"
  gateway_ip  = "10.77.77.1"
  dns_servers = [
    "1.1.1.1",
  ]
}

resource "maas_subnet_ip_range" "dynamic_ip_range_1_1" {
  subnet   = maas_subnet.subnet_1.id
  type     = "dynamic"
  start_ip = "10.77.77.2"
  end_ip   = "10.77.77.60"
}

resource "maas_subnet_ip_range" "dynamic_ip_range_1_2" {
  subnet   = maas_subnet.subnet_1.id
  type     = "dynamic"
  start_ip = "10.77.77.61"
  end_ip   = "10.77.77.120"
}

resource "maas_vlan_dhcp" "dhcp" {
    vlan = data.maas_vlan.id

    ip_ranges = [
        maas_subnet_ip_range.dynamic_ip_range_1_1,
        maas_subnet_ip_range.dynamic_ip_range_1_2,
    ]
    // Optional additional field
    // subnets = [
    //   maas_subnet.subnet_1.id,
    // ]

    // Optional
    relay_vlan = data.maas_vlan.relay_vlan.id
    // XOR
    primary_rack_controller = data.maas_rack_controller.controller_primary.id
    secondary_rack_controller = data.maas_rack_controller.controller_secondary.id
}
troyanov commented 9 months ago

I was thinking a solution that involves the development of a new resource named e.g. maas_vlan_dhcp and the removal of field dhcp_on from maas_vlan.

IIUC users will have to pick one of:

  1. maas_vlan_dhcp (like as it would be maas_vlan with dhcp_on = true)
  2. maas_vlan (same as dhcp_on = false)

I am wondering how it will be possible to "enable/disable DHCP on certain VLAN" in this case?

  1. This approach is not taking into consideration the existing embedded ip_ranges inside a maas_subnet. A complete solution will do one of the two things:

    • Remove the maas_subnet embedded ip_ranges field and keep only the separated resource maas_subnet_ip_range. Breaking change but cleaner
    • Define an optional field subnets := list(subnet_ids) to define dependencies either through it or through ip_ranges to the new resource maas_vlan_dhcp.

I like the idea with maas_subnet_ip_range

skatsaounis commented 9 months ago

I was thinking a solution that involves the development of a new resource named e.g. maas_vlan_dhcp and the removal of field dhcp_on from maas_vlan.

IIUC users will have to pick one of:

1. `maas_vlan_dhcp` (like as it would be `maas_vlan` with `dhcp_on = true`)

2. `maas_vlan` (same as `dhcp_on = false`)

I am wondering how it will be possible to "enable/disable DHCP on certain VLAN" in this case?

Not exactly that, but close to that. With the proposed solution, DHCP of a VLAN is decoupled of its lifecycle. So maas_vlan will be used only to create/update/delete VLAN except its DHCP related configuration. For DHCP only config, the new resource maas_vlan_dhcp will be used.

The existence of this new resource will mean DHCP is enabled to the VLAN, linked by id. To achieve that, user has to additionally define the primary rack controller which will serve the DHCP. A secondary rack controller can be to defined with the relevant optional field.

In case user wants to enable DHCP by relay VLAN, instead of providing a primary rack (+ optional secondary), they have to set the relay_vlan ID.

The deletion of a maas_vlan_dhcp resource will mean that DHCP is no longer available to that VLAN, so let's disable it.

brahman81 commented 6 months ago

We are also impacted by this feature request. We're using this Terraform provider to manage our reasonably large maas deployment of about 1500 vlans and about 1000 machines per site and would greatly benefit from being able to define a maas_vlan_dhcp resource with DHCP relay configuration in relay_vlan or direct to rack controller in rack_controller parameters.

This would save us a lot of toil and keep all MAAS configuration defined inside our Terraform repo instead of in ancillary scripts.

With no understanding of the project and feature timeline, I am wondering if there is a process and/or potential for us to contribute to this feature via PR ?