main.tf wrote:
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = ">= 2.26"
}
}
}
provider "azurerm" {
features {}
}
resource "azurerm_resource_group" "rg" {
name = "Product-RG"
location = var.location
}
resource "azurerm_virtual_network" "vnet" {
resource_group_name = azurerm_resource_group.rg.name
name = "Product-VNet"
address_space = [lookup(var.vnetAddress, var.location)]
location = var.location
subnet {
name = "Web-Sub1"
address_prefix = ["${lookup(var.subnetAddress[var.location], "web1")}"]
}
subnet {
name = "Web-Sub2"
address_prefix = [lookup(var.subnetAddress[var.location], "web2")]
}
In Web-Sub1, i originally brought address_prefix like Web-Sub2, but now i'm trying like address_prefix on Web-Sub1 after the error occurred.
An error has occurred as below.
Error: Incorrect attribute value type
on main.tf line 27, in resource "azurerm_virtual_network" "vnet":
27: address_prefix = ["${lookup(var.subnetAddress[var.location], "web1")}"]
Inappropriate value for attribute "address_prefix": string required.
Error: Incorrect attribute value type
on main.tf line 31, in resource "azurerm_virtual_network" "vnet":
31: address_prefix = [lookup(var.subnetAddress[var.location], "web2")]
Inappropriate value for attribute "address_prefix": string required.
variable.tf wrote:
variable "location" {}
variable "vnetAddress" {
type = map
default = {
westus = "192.168.1.0/27"
eastus = "192.168.11.0/27"
}
}
variable "subnetAddress" {
type = map
default = {
westus = {
web1 = "192.168.1.0/27"
web2 = "192.168.1.32/27"
was1 = "192.168.1.64/27"
was2 = "192.168.1.96/27"
db1 = "192.168.1.128/27"
db2 = "192.168.1.160/27"
}
eastus = {
web1 = "192.168.11.0/27"
web2 = "192.168.11.32/27"
was1 = "192.168.11.64/27"
was2 = "192.168.11.96/27"
db1 = "192.168.11.128/27"
db2 = "192.168.11.160/27"
}
}
}
I wonder why there is an error that needs to be written in string format and why I can't bring the data.
You are almost there, just that address_prefix argument needs to be a string and you are passing a list of strings address_prefix = [lookup(var.subnetAddress[var.location], "web2")]
subnet {
name = "Web-Sub1"
address_prefix = lookup(var.subnetAddress[var.location], "web1")
}
subnet {
name = "Web-Sub2"
address_prefix = lookup(var.subnetAddress[var.location], "web2")
}
This should work.
Refer azurerm_virtual_network resource, address_prefix is passed as a string rather a list of strings.
Related
I am caught in a bit of a loop on this one. Need to provide the azure_windows_virtual_machine with a list of network interface IDs. The network interfaces are created using a separate resource block. In my variable definition for the windows vm, I provide an argument for the name[s] of said network interfaces so that we can correctly associate the nics that we want with each virtual machine. If we have 100 nics and 90 VMs, some of the VMs could get two NICs, so we want to be sure we provide some link between NIC name and VM name.
The network interface names are therefore a list(string).
I have been trying to use the values function to get the list of NIC IDs (given the names), but running into a failure: "The each object can be used only in "module" or "resource" blocks, and only when the "for_each" argument is set."
If I use a data source in the resource block, which seemed most logical, it fails too because I have a list(string) specified for the network_interface_names argument, but the data source cannot take that. It of course needs a single string. But it's never going to be a single string, it's always going to be a list (since we can have more than one NIC per VM).
I think the correct answer is to maybe create the list of IDs beforehand - trick is that it would need to almost be dynamic for each defined VM - because each VM will have a different list of network_interface_names. We therefore need to generate the new list on the fly for each VM.
Variables
variable "resource_groups" {
description = "Resource groups"
type = map(object({
location = string
}))
}
variable "virtual_networks" {
description = "virtual networks and properties"
type = map(object({
resource_group_name = string
address_space = list(string)
}))
}
variable "subnets" {
description = "subnet and their properties"
type = map(object({
resource_group_name = string
virtual_network_name = string
address_prefixes = list(string)
}))
}
variable "nic" {
description = "network interfaces"
type = map(object({
subnet_name = string
resource_group_name = string
}))
}
variable "admin_password" {
type = string
sensitive = true
}
variable "admin_user" {
type = string
sensitive = true
}
variable "windows_vm" {
description = "Windows virtual machine"
type = map(object({
network_interface_names = list(string)
resource_group_name = string
size = string
timezone = string
}))
}
INPUTS
resource_groups = {
rg-eastus-dev1 = {
location = "eastus"
}
}
virtual_networks = {
vnet-dev1 = {
resource_group_name = "rg-eastus-dev1"
address_space = ["10.0.0.0/16"]
}
}
subnets = {
snet-01 = {
resource_group_name = "rg-eastus-dev1"
virtual_network_name = "vnet-dev1"
address_prefixes = ["10.0.1.0/24"]
}
}
nic = {
nic1 = {
subnet_name = "snet-01"
resource_group_name = "rg-eastus-dev1"
}
}
admin_password = "s}8cpH96qa.1BQ"
admin_user = "padmin"
windows_vm = {
winvm1 = {
network_interface_names = ["nic1"]
resource_group_name = "rg-eastus-dev1"
size = "Standard_B2s"
timezone = "Eastern Standard Time"
}
}
MAIN
resource "azurerm_resource_group" "rgs" {
for_each = var.resource_groups
name = each.key
location = each.value["location"]
}
data "azurerm_resource_group" "rgs" {
for_each = var.resource_groups
name = each.key
depends_on = [
azurerm_resource_group.rgs
]
}
resource "azurerm_virtual_network" "vnet" {
for_each = var.virtual_networks
name = each.key
resource_group_name = each.value["resource_group_name"]
address_space = each.value["address_space"]
location = data.azurerm_resource_group.rgs[each.value["resource_group_name"]].location
}
resource "azurerm_subnet" "subnet" {
for_each = var.subnets
name = each.key
resource_group_name = each.value["resource_group_name"]
virtual_network_name = each.value["virtual_network_name"]
address_prefixes = each.value["address_prefixes"]
depends_on = [
azurerm_virtual_network.vnet
]
}
data "azurerm_subnet" "subnet" {
for_each = var.subnets
name = each.key
virtual_network_name = each.value["virtual_network_name"]
resource_group_name = each.value["resource_group_name"]
depends_on = [
azurerm_resource_group.rgs
]
}
resource "azurerm_network_interface" "nics" {
for_each = var.nic
ip_configuration {
name = each.key
subnet_id = data.azurerm_subnet.subnet[each.value["subnet_name"]].id
private_ip_address_allocation = "Dynamic"
}
location = data.azurerm_resource_group.rgs[each.value["resource_group_name"]].location
name = each.key
resource_group_name = each.value["resource_group_name"]
depends_on = [
azurerm_resource_group.rgs,
azurerm_subnet.subnet
]
}
data "azurerm_network_interface" "nics" {
for_each = var.nic
name = each.key
resource_group_name = each.value["resource_group_name"]
depends_on = [
azurerm_resource_group.rgs
]
}
resource "azurerm_windows_virtual_machine" "windows_vm" {
for_each = var.windows_vm
admin_password = var.admin_password
admin_username = var.admin_user
location = data.azurerm_resource_group.rgs[each.value["resource_group_name"]].location
name = each.key
network_interface_ids = values(data.azurerm_network_interface.nics[each.value["network_interface_names"]].id)
os_disk {
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
}
resource_group_name = each.value["resource_group_name"]
size = each.value["size"]
timezone = each.value["timezone"]
source_image_reference {
publisher = "MicrosoftWindowsServer"
offer = "WindowsServer"
sku = "2019-Datacenter"
version = "latest"
}
}
Current Error on Plan
╷
│ Error: Invalid index
│
│ on main.tf line 75, in resource "azurerm_windows_virtual_machine" "windows_vm":
│ 75: network_interface_ids = values(data.azurerm_network_interface.nics[each.value["network_interface_names"]].id)
│ ├────────────────
│ │ data.azurerm_network_interface.nics is object with 1 attribute "nic1"
│ │ each.value["network_interface_names"] is list of string with 1 element
│
│ The given key does not identify an element in this collection value: string required.
Possible Solution - But Not working
Provide a map, keyed off the VM name, of NIC IDs. Then, in the windows_vm resource, take that map and try to get the list of NIC ID values.
locals {
nic_ids {
[for k, v in var.windows_vm : k => v {data.azurerm_network_interface.nics[v.network_interface_names]}.id]
}
}
resource "azurerm_windows_virtual_machine" "windows_vm" {
for_each = var.windows_vm
admin_password = var.admin_password
admin_username = var.admin_user
location = data.azurerm_resource_group.rgs[each.value["resource_group_name"]].location
name = each.key
network_interface_ids = values(local.nic_ids[each.key])
os_disk {
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
}
resource_group_name = each.value["resource_group_name"]
size = each.value["size"]
timezone = each.value["timezone"]
source_image_reference {
publisher = "MicrosoftWindowsServer"
offer = "WindowsServer"
sku = "2019-Datacenter"
version = "latest"
}
}
First of all, you do not need to call data after creation of each resource. The resource itself will contain all the information that you need. So you should eliminate all data sources in your code and use resource directly.
But returning to the error you provided. One way to generate the list dynamically, would be:
network_interface_ids = [for ni_name in each.value["network_interface_names"]: azurerm_network_interface.nics[ni_name].id]
I'm completely new to terraform and I'm trying to learn and write a TF code to automate Azure VM deployment. I'm trying to cover each parts as modules (except rg) rather than keeping it in a single main.tf file.
My intention is to create 1 vnet (TESTVNET) and create multiple subnets in same Vnet, where I can define the subnet name and address in my tfvars file.
I'm able to reach till creation on VNet, but cant loop through the defined subnets
Please go through my code. File Main.tf
resource "azurerm_resource_group" "resource_group" {
name = var.RGname
location = var.RGlocation
}
module "VNET" {
source = "./Modules/NetworkConfig"
name = var.VNETname
address_space = var.address_space
location = var.RGlocation
resource_group_name = azurerm_resource_group.resource_group.name
}
module "SUBNETS" {
source = "./Modules/SubnetConfig"
Subnetlist = var.Subnetlist
virtual_network_name = module.VNET.vnet_name
resource_group_name = azurerm_resource_group.resource_group.name
depends_on = [azurerm_resource_group.resource_group, module.VNET.vnet]
}
Variables.tf (of main)
variable "RGlocation" {
}
variable "RGname" {
}
variable "VNETname" {
}
variable "address_space" {
}
variable "Subnetlist" {
type = map(object({
name = list(string)
address = list(string)
}))
}
File main.tfvars
RGlocation = "westus"
RGname = "TEST-RG1"
VNETname = "TEST-VNET-01"
address_space = "10.0.0.0/16"
Subnetlist = {
"list" = {
name = ["TESTSUBNET","TESTSUBNET1","TESTSUBNET2"]
address = ["10.0.1.0/24","10.0.2.0/24","10.0.3.0/24"]
}
}
File Subnets.tf (module)
resource "azurerm_subnet" "SUBNETS" {
for_each=var.Subnetlist
name=each.value.name
address_prefixes=each.value.address
resource_group_name = var.resource_group_name
virtual_network_name = var.virtual_network_name
}
File variable.tf (subnet module)
variable "resource_group_name" {
}
variable "virtual_network_name" {
}
variable "Subnetlist" {
type = map(object({
name = list(string)
address = list(string)
}))
}
Below if the error that I'm getting
╷
│ Error: Incorrect attribute value type
│
│ on Modules\SubnetConfig\Subnet.tf line 3, in resource "azurerm_subnet" "SUBNETS":
│ 3: name=each.value.name
│ ├────────────────
│ │ each.value.name is list of string with 3 elements
│
│ Inappropriate value for attribute "name": string required.
Could anyone please tell me how to resolve it? Also, please do let me know if this is not the right approach.
The way you iterate over Subnetlist is incorrect - you only get the value of "list" key, ending up with a bundle of subnets instead of individual items. Make it a map of individual subnet objects instead:
variable "Subnetlist" {
type = map(object({
name = string
address = string
}))
}
Then pass it in tfvars like:
Subnetlist = {
"s1" = { name = "TESTSUBNET", address = "10.0.1.0/24" },
"s2" = { name = "TESTSUBNET1", address = "10.0.2.0/24" },
"s3" = { name = "TESTSUBNET2", address = "10.0.3.0/24" }
}
Finally consume it in the module like this:
resource "azurerm_subnet" "SUBNETS" {
for_each = var.Subnetlist
name = each.value.name
address_prefixes = each.value.address
resource_group_name = var.resource_group_name
virtual_network_name = var.virtual_network_name
}
For a project I use remote modules (git modules) these are called and executed in a terraformMain.tf file.
For example, I use an Azure Resource Group Module, this module is looped in the terraformMain.tf by "count = length (var.resourcegroups)". The problem I have now is that I want to use one of the two created Resource groups in the next module (creating VNET) but I keep encountering the following error:
Error: Unsupported attribute
on outputs.tf line 2, in output "RG": 2: value =
[module.resourceGroups.resource_group_name]
This value does not have any attributes.
Unsupported attribute
on terraformMain.tf line 33, in module "vnet": 33:
resourcegroup_name = module.resourceGroups.resource_group_name[0]
This value does not have any attributes.
The Azure Resource Group module code looks like this :
main.tf
resource "azurerm_resource_group" "RG" {
name = var.resource_group_name
location = var.location
}
variables.tf
variable "location" {
type = string
}
variable "resource_group_name" {
type = string
}
outputs.tf
output "resource_group_names" {
value = concat(azurerm_resource_group.RG.*.name, [""])[0]
}
The code of the terraformMain.tf looks like this:
terraformMain.tf
terraform {
required_version = ">= 0.13"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "2.45.1"
}
}
backend "azurerm" {
resource_group_name = "__terraformresourcegroup__"
storage_account_name = "__terraformstorageaccount__"
container_name = "__terraformcontainer__"
key = "__terraformkey__"
}
}
provider "azurerm" {
features {}
}
module "resourceGroups" {
count = length(var.resourcegroups)
source = "git::https://*****#dev.azure.com/****/TerraformAzureModules/_git/ResourceGroup"
location = var.location
resource_group_name = var.resourcegroups[count.index]
}
module "vnet" {
source = "git::https://*****#dev.azure.com/****/TerraformAzureModules/_git/VirtualNetwork"
resourcegroup_name = module.resourceGroups.resource_group_name[0]
location = var.location
vnet_name = var.vnet_name
count = length(var.subnet_names)
vnet_cidr = var.vnet_cidr[count.index]
subnet_cidr = var.subnet_cidr[count.index]
subnet_name = var.subnet_names[count.index]
}
variables.tf
variable "location" {
default = "westeurope"
}
variable "resourcegroups" {
default = ["rg1", "rg2"]
}
#Azure Vnet / Subnet
variable "vnet_name" {
default = "vnet_1"
}
variable "subnet_names" {
default = ["subnet1", "subnet2"]
}
variable "vnet_cidr" {
default = ["10.116.15.0/24"]
}
variable "subnet_cidr" {
default = ["10.116.15.0/26", "10.116.15.128/27"]
}
outputs.tf
output "RG" {
value = [module.resourceGroups.resource_group_name]
}
any help is appreciated!
Your resourceGroups module has count = length(var.resourcegroups) set, and so module.resourceGroups is a list of objects and therefore you will need to request a specific element from the list before accessing an attribute:
module.resourceGroups[0].resource_group_name
Or, if your goal was to return a list of all of the resource group names, you can use the [*] operator to concisely access the resource_group_name argument from each of the elements and return the result as a list:
resource.resourceGroups[*].resource_group_name
The variables in the module need to have a type or a default.
For example, this would be a valid file:
variable "location" {
type = string
}
variable "resource_group_name" {
type = string
}
The solution we have applied is to move the count from the terraformMain.tf to the resource module main.tf. this allowed us to pass the resoucgroups to the terraformMain through the output.tf of the module.
ResourceGroup module:
main.tf
resource "azurerm_resource_group" "RG" {
count = length(var.resource_group_name)
name = var.resource_group_name[count.index]
location = var.location
}
outputs.tf
output "resource_group_names" {
value = azurerm_resource_group.RG.*.name
}
terraformMain.tf code:
terraform {
required_version = ">= 0.13"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "2.45.1"
}
}
backend "azurerm" {
resource_group_name = "__terraformresourcegroup__"
storage_account_name = "__terraformstorageaccount__"
container_name = "__terraformcontainer__"
key = "__terraformkey__"
}
}
provider "azurerm" {
features {}
}
module "resourceGroups" {
source = "git::https://*****#dev.azure.com/*****/TerraformAzureModules/_git/ResourceGroup"
location = var.location
resource_group_name = var.resourcegroups
}
module "vnet" {
source = "git::https://******#dev.azure.com/*****/TerraformAzureModules/_git/VirtualNetwork"
resourcegroup_name = module.resourceGroups.resource_group_names[0]
location = var.location
vnet_name = var.vnet_name
vnet_cidr = var.vnet_cidr
subnet_cidr = var.subnet_cidr
subnet_name = var.subnet_names
}
I want to thank you for your contribution
Also for public ip id getting: "
Error: Can not parse "ip_configuration.0.public_ip_address_id" as a
resource id: Cannot parse Azure ID: parse
module.resource.azurerm_public_ip.primary.id: invalid URI for request
"
As the network is a nested module for the resource module, will you please suggest, where I'm missing?
main.tf file:
#Select provider
provider "azurerm" {
subscription_id = "xxxxxxxxxxxxxxxxxxxxxx"
version = "~> 2.2"
features {}
}
module "resource" {
source = "./modules/resource"
resource_group_name = "DevOpsPoc-primary"
location = "southeastasia"
}
module "network" {
source = "./modules/network"
virtual_network = "primaryvnet"
subnet = "primarysubnet"
address_space = "192.168.0.0/16"
address_prefix = "192.168.1.0/24"
public_ip = "backendvmpip"
location = "southeastasia"
primary_nic = "backendvmnic"
#vnet_subnet_id = element(module.network.vnet_subnets, 0)
primary_ip_conf = "backendvm"
}
resource module main.tf file:
resource "azurerm_resource_group" "primary" {
name = "var.resource_group_name"
location = "var.location"
tags = {
environment = "env"
}
}
network module main.tf file:
#Create Virtual Network in Primary Resource Group
resource "azurerm_virtual_network" "primary" {
name = "var.virtual_network"
resource_group_name = "module.resource.azurerm_resource_group.primary.name"
address_space = ["var.address_space"]
location = "module.resource.azurerm_resource_group.primary.location"
tags = {
environment = "env"
}
}
#Create Subnet in Virtual Network
resource "azurerm_subnet" "primary" {
name = "var.subnet"
resource_group_name = "module.resource.azurerm_resource_group.primary.name"
virtual_network_name = "module.resource.azurerm_virtual_network.primary.name"
address_prefix = "var.address_prefix"
# tags = {
# environment = "env"
# }
}
output "subnet_id"{
value = "module.resource.azurerm_subnet.primary.id"
}
#Create public IP address
resource "azurerm_public_ip" "primary" {
name = "var.public_ip"
location = "module.resource.azurerm_resource_group.primary.location"
resource_group_name = "module.resource.azurerm_resource_group.primary.name"
allocation_method = "Dynamic"
tags = {
environment = "env"
}
}
output "public_ip_id"{
value = "module.resource.azurerm_public_ip.id"
}
#Create Network Interface
resource "azurerm_network_interface" "primary" {
name = "var.primary_nic"
location = "module.resource.azurerm_resource_group.primary.location"
resource_group_name = "module.resource.azurerm_resource_group.primary.name"
ip_configuration {
name = "var.primary_ip_conf"
subnet_id = "module.resource.azurerm_subnet.primary.id"
private_ip_address_allocation = "Dynamic"
public_ip_address_id = "module.resource.azurerm_public_ip.primary.id"
}
tags = {
environment = "env"
}
}
There are some places need to be corrected in your codes:
You don't need double quotes"" in variables or expression refers to Interpolation Syntax. For example "var.virtual_network" should be var.virtual_network.
You can directly reference resources in the same main.tf file instead of from the module block. For example, change virtual_network_name = "module.resource.azurerm_virtual_network.primary.name" to virtual_network_name = azurerm_virtual_network.primary.name in the resource "azurerm_subnet" block.
The syntax for referencing module outputs is ${module.NAME.OUTPUT}, where NAME is the module name given in the header of the module configuration block and OUTPUT is the name of the output to reference. You can declare resource group name and location in module "network" instead of using it from the ./modules/network/main.tf file.
Here is the working code and you could get more references in this document:
main.tf file in the root directory
module "resource" {
source = "./modules/resource"
resource_group_name = "DevOpsPoc-primary"
location = "southeastasia"
}
module "network" {
source = "./modules/network"
resource_group_name = module.resource.RGname
location = module.resource.location
virtual_network = "primaryvnet"
subnet = "primarysubnet"
address_space = ["192.168.0.0/16"]
address_prefix = "192.168.1.0/24"
public_ip = "backendvmpip"
primary_nic = "backendvmnic"
#vnet_subnet_id = element(module.network.vnet_subnets, 0)
primary_ip_conf = "backendvm"
}
main.tf in the directory ./modules/resource
variable "resource_group_name" {}
variable "location" {}
resource "azurerm_resource_group" "primary" {
name = var.resource_group_name
location = var.location
}
output "RGname" {
value = "${azurerm_resource_group.primary.name}"
}
output "location" {
value = "${azurerm_resource_group.primary.location}"
}
main.tf in the directory ./modules/network and also declare the variables in the same directory.
#Create Virtual Network in Primary Resource Group
resource "azurerm_virtual_network" "primary" {
name = var.virtual_network
resource_group_name = var.resource_group_name
address_space = var.address_space
location = var.location
}
#Create Subnet in Virtual Network
resource "azurerm_subnet" "primary" {
name = var.subnet
resource_group_name = var.resource_group_name
virtual_network_name = azurerm_virtual_network.primary.name
address_prefix = var.address_prefix
}
output "subnet_id"{
value = azurerm_subnet.primary.id
}
#Create public IP address
resource "azurerm_public_ip" "primary" {
name = var.public_ip
location = var.location
resource_group_name = var.resource_group_name
allocation_method = "Dynamic"
}
output "public_ip_id"{
value = azurerm_public_ip.primary.id
}
#Create Network Interface
resource "azurerm_network_interface" "primary" {
name = var.primary_nic
location = var.location
resource_group_name = var.resource_group_name
ip_configuration {
name = var.primary_ip_conf
subnet_id = azurerm_subnet.primary.id
private_ip_address_allocation = "Dynamic"
public_ip_address_id = azurerm_public_ip.primary.id
}
}
I had a similar error when setting up an Azure App Service using Terraform.
module.app_service.azurerm_app_service.app_service: Creating...
│ Error: Cannot parse Azure ID: parse "27220": invalid URI for request
│
│ with module.app_service.azurerm_app_service.app_service,
│ on ../../../modules/azure/app-service/main.tf line 1, in resource "azurerm_app_service" "app_service":
│ 1: resource "azurerm_app_service" "app_service" {
Here's how I fixed it:
The issue was that I used the wrong value for the App Service Plan ID in my module.
I was using 27220 as the App Service Plan ID, instead of the actual value of the App Service Plan ID which of this format:
"/subscriptions/fec545cd-bead-43ba-84c6-5738cdc7e458/resourceGroups/MyDevRG/providers/Microsoft.Web/serverfarms/MyDevLinuxASP"
That's all
In its simplest form,
main.tf is as below:
data "azurerm_resource_group" "tf-rg-external" {
name = var.rg_name
}
# Reference existing Virtual Network
data "azurerm_virtual_network" "tf-vn" {
name = var.vnet_name
resource_group_name = data.azurerm_resource_group.tf-rg-external.name
}
# Reference existing subnet
data "azurerm_subnet" "tf-sn" {
name = var.subnet_name
virtual_network_name = data.azurerm_virtual_network.tf-vn.name
resource_group_name = data.azurerm_resource_group.tf-rg-external.name
}
resource "azurerm_network_security_group" "tf-nsg" {
name = var.app_nsg
location = data.azurerm_virtual_network.tf-vn.location
resource_group_name = data.azurerm_resource_group.tf-rg-external.name
}
resource "azurerm_network_security_rule" "tf-nsr-5986" {
name = "Open Port 5986"
priority = 101
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "5986"
source_address_prefixes = var.allowed_source_ips
destination_address_prefix = "VirtualNetwork"
resource_group_name = data.azurerm_resource_group.tf-rg-external.name
network_security_group_name = azurerm_network_security_group.tf-nsg.name
}
resource "azurerm_network_security_rule" "tf-nsr-3389" {
name = "Open Port 3389"
priority = 102
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "3389"
source_address_prefixes = var.allowed_source_ips
destination_address_prefix = "VirtualNetwork"
resource_group_name = data.azurerm_resource_group.tf-rg-external.name
network_security_group_name = azurerm_network_security_group.tf-nsg.name
}
# Assosciate NSG to subnet
resource "azurerm_subnet_network_security_group_association" "tf-snnsg" {
subnet_id = data.azurerm_subnet.tf-sn.id
network_security_group_id = azurerm_network_security_group.tf-nsg.id
}
# Network inteface for Interface
resource "azurerm_network_interface" "tf-ni" {
count = var.vm_count
name = "${var.base_hostname}${format("%02d", count.index + 1)}-nic01"
location = data.azurerm_virtual_network.tf-vn.location
resource_group_name = data.azurerm_resource_group.tf-rg-external.name
ip_configuration {
name = "${var.base_hostname}${format("%02d", count.index)}-iip01"
subnet_id = data.azurerm_subnet.tf-sn.id
private_ip_address_allocation = "dynamic"
public_ip_address_id = element(azurerm_public_ip.tf-pip.*.id, count.index)
}
}
resource "azurerm_public_ip" "tf-pip" {
count = var.vm_count
location = data.azurerm_virtual_network.tf-vn.location
name = "${var.base_hostname}${format("%02d", count.index + 1)}-pip01"
resource_group_name = data.azurerm_resource_group.tf-rg-external.name
allocation_method = "Dynamic"
}
# Storage Account
resource "azurerm_storage_account" "tf-sa" {
count = var.vm_count
name = "${lower(var.base_hostname)}${format("%02d", count.index + 1)}${var.sto_acc_suffix}01"
location = data.azurerm_virtual_network.tf-vn.location
resource_group_name = data.azurerm_resource_group.tf-rg-external.name
account_tier = var.sto_acc_tier_std
account_replication_type = var.sto_acc_rep_type_lrs
}
resource "azurerm_virtual_machine" "tf-vm" {
count = var.vm_count
name = "${var.base_hostname}${format("%02d", count.index + 1)}"
location = data.azurerm_virtual_network.tf-vn.location
resource_group_name = data.azurerm_resource_group.tf-rg-external.name
network_interface_ids = [element(azurerm_network_interface.tf-ni.*.id, count.index)]
vm_size = var.vm_size
delete_os_disk_on_termination = true
delete_data_disks_on_termination = true
storage_image_reference {
publisher = var.vm_publisher
offer = var.vm_offer
sku = var.vm_sku
version = var.vm_img_version
}
storage_os_disk {
name = "${var.base_hostname}${format("%02d", count.index + 1)}-wosdsk01"
caching = var.caching_option
create_option = var.create_option
managed_disk_type = var.managed_disk_std_lrs
}
os_profile {
computer_name = "${var.base_hostname}${format("%02d", count.index + 1)}"
admin_username = var.username
admin_password = var.password
}
os_profile_windows_config {
enable_automatic_upgrades = false
provision_vm_agent = "true"
}
}
variables.tf is below:
# Declare env variable
variable "rg_name" {
type = string
}
variable "vnet_name" {
type = string
}
variable "subnet_name" {
type = string
}
variable "app_nsg" {
type = string
}
variable "vm_count" {
type = number
}
variable "base_hostname" {
type = string
}
variable "sto_acc_suffix" {
type = string
}
variable "sto_acc_tier_std" {
type = string
default = "Standard"
}
variable "sto_acc_rep_type_lrs" {
type = string
default = "LRS"
}
variable "vm_size" {
type = string
}
variable "vm_publisher" {
type = string
}
variable "vm_offer" {
type = string
}
variable "vm_sku" {
type = string
}
variable "vm_img_version" {
type = string
}
variable "username" {
type = string
}
variable "password" {
type = string
}
variable "caching_option" {
type = string
default = "ReadWrite"
}
variable "create_option" {
type = string
default = "FromImage"
}
variable "managed_disk_std_lrs" {
type = string
default = "Standard_LRS"
}
variable "managed_disk_prem_lrs" {
type = string
default = "Premium_LRS"
}
variable "allowed_source_ips" {
description = "List of ips from which inbound connection to VMs is allowed"
type = list(string)
}
I run below command for upgrading terraform config to 0.12 and above
terraform 0.12upgrade
Error:
Error: Syntax error in configuration file
on main.tf line 22, in data "azurerm_resource_group" "tf-rg-external":
22: name = var.rg_name
Error while parsing: At 22:10: Unknown token: 22:10 IDENT var.rg_name
Error: Syntax error in configuration file
on variable.tf line 3, in variable "rg_name":
3: type = string
Error while parsing: At 3:10: Unknown token: 3:10 IDENT string
Any idea, what is the problem? this would work if I don't run terrafom 0.12upgrade command. It is intriguing me why it is not working. I did same upgrade command in another terraform config and I get similar error there.
One observation. This IDENT error comes for first variable in main.tf and variable.tf file. Unable to correlate this error.
You're already using 0.12 syntax, the 0.12upgrade command expects to find 0.11 syntax and will attempt to automatically update it.
e.g. name = var.rg_name - note the lack of ${}
See https://www.terraform.io/docs/commands/0.12upgrade.html
The terraform 0.12upgrade command applies several automatic upgrade rules to help prepare a module that was written for Terraform v0.11 to be used with Terraform v0.12.
(Emphasis mine)