Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

crash when passing invalid value to object attribute with defaults #32752

Closed
merecogroup opened this issue Feb 28, 2023 · 7 comments · Fixed by #32775
Closed

crash when passing invalid value to object attribute with defaults #32752

merecogroup opened this issue Feb 28, 2023 · 7 comments · Fixed by #32775
Assignees
Labels
bug config confirmed a Terraform Core team member has reproduced this issue

Comments

@merecogroup
Copy link

Terraform Version

Terraform v1.3.9
on linux_amd64
+ provider registry.terraform.io/cloudflare/cloudflare v2.27.0
+ provider registry.terraform.io/hashicorp/azuread v2.28.1
+ provider registry.terraform.io/hashicorp/azurerm v3.45.0
+ provider registry.terraform.io/hashicorp/null v3.2.1
+ provider registry.terraform.io/hashicorp/random v3.4.3
+ provider registry.terraform.io/hashicorp/time v0.9.1

Terraform Configuration Files

data "azurerm_dns_a_record" "mysql_server_ip" {
  name                = "some_name"
  zone_name           = "mysql.database.azure.com"
  resource_group_name = azurerm_resource_group.rg.name
}

module "firewall_rule" {
  ...
  nat_rules = {
    ...
    translated_address    = tolist(data.azurerm_dns_a_record.mysql_server_ip.records)[0]
  }
}

Debug Output

error.log

Expected Behavior

Either passing validate or outputting a validation error

Actual Behavior

Terraform crashes

Steps to Reproduce

terraform init
terraform validate

Additional Context

No response

References

No response

@merecogroup merecogroup added bug new new issue not yet triaged labels Feb 28, 2023
@jbardin
Copy link
Member

jbardin commented Feb 28, 2023

Hi @merecogroup,

Thanks for filing the issue. The error here seems to be originating when applying the variable defaults. Can you show the variable type definition for the module?

Thanks!

@jbardin jbardin added waiting-response An issue/pull request is waiting for a response from the community waiting for reproduction unable to reproduce issue without further information and removed new new issue not yet triaged labels Feb 28, 2023
@merecogroup
Copy link
Author

Hi @jbardin,

the variable type is:

variable "nat_rules" {
  type = map(object({
    priority = number
    action   = optional(string, "Dnat")
    rules = map(object({
      description           = string
      protocols             = optional(list(string), ["TCP"])
      source_addresses      = optional(list(string), [])
      source_ip_groups      = optional(list(string), [])
      destination_ports     = list(string)
      destination_addresses = optional(list(string), [])
      translated_address    = string
      translated_port       = string
    }))
  }))
  default = {}
}

I tested some further and I only get the crash with terraform version 1.3.9, if I use 1.3.2 I get the validation error:

Validation failed: .
╷
│ Error: Invalid value for input variable
│ 
│   on firewall.tf line 28, in module "firewall_rule":
│   28:   nat_rules = {
│   29:     mysql = {
│   30:       priority = 1000
│   31:       rules = {
│   32:         description           = "Port forward"
│   33:         destination_ports     = ["3306"]
│   34:         destination_addresses = [module.firewall.public_ip]
│   35:         translated_address    = tolist(data.azurerm_dns_a_record.mysql_server_ip.records)[0]
│   36:         translated_port       = "3306"
│   37:       }
│   38:     }
│   39:   }
│ 
│ The given value is not suitable for
│ module.firewall_rules_mysql.var.nat_rules declared at
│ .terraform/modules/firewall_rules_mysql/variables.tf:52,1-21: element
│ "mysql": attribute "rules": element "destination_ports": object required.
╵

What is expected behaviour for me.

Thank you for your help

@jbardin
Copy link
Member

jbardin commented Feb 28, 2023

Are you certain the translated_address assignment is the problematic line? The destination_ports error looks correct if you didn't assign it, because that attribute is not optional. Can you show the entire nat_rules, even better if you can supply sample data to reproduce the crash?

Thanks!

@merecogroup
Copy link
Author

I'm certain it is translated_address as I had 'data.azurerm_dns_a_record.mysql_server_ip.records[0] which didn't crash and after I changed it to tolist(data.azurerm_dns_a_record.mysql_server_ip.records)[0] terraform validate crashed.

The code is:

data "azurerm_dns_a_record" "mysql_server_ip" {
  name                = "some_name"
  zone_name           = "mysql.database.azure.com"
  resource_group_name = azurerm_resource_group.rg.name
}

module "firewall_rule" {
  depends_on                   = [module.firewall]
  source                       = "git::ssh://git-url"
  firewall_name                = module.firewall.firewall_name
  firewall_resource_group_name = azurerm_resource_group.rg.name

  nat_rules = {
    mysql = {
      priority = 1000
      rules = {
        description           = "Port forward"
        destination_ports     = ["3306"]
        destination_addresses = [module.firewall.public_ip]
        translated_address    = tolist(data.azurerm_dns_a_record.mysql_server_ip.records)[0]
        translated_port       = "3306"
      }
    }
  }
}

And the code from the module is:

variable "firewall_resource_group_name" {
  type        = string
}

variable "firewall_name" {
  type        = string
}

variable "nat_rules" {
  type = map(object({
    priority = number
    action   = optional(string, "Dnat")
    rules = map(object({
      description           = string
      protocols             = optional(list(string), ["TCP"])
      source_addresses      = optional(list(string), [])
      source_ip_groups      = optional(list(string), [])
      destination_ports     = list(string)
      destination_addresses = optional(list(string), [])
      translated_address    = string
      translated_port       = string
    }))
  }))
  default = {}
}

resource "azurerm_firewall_nat_rule_collection" "dnat_rules" {
  for_each            = var.nat_rules
  name                = each.key
  azure_firewall_name = var.firewall_name
  resource_group_name = var.firewall_resource_group_name
  priority            = each.value.priority
  action              = each.value.action

  dynamic "rule" {
    for_each = each.value.rules
    content {
      name                  = rule.key
      description           = rule.value.description
      protocols             = rule.value.protocols
      destination_addresses = rule.value.destination_addresses
      destination_ports     = rule.value.destination_ports
      source_addresses      = rule.value.source_addresses
      source_ip_groups      = rule.value.source_ip_groups
      translated_address    = rule.value.translated_address
      translated_port       = rule.value.translated_port
    }
  }
}

How can I get the sample data you need?

@jbardin
Copy link
Member

jbardin commented Feb 28, 2023

Oh, actually piecing these together I can get a reproducible crash now. The problem here is that the type for rules is a map of objects, but you are passing a single object and Terraform is attempting to convert each attribute to the required object type. The validation error was correct, but a bit misleading because it was describing the missing attributes from the wrong value being passed in. The key part is "destination_ports": object required, the key destination_ports should have an object argument, because the type definition says rules is a map of objects.

If you change rules to a map this will pass correctly. The crash is a bug in when trying to convert incompatible data.

Thanks!

@jbardin jbardin added config confirmed a Terraform Core team member has reproduced this issue and removed waiting-response An issue/pull request is waiting for a response from the community waiting for reproduction unable to reproduce issue without further information labels Feb 28, 2023
@jbardin jbardin changed the title Terraform validate crashes for tolist(data.azurerm_dns_a_record.mysql_server_ip.records)[0] crash when passing invalid value to object attribute with defaults Mar 1, 2023
@liamcervante liamcervante self-assigned this Mar 3, 2023
@liamcervante
Copy link
Member

The fix for this should be merged in time for the v1.4.1 release.

@github-actions
Copy link

github-actions bot commented Apr 9, 2023

I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues.
If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 9, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug config confirmed a Terraform Core team member has reproduced this issue
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants