Setting a static IP Address to an Virtual Machine from OVF Template - terraform

I'm using Terraform's vSphere Provider. I have a local OVF template that I'm trying to deploy a VM from. I wish to set a static IP address for the soon-to-be-deployed VM, but Terraform keeps complaining
"Argument named ipv4_address is not expected here."
"Argument named ipv4_netmask is not expected here."
"Argument named "ipv4_gateway` is not expected here."
DHCP is not an option so I have to set it manually. Terraform gives an option to allocate IPs manually, so what can I do?
This is the Template I'm using:
data "vsphere_ovf_vm_template" "ovfRemote" {
name = "foo"
disk_provisioning = "thick"
datastore_id = data.vsphere_datastore.datastore.id
host_system_id = data.vsphere_host.host.id
resource_pool_id = data.vsphere_resource_pool.default.id
local_ovf_path = "/path/to/ovf"
ip_protocol = "IPV4"
ip_allocation_policy = "STATIC_MANUAL"
ovf_network_map = {
"Network" : data.vsphere_network.network.id
}
}
and here's the Virtual Machine's I'm trying to create:
resource "vsphere_virtual_machine" "vmFromLocalOvf" {
name = "terraform-using-ovf-template"
datacenter_id = data.vsphere_datacenter.datacenter.id
datastore_id = data.vsphere_datastore.datastore.id
host_system_id = data.vsphere_host.host.id
resource_pool_id = data.vsphere_resource_pool.default.id
wait_for_guest_net_timeout = 0
wait_for_guest_ip_timeout = 0
num_cpus = data.vsphere_ovf_vm_template.ovfRemote.num_cpus
memory = data.vsphere_ovf_vm_template.ovfRemote.memory
guest_id = data.vsphere_ovf_vm_template.ovfRemote.guest_id
ovf_deploy {
allow_unverified_ssl_cert = false
enable_hidden_properties = false
local_ovf_path = data.vsphere_ovf_vm_template.ovfRemote.local_ovf_path
disk_provisioning = data.vsphere_ovf_vm_template.ovfRemote.disk_provisioning
ip_protocol = data.vsphere_ovf_vm_template.ovfRemote.ip_protocol
ip_allocation_policy = data.vsphere_ovf_vm_template.ovfRemote.ip_allocation_policy
ovf_network_map = data.vsphere_ovf_vm_template.ovfRemote.ovf_network_map
}
#### HERE IS THE PROBLEM I'M FACING ###
# With the provider 'vsphere_virtual_machine' I should be able to specify
# a network interface. Specifically, I'm interested in setting a
# * ipv4_address
# * ipv4_netmask
# * ipv4_gateway
network_interface {
ipv4_address = "11.22.33.44"
ipv4_netmask = 24
}
ipv4_gateway = "55.66.77.88"
Errors:
$ terraform plan
╷
│ Error: Unsupported argument
│
│ on main.tf line 82, in resource "vsphere_virtual_machine" "vmFromLocalOvf":
│ 82: ipv4_address = "10.112.128.22"
│
│ An argument named "ipv4_address" is not expected here.
╵
╷
│ Error: Unsupported argument
│
│ on main.tf line 83, in resource "vsphere_virtual_machine" "vmFromLocalOvf":
│ 83: ipv4_netmask = 24
│
│ An argument named "ipv4_netmask" is not expected here.
╵
╷
│ Error: Unsupported argument
│
│ on main.tf line 86, in resource "vsphere_virtual_machine" "vmFromLocalOvf":
│ 86: ipv4_gateway = "10.112.128.1"
│
│ An argument named "ipv4_gateway" is not expected here.

Related

Terraform dynamicly attach disks and network when vps is counted

I can't figure out how to dynamically connect disks and networks to virtual machines if they are counted
I expect i will pass variables like this:
module "vps-test" {
source = "../module"
count = 3
server_name = "vpstest"
server_image = "debian-11"
server_type = "cx21"
server_datacenter = "fsn1-dc14"
labels = { groups = "test_offline.test_vps" }
server_network = {
backend_network = {
subnet_id = (data.terraform_remote_state.htz_network.outputs.main-subnet-id)
ip = "" #DHCP
}
custom_network = {
subnet_id = "1867414"
ip = ""
}
}
volumes = {
firts_volume = {
name = "volume1"
size = "20"
}
second_volume = {
name = "volume1"
size = "20"
}
}
hetzner_cloud_token = var.hetzner_cloud_offline_main_api_token
cloud_init_file_path = "../module/scripts/user.yaml"
}
and the module will create 3 identical VMs, where each will have 2 disks and 2 networks
It's Hetznere cloud provider, here is my simple code:
resource "hcloud_server" "vps" {
count = var.server_count
name = var.server_count > 1 ? "${var.server_name}-${count.index}" : var.server_name
image = var.server_image
server_type = var.server_type
datacenter = var.server_datacenter
user_data = data.template_file.ansible_user_data.rendered
labels = var.labels
}
resource "hcloud_volume" "volume" {
for_each = var.volumes
name = tostring(each.value["name"])
size = tonumber(each.value["size"])
server_id = hcloud_server.vps.id
automount = true
format = var.volume_filesystem
}
resource "hcloud_server_network" "network" {
for_each = var.server_network
server_id = hcloud_server.vps.id
subnet_id = each.value["subnet_id"]
ip = tostring(each.value["ip"])
}
Errors:
│ Error: Missing resource instance key
│
│ on ../module/resource.tf line 15, in resource "hcloud_volume" "volume":
│ 15: server_id = hcloud_server.vps.id
│
│ Because hcloud_server.vps has "count" set, its attributes must be accessed on specific instances.
│
│ For example, to correlate with indices of a referring resource, use:
│ hcloud_server.vps[count.index]
╵
╷
│ Error: Missing resource instance key
│
│ on ../module/resource.tf line 22, in resource "hcloud_server_network" "network":
│ 22: server_id = hcloud_server.vps.id
│
│ Because hcloud_server.vps has "count" set, its attributes must be accessed on specific instances.
│
│ For example, to correlate with indices of a referring resource, use:
│ hcloud_server.vps[count.index]
if using recommends from error log
│ Error: Reference to "count" in non-counted context
│
│ on ../module/resource.tf line 15, in resource "hcloud_volume" "volume":
│ 15: server_id = hcloud_server.vps[count.index].id
│
│ The "count" object can only be used in "module", "resource", and "data" blocks, and only when the "count" argument is set.
╵
╷
│ Error: Reference to "count" in non-counted context
│
│ on ../module/resource.tf line 22, in resource "hcloud_server_network" "network":
│ 22: server_id = hcloud_server.vps[count.index].id
│
│ The "count" object can only be used in "module", "resource", and "data" blocks, and only when the "count" argument is set.
but if server_id = hcloud_server.vps[0].id (or any specific index) - working
where is the correct way
Since you are using both count and for_each you need to iterate over both of them. Basically it means you need a double for loop. One way to do it in TF is with the help of setproduct:
resource "hcloud_volume" "volume" {
for_each = {for idx, val in setproduct(range(var.server_count), keys(var.volumes)): idx => val}
name = tostring(var.volume[each.value[1]].name)
size = tonumber(var.volume[each.value[1]].size)
server_id = hcloud_server.vps[each.value[0]].id
automount = true
format = var.volume_filesystem
}
resource "hcloud_server_network" "network" {
for_each = {for idx, val in setproduct(range(var.server_count), keys(var.server_network)): idx => val}
server_id = hcloud_server.vps[each.value[0]].id
subnet_id = var.server_network[each.value[1]].subnet_id
ip = tostring(var.server_network[each.value[1]].ip)
}

How to add VPC-CIDR authorization rule in VPN

How to add module's(vpc) output of vpc-cidr to vpn's authorization rule.
Tried the below way
cat modules/vpn/vpn.tf
...
resource "aws_ec2_client_vpn_authorization_rule" "vpn_vpc_cidr" {
client_vpn_endpoint_id = aws_ec2_client_vpn_endpoint.vaya-vpn.id
target_network_cidr = var.cidr-vpc
authorize_all_groups = true
}
cat main.tf
module "vpn" {
source = "./modules/vpn"
acm_vpn_server = module.acm_cert.acm_vpn_server
vpc_id = module.vpc.vpc_id
# private_subnet_ids = module.vpc.private_subnet_ids
subnet_ids = module.vpc.subnet_ids
cidr-vpc = module.vpc.cidr-vpc
cidr-subnets = module.vpc.cidr-subnets
env = var.env
}
But getting the below error
╷
│ Error: Unsupported attribute
│
│ on main.tf line 79, in module "vpn":
│ 79: cidr-vpc = module.vpc.cidr-vpc
│ ├────────────────
│ │ module.vpc is a object
│
│ This object does not have an attribute named "cidr-vpc".

Terraform keep saying variable not defined though its defined

I am trying to create a resource in azure via Terraform. Even though I have declared all required variables, its erroring out. I am using modules for the same...
Here is the below code that I tried:
My Module's Bastion/main.tf that used to create resource:
resource "azurerm_public_ip" "syn_pip" {
name = "pip-${var.prefix}-${var.postfix}"
location = var.location
resource_group_name = var.rg_name
allocation_method = var.bastion_allocation_method
sku = var.bastion_sku_type
}
My modules's Bastion/variables.tf :
variable "bastion_allocation_method" {
type = string
description = "allocation method for bastion"
}
variable "bastion_sku_type" {
type = string
description = "sku to be used for bastion"
}
My root module bastion.tf :
module "bastion" {
source = "../modules/bastion"
rg_name = module.resource_group.name
location = module.resource_group.location
allocation_method = var.bastion_allocation_method
sku = var.bastion_sku_type
prefix = var.prefix
postfix = random_string.postfix.result
subnet_id = azurerm_subnet.bastion_subnet.id
}
root module's variable.tf:
variable "bastion_allocation_method" {
type = string
}
variable "bastion_sku_type" {
type = string
}
my terraform.tfvars which passed to terraform plan :
"bastion_allocation_method": "Static",
"bastion_sku_type": "Standard"
Error that I get:
│ Error: Missing required argument
│
│ on bastion.tf line 1, in module "bastion":
│ 1: module "bastion" {
│
│ The argument "bastion_allocation_method" is required, but no definition was found.
╵
╷
│ Error: Missing required argument
│
│ on bastion.tf line 1, in module "bastion":
│ 1: module "bastion" {
│
│ The argument "bastion_sku_type" is required, but no definition was found.
╵
╷
│ Error: Unsupported argument
│
│ on bastion.tf line 7, in module "bastion":
│ 7: allocation_method = var.bastion_allocation_method
│
│ An argument named "allocation_method" is not expected here.
╵
╷
│ Error: Unsupported argument
│
│ on bastion.tf line 8, in module "bastion":
│ 8: sku = var.bastion_sku_type
│
│ An argument named "sku" is not expected here.
╵
Exited with code exit status 1
Can someone suggest, what is the mistake I am doing ?
In your Bastion module in the variables.tf you specify the arguments
variable "bastion_allocation_method" {
...
}
variable "bastion_sku_type" {
...
}
In your case your module expects the vars bastion_allocation_method and bastion_sku_type
But when you call the module, you dont pass the variable names properly
module "bastion" {
source = "../modules/bastion"
...
allocation_method = var.bastion_allocation_method
sku = var.bastion_sku_type
...
}
Use instead
module "bastion" {
source = "../modules/bastion"
...
bastion_allocation_method = var.bastion_allocation_method
bastion_sku_type = var.bastion_sku_type
...
}
The variable assignments that you pass in module clause should match the definitions in the module's variables.tf

Reference to undeclared resource

Azure Loadbalancer Rule Module code is like below:
main.tf.
resource "azurerm_lb_rule" "lb_rule" {
count = length(var.lb_rule_specs)
name = var.lb_rule_specs[count.index]["name"]
resource_group_name = var.resource_group_name
loadbalancer_id = var.loadbalancer_id
frontend_ip_configuration_name = var.lb_rule_specs[count.index]["frontend_ip_configuration_name"]
protocol = var.lb_rule_specs[count.index]["protocol"]
frontend_port = var.lb_rule_specs[count.index]["frontend_port"]
backend_port = var.lb_rule_specs[count.index]["backend_port"]
probe_id = var.probe_id
load_distribution = var.load_distribution
backend_address_pool_id = var.backend_address_pool_id
}
variables.tf
variable "lb_rule_specs" {
description = "Load balancer rules specifications"
type = list(map(string))
}
variable "resource_group_name" {
description = "Name of the resource group"
type = string
}
variable "loadbalancer_id" {
description = "ID of the load balancer"
type = string
}
variable "backend_address_pool_id" {
description = "Backend address pool id for the load balancer"
type = string
}
variable "probe_id" {
description = "ID of the loadbalancer probe"
type = string
default = ""
}
variable "load_distribution" {
description = "Specifies the load balancing distribution type to be used by the Load Balancer. Possible values are: Default – The load balancer is configured to use a 5 tuple hash to map traffic to available servers. SourceIP – The load balancer is configured to use a 2 tuple hash to map traffic to available servers. SourceIPProtocol – The load balancer is configured to use a 3 tuple hash to map traffic to available servers. Also known as Session Persistence, where the options are called None, Client IP and Client IP and Protocol respectively."
type = string
default = ""
}
Calling module as below:
variable "loadbalancer_rule" {
description = "Map of loadbalancer-rule objects"
type = any
default = null
}
module "loadbalancer_rule" {
for_each = coalesce(var.loadbalancer_rule, {})
source = "company.com.au/tfmodules/loadbalancer-rule/azurerm"
version = "7.0.0-2-1.0"
backend_address_pool_id = try(each.value.backend_address_pool_id, null)
load_distribution = try(each.value.load_distribution, "")
loadbalancer_id = each.value.loadbalancer_ref != null ? module.loadbalancer[each.value.loadbalancer_ref].id : null
probe_id = each.value.probe_ref != null ? module.loadbalancer_probe[each.value.probe_ref].id : null
resource_group_name = var.__ngc.environment_resource_groups
lb_rule_specs = [
for lb_rule_spec in each.value.lb_rule_specs :
{
frontend_ip_configuration_name = try(for_each.lb_rule_spec.frontend_ip_configuration_name, null)
protocol = try(for_each.lb_rule_spec.protocol, null)
frontend_port = try(for_each.lb_rule_spec.frontend_port, null)
backend_port = try(for_each.lb_rule_spec.backend_port, null)
}
]
}
lbrule.auto.tfvars.json file like below:
{
"loadbalancer_rule": {
"patterns_default_loadbalancer_rule": {
"backend_address_pool_id": null,
"lb_rule_specs" : {
"name" : "test2",
"protocol": "tcp",
"frontend_port": "8080",
"backend_port": "8081",
"frontend_ip_configuration_name": "LBFrontendIPConfig_1"
},
"name" : "test2",
"protocol": "tcp",
"frontend_port": "8100",
"backend_port": "9100",
"frontend_ip_configuration_name": "LBFrontendIPConfig_2"
},
"load_distribution": "",
"loadbalancer_ref": "patterns_default_loadbalancer",
"probe_ref": "patterns_default_loadbalancer_probe"
}
}
Unfortunately, I get error as like below:
│ Error: Reference to undeclared resource
│
│ on loadbalancer_rule.tf line 20, in module "loadbalancer_rule":
│ 20: frontend_ip_configuration_name = try(for_each.lb_rule_spec.frontend_ip_configuration_name, null)
│
│ A managed resource "for_each" "lb_rule_spec" has not been declared in the
│ root module.
╵
╷
│ Error: Reference to undeclared resource
│
│ on loadbalancer_rule.tf line 21, in module "loadbalancer_rule":
│ 21: protocol = try(for_each.lb_rule_spec.protocol, null)
│
│ A managed resource "for_each" "lb_rule_spec" has not been declared in the
│ root module.
╵
╷
│ Error: Reference to undeclared resource
│
│ on loadbalancer_rule.tf line 22, in module "loadbalancer_rule":
│ 22: frontend_port = try(for_each.lb_rule_spec.frontend_port, null)
│
│ A managed resource "for_each" "lb_rule_spec" has not been declared in the
│ root module.
╵
╷
│ Error: Reference to undeclared resource
│
│ on loadbalancer_rule.tf line 23, in module "loadbalancer_rule":
│ 23: backend_port = try(for_each.lb_rule_spec.backend_port, null)
│
│ A managed resource "for_each" "lb_rule_spec" has not been declared in the
│ root module.
I am guessing that I am not writing outer OR inner loop properly? or perhaps the definition file (variable file) is not right?
There could be one or more lb rules and for each of those there could be 1 or more front end ip, protocol, front end port and backend port.

Error Reference to undeclared resource - Trying to get terraform modules to work

New terraform learner here, trying to learn by example and by coding. I was looking for terraform modules that would allow one to create a VM, found the example here https://faun.pub/creating-a-windows-vm-in-azure-using-terraform-which-way-is-best-13aff3ed9b74 which I thought would take my very basic terraform knowledge up a notch, since creating a VM is a process I am familiar with and can build upon. The experience has been nothing but frustrating. This is my 3rd week on it, and it still feels like miles away.
I read up the first solution and my files are structured in exactly thesame way as described.Mind, I have tried the first method, and it was riddled with errors, so I decided to try the second method which was supposed to be simpler.
I created a folder called simple_vm and inside it, another folder called vm.
Here are the contents.
vm_module_local_example.tf
# Create an Azure VM cluster with Terraform calling a Module. Creates 1 for Windows 10 desktop and 1 for Windows 2019 Server.
module windows_desktop_vm_using_local_module {
source = "./vm"
resource_group_name = azurerm_resource_group.rg.name
location = "uksouth"
sloc = "uks"
vm_subnet_id = module.network.vnet_subnets[0]
vm_name = "tfdtlocmod"
vm_size = var.desktop_vm_size
publisher = var.desktop_vm_image_publisher
offer = var.desktop_vm_image_offer
sku = var.desktop_vm_image_sku
static_ip_address = "10.0.1.15"
activity_tag = "Windows Desktop"
admin_password = module.vmpassword.secretvalue
}
module windows_server_vm_using_local_module {
source = "./vm"
resource_group_name = azurerm_resource_group.rg.name
location = "uksouth"
sloc = "uks"
vm_subnet_id = module.network.vnet_subnets[1]
vm_name = "tfsvlocmod"
vm_size = var.server_vm_size
publisher = var.server_vm_image_publisher
offer = var.server_vm_image_offer
sku = var.server_vm_image_sku
static_ip_address = "10.0.2.15"
activity_tag = "Windows Server"
admin_password = module.vmpassword.secretvalue
}
Within the folder called VM. I have the following files.
main.tf
resource "random_string" "nic_prefix" {
length = 4
special = false
}
resource "azurerm_network_interface" "vm_nic" {
name = "${var.vm_name}-nic1"
location = var.location
resource_group_name = var.resource_group_name
ip_configuration {
name = "${var.vm_name}_nic_${random_string.nic_prefix.result}"
subnet_id = var.vm_subnet_id
private_ip_address_allocation = "Static"
private_ip_address = var.static_ip_address
}
tags = var.tags
}
resource "azurerm_network_interface_security_group_association" "vm_nic_sg" {
network_interface_id = azurerm_network_interface.vm_nic.id
network_security_group_id = var.network_security_group_id
count = var.network_security_group_id == "" ? 0 : 1
}
resource "azurerm_virtual_machine" "windows_vm" {
name = var.vm_name
vm_size = var.vm_size
location = var.location
resource_group_name = var.resource_group_name
tags = merge(var.tags, { activityName = "${var.activity_tag} " })
network_interface_ids = [
"${azurerm_network_interface.vm_nic.id}",
]
storage_image_reference {
publisher = var.publisher
offer = var.offer
sku = var.sku
version = "latest"
}
identity {
type = "SystemAssigned"
}
storage_os_disk {
name = "${var.vm_name}-os-disk"
caching = "ReadWrite"
create_option = "FromImage"
managed_disk_type = "Standard_LRS"
}
os_profile {
admin_password = module.vmpassword.secretvalue
admin_username = "azureuser"
computer_name = var.vm_name
}
os_profile_windows_config {
provision_vm_agent = true
}
delete_os_disk_on_termination = var.vm_os_disk_delete_flag
delete_data_disks_on_termination = var.vm_data_disk_delete_flag
}
outputs.tf
output "vm_id" {
value = "${azurerm_virtual_machine.windows_vm.id}"
}
output "vm_name" {
value = "${azurerm_virtual_machine.windows_vm.name}"
}
output "vm_location" {
value = "${azurerm_virtual_machine.windows_vm.location}"
}
output "vm_resource_group_name" {
value = "${azurerm_virtual_machine.windows_vm.resource_group_name}"
}
variables.tf
variable "resource_group_name" {
}
variable "location" {
}
variable "sloc" {
}
variable "vm_size" {
default = "Standard_B1s"
}
variable "vm_subnet_id" {
}
variable "vm_name" {
}
variable "vm_os_disk_delete_flag" {
default = true
}
variable "vm_data_disk_delete_flag" {
default = true
}
variable "network_security_group_id" {
default = ""
}
variable "static_ip_address" {
}
variable "publisher" {
}
variable "offer" {
}
variable "sku" {
}
variable "tags" {
type = map
description = "All mandatory tags to use on all assets"
default = {
activityName = "AzureVMWindowsDemo"
automation = "Terraform"
costCenter1 = "A00000"
dataClassification = "Demo"
managedBy = "example#test.com"
solutionOwner = "example#test.com"
}
}
variable "activity_tag" {
}
variable "admin_password" {
}
Taking what is on the website, I get the following errors.
Error: Reference to undeclared resource
│
│ on vm_module_local_example.tf line 4, in module "windows_desktop_vm_using_local_module":
│ 4: resource_group_name = azurerm_resource_group.rg.name
│
│ A managed resource "azurerm_resource_group" "rg" has not been declared in the root module.
╵
╷
│ Error: Reference to undeclared module
│
│ on vm_module_local_example.tf line 7, in module "windows_desktop_vm_using_local_module":
│ 7: vm_subnet_id = module.network.vnet_subnets[0]
│
│ No module call named "network" is declared in the root module.
╵
╷
│ Error: Reference to undeclared input variable
│
│ on vm_module_local_example.tf line 9, in module "windows_desktop_vm_using_local_module":
│ 9: vm_size = var.desktop_vm_size
│
│ An input variable with the name "desktop_vm_size" has not been declared. This variable can be declared with a variable "desktop_vm_size" {} block.
╵
╷
│ Error: Reference to undeclared input variable
│
│ on vm_module_local_example.tf line 10, in module "windows_desktop_vm_using_local_module":
│ 10: publisher = var.desktop_vm_image_publisher
│
│ An input variable with the name "desktop_vm_image_publisher" has not been declared. This variable can be declared with a variable "desktop_vm_image_publisher" {} block.
╵
╷
│ Error: Reference to undeclared input variable
│
│ on vm_module_local_example.tf line 11, in module "windows_desktop_vm_using_local_module":
│ 11: offer = var.desktop_vm_image_offer
│
│ An input variable with the name "desktop_vm_image_offer" has not been declared. This variable can be declared with a variable "desktop_vm_image_offer" {} block.
╵
╷
│ Error: Reference to undeclared input variable
│
│ on vm_module_local_example.tf line 12, in module "windows_desktop_vm_using_local_module":
│ 12: sku = var.desktop_vm_image_sku
│
│ An input variable with the name "desktop_vm_image_sku" has not been declared. This variable can be declared with a variable "desktop_vm_image_sku" {} block.
╵
╷
│ Error: Reference to undeclared module
│
│ on vm_module_local_example.tf line 15, in module "windows_desktop_vm_using_local_module":
│ 15: admin_password = module.vmpassword.secretvalue
│
│ No module call named "vmpassword" is declared in the root module.
╵
╷
│ Error: Reference to undeclared resource
│
│ on vm_module_local_example.tf line 19, in module "windows_server_vm_using_local_module":
│ 19: resource_group_name = azurerm_resource_group.rg.name
│
│ A managed resource "azurerm_resource_group" "rg" has not been declared in the root module.
╵
╷
│ Error: Reference to undeclared module
│
│ on vm_module_local_example.tf line 22, in module "windows_server_vm_using_local_module":
│ 22: vm_subnet_id = module.network.vnet_subnets[1]
│
│ No module call named "network" is declared in the root module.
╵
╷
│ Error: Reference to undeclared input variable
│
│ on vm_module_local_example.tf line 24, in module "windows_server_vm_using_local_module":
│ 24: vm_size = var.server_vm_size
│
│ An input variable with the name "server_vm_size" has not been declared. This variable can be declared with a variable "server_vm_size" {} block.
╵
╷
│ Error: Reference to undeclared input variable
│
│ on vm_module_local_example.tf line 25, in module "windows_server_vm_using_local_module":
│ 25: publisher = var.server_vm_image_publisher
│
│ An input variable with the name "server_vm_image_publisher" has not been declared. This variable can be declared with a variable "server_vm_image_publisher" {} block.
╵
╷
│ Error: Reference to undeclared input variable
│
│ on vm_module_local_example.tf line 26, in module "windows_server_vm_using_local_module":
│ 26: offer = var.server_vm_image_offer
│
│ An input variable with the name "server_vm_image_offer" has not been declared. This variable can be declared with a variable "server_vm_image_offer" {} block.
╵
╷
│ Error: Reference to undeclared input variable
│
│ on vm_module_local_example.tf line 27, in module "windows_server_vm_using_local_module":
│ 27: sku = var.server_vm_image_sku
│
│ An input variable with the name "server_vm_image_sku" has not been declared. This variable can be declared with a variable "server_vm_image_sku" {} block.
╵
╷
│ Error: Reference to undeclared module
│
│ on vm_module_local_example.tf line 30, in module "windows_server_vm_using_local_module":
│ 30: admin_password = module.vmpassword.secretvalue
│
│ No module call named "vmpassword" is declared in the root module.
I can see that a lot of the errors relate to undeclared variables. I then create a variable file as follows (not within the vm folder).
variable "subscription_id" {
}
variable "client_id" {
}
variable "client_secret" {
}
variable "tenant_id" {
}
variable "global_settings" {
}
variable "desktop_vm_image_publisher" {
}
variable "desktop_vm_image_offer" {
}
variable "desktop_vm_image_sku" {
}
variable "desktop_vm_image_version" {
}
variable "desktop_vm_size" {
}
variable "server_vm_image_publisher" {
}
variable "server_vm_image_offer" {
}
variable "server_vm_image_sku" {
}
variable "server_vm_image_version" {
}
variable "server_vm_size" {
}
created a file called terraform.auto.tfvars.
# This file should not be checked into source control (add to .gitignore)
subscription_id = "xxxxxxxxxxxxxx"
client_id = "xxxxxxxxxxxxxx"
client_secret = "xxxxxxxxxxxxxx"
tenant_id = "xxxxxxxxxxxxxx"
## globalsettings
global_settings = {
#Set of tags
tags = {
applicationName = "Windows VM Demo"
businessUnit = "Technical Solutions"
costCenter = "MPN Sponsorship"
DR = "NON-DR-ENABLED"
deploymentType = "Terraform"
environment = "Dev"
owner = "Jack Roper"
version = "0.1"
}
}
# Desktop VM variables
desktop_vm_image_publisher = "MicrosoftWindowsDesktop"
desktop_vm_image_offer = "Windows-10"
desktop_vm_image_sku = "20h1-pro"
desktop_vm_image_version = "latest"
desktop_vm_size = "Standard_B1s"
# Server VM Variables
server_vm_image_publisher = "MicrosoftWindowsServer"
server_vm_image_offer = "WindowsServer"
server_vm_image_sku = "2019-Datacenter"
server_vm_image_version = "latest"
server_vm_size = "Standard_B1s"
Running terraform plan this time, I get the following errors.
Error: Reference to undeclared resource
│
│ on vm_module_local_example.tf line 4, in module "windows_desktop_vm_using_local_module":
│ 4: resource_group_name = azurerm_resource_group.rg.name
│
│ A managed resource "azurerm_resource_group" "rg" has not been declared in the root module.
╵
╷
│ Error: Reference to undeclared module
│
│ on vm_module_local_example.tf line 7, in module "windows_desktop_vm_using_local_module":
│ 7: vm_subnet_id = module.network.vnet_subnets[0]
│
│ No module call named "network" is declared in the root module.
╵
╷
│ Error: Reference to undeclared module
│
│ on vm_module_local_example.tf line 15, in module "windows_desktop_vm_using_local_module":
│ 15: admin_password = module.vmpassword.secretvalue
│
│ No module call named "vmpassword" is declared in the root module.
╵
╷
│ Error: Reference to undeclared resource
│
│ on vm_module_local_example.tf line 19, in module "windows_server_vm_using_local_module":
│ 19: resource_group_name = azurerm_resource_group.rg.name
│
│ A managed resource "azurerm_resource_group" "rg" has not been declared in the root module.
╵
╷
│ Error: Reference to undeclared module
│
│ on vm_module_local_example.tf line 22, in module "windows_server_vm_using_local_module":
│ 22: vm_subnet_id = module.network.vnet_subnets[1]
│
│ No module call named "network" is declared in the root module.
╵
╷
│ Error: Reference to undeclared module
│
│ on vm_module_local_example.tf line 30, in module "windows_server_vm_using_local_module":
│ 30: admin_password = module.vmpassword.secretvalue
│
│ No module call named "vmpassword" is declared in the root module.
╵
Now, It appears I have been extremely unlucky with examples online, in the above there are a lot of missing variables, the author doesnt specify if certain files should be used from a different example (there is a lot of code on the link apparently for different techniques for achieving the same goal). At the same time, I am new to this and wasn't sure if I can truly say there are missing files/details in the solution posted. I have had no luck with contacting the author, no github repo to check that I have the right setup, hence why I have turned here for help. All I want to do is improve my knowledge on terraform modules, I prefer to have explanations and examples so that I can also practice. I could look at git repos, but that would only be giving me solutions without explanation or learning opportunities.
As people in the comments have mentioned it looks like you are following an incomplete or out of date tutorial. I thought it might help you if I explain how to understand the errors produced so you can tackle this hurdle in future.
Error: Reference to undeclared resource
│
│ on vm_module_local_example.tf line 4, in module "windows_desktop_vm_using_local_module":
│ 4: resource_group_name = azurerm_resource_group.rg.name
│
│ A managed resource "azurerm_resource_group" "rg" has not been declared in the root module.
╵
In the above message Terraform is saying "On line 4 in the file vm_module_local_example.tf, you've set the resource_group_name to be the value of azurerm_resource_group.rg.name but when I tried to find a resource "azure_resource_group" with the name "rg" I couldn't find anything. To fix it you'd need to code up a resource like:
resource "azurerm_resource_group" "rg" {
name = "example"
location = "West Europe"
}
Once that's done your line 4 will set resource_group_name to be "example".
╷
│ Error: Reference to undeclared module
│
│ on vm_module_local_example.tf line 7, in module "windows_desktop_vm_using_local_module":
│ 7: vm_subnet_id = module.network.vnet_subnets[0]
│
│ No module call named "network" is declared in the root module.
This is a good one, on line 7 in the file named vm_module_local_example.tf there is a call to module.network.vnet_subnets[0]. So Terraform will look for a module called network before proceeding further. You'd need code like this:
module "network" {
# pass in whatever the module needs...
}
Based on the error it looks like the module is expected to contain a resource called vnet_subnets generated with count as it's relying on a zero based index (that's the [0] part).
Anyways, hope this helps!

Resources