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

12,294

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
}
Share:
12,294
learner
Author by

learner

Life is a constant learning journey. I am always hungry to learn new things. Never stop learning.

Updated on June 18, 2022

Comments

  • learner
    learner almost 2 years

    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.