Referencing outputs from a for_each module - terraform

I have a module which has a variable defined using for_each, and its output is as below:
output "nic_ids" {
value = [for x in azurerm_network_interface.nic : x.id]
}
nic_ids = [
"/subscriptions/*****/resourceGroups/test-rg/providers/Microsoft.Network/networkInterfaces/test-nic-1",
"/subscriptions/*****/resourceGroups/test-rg/providers/Microsoft.Network/networkInterfaces/test-nic-2",
]
My aim is to pass above NIC ids to the VM module and have 1:1 mapping between NIC id and VM (test-nic-1 should only be attached to vm-1, test-nic-2 to vm-2 etc.)
module "vm" {
source = "*****/vm/azurerm"
version = "0.1.0"
vms = var.vms
nic_ids = module.nic[each.value.id].nic_ids
}
I am getting below error:
Error: each.value cannot be used in this context
on main.tf line 58, in module "vm":
58: nic_ids = module.nic[each.value.id].nic_ids
A reference to "each.value" has been used in a context in which it
unavailable, such as when the configuration no longer contains the value in
its "for_each" expression. Remove this reference to each.value in your
configuration to work around this error.
I used this similar question as reference.
Can you please suggest?

You could pass the above NIC id list to the VM modules with the count.
module "vm" {
source = "./modules/vms"
vm_names = ["aaa","bbb"]
nic_ids = module.nic.network_interface_nics
}
module "nic" {
source = "./modules/nic"
nic_names = ["nic1","nic2"]
}
the main.tf in the VM module:
resource "azurerm_virtual_machine" "vm-windows" {
count = length(var.vm_names)
name = var.vm_names[count.index]
resource_group_name = data.azurerm_resource_group.vm.name
location = var.location
vm_size = var.vm_size
network_interface_ids = [ var.nic_ids[count.index] ]
...
}
The output.tf in the NIC module:
output "network_interface_nics" {
description = "ids of the vm nics provisoned."
value = [for x in azurerm_network_interface.nic : x.id]
}

Related

Azure/Terraform:Link subnets to NSGs(ERROR-for_each map includes keys derived from resource attributes that cannot be determined until apply)

