Terraform complains parent resource does not exist even though exist - azure

I am trying to create some resources in azure with terraform.
What I have:
resource "azurerm_log_analytics_workspace" "logws" {
name = lower("log-${var.env}-${local.location_prefix[coalesce(var.location)]}-${random_string.postfix.result}")
resource_group_name = azurerm_resource_group.rg[0].name
location = azurerm_resource_group.rg[0].location
sku = var.log_analytics_workspace_sku
retention_in_days = var.log_analytics_logs_retention_in_days
tags = local.common_tags
}
resource "azurerm_monitor_private_link_scoped_service" "logscopelink" {
name = "scoped-${azurerm_log_analytics_workspace.logws.name}"
resource_group_name = azurerm_resource_group.rg[0].name
scope_name = azurerm_log_analytics_workspace.logws.name
linked_resource_id = azurerm_log_analytics_workspace.logws.id
depends_on = [azurerm_log_analytics_workspace.logws]
}
log analytics workspace is created but its when it try to create private_link_scoped_service it fails saying, parent resource not found.
Error I get:
│ Error: creating/updating Private Link Scoped Service: (Scoped Resource Name "scoped-log-sbx-we-oe728m" / Private Link Scope Name "log-sbx-we-oe728m" / Resource Group "hub"): insights.PrivateLinkScopedResourcesClient#CreateOrUpdate: Failure sending request: StatusCode=404 -- Original Error: Code="ParentResourceNotFound" Message="Can not perform requested operation on nested resource. Parent resource 'log-sbx-we-oe728m' not found."
I verified via azure portal, that logws does exist.
Can someone suggest what is wrong here.

You need to create a new azurerm_monitor_private_link_scope resource, then reference it in the scope_name attribute of the azurerm_monitor_private_link_scoped_service resource, example:
resource "azurerm_log_analytics_workspace" "logws" {
name = lower("log-${var.env}-${local.location_prefix[coalesce(var.location)]}-${random_string.postfix.result}")
resource_group_name = azurerm_resource_group.rg[0].name
location = azurerm_resource_group.rg[0].location
sku = var.log_analytics_workspace_sku
retention_in_days = var.log_analytics_logs_retention_in_days
tags = local.common_tags
}
# New resource required
resource "azurerm_monitor_private_link_scope" "example" {
name = var.private_link_scope_name
resource_group_name = azurerm_resource_group.rg[0].name
}
resource "azurerm_monitor_private_link_scoped_service" "logscopelink" {
name = "scoped-${azurerm_log_analytics_workspace.logws.name}"
resource_group_name = azurerm_resource_group.rg[0].name
scope_name = azurerm_monitor_private_link_scope.example.name
linked_resource_id = azurerm_log_analytics_workspace.logws.id
}
Note that I've removed the explicit depends_on attribute as Terraform can infer on its own the dependencies between resources when you reference an attribute from a resource in another resource block.

Related

Creating data lake causes error code 403 or 409. checking for existence of existing File System and then never finds it in azure terraform

