Azure Databricks workspace using terraform - terraform

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
}

Related

Unable to update address space on Azure vnet using terraform

Objective: I am trying to update existing address space (4 ranges) as it was wrong cidr range given when creating it orginally
Context: Existing vnet consists of address_space as
["xx.xxx.0.0/24","xx.xxx.0.0/20","xx.xxx.0.0/24","xx.xxx.0.0/20"]
Now, I changed this to
["xx.xxx.0.0/24","xx.xxx.0.0/24","xx.xxx.0.0/24","xx.xxx.0.0/20"]
But when I rerun my terraform, plan does not pick this up as change. By the way, this is not having any vnet peering
The code that I use for creating Vnet :
resource "azurerm_virtual_network" "vnet" {
name = var.hub_vnet_name
location = azurerm_resource_group.rg[0].location
resource_group_name = azurerm_resource_group.rg[0].name
address_space = var.vnet_address_space
dns_servers = var.dns_servers
tags = {
environment = "${var.env}"
costcentre = "xxx"
}
dynamic "ddos_protection_plan" {
for_each = local.if_ddos_enabled
content {
id = azurerm_network_ddos_protection_plan.ddos[0].id
enable = false
}
}
}
Varaibles.tf:
variable "vnet_address_space" {
description = "The address space to be used for the Azure virtual network."
default = ["xx.xxx.0.0/24","xx.xxx.0.0/24","xx.xxx.0.0/24","xx.xxx.0.0/20"]
}
Really not sure why terraform is not able to see this change, can some one guide
no there is no erros it says during the plan

Subnet is showing as destroyed in terraform destroy but it is not getting removed from azure portal