Locked for 3 days. Comments on this question have been disabled, but it is still accepting new answers and other interactions. Learn more.
Objective:Link multiple subnets in the environment to corresponding NSGs using a module (NSGs and Subnets have been created using separate modules)
Root Module:
1.main.tf
resource "azurerm_subnet_network_security_group_association" "root_subnet_nsg_association" {
subnet_id = var.subnet_id
network_security_group_id = var.nsg_id
}
2.variables.tf
variable "subnet_id"{
type=number
description="ID of the subnet which is to be attached to NSG"
#default=""
}
variable "nsg_id"{
type=number
description="ID of the NSG which is to be associated with a subnet"
#default=""
}
Calling Module in Projects Folder:
(for_each used to iterate the module)
1.nsg_subnet_association.tf
module "nsg_subnet_asosciation_module"{
source="../../Modules/network/nsg_subnet_association"
#Variable names to be passed into the root module:
#Use for_each to loop the module:
#for_each accepts a set or map but not list as a value
for_each = local.nsg_subnet_association
subnet_id=each.key
nsg_id=each.value
}
2.locals block passing in values to the calling module:
NOTE:It is possible to have dynamic keys in the map using parenthesis ()
locals{ //Key in subnet name and NSG name for each element of the LIST
//Implicit dependence on Subnet and NSG being created before attempt to associate
#It is possible to have dynamic keys using parenthesis () as seen on left below
nsg_subnet_association={
(module.subnet_module["MGT-Subnet-1"].subnet_id)= module.nsg_module["HUB-NSG"].nsg_id
(module.subnet_module["MGT-Subnet-1"].subnet_id) = module.nsg_module["MGT-NSG"].nsg_id
(module.subnet_module["SEC-Subnet-1"].subnet_id) = module.nsg_module["SEC-NSG"].nsg_id
}
}
This ends up with the following error:
The "for_each" map includes keys derived from resource attributes that cannot be determined until apply, and so Terraform cannot determine the full set of keys that will identify the instances of this resource.
When working with unknown values in for_each, it's better to define the map keys statically in your configuration and place apply-time results only in the map values.
Alternatively, you could use the -target planning option to first apply only the resources that the for_each value depends on, and then apply a second time to fully converge.
In Terraform , when dynamically getting the value of vnets or subnets , it may take time to create and the rest of the dependent resources cannot get desired values and so this error occurs.
Error:
The "for_each" map includes keys derived from resource attributes that cannot be determined until apply, and so Terraform cannot determine the full set of keys that will identify the instances of this resource.
Use a code where the values are defined statically to resolve the error:
example:
Code:
Variables.tf:
variable "virtual_network_name" {
type = string
default = "my-virtual-network"
}
variable "subnet_address_prefixes" {
type = list(string)
default = ["10.0.1.0/24", "10.0.2.0/24"]
}
variable "subnet_names" {
type = set(string)
default = ["subnet1", "subnet2"]
}
variable "nsg_names" {
type = set(string)
default = ["nsg1", "nsg2"]
}
variable "subnet_nsg_mappings" {
type = map(string)
default = {
"subnet1" = "nsg1"
"subnet2" = "nsg2"
}
}
Main.tf
resource "azurerm_virtual_network" "virtual_network" {
name = var.virtual_network_name
address_space = ["10.0.0.0/16"]
location = data.azurerm_resource_group.example.location
resource_group_name = data.azurerm_resource_group.example.name
}
resource "azurerm_network_security_group" "nsg" {
for_each = toset(var.nsg_names)
name = each.value
location = data.azurerm_resource_group.example.location
resource_group_name = data.azurerm_resource_group.example.name
security_rule {
name = "allow_http"
priority = 100
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "80"
source_address_prefix = "*"
destination_address_prefix = "*"
}
}
resource "azurerm_subnet" "subnet" {
for_each = toset(var.subnet_names)
name = each.value
virtual_network_name = azurerm_virtual_network.virtual_network.name
address_prefixes = var.subnet_address_prefixes
resource_group_name = data.azurerm_resource_group.example.name
// enable_multiple_address_prefixes = true
}
# Associate each subnet with its corresponding NSG
resource "azurerm_subnet_network_security_group_association" "subnet_nsg" {
for_each = var.subnet_nsg_mappings
subnet_id = azurerm_subnet.subnet[each.key].id
network_security_group_id = azurerm_network_security_group.nsg[each.value].id
//subnet_id = azurerm_subnet.subnet[each.key].id
// network_security_group_id = azurerm_network_security_group.nsg[var.subnet_nsg_mappings[each.value]].id
}
Or
Define locals for mappings .
locals {
subnet_nsg_mappings = {
"subnet1" = "nsg1",
"subnet2" = "nsg2",
"subnet3" = "nsg3"
}
}
resource "azurerm_subnet_network_security_group_association" "subnet_nsg" {
for_each = toset(var.subnet_names)
subnet_id = azurerm_subnet.subnet[each.value].id
network_security_group_id = azurerm_network_security_group.nsg[local.subnet_nsg_mappings[each.value]].id
}
If dynamic values must be used for_each keys cannot be determined during apply time. In that case use the -target option to first apply vnet and subnet values i.e; the resources that the for_each value depends on and apply completely.
terraform apply -target="azurerm_virtual_network.virtual_network" -target="azurerm_subnet.subnet"
Reference:
azurerm_subnet_network_security_group_association | Resources | hashicorp/azurerm | Terraform Registry

Terraform Data source is not picking subnet or resource group properly