I'm working on some terraform code and I have it set up that I call a module that is a storage account and data lake module. I call that to my main repo to work on it. The issue is I keep getting various error codes from the different runs I've made
Error: checking for existence of existing File System "examplenameofdl" (Account "sadl123"): datalakestore.Client#GetProperties: Failure responding to request: StatusCode=403 -- Original Error: autorest/azure: error response cannot be parsed: {"" '\x00' '\x00'} error: EOF
and
checking for existence of existing File System "examplenameofdl" (Account "sadl123"): datalakestore.Client#GetProperties: Failure sending request: StatusCode=409 -- Original Error: autorest/azure: Service returned an error. Status=
Here is the code I'm using for the storage account/ data lake
resource "azurerm_storage_account" "storage_account" {
name = var.name
location = var.location
resource_group_name = var.rg_name
tags = var.tags
account_tier = var.account_tier
account_replication_type = var.account_replication_type
account_kind = var.account_kind
access_tier = var.access_tier
is_hns_enabled = var.hnsenabled
network_rules {
default_action = var.default_network_action
ip_rules = var.ip_rules
virtual_network_subnet_ids = var.virtual_network_subnet_ids
bypass = var.bypass_network_rules
}
}
resource "azurerm_storage_data_lake_gen2_filesystem" "example" {
count = var.dlenabled ? 1 : 0 //this is to check if the data lake is needed
name = "examplenameofdl"
storage_account_id = azurerm_storage_account.storage_account.id
properties = {
hello = "aGVsbG8="
}
}
This is then called into a separate repo that has the variables where the resource group is created and then passed to it from a separate module. Whenever it's run it causes this error
│ Error: checking for existence of existing File System "examplenameofdl" (Account "sadl123"): datalakestore.Client#GetProperties: Failure responding to request: StatusCode=403 -- Original Error: autorest/azure: error response cannot be parsed: {"" '\x00' '\x00'} error: EOF
│
│ with module.storage_account1["sa-01"].azurerm_storage_data_lake_gen2_filesystem.example[0],
│ on .terraform/modules/storage_account1/main.tf line 76, in resource "azurerm_storage_data_lake_gen2_filesystem" "example":
│ 76: resource "azurerm_storage_data_lake_gen2_filesystem" "example" {
It never creates the file system so why is it checking for the existence of it? I've tried assigning permissions to the resource group to have Storage Blob Data Owner
resource "azurerm_role_assignment" "role_assignment" {
scope = azurerm_resource_group.spoke_rgs["sadl-rg-01"].id
role_definition_name = "Storage Blob Data Owner"
principal_id = data.azurerm_client_config.current.object_id
}
I've also tried to assign the storage account the same permissions, but nothing gets rid of this error. I'm completely lost on how to proceed
I tried in my environment and got below results:
Initially I tried same process and got a same error.
Console:
According to this Document, if you need to create data lake file system it requires roles like Storage blob contributor, storage blob data owner, storage account contributor, storage blob data reader.
You can assign through portal and also terraform:
data "azurerm_subscription" "primary" {
}
data "azurerm_client_config" "example" {
}
resource "azurerm_role_assignment" "example" {
scope = data.azurerm_subscription.primary.id
role_definition_name = "storage blob data owner"
principal_id = data.azurerm_client_config.example.object_id
}
Portal:
terraform.tf
provider "azurerm" {
features {}
}
resource "azurerm_resource_group" "example" {
name = "example-resources"
location = "West Europe"
}
resource "azurerm_virtual_network" "example" {
name = "example-vnet"
address_space = ["10.0.0.0/16"]
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
}
resource "azurerm_subnet" "example" {
name = "example-subnet"
resource_group_name = azurerm_resource_group.example.name
virtual_network_name = azurerm_virtual_network.example.name
address_prefixes = ["10.0.2.0/24"]
service_endpoints = ["Microsoft.Storage"]
}
resource "azurerm_storage_account" "example" {
name = "venky326"
resource_group_name = azurerm_resource_group.example.name
location = azurerm_resource_group.example.location
account_tier = "Standard"
account_replication_type = "LRS"
account_kind = "StorageV2"
is_hns_enabled = "true"
tags = {
environment = "staging"
}
}
resource "azurerm_storage_account_network_rules" "example" {
storage_account_id = azurerm_storage_account.example.id
default_action = "Allow"
ip_rules = ["127.0.0.1"]
virtual_network_subnet_ids = [azurerm_subnet.example.id]
bypass = ["Metrics"]
}
resource "azurerm_storage_data_lake_gen2_filesystem" "example" {
name = "datelake132"
storage_account_id = azurerm_storage_account.example.id
properties = {
hello = "aGVsbG8="
}
}
After assigning role to storage account, the code executed successfully.
Console:
Portal:
checking for existence of existing File System "examplenameofdl" (Account "sadl123"): datalakestore.Client#GetProperties: Failure sending request: StatusCode=409 -- Original Error: autorest/azure: Service returned an error. Status=
The above 409 error indicates in a small period of time,if the code in your application deletes and then immediately recreates a blob container with the same name.
Reference:
Troubleshoot client application errors in Azure Storage accounts | Microsoft Learn

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.

Azure Databricks workspace using 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
}

Could not read output attribute from remote state datasource

I am new to terraform so I will attempt to explain with the best of my ability. Terraform will not read in the variable/output from the statefile and use that value in another file.
I have tried searching the internet for everything I could find to see if anyone how has had this problem and how they fixed it.
###vnet.tf
#Remote State pulling data from bastion resource group state
data "terraform_remote_state" "network" {
backend = "azurerm"
config = {
storage_account_name = "terraformstatetracking"
container_name = "bastionresourcegroups"
key = "terraform.terraformstate"
}
}
#creating virtual network and putting that network in resource group created by bastion.tf file
module "quannetwork" {
source = "Azure/network/azurerm"
resource_group_name = "data.terraform_remote_state.network.outputs.quan_netwk"
location = "centralus"
vnet_name = "quan"
address_space = "10.0.0.0/16"
subnet_prefixes = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
subnet_names = ["subnet1", "subnet2", "subnet3"]
tags = {
environment = "quan"
costcenter = "it"
}
}
terraform {
backend "azurerm" {
storage_account_name = "terraformstatetracking"
container_name = "quannetwork"
key = "terraform.terraformstate"
}
}
###resourcegroups.tf
# Create a resource group
#Bastion
resource "azurerm_resource_group" "cm" {
name = "${var.prefix}cm.RG"
location = "${var.location}"
tags = "${var.tags}"
}
#Bastion1
resource "azurerm_resource_group" "network" {
name = "${var.prefix}network.RG"
location = "${var.location}"
tags = "${var.tags}"
}
#bastion2
resource "azurerm_resource_group" "storage" {
name = "${var.prefix}storage.RG"
location = "${var.location}"
tags = "${var.tags}"
}
terraform {
backend "azurerm" {
storage_account_name = "terraformstatetracking"
container_name = "bastionresourcegroups"
key = "terraform.terraformstate"
}
}
###outputs.tf
output "quan_netwk" {
description = "Quan Network Resource Group"
value = "${azurerm_resource_group.network.id}"
}
When running the vnet.tf code it should read in the output from the outputs.tf which is stored in the azure backend storage account statefile file and use that value for the resource_group_name in the quannetwork module. Instead it creates a resource group named data.terraform_remote_state.network.outputs.quan_netwk. Any help would be greatly appreciated.
First, you need to input a string for the resource_group_name in your module quannetwork, not the resource group Id.
Second, if you want to quote something in the remote state, do not just put it in the Double quotes, the right format below:
resource_group_name = "${data.terraform_remote_state.network.outputs.quan_netwk}"