I have written a module called network_resources in which I am creating vnets and subnets attached to it. Below is the code for the module and how the module is being called:
main.tf
resource "azurerm_virtual_network" "vnets" {
for_each = var.vnets
name = each.key
resource_group_name = var.resource_group_name
location = var.location
address_space = [each.value.address_space]
dns_servers = each.value.dns_servers
}
resource "azurerm_subnet" "subnets" {
for_each = local.subnets
name = each.value.subnet_name
resource_group_name = var.resource_group_name
virtual_network_name = azurerm_virtual_network.vnets[each.value.vnet_name].name
address_prefixes = [each.value.subnet_address]
service_endpoints = each.value.service_endpoints
}
local.tf
locals {
subnets_flatlist = flatten([for key, val in var.vnets : [
for subnet in val.subnets : {
vnet_name = key
subnet_name = subnet.subnet_name
subnet_address = subnet.subnet_address
service_endpoints = subnet.service_endpoints
}
]
])
subnets = { for subnet in local.subnets_flatlist : subnet.subnet_address => subnet }
}
variables.tf
variable "resource_group_name" {
description = "Name of the resource group to be imported."
type = string
}
variable "location" {
description = "The location of the vnet to create. Defaults to the location of the resource group."
type = string
default = null
}
variable "vnets" {
type = map(object({
address_space = string
dns_servers = list(string)
subnets = list(object({
subnet_name = string
subnet_address = string
service_endpoints = list(string)
}))
}))
}
Code to call the module:
module "network_aks_prod1" {
source = "./network_resources_dns"
vnets = var.vnets_aks_prod1
resource_group_name = azurerm_resource_group.rg2.name
location = azurerm_resource_group.rg2.location
}
Variables.tf
vnets_aks_prod1 = {
"bupaanz-mel-prod-caas-vnet01" = {
address_space = "10.80.0.0/18"
#dns_servers = ["10.0.0.4" , "10.0.0.5"]
dns_servers = ["10.0.0.6","10.0.0.5", "10.0.0.6", "10.0.0.4","10.64.150.11"]
subnets = [
{
subnet_name = "subnet-mel-prod-aks-mgmt-10.80.9.64"
subnet_address = "10.80.9.64/26"
service_endpoints = []
},
{
subnet_name = "subnet-mel-prod-aks-internal1-10.80.0.0"
subnet_address = "10.80.0.0/22"
service_endpoints = []
},
{
subnet_name = "GatewaySubnet"
subnet_address = "10.80.9.0/26"
service_endpoints = []
},
{
subnet_name = "subnet-mel-prod-aks-internal2-10.80.4.0"
subnet_address = "10.80.4.0/22"
service_endpoints = []
},
{
subnet_name = "subnet-mel-prod-aks-pa1-ext-10.80.8.0"
subnet_address = "10.80.8.0/25"
service_endpoints = []
},
{
subnet_name = "subnet-mel-prod-aks-pa2-int-10.80.8.128"
subnet_address = "10.80.8.128/25"
service_endpoints = []
},
]
},
}
All the vnets and subnets get created successfully with the above code.
Now if I have to delete one subnet, i am removing the code for one of the subnet with all its attributes.
Now when I run the terraform plan and apply again, it informs that one subnet will be deleted. It is showing in terraform apply also the subnet has got deleted but it is not getting deleted in the portal. Please can you let me know how the subnet will get deleted in the portal with the terraform code only using the code which I am using.
Update as of 18th May 2022
Following further triage, it appears that azurerm_virtual_network resource is being modified because of a change of tags/edge_zone/bgp_community/flow_timeout_in_minutes attributes.
While deleting a subnet, terraform plan shows it is going to modify above attributes but under the hoods, it is updating the azurerm_virtual_network resource from the state file which includes the subnet azurerm_subnet just deleted.
Workaround to get it working with azurerm_virtual_network is to add lifecycle block as shown below..
resource "azurerm_virtual_network" "vnets" {
for_each = var.vnets
name = each.key
resource_group_name = var.resource_group_name
location = var.location
address_space = [each.value.address_space]
dns_servers = each.value.dns_servers
lifecycle {
ignore_changes = [
# one or more of the below attributes
tags, edge_zone, bgp_community, flow_timeout_in_minutes
]
}
}
TBH, I'm not sure of the side-effects of the above attributes by including them into lifecycle block but it doesn't update the vnet resources when these gets changed.
However this is a bug on Terraform provider, you must create an issue there to get this fixed.
You are unable to delete the subnet because you haven't set subnet = [] in the azurerm_virtual_network resource. Below is what the documentation here says::
Since subnet can be configured both inline and via the separate
azurerm_subnet resource, we have to explicitly set it to empty slice
([]) to remove it.
Also, the doc says below::
Terraform currently provides both a standalone Subnet resource, and
allows for Subnets to be defined in-line within the Virtual Network
resource. At this time you cannot use a Virtual Network with in-line
Subnets in conjunction with any Subnet resources. Doing so will cause
a conflict of Subnet configurations and will overwrite subnets.
Nevertheless, applying an empty slice gave even worse results as it wiped off all subnets. I think it's better you use dynamic-blocks to create subnets as part of vnet resource rather than using subnet specific resource.
subnet {
name = "subnet-mel-prod-aks-pa1-ext-10.80.8.0"
address_prefix = "10.80.8.0/25"
}
/*
subnet {
name = "subnet-mel-prod-aks-pa2-int-10.80.8.128"
address_prefix = "10.80.8.128/25"
}
*/
...
From the above snippet, when I commented on the subnet, it did delete the only subnet I commented out. I'm not sure whether there is a bug to fix azurerm_subnet as its behavior is very weird.

Terraform tried creating a "implicit dependency" but the next stage of my code still fails to find the Azure resource group just created

