Closed AndyAtTib closed 5 months ago
Good callout, I noticed the 1.8-alpha release of Terraform is allowing for unknown values in count
. This could be worth trying for now. Alternatively we could implement a dedicated variable managing creation e.g. subnet_creation_enabled
.
It depends on the standard pattern you want to adopt. Is there an AVM standard for this kind of thing? It seems like it must be a common pattern.
I think feature toggles are easy to understand. I think verb_thing
feature toggles names like create_subnet
, allow_ssh
are short and easy to remember. Is there an AVM standard for feature toggle naming, too?
In terms of >= 1.8 vs feature toggle:
With feature toggles, if you need to you could enforce input consistency using resource "terraform_data"
with preconditions in it. For example you can throw an error if someone has supplied a subnet_id
but also set a toggle create_subnet
to true
.
resource "terraform_data" "subnet_var_validation" {
lifecycle {
precondition {
condition = (
var.create_subnet == (try(var.subnet_id, "") == "")
)
error_message = <<EOT
Inconsistent variables: `create_subnet` must be `false` if `subnet_id` is set;
otherwise `create_subnet` must be `true`"
EOT
}
}
}
resource "subnet" "main" {
...
depends_on = [terraform_data.subnet_var_validation]
}
There is a standard - here's the link TFNFR16. So in our case it would subnet_creation_enabled
.
Is there an existing issue for this?
Greenfield/Brownfield provisioning
greenfield
Terraform Version
1.7.1
Module Version
0.2.1
AzureRM Provider Version
3.89.0
Affected Resource(s)/Data Source(s)
azurerm_subnet.vgw
https://github.com/Azure/terraform-azurerm-avm-ptn-vnetgateway/blob/5932b334dcb6febb4d2fe386ee0d070dc400ba1d/main.tf#L2
Terraform Configuration Files
Click to expand for MRE configuration file
```hcl #region Providers terraform { required_version = "1.7.1" required_providers { azurerm = { source = "hashicorp/azurerm" version = "3.89.0" } local = { source = "hashicorp/local" version = "2.4.1" } random = { source = "hashicorp/random" version = "3.6.0" } tls = { source = "hashicorp/tls" version = "4.0.5" } } } provider "azurerm" { features { resource_group { prevent_deletion_if_contains_resources = false } } skip_provider_registration = true storage_use_azuread = true } provider "local" {} provider "tls" {} #endregion Providers #region Vnet locals { ic00_region = "westeurope" ic00_region_abbrev = "aweu" ic00_cidr = cidrsubnet("10.0.0.0/8", 8, 0) in00_global = { region = local.ic00_region region_abbrev = local.ic00_region_abbrev network_cidr = local.ic00_cidr } in00_naming = { workload = "modtest" region = local.ic00_region_abbrev idx = "000" } in01_snets = [ { name = "snet-000", address_prefix = cidrsubnet(local.ic00_cidr, 8, 0) }, { name = "snet-001", address_prefix = cidrsubnet(local.ic00_cidr, 8, 1) }, { name = "GatewaySubnet", address_prefix = cidrsubnet(local.ic00_cidr, 8, 2) }, ] } module "naming_vnet" { # source = "Azure/naming/azurerm" # version = "0.4.0" # "8a1c8616d4cd05423e53c3260a016919ce0df33d" source = "git::https://github.com/Azure/terraform-azurerm-naming.git?ref=8a1c8616d4cd05423e53c3260a016919ce0df33d" suffix = [ local.in00_naming.workload, "vnet", local.in00_naming.region, local.in00_naming.idx ] } resource "azurerm_resource_group" "vnet" { location = local.in00_global.region name = module.naming_vnet.resource_group.name_unique } resource "azurerm_virtual_network" "main" { name = module.naming_vnet.virtual_network.name_unique resource_group_name = azurerm_resource_group.vnet.name location = local.in00_global.region address_space = [local.in00_global.network_cidr] } resource "azurerm_subnet" "all" { for_each = { for x in local.in01_snets : x.name => x } resource_group_name = azurerm_resource_group.vnet.name virtual_network_name = azurerm_virtual_network.main.name name = each.value.name address_prefixes = [each.value.address_prefix] } data "azurerm_virtual_network" "main" { depends_on = [azurerm_virtual_network.main, azurerm_subnet.all] resource_group_name = azurerm_resource_group.vnet.name name = azurerm_virtual_network.main.name } data "azurerm_subnet" "all" { for_each = { for x in local.in01_snets[*].name : x => x } depends_on = [azurerm_virtual_network.main, azurerm_subnet.all] resource_group_name = azurerm_resource_group.vnet.name virtual_network_name = data.azurerm_virtual_network.main.name name = each.value } #endregion Vnet #region Vpn locals { ic03_vpn_subnet = [ for k, v in azurerm_subnet.all : v if k == "GatewaySubnet" ][0] in03_vpn = { gw_params = { subnet = local.ic03_vpn_subnet apipa_prefix_bits = 0 } } } module "naming_vpn" { # source = "Azure/naming/azurerm" # version = "0.4.0" # "8a1c8616d4cd05423e53c3260a016919ce0df33d" source = "git::https://github.com/Azure/terraform-azurerm-naming.git?ref=8a1c8616d4cd05423e53c3260a016919ce0df33d" suffix = [ local.in00_naming.workload, "vpn", local.in00_naming.region, "000" ] } module "vpn" { # source = "Azure/avm-ptn-vnetgateway/azurerm" # version = "0.2.1" # "5932b334dcb6febb4d2fe386ee0d070dc400ba1d" source = "git::https://github.com/Azure/terraform-azurerm-avm-ptn-vnetgateway.git?ref=5932b334dcb6febb4d2fe386ee0d070dc400ba1d" virtual_network_resource_group_name = data.azurerm_virtual_network.main.resource_group_name location = local.in00_global.region virtual_network_name = data.azurerm_virtual_network.main.name name = module.naming_vpn.virtual_network_gateway.name_unique # TODO: causes failure /* Error: Invalid count argument on .terraform/modules/vpn/main.tf line 2, in resource "azurerm_subnet" "vgw": 2: count = var.subnet_id != "" ? 0 : 1 The "count" value depends on resource attributes that cannot be determined until apply, so Terraform cannot predict how many instances will be created. To work around this, use the -target argument to first apply only the resources that the count depends on. */ subnet_id = local.in03_vpn.gw_params.subnet.id type = "Vpn" vpn_generation = "Generation2" sku = "VpnGw2" vpn_private_ip_address_enabled = false vpn_active_active_enabled = true ip_configurations = { for y in [ for x in range(0, 2) : { ip_configuration_name = "ipc-${format("%03d", x)}" private_ip_address_allocation = "Dynamic" apipa_address = cidrsubnet("169.254.2${x + 1}.0/24", 6, local.in03_vpn.gw_params.apipa_prefix_bits) public_ip = { name = "${module.naming_vpn.public_ip.name_unique}--${format("%02d", x)}" allocation_method = "Dynamic" sku = "Basic" tags = null } } ] : y.ip_configuration_name => y } express_route_circuits = {} local_network_gateways = {} vpn_type = "RouteBased" vpn_bgp_enabled = false vpn_bgp_settings = {} route_table_creation_enabled = false vpn_point_to_site = null } #endregion Vpn ```
tfvars variables values
Debug Output/Panic Output
Expected Behaviour
The module works in a configuration with a gateway subnet that is created by the configuration that calls the module.
Actual Behaviour
If a new vnet and subnets are created in the configuration calling this module, when the subnet_id is used as the module argument, then the module fails with the error shown at the plan stage.
Steps to Reproduce
terraform init && terraform plan -out tfplan
Important Factoids
no
References
none