The problem here is that following official Terraform documentation (v3.11) it´s impossible to associate a a Public IP id to the NAT Gateway body.
resource "azurerm_nat_gateway" "nat_gateway" {
name = var.nat_gateway_name
location = "northeurope"
resource_group_name = var.resource_group_name
public_ip_address_ids = [azurerm_public_ip.pip.id]
sku_name = "Standard"
idle_timeout_in_minutes = 10
zones = ["1"]
}
I tried hardcoding the ID value and creating a empty variable, but nothing worked.
The error message is:
│ Error: Unsupported argument
│
│ on ../modules/function-app-module/main.tf line 40, in resource "azurerm_nat_gateway" "nat_gateway":
│ 40: public_ip_address_ids = [azurerm_public_ip.pip.id]
│
│ An argument named "public_ip_address_ids" is not expected here.
The solution here is to associate the Public IP to to NAT Gateway using "azurerm_nat_gateway_public_ip_association". The code will be:
resource "azurerm_nat_gateway_public_ip_association" "nat_gateway_pip_association" {
nat_gateway_id = azurerm_nat_gateway.nat_gateway.id
public_ip_address_id = azurerm_public_ip.pip.id
}
Related
I have an azure virtual machine scale set and would like to schedule a vm shutdown through azurerm_dev_test_global_vm_shutdown_schedule resource. But it is throwing the below error, I assume while trying to get the virtual_machine_id. Anyone faced similar issue?
resource "azurerm_dev_test_global_vm_shutdown_schedule" "vm_shutdown" {
virtual_machine_id = azurerm_linux_virtual_machine_scale_set.vmss.id
location = data.azurerm_resource_group.rg.location
enabled = true
depends_on = [azurerm_linux_virtual_machine_scale_set.vmss]
daily_recurrence_time = "2000"
timezone = "Central Europe Standard Time"
notification_settings {
enabled = true
}
}
I am getting the below error during Terraform plan:
Error: ID was missing the virtualMachines element
│
│ with azurerm_dev_test_global_vm_shutdown_schedule.vm_shutdown,
│ on 04_linux_virtual_machine_scale_set.tf line 57, in resource "azurerm_dev_test_global_vm_shutdown_schedule" "vm_shutdown":
│ 57: virtual_machine_id = azurerm_linux_virtual_machine_scale_set.vmss.id
For the virtual_machine_id you have to use ID of a azurerm_linux_virtual_machine, not azurerm_linux_virtual_machine_scale_set.
So my goal is to have write a terraform code to deploy 3 resource groups in AZ dev, uat and prod with each having the following resources.
SQL Database
Key Vault
variable.tf
variable "resource_group_name" {
description = "deafault resource group"
type = list (string)
default = ["Test-dev","Test-uat","Test-prod"]
}
variable "storage_account_name" {
description = "name for storage account"
default = "test-storageact"
}
main.tf
resource "azurerm_resource_group" "resgrp" {
for_each = toset(var.resource_group_name)
name = "${var.resource_group_name}-rg-${each.value}"
location = var.location
tags = {
"Environment" = "${var.env}-${each.value}"
}
}
resource "azurerm_storage_account" "storageact" {
for_each = toset(var.resource_group_name)
name = "${var.storage_account_name}-${each.value}"
resource_group_name = azurerm_resource_group.resgrp["${each.value}"].location
location = azurerm_resource_group.resgrp["${each.value}"].name
account_tier = "Standard"
account_replication_type = "LRS"
tags = {
"Environment" = "${var.env}-${each.value}"
}
}
error message
│ Error: Invalid template interpolation value
│
│ on main.tf line 3, in resource "azurerm_resource_group" "resgrp":
│ 3: name = "${var.resource_group_name}-rg-${each.value}"
│ ├────────────────
│ │ var.resource_group_name is list of string with 3 elements
│
│ on main.tf line 6, in resource "azurerm_resource_group" "resgrp":
│ 6: "Environment" = "${var.env}-${each.value}"
│ ├────────────────
│ │ var.env is map of string with 3 elements
│
│ Cannot include the given value in a string template: string required.
╵
Operation failed: failed running terraform plan (exit 1)
please any help will be greatly appreciated.
i tried using type = map(string) in the variable but still gave me an error.
There are a few problems with the code.
var.resource_group_name is a list containing 3 string elements (by default), and thus the error: var.resource_group_name is list of string with 3 elements explains the problem, and is illustrated below.
The var.env is a map consisting of 3 elements and also being used as a string and fails for the same reason.
resource "azurerm_resource_group" "resgrp" {
for_each = toset(var.resource_group_name)
# var.resource_group_name is actually a list, but it's being
# used as a string here, which will fail.
name = "${var.resource_group_name}-rg-${each.value}"
location = var.location
tags = {
"Environment" = "${var.env}-${each.value}"
}
}
You probably instead want:
resource "azurerm_resource_group" "resgrp" {
for_each = toset(var.resource_group_name)
name = "${each.value}-rg"
location = var.location
tags = {
"Environment" = "${each.value}"
}
}
Additionally, as an alternative to the approach of putting multiple environments in a single resource construct, consider using modules to create reusable infrastructure for your resources and then calling each module for the environment that you're using, this is a best practice when implementing duplicate or near-duplicate infrastructure across multiple environments and allows you some flexibility with naming conventions and other parameters that would differ based upon the environment.
Rough example:
module "test-dev" {
source = "../modules/infrastructure"
environment = "Test-dev"
vm_count = 1
}
module "test-uat" {
source = "../modules/infrastructure"
environment = "Test-dev"
vm_count = 3
}
module "test-prod" {
source = "../modules/infrastructure"
environment = "Test-prod"
account_tier = "Premium"
vm_count = 6
}
Objective: Trying to create Azure VNet (virtual network) with multiple address spaces with Terraform aka this vnet should be created with 4 address spaces
Code that I am using:
main.tf:
#-------------------------------------
# VNET Creation - Default is "true"
#-------------------------------------
resource "azurerm_virtual_network" "vnet" {
name = lower("vnet-${var.hub_vnet_name}-${var.location}")
location = var.location
resource_group_name = var.resource_group_name
address_space = [var.vnet_address_space]
dns_servers = [var.dns_servers]
tags = merge({ "ResourceName" =
lower("vnet-${var.hub_vnet_name}-${var.location}") }, var.tags, )
variable.tf
variable "vnet_address_space" {
description = "The address space to be used for the Azure virtual network."
default = ["10.350.0.0/24","10.351.0.0/20","10.352.0.0/24","10.353.0.0/24"]
}
terraform.tfvars
"vnet_address_space":["10.250.0.0/24","10.251.0.0/20","10.252.0.0/24","10.253.0.0/24"]
Error I am getting:
Error:
Incorrect attribute value type
│
│ on main.tf line 71, in resource "azurerm_virtual_network" "vnet":
│ 71: address_space = [var.vnet_address_space]
│ ├────────────────
│ │ var.vnet_address_space is tuple with 4 elements
│
│ Inappropriate value for attribute "address_space": element 0: string required.
Please let me know what mistake I am doing. Thanks in advance.
Your var.vnet_address_space is already a list. So it should be:
address_space = var.vnet_address_space
Objective: I am trying to create azure resources with Terraform
Code I used in main.tf:
resource "azurerm_subnet" "clientdata_snet" {
count = var.clientdata_subnet_address_space != null ? 1 : 0
name = "ClientDataSubnet"
resource_group_name = var.resource_group_name
virtual_network_name = azurerm_virtual_network.vnet.name
address_prefixes = ["${var.clientdata_subnet_address_space}"]
service_endpoints = var.service_endpoints
}
and now subsequently want to use client_snet.id for creating storage endpoint
resource "azurerm_private_endpoint" "sa_pe_blob" {
name = "pe-stdlorpcbcntldevwe-blob-${random_string.postfix.result}"
location = var.location
resource_group_name = var.resource_group_name
subnet_id = azurerm_subnet.clientdata_snet.id
Error I get is:
Error: Missing resource instance key
│
│ on main.tf line 470, in resource "azurerm_private_endpoint" "sa_pe_blob":
│ 470: subnet_id = azurerm_subnet.clientdata_snet.id
│
│ Because azurerm_subnet.clientdata_snet has "count" set, its attributes must be accessed on specific instances.
│
│ For example, to correlate with indices of a referring resource, use:
│ azurerm_subnet.clientdata_snet[count.index]
Then I referred to some posts here.. where I need to use like below:
subnet_id = azurerm_subnet.clientdata_snet[count.index].id
then its giving me this error:
Error: Reference to "count" in non-counted context
│
│ on main.tf line 470, in resource "azurerm_private_endpoint" "sa_pe_blob":
│ 470: subnet_id = azurerm_subnet.clientdata_snet[count.index].id
│
│ The "count" object can only be used in "module", "resource", and "data" blocks, and only when the "count" argument is set.
Really confused, both ways its giving me error. I have only root module, I dont have any other modules.Can someone suggest what is correct way to do it ?
If you are using count meta-argument, you have to use either the right index or use the same way of creating the second resource, by referencing the same variable to decide what the count will be. So the options are:
resource "azurerm_private_endpoint" "sa_pe_blob" {
name = "pe-stdlorpcbcntldevwe-blob-${random_string.postfix.result}"
location = var.location
resource_group_name = var.resource_group_name
subnet_id = azurerm_subnet.clientdata_snet[0].id # exact index
}
As you can see, the subnet_id is now referencing a previously created resource with index of 0. To understand how references to instances work when count is used, look in [1].
The second way you could do it is like this:
resource "azurerm_private_endpoint" "sa_pe_blob" {
count = var.clientdata_subnet_address_space != null ? 1 : 0
name = "pe-stdlorpcbcntldevwe-blob-${random_string.postfix.result}"
location = var.location
resource_group_name = var.resource_group_name
subnet_id = azurerm_subnet.clientdata_snet[count.index].id # using count.index
}
This way you will create a dependency between the subnet and the endpoint resources.
As you can see here, the resources created with count can be referenced either by specifying the exact index which is fine when there is only one resource, but much harder when there are more and the code would have to be repeated. The other way is to use the same variable with the count meta-argument.
I strongly suggest going through the documentation to understand the count meta-argument better.
[1] https://www.terraform.io/language/meta-arguments/count#referring-to-instances
Hi I am trying to follow this offical guide to manage aks resources. There terraform_remote_state is used to get the resource_group_name and kubernetes_cluster_name.
data "terraform_remote_state" "aks" {
backend = "local"
config = {
path = "/path/to/base/project/terraform.tfstate"
}
}
# Retrieve AKS cluster information
provider "azurerm" {
features {}
}
data "azurerm_kubernetes_cluster" "cluster" {
name = data.terraform_remote_state.aks.outputs.kubernetes_cluster_name
resource_group_name = data.terraform_remote_state.aks.outputs.resource_group_name
}
I have created the inital aks cluster with the aks module. Looking at its output in the documentation, it doesnt export the resource group name or cluster name.
Now I wonder how I can get the information. I have tried the below in the base project.
module "aks" {
...
}
output "resource_group_name" {
value = module.aks.resource_group_name
}
output "kubernetes_cluster_name" {
value = module.aks.cluster_name
}
But I get erros when trying terraform plan
Error: Unsupported attribute
│
│ on main.tf line 59, in output "resource_group_name":
│ 59: value = module.aks.resource_group_name
│ ├────────────────
│ │ module.aks is a object, known only after apply
│
│ This object does not have an attribute named "resource_group_name".
╵
╷
│ Error: Unsupported attribute
│
│ on main.tf line 63, in output "kubernetes_cluster_name":
│ 63: value = module.aks.cluster_name
│ ├────────────────
│ │ module.aks is a object, known only after apply
│
│ This object does not have an attribute named "cluster_name".
Those are listed under inputs for that module though. Now I dont have an idea know how to get those values from the terraform_remote_state.
As the module itself doesn’t have name and resource group as output , we have to declare outputs there first and then call it while deploying or in remote state as well.
So we have to add 2 outputs in output.tf for aks module after doing terraform init.
output "kubernetes_cluster_name" {
value = azurerm_kubernetes_cluster.main.name
}
output "resource_group_name" {
value = azurerm_kubernetes_cluster.main.resource_group_name
}
Then call outputs in main.tf after defining the modules i.e. network and aks , you can see your Kubernetes cluster name in plan as well and after applying it.
output "kuberneteclustername" {
value = module.aks.kubernetes_cluster_name
}
output "resourcegroupname" {
value = module.aks.resource_group_name
}
Now lets test it from the remote state :
data "terraform_remote_state" "aks" {
backend = "local"
config = {
path = "path/to/terraform/aksmodule/terraform.tfstate"
}
}
# Retrieve AKS cluster information
provider "azurerm" {
features {}
}
data "azurerm_kubernetes_cluster" "cluster" {
name = data.terraform_remote_state.aks.outputs.kuberneteclustername
resource_group_name = data.terraform_remote_state.aks.outputs.resourcegroupname
}
output "aks" {
value = data.azurerm_kubernetes_cluster.cluster.name
}
output "rg" {
value = data.azurerm_kubernetes_cluster.cluster.resource_group_name
}