terraformciscocisco-dnac

Error: Failure when executing a Terraform Resource creation request


I am working on a scripts for creating a site hierarchy in Cisco DNA/Catalyst Center. I have structure that looks like this:

├── main.tf
├── variables.tf
├── modules 
│ └── site_settings 
│   └── ip-pools.tf 
│   └── variables.tf
├── Site-1
│ └── site-1.tfvars

In ./main.tf I have:

provider "dnacenter" {

    base_url = var.dnac_url
    debug = "true"
    ssl_verify = "false"
}

module "site_settings" {
  # Using m0_general_settings module to configure general settings
  source = "../modules/site_settings"

  ip_pools = var.ip_pools
}

The ./modules/site_settings/ip-pools.tf has:

resource "dnacenter_reserve_ip_subpool" "pool" {
  for_each = { for pool in var.ip_pools : pool.name => pool }
  provider = dnacenter
  parameters {
    ipv4_dhcp_servers  = "${each.value.dhcp_server_ips}"
    ipv4_dns_servers   = "${each.value.dns_server_ips}"
    ipv4_gate_way      = "${each.value.ipv4_gate_way}"
    ipv4_global_pool   = "${each.value.ipv4_global_pool}"
    ipv4_prefix        = "true"
    ipv4_prefix_length = "${each.value.ipv4_prefix_length}"
    ipv4_subnet        = "${each.value.subnet_id}"
    ipv6_address_space = "false"
    name               = "${each.value.name}"
    site_id            = dnacenter_area.site.item.0.id
    type               = each.value.type
  }
}

These are the varialbe values in ./site-1.tfvars :

ip_pools = [{
subnet_id = "10.0.4.0"
ipv4_prefix_length = "24"
name = "Site-1-USER"
reso_code = "Site-1"
ipv4_gate_way = "10.0.4.1"
type = "General"
dns_server_ips = ["10.10.1.30" , "10.10.1.31"]
dhcp_server_ips = ["10.10.10.112" , "10.10.10.116" , "10.10.11.112" , "10.10.11.116"]
ipv4_global_pool = "10.0.0.0/16" 
}]

These are the variables defined in ./variables.tf

variable "dnac_username" {
    sensitive = true
}
variable "dnac_password" {
    sensitive = true
}
variable "dnac_url" {
  type = string
}
variable "ip_pools" {
  type = list(object({
    name = string
    subnet_id = string
    type = string
    dhcp_server_ips = list(string)
    dns_server_ips = list(string)
    ipv4_gate_way = string
    ipv4_global_pool = string
    ipv4_prefix_length = string
    }))
}

And in the ./modules/site_settings/variables.tf vars I have:

variable "ip_pools" {}

When I try to run the plan command, it looks fine... I think:

# module.site_settings.dnacenter_reserve_ip_subpool.pool["Site-1-USER"] will be created
  + resource "dnacenter_reserve_ip_subpool" "pool" {
      + id           = (known after apply)
      + item         = (known after apply)
      + last_updated = (known after apply)

      + parameters {
          + ipv4_dhcp_servers  = [
              + "10.10.10.112",
              + "10.10.10.116",
              + "10.10.11.112",
              + "10.10.11.116",
            ]
          + ipv4_dns_servers   = [
              + "10.10.1.30",
              + "10.10.1.31",
            ]
          + ipv4_gate_way      = "10.0.4.1"
          + ipv4_global_pool   = "10.0.0.0/16"
          + ipv4_prefix        = "true"
          + ipv4_prefix_length = 24
          + ipv4_subnet        = "10.0.4.0"
          + ipv4_total_host    = (known after apply)
          + ipv6_address_space = "false"
          + ipv6_dhcp_servers  = (known after apply)
          + ipv6_dns_servers   = (known after apply)
          + ipv6_gate_way      = (known after apply)
          + ipv6_global_pool   = (known after apply)
          + ipv6_prefix        = (known after apply)
          + ipv6_prefix_length = (known after apply)
          + ipv6_subnet        = (known after apply)
          + ipv6_total_host    = (known after apply)
          + name               = "Site-1-USER"
          + site_id            = "61c4c037-ab4a-xxxx-xxxx-xxxxxxxxxxx"
          + slaac_support      = (known after apply)
          + type               = "General"
        }
    }

However when I try to apply, I get this error which is not very descriptive:

Error: Failure when executing ReserveIPSubpool
│ 
│   with module.site_settings.dnacenter_reserve_ip_subpool.pool["Site-1-USER"],
│   on modules/site_settings/ip-pools.tf line 16, in resource "dnacenter_reserve_ip_subpool" "pool":
│   16: resource "dnacenter_reserve_ip_subpool" "pool" {
│ 

What do you think might be wrong here? Or how can I do a debug or get some more meaningful output what the issue is? Thanks!


Solution

  • This error appears to be returned by the cisco-en-programmability/dnacenter provider, rather than by Terraform Core. Therefore I searched the provider's source code to find situations that would cause this error message, and found four:

    1. resource_reserve_ip_subpool.go:441 returns an error with this summary. However, I think we can eliminate this one because this one would return an error with the "detail" field populated, which would cause there to be additional text at the bottom of the error message, while yours seems to only include the "Failure when executing ReserveIPSubpool" summary text.
    2. resource_reserve_ip_subpool.go:445 seems like a plausible candidate, because the provider would reach here if resp1 is nil, even if err is also nil. That case would cause an error like the one you shared, which includes only a summary and no detail paragraph.
    3. resource_reserve_ip_subpool.go:478 also seems plausible: it passes err to diagError but the condition that leads into this result is only about the response status, and so doesn't consider whether err is nil. Therefore that case would cause an error like you saw here.
    4. resource_reserve_ip_subpool.go:485 has the matching summary text but always passes a non-nil error to diagError, so it should never generate a message without a detail paragraph, and so I also eliminate this one.

    That means we now only need to distinguish between cases 2 and 3 to find the ultimate cause.

    Case 2 does not offer any additional context, but just before case 3 there is a statement log.Printf("[DEBUG] Error %s", response2.BapiError) which seems like it would write more detail about the error into the provider's internal debug log.

    Therefore you should be able to observe that error if you run terraform apply with provider debug logging enabled, by setting the environment variable TF_LOG_PROVIDER=debug in your shell before you run Terraform. Somewhere near the end of the verbose log output you might find a message including [DEBUG] Error followed by an error code or message returned by the remote API, in which case this is case 3 and hopefully the detail in the log message is helpful for debugging further.

    If you don't find that message then that suggests case 2, and unfortunately I cannot speculate any further for that case.


    The way the error gets returned in case 3 seems like it might be an unintentional bug: the log message above takes the cause text from response2.BapiError, but the returned error uses the symbol err that doesn't appear to be relevant to this error return path. Perhaps the author of this code intended to write it like this instead:

                diags = append(diags, diagError(
                    "Failure when executing ReserveIPSubpool", response2.BapiError))
    

    That would then cause the error message or code from the remote API to be included in the detail part of the error message from Terraform, which would hopefully make it clearer what the problem was.

    If I'm right about that, then after you've debugged this it may be worth opening an issue in the provider's GitHub repository to report this unhelpful error message, in the hope that the provider developers can make it include additional context in future versions of the provider.