In Terraform, I want to build a Azure route table and assign it to an existing subnet. To do this, I need the subnet_id. Is there an easy way to pull this information into Terraform?
Below is the route table association resource I am using.
resource "azurerm_subnet_route_table_association" "test" {
subnet_id = "${data.azurerm_subnet.spoke.subnet_id}"
route_table_id = "${module.routetable.routetable_id}"
}
Assuming you already set up data.azurerm_subnet.spoke, it looks like your mistake is using subnet_id instead of just id.
resource "azurerm_subnet_route_table_association" "test" {
subnet_id = "${data.azurerm_subnet.spoke.id}"
route_table_id = "${module.routetable.routetable_id}"
}
The documentation shows which values are available under Attributes Reference.
If you haven't set up the data source, it should look something like this:
data "azurerm_subnet" "spoke" {
name = "<NAME>"
virtual_network_name = "<VIRTUAL_NETWORK_NAME>"
resource_group_name = "<RESOURCE_GROUP_NAME>"
}
Related
I have been trying to figure out what would be the most ideal option to deploy some fundamental, mostly identical resources (vnet, subnet, bastion host, nsg, etc.) resources in Azure, using Terraform.
I have tried it with for_each and it was working just fine until I have faced a problem where I had to pass a value to an attribute from a resource which was created with for_each. Let me show you:
So this is obviously working, nothing wrong with the following resources:
resource "azurerm_subnet" "AzureBastionSubnet" {
for_each = var.bastion_subnet
name = each.value["name"]
resource_group_name = azurerm_resource_group.rg.name
virtual_network_name = azurerm_virtual_network.vnet[each.key].name
address_prefixes = each.value["address_prefixes"]
depends_on = [azurerm_virtual_network.vnet]
}
resource "azurerm_public_ip" "bastion_public_ip" {
for_each = toset(var.public_ip_location)
name = "bastion-public-ip-${each.value}"
location = each.value
resource_group_name = azurerm_resource_group.rg.name
allocation_method = "Static"
sku = "Standard"
depends_on = [azurerm_subnet.AzureBastionSubnet]
}
But the problem starts now when in the following resource I need to pass attribute values from resources which were created with for_each. How on earth do I pass the right attributes from the created bastion subnets and public IPs to the subnet_id and public_ip_address_id?
resource "azurerm_bastion_host" "bastion" {
for_each = toset(var.location_list)
name = "bastion-${each.value}"
location = each.value
resource_group_name = azurerm_resource_group.rg.name
ip_configuration {
name = "configuration"
subnet_id = azurerm_subnet.AzureBastionSubnet.id
public_ip_address_id = azurerm_public_ip.bastion_public_ip.id
}
depends_on = [azurerm_public_ip.bastion_public_ip]
}
Thanks!
I was looking into Terraform's lookup, and also the for loop and I am sure they could make it work but I just cannot seem to figure it out.
You might be creating multiple items of azurerm_subnet.AzureBastionSubnet as you are using for_each here
resource "azurerm_subnet" "AzureBastionSubnet" {
for_each = var.bastion_subnet
name = each.value["name"]
resource_group_name = azurerm_resource_group.rg.name
virtual_network_name = azurerm_virtual_network.vnet[each.key].name
address_prefixes = each.value["address_prefixes"]
depends_on = [azurerm_virtual_network.vnet]
}
So you may want to refer to your individual azurerm_subnet instance by passing your var.bastion_subnet set member, or its map key.
for example:
resource "azurerm_bastion_host" "bastion" {
..
ip_configuration {
...
subnet_id = azurerm_subnet.AzureBastionSubnet["subnet-1"].id
}
depends_on = [azurerm_public_ip.bastion_public_ip]
}
Where subnet-1 is a key in my var.bastion_subnet map.
From Terraform documentation:
Referring to Instances
When for_each is set, Terraform distinguishes between the block
itself and the multiple resource or module instances associated with
it. Instances are identified by a map key (or set member) from the
value provided to for_each.
<TYPE>.<NAME> or module.<NAME> (for example,
azurerm_resource_group.rg) refers to the block. <TYPE>.<NAME>[<KEY>]
or module.<NAME>[<KEY>] (for example,
azurerm_resource_group.rg["a_group"],
azurerm_resource_group.rg["another_group"], etc.) refers to individual
instances.
Trying to create Databricks workspace using terraform but unsupported arguments:
resource "azurerm_databricks_workspace" "workspace" {
name = "testdata"
resource_group_name = "cloud-terraform"
location = "east us"
sku = "premium"
virtual_network_id = azurerm_virtual_network.vnet.id
public_subnet_name = "databrickpublicsubnet"
public_subnet_cidr = "10.0.0.0/22"
private_subnet_name = "databrickprivatesubnet"
private_subnet_cidr = "10.0.0.0/22"
tags = {
Environment = "terraformtest"
}
}
Error: An argument named "virtual_network_id" is not expected here. An argument named "public_subnet_name" is not expected here. An argument named "public_subnet_cidr" is not expected here.
I haven't tried to set up databricks via Terraform, but I believe (per the docs) you need add those properties in a block:
resource "azurerm_databricks_workspace" "workspace" {
name = "testdata"
resource_group_name = "cloud-terraform"
location = "east us"
sku = "premium"
custom_parameters {
virtual_network_id = azurerm_virtual_network.vnet.id
public_subnet_name = "databrickpublicsubnet"
private_subnet_name = "databrickprivatesubnet"
}
tags = {
Environment = "terraformtest"
}
}
The two cidr entries aren't part of the TF documentation.
true. you can add terraform commands to create the subnets (assuming vnet already exists, you can use data azurerm_virtual_network then create the two new subnets, then reference the names of the two new public/private subnets.
Then you run into what seems to be a chicken/egg issue though.
You get Error: you must define a value for 'public_subnet_network_security_group_association_id' if 'public_subnet_name' is set.
Problem is, the network security group is typically auto-generated on creation of the databrick workspace (like databricksnsgrandomstring), which works when creating it in the portal, but via terraform, I have to define it to create the workspace, but it doesn't yet exist until I create the workspace. The fix is to not let it generate it's own nsg name, but name it yourself with an nsg resource block.
below is code I use (dbname means databricks name!). here I'm
adding to an existing resource group 'qa' and existing vnet as well, only showing the public subnet and nsg association, you can easily add the private ones). just copy/modify in your own tf file(s). and you'll definitely need to change the address_prefix to your own CIDR values that works within your vnet and not stomp on existing subnets within.
resource "azurerm_subnet" "public" {
name = "${var.dbname}-public-subnet"
resource_group_name = data.azurerm_resource_group.qa.name
virtual_network_name = data.azurerm_virtual_network.vnet.name
address_prefixes = ["1.2.3.4/24"]
delegation {
name = "databricks_public"
service_delegation {
name = "Microsoft.Databricks/workspaces"
}
}
}
resource "azurerm_network_security_group" "nsg" {
name = "${var.dbname}-qa-databricks-nsg"
resource_group_name = data.azurerm_resource_group.qa.name
location= data.azurerm_resource_group.qa.location
}
resource "azurerm_subnet_network_security_group_association" "nsga_public" {
network_security_group_id = azurerm_network_security_group.nsg.id
subnet_id = azurerm_subnet.public.id
}
Then in your databricks_workspace block, replace your custom parameters with
custom_parameters {
public_subnet_name = azurerm_subnet.public.name
public_subnet_network_security_group_association_id = azurerm_subnet_network_security_group_association.nsga_public.id
private_subnet_name = azurerm_subnet.private.name
private_subnet_network_security_group_association_id = azurerm_subnet_network_security_group_association.nsga_private.id
virtual_network_id = data.azurerm_virtual_network.vnet.id
}
I want to create resources in a new resource group but i want to use a virtual network for those resources which is in another resource group. How do i do this? For example, i want to create redis/postgresql in resourcegroupA but i want to make use of the virtual network which is in resourcegroupB. Is it possible?
This is the resource group from where i am retrieving the vnet-
resource "azurerm_resource_group" "azresourcegroup" {
name =
"resourcegroupA"
location = var.resource_group_location
}
#-----CREATING VIRTUAL NETWORK-----
resource "azurerm_virtual_network" "vnet2" {
name = "virtualnetworkA"
location = azurerm_resource_group.azresourcegroup.location
resource_group_name = azurerm_resource_group.azresourcegroup.name
address_space = [var.virtual_network_address_prefix_infra,var.virtual_network_address_prefix]
I retrieved it while using it for another resource group like this-
data "azurerm_resource_group" "azresourcegroup" {
name = "resoucegroupA"
}
data "azurerm_virtual_network" "vnet2" {
name = "virtualnetworkA"
resource_group_name = data.azurerm_resource_group.azresourcegroup.name
}
I want to use the above virtual network but want to create the other resources in the new resource group which is-
resource "azurerm_resource_group" "main" {
name = "resourcegroupB"
location = var.resource_group_location
}
I am making use of module to create redis cache that requires the vnet which is created in other RG-
module "rediscache" {
source = "../../modules/rediscache"
prefix = var.prefix
environmentType = var.environmentType
virtual_network_name = var.virtual_network_name
unique_identifier = var.unique_identifier_kube
resource_group_name = azurerm_resource_group.main.name
resource_group_location = var.resource_group_location
redis_subnet_address_prefix = var.redis_subnet_address_prefix
azurerm_virtual_network_name = data.azurerm_virtual_network.vnet2.name
azurerm_log_analytics_workspace_id = azurerm_log_analytics_workspace.workspace.id
}
To simplify this, vnet is created in other resource group and redis in another one.But i want to use that vnet. also if i change the resource group name argument used in module, from azurerm_resource_group.main.name to data.azurerm_resource_group.azresourcegroup.name then it creates the redis in the 1st resource group which i dont want.
Please help.
Of course, it's possible. The only condition is that the virtual network should be in the same location. Then you can quote it in the Terraform code via the Terraform Data Source azurerm_virtual_network like this:
data "azurerm_virtual_network" "example" {
name = "production"
resource_group_name = "networking"
}
I want to pull the VNET location using just the azurerm_virtual_network data resource. Terraform's documentation says teh location attribute is available, but it is not working for me.
Here is my code:
data "azurerm_virtual_network" "vnet" {
name = "my-vnet"
resource_group_name = "my-vnet-resource-group"
}
output "LOCATION" {
value = "${data.azurerm_virtual_network.vnet.location}"
}
This is the error message I am receiving..
output.LOCATION: Resource 'data.azurerm_virtual_network.vnet'
does not have attribute 'location' for variable
'data.azurerm_virtual_network.vnet.location'
Any help getting around this is sincerely appreciated!
So doesn't seem there is a way to do it through the azurerm_virtual_network data resource. However, I was able to get it working by using the azurerm_resource_group data resource in conjunction with azurerm_virtual_network.
data "azurerm_virtual_network" "vnet" {
name = "my-vnet"
resource_group_name = "my-vnet-resource-group"
}
data "azurerm_resource_group" "rg" {
name = "${data.azurerm_virtual_network.vnet.resource_group_name}"
}
output "LOCATION" {
value = "${data.azurerm_resource_group.rg.location}"
}
according to this it is not possible. honestly, terraform is just bad ;)
I'm trying create a resource in terraform that will create a number of subnets based on a list variable.
I'm having trouble with references to existing resources. For example in the following code network_security_group_id is hardcoded to azurerm_network_security_group.k8s.id:
variable "resources_large" {
description = "List of Large Networks"
default = [
"k8s",
"storm"
]
}
resource "azurerm_subnet" "large" {
name = "ue-${var.environment}-${var.resources_large[count.index]}-subnet-${replace("${cidrsubnet("${local.subnet_ranges["large"]}", "${var.newbit_size["large"] }", count.index )}", "/[./]/", "-" ) }"
resource_group_name = "ue-${var.environment}-${var.resources_large[count.index]}-rg"
virtual_network_name = "${azurerm_virtual_network.dev.name}"
address_prefix = "${cidrsubnet("${local.subnet_ranges["large"]}", "${var.newbit_size["large"] }", count.index )}"
network_security_group_id = "${azurerm_network_security_group.k8s.id}"
count = "${length(var.resources_large)}"
depends_on = ["azurerm_virtual_network.dev"]
}
This needs to reference existing security groups based on the name in the resources_large list.
What I'd like to have is something which looks likes this:
network_security_group_id = "${azurerm_network_security_group.${var.resources_large[count.index]}.id}"
Which doesn't work, I'm guessing due to the lack of variable interpolation support.
Is there any way to reference other resources based on variable?
Maybe something like this
locals {
sgs = {
k8s = "${azurerm_network_security_group.k8s.id}"
storm = "${azurerm_network_security_group.storm.id}"
}
}
...
network_security_group_id = "${lookup( locals.sgs, var.resources_large[count.index])}"
may work.
If you create the SG using the same counter, it can be just
network_security_group_id = "${element(azurerm_network_security_group.*.id, count.index)}"
HTH