1
votes

I had my code setup to export the dynamic private ip address when the VM is created. I did this via an outputs value. Since then, I have updated to tf 0.13 and I'm using a for_each in the module but when I reference this value now I get the below error. I'm not sure how I can export the dynamic private address attribute of the NIC now the for_each has been set to be used in the source_address_prefixes. I understand what the error is saying but not sure on correct way of exporting the value to the object map?

Error: Unsupported attribute

  on main.tf line 66, in resource "azurerm_network_security_rule" "fico-app-sr-80":
  66:   source_address_prefixes     = module.fico_web_vm.linux_vm_ips[0]
    |----------------
    | module.fico_web_vm is object with 1 attribute "web-1"

This object does not have an attribute named "linux_vm_ips".

The outputs.tf file:

output "linux_vm_names" {
  value = [azurerm_linux_virtual_machine.virtual_machine.*.name]
}

output "linux_vm_ips" {
  value = [azurerm_network_interface.network_interface.*.private_ip_address]
}

output "linux_vm_nsg" {
  value = azurerm_network_security_group.network_security_group.name
}

Security rule where the error is referencing, located in the main.tf:

resource "azurerm_network_security_rule" "fico-app-sr-80" {
  name                        = "nsr-${var.environment}-${var.directorate}-${var.business_unit}-${var.vm_identifier}${var.instance_number}-http80"
  priority                    = 100
  direction                   = "Inbound"
  access                      = "Allow"
  protocol                    = "*"
  source_port_range           = "*"
  destination_port_range      = "80"
  source_address_prefixes     = module.fico_web_vm.linux_vm_ips[0]
  destination_address_prefix  = "VirtualNetwork"
  resource_group_name         = azurerm_resource_group.rg_dwp_fico_app.name
  network_security_group_name = "module.fico_app_vm.linux_vm_nsg"
}

The NIC which is in the root module:

resource "azurerm_network_interface" "network_interface" {
  name                          = "nic-${var.environment}-${var.directorate}-${var.business_unit}-${var.vm_identifier}-${var.vm_name}"
  resource_group_name           = var.resource_group
  location                      = var.location
  enable_ip_forwarding          = "false"
  enable_accelerated_networking = "false"

  ip_configuration {
    name                          = "ipconfig1"
    subnet_id                     = data.azurerm_subnet.dwp_subnet.id
    private_ip_address_allocation = "Dynamic"
    primary                       = "true"
  }

The module that builds the web_vm in main.tf:

module "fico_web_vm" {
  for_each                     = var.web_servers
  source                       = "../modules/compute/linux_vm"
  source_image_id              = var.web_image_id
  location                     = var.location
  vm_name                      = each.key
  vm_identifier                = "${var.vm_identifier}${var.instance_number}"
  vm                           = each.value
  disks                        = each.value["disks"]
  resource_group               = azurerm_resource_group.rg_dwp_fico_web.name
  directorate                  = var.directorate
  business_unit                = var.business_unit
  environment                  = var.environment
  network_rg_identifier        = var.network_rg_identifier
  subnet_name                  = "sub-dwp-${var.environment}-${var.directorate}-${var.business_unit}-fe01"
  diag_storage_account_name    = var.diag_storage_account_name
  ansible_storage_account_name = var.ansible_storage_account_name
  ansible_storage_account_key  = var.ansible_storage_account_key
  log_analytics_workspace_name = var.log_analytics_workspace_name
  backup_policy_name           = var.backup_policy_name
}

variables for the app in the main.tf:

# Web VM Variables
variable "web_servers" {
  description = "Variable for defining each instance"
  type = map(object({
      size           = string
      admin_username = string
      public_key      = string
      disks          = list(number)
      zone_vm        = string
      zone_disk      = list(string)
  }))
}

The tfvars file that the variables.tf translates to and which the for_each loops over:

web_servers ={
  web-1 = {
    size           = "Standard_B2s"
    admin_username = xxxx
    public_key     = xxxx
    disks          = [32, 32]
    zone_vm        = "1"
    zone_disk      = ["1"]
  }
}
1
Any updates on this question? Does it solve your problem?Charles Xu

1 Answers

1
votes

As I see, there two mistakes in your code.

First:

network_security_group_name = "module.fico_app_vm.linux_vm_nsg"

need to change into:

network_security_group_name = module.fico_app_vm.linux_vm_nsg

The double quotes are usually used to set a string when you use them only, not other resources.

Second:

source_address_prefixes     = module.fico_web_vm.linux_vm_ips[0]

need to change into:

source_address_prefixes     = module.fico_web_vm.linux_vm_ips

and the output also should be change into:

output "linux_vm_ips" {
  value = azurerm_network_interface.network_interface.*.private_ip_address
}

I see you just create one NIC without count and for_each, but when you set the value with azurerm_network_interface.network_interface.*.private_ip_address then it also returns a list. And the source_address_prefixes option expects a list, so you just need to give the output.

Maybe it's better to change the output like this:

output "linux_vm_ip" {
  value = azurerm_network_interface.network_interface.private_ip_address
}

And then you can set the source_address_prefixes like this:

source_address_prefixes     = [ module.fico_web_vm.linux_vm_ip ]