Would be grateful for any assistance, I thought I had nailed this one when I stumbled across the following link ...
Creating a resource group with terraform in azure: Cannot find resource group directly after creating it
However, the next stage of my code is still failing...
Error: Code="ResourceGroupNotFound" Message="Resource group 'ShowTell' could not be found
# We strongly recommend using the required_providers block to set the
# Azure Provider source and version being used
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "=2.64.0"
}
}
}
# Configure the Microsoft Azure Provider
provider "azurerm" {
features {}
}
variable "resource_group_name" {
type = string
default = "ShowTell"
description = ""
}
# Create your resource group
resource "azurerm_resource_group" "example" {
name = var.resource_group_name
location = "UK South"
}
# Should be accessible from LukesContainer.uksouth.azurecontainer.io
resource "azurerm_container_group" "LukesContainer" {
name = "LukesContainer"
location = "UK South"
resource_group_name = "${var.resource_group_name}"
ip_address_type = "public"
dns_name_label = "LukesContainer"
os_type = "Linux"
container {
name = "hello-world"
image = "microsoft/aci-helloworld:latest"
cpu = "0.5"
memory = "1.5"
ports {
port = "443"
protocol = "TCP"
}
}
container {
name = "sidecar"
image = "microsoft/aci-tutorial-sidecar"
cpu = "0.5"
memory = "1.5"
}
tags = {
environment = "testing"
}
}
In order to create an implicit dependency you must refer directly to the object that the dependency relates to. In your case, that means deriving the resource group name from the resource group object itself, rather than from the variable you'd used to configure that object:
resource "azurerm_container_group" "LukesContainer" {
name = "LukesContainer"
location = "UK South"
resource_group_name = azurerm_resource_group.example.name
# ...
}
With the configuration you included in your question, both the resource group and the container group depend on var.resource_group_name but there was no dependency between azurerm_container_group.LukesContainer and azurerm_resource_group.example, and so Terraform is therefore free to create those two objects in either order.
By deriving the container group's resource group name from the resource group object you tell Terraform that the resource group must be processed first, and then its results used to populate the container group.

How to use existing resources from another resource group to make deployments in new resource group using Terraform

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"
}

Terraform on Azure - Deploy multiple subnet

I'm trying to implement a Terraform script to create multiple subnets.
resource "azurerm_subnet" "test_subnet" {
name = "testSUBNET"
resource_group_name = "${local.resource_group_name}"
virtual_network_name = "${azurerm_virtual_network.lab_vnet.name}"
address_prefix = "10.0.1.0/24"
}
Is there a way to do a for-each or a loop on a variable in order to create them at the same time?
You can achieve this using a variable and count index as follows:
variable "subnet_prefix" {
type = "list"
default = [
{
ip = "10.0.1.0/24"
name = "subnet-1"
},
{
ip = "10.0.2.0/24"
name = "subnet-2"
}
]
}
resource "azurerm_subnet" "test_subnet" {
name = "${lookup(element(var.subnet_prefix, count.index), "name")}"
count = "${length(var.subnet_prefix)}"
resource_group_name = "${local.resource_group_name}"
virtual_network_name = "${azurerm_virtual_network.lab_vnet.name}"
address_prefix = "${lookup(element(var.subnet_prefix, count.index), "ip")}"
}
There is also preview feature available for-each in the new version
If you are using Terraform 12 this can be achieved using the for-each capability or the count capability
count should be used if you are looking to create almost identical resources.
for-each should be used to create multiple of each instance based on a different map or set of values.
Using an list of strings and the toset() function to convert this is a neat way to achieve this
variable "subnet_ids" {
type = list(string)
}
resource "aws_instance" "server" {
for_each = toset(var.subnet_ids)
ami = "ami-a1b2c3d4"
instance_type = "t2.micro"
subnet_id = each.key # note: each.key and each.value are the same for a set
tags = {
Name = "Server ${each.key}"
}
}
Or you could achieve this by using something like the below:
resource "azurerm_resource_group" "rg" {
for_each = {
a_group = "eastus"
another_group = "westus2"
}
name = each.key
location = each.value
}
If you are looking to achieve this with Terraform 11 the count and variable capabilities are the only way other than code duplication. (Rajat Arora has mentioned)
I would strongly recommended using Terraform 12 as the providers for Terraform 11 will be unsupported in the not to far future and if you can save yourself from refactoring now, you should!

Resources