I started writing terraform to automate the iac for provisioning VMs in Azure. However I wrote the entire code but am unable to use the existing subnet/vnet/resource group properly.
main.tf
# Configure the Microsoft Azure Provider
provider "azurerm" {
# The "feature" block is required for AzureRM provider 2.x.
# If you're using version 1.x, the "features" block is not allowed.
#version = "~>2.20.0"
features {}
subscription_id = var.subscription_id
tenant_id = var.tenant_id
client_id = var.client_id
client_secret = var.client_secret
}
#terraform {
# backend "azurerm" {
# snapshot = true
#}
#}
# Refer to resource group
data "azurerm_resource_group" "nwrk_group" {
name = var.nwrk_resource_group
}
data "azurerm_resource_group" "resource_group" {
name = var.resource_group
}
# Refer to a subnet
data "azurerm_subnet" "subnet" {
name = var.nwrk_subnet_name
virtual_network_name = var.nwrk_name
resource_group_name = data.azurerm_resource_group.nwrk_group.name
}
# Refer to Network Security Group and rule
data "azurerm_network_security_group" "nwrk_security_group" {
name = var.nwrk_security_grp
resource_group_name = data.azurerm_resource_group.nwrk_group.name
}
module "vm" {
source = "../modules/windows_vm"
node = var.node
node_username = var.node_username
node_password = var.node_password
tags = var.tags
deployment_environment = var.deployment_environment
nwrk_group_location = data.azurerm_resource_group.resource_group.location
nwrk_group_name = data.azurerm_resource_group.resource_group.name
subnet_id = data.azurerm_subnet.subnet.id
nwrk_security_group_id = data.azurerm_network_security_group.nwrk_security_group.id
resource_group_location = data.azurerm_resource_group.resource_group.location
resource_group_name = data.azurerm_resource_group.resource_group.name
}
terraform.tfvars
tags = {
project = "SEPS_Terraform"
environment = "test_tfm"
}
deployment_environment = "DEV"
node_username = "saz76test"
node_password = "SA82nd2"
nwrk_subnet_name = "SUBNET_45_0"
node = {
general_info = {
name = "gateway.test.com"
private_ip = "153.78.51.92"
vm_template = "Standard_B2s"
disk_type = "StandardSSD_LRS"
nwrk_resource_group = "SWS_LAB_36_192"
nwrk_name = "SUB_VNET_36_192"
nwrk_security_group = "N-Untrusted"
nwrk_subnet_name = "SUB_51_0"
}
os_image = {
publisher = "MicrosoftWindowsServer"
offer = "WindowsServer"
sku = "2019-DataCenter"
version = "latest"
}
storage_disk = {
type = "StandardSSD_LRS"
size = 256
}
}
variables.tf
variable "subscription_id" {
type = string
description = "Azure subscription id to provision infra."
}
variable "tenant_id" {
type = string
description = "Azure subscription tenant id"
}
variable "client_id" {
type = string
description = "App id to authenticate to azure."
}
variable "client_secret" {
type = string
description = "App password to authenticate to azure"
}
variable "resource_group" {
type = string
description = "Resource group in which resources will be added other than network resources"
}
variable "nwrk_resource_group" {
type = string
description = "Resource group for network resources"
}
variable "nwrk_name" {
type = string
description = "VPC network name where the network resources belong to"
}
variable "nwrk_subnet_name" {
type = string
description = "Subnet of the VPC network"
}
variable "nwrk_security_grp" {
type = string
description = "Security group to which the network belong to"
}
variable "tags" {
type = map(string)
description = "Tags to attach to resources"
}
variable "deployment_environment" {
type = string
description = "Environment these VMs belong to"
}
variable "node" {
type = map(map(string))
description = "web node with specifications."
}
variable "node_username" {
type = string
description = "Login username for node"
}
variable "node_password" {
type = string
description = "Login password for node"
}
module_code:
# Create network interface
resource "azurerm_network_interface" "nic" {
name = "${var.node["general_info"]["name"]}_nic"
location = var.nwrk_group_location
resource_group_name = var.nwrk_group_name
ip_configuration {
name = "${var.node["general_info"]["name"]}_nicConfiguration"
subnet_id = var.subnet_id
private_ip_address_allocation = "Static"
private_ip_address = var.node["general_info"]["private_ip"]
}
tags = var.tags
}
# Connect the security group to the network interface
resource "azurerm_network_interface_security_group_association" "example" {
network_interface_id = azurerm_network_interface.nic.id
network_security_group_id = var.nwrk_security_group_id
}
resource "azurerm_windows_virtual_machine" "vm" {
name = var.node["general_info"]["name"]
location = var.resource_group_location
resource_group_name = var.resource_group_name
network_interface_ids = [azurerm_network_interface.nic.id]
size = var.node["general_info"]["vm_template"]
computer_name = var.node["general_info"]["name"]
admin_username = var.node_username
admin_password = var.node_password
os_disk {
name = "${var.node["general_info"]["name"]}-osDisk"
caching = "ReadWrite"
storage_account_type = var.node["general_info"]["disk_type"]
}
source_image_reference {
publisher = var.node["os_image"]["publisher"]
offer = var.node["os_image"]["offer"]
sku = var.node["os_image"]["sku"]
version = var.node["os_image"]["version"]
}
tags = var.tags
}
output "vm_id" {
value = azurerm_windows_virtual_machine.vm.id
}
output "vm_name" {
value = azurerm_windows_virtual_machine.vm.name
}
output "vm_ip_address" {
value = azurerm_network_interface.nic.private_ip_address
}
My code is above one which am trying to execute init working but plan is failing to do. Can someone please help me on this what I am missing. ?? The error is getting like it.
Error :
Warning: Value for undeclared variable
│
│ The root module does not declare a variable named "nwrk_security_group" but a value was found in file "subscription.tfvars". If you meant to use
│ this value, add a "variable" block to the configuration.
│
│ To silence these warnings, use TF_VAR_... environment variables to provide certain "global" settings to all configurations in your organization.
│ To reduce the verbosity of these warnings, use the -compact-warnings option.
╵
╷
│ Warning: Resource targeting is in effect
│
│ You are creating a plan with the -target option, which means that the result of this plan may not represent all of the changes requested by the
│ current configuration.
│
│ The -target option is not for routine use, and is provided only for exceptional situations such as recovering from errors or mistakes, or when
│ Terraform specifically suggests to use it as part of an error message.
╵
╷
│ Error: Error: Subnet "SUBNET_45_0" (Virtual Network "SUB_VNET_36_192" / Resource Group "SWS_LAB_36_192") was not found
│
│ with data.azurerm_subnet.subnet,
│ on main.tf line 31, in data "azurerm_subnet" "subnet":
│ 31: data "azurerm_subnet" "subnet" {
│
╵
╷
│ Error: Error: Network Security Group "NSG" (Resource Group "SWS_LAB_36_192") was not found
│
│ with data.azurerm_network_security_group.nwrk_security_group,
│ on main.tf line 38, in data "azurerm_network_security_group" "nwrk_security_group":
│ 38: data "azurerm_network_security_group" "nwrk_security_group" {
Subscription.tfvars
subscription_id = "fdssssssssssssss"
client_id = "sdsdsdsdsdsdsdsdsdsdsdsd"
client_secret = ".dssssssssssssssssss
tenant_id = "asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdf"
resource_group = "SWS_LAB_36_192"
nwrk_resource_group = "SWS_LAB_36_192"
nwrk_name = "SUB_VNET_36_192"
nwrk_security_group = "N-Untrusted"
There could potentially be many different problems because I am not sure what the outlook of the root module and child modules are, but as per the error you are getting, it seems that the value defined for the variable in the subscription.tfvars is not being declared anywhere and the one that is supposed to be declared is missing, the data source does not return anything, hence there is the error from the child module as well. Currently it is defined as:
variable "nwrk_security_grp" {
type = string
description = "Security group to which the network belong to"
}
If you take a look at the values in subscription.tfvars, there is no nwrk_security_grp, but there is a nwrk_security_group. One option to fix this would probably be to change the name of the variable in the variables.tf:
variable "nwrk_security_group" {
type = string
description = "Security group to which the network belong to"
}
In that case, you would have to adapt the data source to use the new variable name:
data "azurerm_network_security_group" "nwrk_security_group" {
name = var.nwrk_security_group
resource_group_name = data.azurerm_resource_group.nwrk_group.name
}
Alternatively (and probably easier), you can change the name of the variable you are assigning the value to in subscription.tfvars:
nwrk_security_grp = "N-Untrusted" # it was nwrk_security_group
What I would strongly suggest going forward is to keep the naming convention for the variables the same because this way you will get into a lot of issues.

Creating multiple subnets in Azure Terraform using modules

I'm trying to deploy two subnets with different ip prefixes and different names and not create too much repeated code. I'm not sure how to approach it best. I tried the below but its not working. My terraform version is 0.14.11 so I think some of what I am doing below might be outdated
My main.tf in root module
module "deploy_subnet" {
source = "./modules/azure_subnet"
subscription_id = var.subscription_id
resource_group_name = var.resource_group_name
region = var.region
vnet_name = var.vnet_name
count_subnets = "${length(var.subnet_prefix)}"
subnet_name = "${lookup(element(var.subnet_prefix, count.index), "name")}"
address_prefix = "${lookup(element(var.subnet_prefix, count.index), "ip")}"
}
My variables.tf in root module (only pasting relevant part)
variable "subnet_prefix" {
type = "list"
default = [
{
ip = "10.0.1.0/24"
name = "aks-sn"
},
{
ip = "10.0.2.0/24"
name = "postgres-sn"
}
]
}
My main.tf in my child module folder
resource "azurerm_subnet" "obc_subnet" {
name = var.subnet_name
count = var.count_subnet
resource_group_name = var.resource_group_name
virtual_network_name = var.vnet_name
address_prefixes = var.address_prefix
}
My variables.tf in my child module folder (only relevant part)
variable "subnet_name" {
description = "Subnet Name"
}
variable "count_subnet" {
description = "count"
}
variable "address_prefix" {
description = "IP Address prefix"
}
I get the error below
Reference to "count" in non-counted context
on main.tf line 8, in module "deploy_subnet":
8: subnet_name = "${lookup(element(var.subnet_prefix, count.index),"name")}"
The "count" object can only be used in "module", "resource", and "data"
blocks, and only when the "count" argument is set
Reference to "count" in non-counted context
on main.tf line 9, in module "deploy_subnet":
9: address_prefix = "${lookup(element(var.subnet_prefix, count.index), "ip")}"
The "count" object can only be used in "module", "resource", and "data"
blocks, and only when the "count" argument is set.
It is exactly what it says. In the root module you try to reference a count.index but there is nothing being counted. All you do is pass a variable to the child module.
You should just pass subnet prefix to the child module, and in the child module set the count to the length of it, and reference count.index for the values of address_prefix and name
Alternatively, and probably more elegant you might look into for_each and each.value

for_each throws an error after it has been "moved"

So, i have used a for_each in each resource earlier.
And now I have moved that to the module.
module "architect" {
source = "./modules/architect"
for_each = toset(var.vm_names)
vm_name = each.value
vm_key = each.key
}
I have also defined up the vm_name and vm_key in /modules/architect/variables.tf:
variable "vm_name" {
type = string
}
variable "vm_key" {
type = string
}
I`m trying to set a public IP address on each VM.
And this worked fine when I had the for_each(commented out) in each resource.
resource "azurerm_public_ip" "pubip" {
#for_each = toset(var.vm_names)
name = "${var.vm_name}-PublicIp"
resource_group_name = azurerm_resource_group.rsg.name
location = azurerm_resource_group.rsg.location
allocation_method = "Dynamic"
}
resource "azurerm_network_interface" "main" {
#for_each = toset(var.vm_names)
name = "${var.vm_name}-nic"
location = azurerm_resource_group.rsg.location
resource_group_name = azurerm_resource_group.rsg.name
ip_configuration {
name = "testconfiguration1"
subnet_id = azurerm_subnet.subnet.id
private_ip_address_allocation = "Dynamic"
public_ip_address_id = azurerm_public_ip.pubip[var.vm_key].id
}
The error it throws here is:
Error: Invalid index
on modules\architect\main.tf line 109, in resource "azurerm_network_interface" "main":
109: public_ip_address_id = azurerm_public_ip.pubip[var.vm_key].id
|----------------
| azurerm_public_ip.pubip is object with 16 attributes
| var.vm_key is "OSL-SPLK-HF01"
The given key does not identify an element in this collection value.
Here is the block for the 109 line, where the last line is the number 109:
ip_configuration {
name = "testconfiguration1"
subnet_id = azurerm_subnet.subnet.id
private_ip_address_allocation = "Dynamic"
public_ip_address_id = azurerm_public_ip.pubip[var.vm_key].id
What is the reason I get this error?
I have used each.key there before.
When you have a resource block without for_each set at all, referring to it in other expressions returns just a single object rather than a map of objects.
For that reason, once you factor out the for_each into the calling module block rather than each individual resource it's no longer correct to try to access individual instances of your resources, as you did in the expression azurerm_public_ip.pubip[var.vm_key].id. Instead, you should just refer directly to the single object that resource now represents:
public_ip_address_id = azurerm_public_ip.pubip.id
Notice that within the namespace of each particular module instance there is only one azurerm_public_ip.pubip, so you can just refer directly to it. Because the for_each is now on the module call itself rather than on the individual resources, Terraform will assign these resources addresses shaped like this:
module.architect["OSL-SPLK-HF01"].azurerm_public_ip.pubip
...whereas when you had the resources in the root with their own for_each arguments, Terraform would address them like this:
module.architect.azurerm_public_ip.pubip["OSL-SPLK-HF01"]
The index now exists in the calling module rather than in the called module, so the architect module itself has no awareness that it's being used with for_each, but any references to the outputs of that module in the caller will need to include a key like you were previously doing with the resource instances:
# the "foo" output value associated with the "OSL-SPLK-HF01"
# instance of the module.
module.architect["OSL-SPLK-HF01"].foo

How to reference a data source from a module to another module and pass it as a variable to root module?

I have terraform directory structure as below:
terraform/
main.tf modules outputs.tf provider.tf variables.tf
./modules:
compute network resourcegroup
./modules/compute:
main.tf outputs.tf variables.tf
./modules/network:
main.tf outputs.tf variables.tf
./modules/resourcegroup:
main.tf outputs.tf variables.tf
resourcegroup module config files as below:
Purpose: In this module, I am referencing an existing resource group which I would like to utilized to create a Virtual machine and its associated objects.
main.tf
data "azurerm_resource_group" "tf-rg-external" {
name = var.rg_name
}
variables.tf
variable "rg_name" {
type = string
}
network module
Purpose: I would like to use resource group from resourcegroup module to be referenced in this module. That way, I define at one place and use it in root and other modules example, compute, app service, aks etc
main.tf
# Reference existing Virtual Network
data "azurerm_virtual_network" "tf-vn" {
name = var.vnet_name
resource_group_name = module.resource_groups.external_rg_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 = module.resource_groups.external_rg_name
}
variables.tf
# Declare env variable
variable "vnet_name" {
type = string
}
variable "subnet_name" {
type = string
}
compute module.
Purpose: To define all attributes for compute(VM). The idea is, root module will use this module to spin up different VM roles.
main.tf
module "vm_iis" {
source = "Azure/compute/azurerm"
location = data.resourcegroup.tf-rg-external.location
vnet_subnet_id = data.network.tf-sn.id
admin_password = var.admin_password
data_sa_type = var.data_sa_type
delete_os_disk_on_termination = var.delete_os_disk_on_termination
nb_instances = var.nb_instances
nb_public_ip = var.nb_public_ip
public_ip_address_allocation = var.public_ip_address_allocation
resource_group_name = data.resourcegroup.tf-rg-external.name
.
.
.
}
variables.tf
variable "admin_password" {
type = string
}
variable "admin_username" {
type = string
}
variable "boot_diagnostics" {
type = bool
}
variable "boot_diagnostics_sa_type" {
type = string
}...
terraform root module.
Purpose: This should utilize modules defined to create a variety of VMs of different sizes and host names
main.tf:
module "sql_vm" {
source = "./modules/compute/"
#location = data.resourcegroup.tf-rg-external.location
#vnet_subnet_id = data.network.tf-sn.id
public_ip_address_allocation = var.public_ip_address_allocation
#resource_group_name = data.resourcegroup.tf-rg-external.name
storage_account_type = var.storage_account_type
vm_hostname = var.vm_hostname
}
variables.tf: Declares all variables in main.tf file.
Note: I have intentionally hard coded the variables in root module main/variable file. This is just get the communication between the modules right. Correct approach to understand and use modules.
However, when I run terraform plan in the root module. I get the error below:
Error: Reference to undeclared resource
on modules/compute/main.tf line 3, in module "vm_iis":
3: location = data.resourcegroup.tf-rg-external.location
A data resource "resourcegroup" "tf-rg-external" has not been declared in
sql_vm.
Error: Reference to undeclared resource
on modules/compute/main.tf line 4, in module "vm_iis":
4: vnet_subnet_id = data.network.tf-sn.id
A data resource "network" "tf-sn" has not been declared in sql_vm.
Error: Reference to undeclared resource
on modules/compute/main.tf line 22, in module "vm_iis":
22: resource_group_name = data.resourcegroup.tf-rg-external.name
A data resource "resourcegroup" "tf-rg-external" has not been declared in
sql_vm.
What is the issue and how to resolve it?
Also, possible to create different (roles) vms by some loop? example sql-vm, iis-vm, testvm, abcvm? What is going to change is their hostnames and vm sizes.
==========
Post answer changes
==========
I updated the values for subnet, resource group and location in
compute/main.tf and terraform/main.tf as like below:
location = module.resourcegroup.tf-rg-external-location
vnet_subnet_id = module.network.subnet-id
resource_group_name = module.resourcegroup.tf-rg-external-name
My outputs.tf file in resourcegroup and network modules look like below:
outputs.tf of network module
output "subnet-id" {
value = "data.network.tf-sn.id"
}
outputs.tf of resourcegroup module
output "tf-rg-external-location" {
value = data.resourcegroup.tf-rg-external.location
}
output "tf-rg-external-name" {
value = data.resourcegroup.tf-rg-external.name
}
I'm unfortunately still getting errors like below
Error: Unsupported argument
on main.tf line 3, in module "sql_vm":
3: location = module.resourcegroup.tf-rg-external-location
An argument named "location" is not expected here.
Error: Unsupported argument
on main.tf line 4, in module "sql_vm":
4: vnet_subnet_id = module.network.subnet-id
An argument named "vnet_subnet_id" is not expected here.
Error: Unsupported argument
on main.tf line 5, in module "sql_vm":
5: resource_group_name = module.resourcegroup.tf-rg-external-name
An argument named "resource_group_name" is not expected here.
So, it appears that we should not be referencing them in the root module?
Also, where their variables should be defined as in root modules variables.tf file as I believe you can override values for a variable of modules in the root module?
Forgive me if I am appearing as stupid. I'm trying to understand how it works in real life.
After last commit and public repo, error's are as below
Error: Reference to undeclared module
on main.tf line 3, in module "sql_vm":
3: location = module.resourcegroup.tf-rg-external-location
No module call named "resourcegroup" is declared in the root module.
Error: Reference to undeclared module
on main.tf line 4, in module "sql_vm":
4: vnet_subnet_id = module.network.subnet-id
No module call named "network" is declared in the root module.
Error: Reference to undeclared module
on main.tf line 5, in module "sql_vm":
5: resource_group_name = module.resourcegroup.tf-rg-external-name
No module call named "resourcegroup" is declared in the root module.
Error: Reference to undeclared module
on modules/compute/main.tf line 3, in module "vm_iis":
3: location = module.resourcegroup.tf-rg-external-location
No module call named "resourcegroup" is declared in sql_vm.
Error: Reference to undeclared module
on modules/compute/main.tf line 4, in module "vm_iis":
4: vnet_subnet_id = module.network.subnet-id
No module call named "network" is declared in sql_vm.
Error: Reference to undeclared module
on modules/compute/main.tf line 5, in module "vm_iis":
5: resource_group_name = module.resourcegroup.tf-rg-external-name
No module call named "resourcegroup" is declared in sql_vm.
Error: Reference to undeclared module
on modules/network/main.tf line 5, in data "azurerm_virtual_network" "tf-vn":
5: resource_group_name = module.resource_groups.external_rg_name
No module call named "resource_groups" is declared in test2.
Error: Reference to undeclared resource
on modules/resourcegroup/outputs.tf line 2, in output "tf-rg-external-location":
2: value = data.resourcegroup.tf-rg-external.location
A data resource "resourcegroup" "tf-rg-external" has not been declared in
test1.
Error: Reference to undeclared resource
on modules/resourcegroup/outputs.tf line 5, in output "tf-rg-external-name":
5: value = data.resourcegroup.tf-rg-external.name
A data resource "resourcegroup" "tf-rg-external" has not been declared in
test1.
Go through the repo you are working on (https://github.com/ameyaagashe/help_me_cross/tree/d7485d2a3db339723e9c791e592b2f1dbc1f0788) . It makes sense for me now.
The problem is, you mix the idea on how to use public modules with your own created modules.
In fact, you needn't set any modules to reference other public terraform registry modules.
Move all codes in sub-modules (module/compute, module/network, module/resourcegroup) to top folder (<repo_root>/main.tf).
such as (codes are not validated, just for reference)
data "azurerm_resource_group" "tf-rg-external" {
name = var.rg_name
}
data "azurerm_virtual_network" "tf-vn" {
name = var.vnet_name
resource_group_name = var.rg_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 = var.rg_name
}
module "sql_vm" {
source = "Azure/compute/azurerm"
location = data.azurerm_resource_group.tf-rg-external.location
vnet_subnet_id = data.azurerm_virtual_network.tf-vn.subnets
resource_group_name = data.azurerm_resource_group.tf-rg-external.name
admin_password = var.admin_password
admin_username = var.admin_username
boot_diagnostics = var.boot_diagnostics
boot_diagnostics_sa_type = var.boot_diagnostics_sa_type
data_disk = var.data_disk
data_disk_size_gb = var.data_disk_size_gb
data_sa_type = var.data_sa_type
delete_os_disk_on_termination = var.delete_os_disk_on_termination
enable_accelerated_networking = var.enable_accelerated_networking
# flag is_windows_image is required only when you use a custom image to spin up a VM
# is_windows_image
# flag vm_os_id is required only when you are using custom image
# you need to provide id of your custom image
# vm_os_id
nb_instances = var.nb_instances
nb_public_ip = var.nb_public_ip
public_ip_address_allocation = var.public_ip_address_allocation
storage_account_type = var.storage_account_type
vm_hostname = var.vm_hostname
vm_os_offer = var.vm_os_offer
vm_os_publisher = var.vm_os_publisher
# vm_os_simple is to be used is you do not wish to specify offer, publisher and sku
# vm_os_simple = UbuntuServer, WindowsServer, RHEL, openSUSE-Leap, CentOS, Debian, CoreOS and SLES
vm_os_sku = var.vm_os_sku
vm_os_version = var.vm_os_version
vm_size = var.vm_size
}

Resources