How to refer to imported terraform resources

I need your help. We have created a resource group (rg_networking) and virtual network(vnet_preprod) and 5 subnets in that (subnet_ad), subnet_app, subnet_ctl etc.
My import of resources works perfectly fine, however, what I don't know is to use/reference the imported resources?
terraform import --var-file=aos-1.tfvars azurerm_virtual_network.vnet_preprod /subscriptions/00000000000000000/resourceGroups/rg_networking/providers/Microsoft.Network/virtualNetworks/vnet_preprod
azurerm_virtual_network.vnet_preprod: Importing from ID "/subscriptions/00000000000000000/resourceGroups/rg_networking/providers/Microsoft.Network/virtualNetworks/vnet_preprod"...
azurerm_virtual_network.vnet_preprod: Import complete!
Imported azurerm_virtual_network (ID: /subscriptions/00000000000000000/resourceGroups/rg_networking/providers/Microsoft.Network/virtualNetworks/vnet_preprod)
azurerm_virtual_network.vnet_preprod: Refreshing state... (ID: /subscriptions/00000000000000000-...rk/virtualNetworks/vnet_preprod)
Import successful!
The resources that were imported are shown above. These resources are now in your Terraform state and will henceforth be managed by Terraform.
In my windows-build-tf file
resource "azurerm_virtual_network" "vnet_preprod" {
name = ""
address_space = ""
location = ""
resource_group_name = ""
}
I had to insert the above snippet else import would not have worked.
My previous working configuration, with Terraform creating everything and not using any imported resources is below:
variables.tfvars
address_space = [ "10.97.0.0/16" ]
virtual_network_subnet_ad = "10.97.1.0/24"
virtual_network_subnet_ad_name="groups-preprod_subnet_ad"
virtual_network_nic_ad="groups-preprod_nic_ad"
build-windows.tf
resource "azurerm_virtual_network" "tf-virtual-network" {
name = "${var.virtual_network_name}"
address_space = "${var.address_space}"
location = "${var.Location}"
resource_group_name = "${var.Resource_group_name}"
}
resource "azurerm_subnet" "tf-virtual-network-subnet-ad" {
name = "${var.virtual_network_subnet_ad_name}"
resource_group_name = "${var.Resource_group_name}"
virtual_network_name = "${azurerm_virtual_network.tf-virtual-network.name}"
address_prefix = "${var.virtual_network_subnet_ad}"
}
resource "azurerm_network_interface" "tf-virtual-network-nic-ad" {
name = "${var.virtual_network_nic_ad}"
location = "${var.Location}"
resource_group_name = "${var.Resource_group_name}"
ip_configuration {
name = "testconfiguration1"
subnet_id = "${azurerm_subnet.tf-virtual-network-subnet-ad.id}"
private_ip_address_allocation = "dynamic"
}
}
resource "azurerm_virtual_machine" "tf-virtual-machine-name" {
name = "${var.virtual_machine_name}"
location = "${var.Location}"
resource_group_name = "${var.Resource_group_name}"
network_interface_ids = ["${azurerm_network_interface.tf-virtual-network-nic-ad.id}"]
vm_size = "Standard_DS3_v2"
}
My question is how to reference the imported resource, I prefer them to be parametric but if its not possible then hard coded values would be the way to move forward? do I need to create my VM in same resource group?
I can see them imported in state file, kindly guide as I'm very much new to Azure and Terraform.
Many Thanks!
You can import and use resources as follows, sounds like you got this imported okay
Import your resource, use the provider / resource name e.g ‘azurerm_virtual_network.web_server_vnet’. Then in terraform re-define this using the same name and the settings it’s currently using in Azure. You can then use this like a resource that you created.
May be you could define this as a data resource instead? You don’t need to add all the attributes and it won’t get destroyed if you do terraform destroy.
Import
https://resources.azure.com/ - handy for getting resource ID
terraform import azurerm_virtual_network.web_server_vnet /subscriptions/xxxxxxxxxx-xxxx-xxxx-xxx-xxxxxxxxxx/resourceGroups/tf-web-rg/providers/Microsoft.Network/virtualNetworks/web-server-vnet
In Terraform
resource "azurerm_virtual_network" "web_server_vnet" {
name = "vnet"
location = "location"
resource_group_name = "resourceGroup"
address_space = ["1.1.1.0/24"]
}
data "azurerm_resource_group" "web_server_rg" {
name = "existing RG Name"
}

Resources