I am trying to pass output of StorageAccount and App Service Plan output values to Function App module. However I am not able to figure it out how to manage the variable.tf for root and child module
Here is my code in detailed to understand better
terraform.tfvars
#Resource Group
resourcegroupname = "eus-dev-test-rg"
asp-resourcegroupname = "eus-dev-shared-asp-rg"
location = "eastus"
#Storage Account
storageaccountname = "euspftestsa001"
#App Servicen Plan
serviceplanname = "eus-dev-shared-asp-01"
ostype = "Windows"
sku = "Y1"
#Function App
functionappname = "eus-dev-test-fnapp-02"
stack_version = { node = "~14" }
main.tf
module "ResourceGroup" {
source = "../../modules/ResourceGroup"
resourcegroupname = var.resourcegroupname
location = var.location
}
module "ASP-ResourceGroup" {
source = "../../modules/ResourceGroup"
resourcegroupname = var.asp-resourcegroupname
location = var.location
}
module "ApplicationServicePlan" {
source = "../../modules/ApplicationServicePlan"
resourcegroupname = module.ASP-ResourceGroup.rg_name_out
serviceplanname = var.serviceplanname
location = var.location
ostype = var.ostype
sku = var.sku
}
module "NODE_WA_StorageAccount" {
source = "../../modules/StorageAccount"
storageaccountname = var.storageaccountname
resourcegroupname = module.ResourceGroup.rg_name_out
location = var.location
}
module "FunctionApp" {
depends_on = [module.ResourceGroup, module.NODE_WA_StorageAccount, module.ApplicationServicePlan]
source = "../../modules/FunctionApp/mrf"
resourcegroupname = module.ResourceGroup.rg_name_out
location = var.location
service_plan_id = module.ApplicationServicePlan.app_sp_out
storageaccountname = module.NODE_WA_StorageAccount.sa_name_out
storage_account_access_key = module.NODE_WA_StorageAccount.sa_primary_access_key_out
functionappname = var.functionappname
stack_version = var.stack_version
}
variables.tf
variable "resourcegroupname" {
type = string
}
variable "asp-resourcegroupname" {
type = string
}
variable "location" {
type = string
}
variable "storageaccountname" {
type = string
}
variable "serviceplanname" {
type = string
}
variable "ostype" {
type = string
}
variable "sku" {
type = string
}
variable "stack_version" {
type = map
}
variable "functionappname" {
type = string
}
Modules code
Resource Group module
main.tf
resource "azurerm_resource_group" "rg" {
name = var.resourcegroupname
location = var.location
}
variable.tf
variable "resourcegroupname" {
type = string
}
variable "location" {
type = string
}
variable "tags" {
type = map(string)
}
output.tf
output "rg_name_out" {
value = azurerm_resource_group.rg.name
}
Storage Account module
main.tf
resource "azurerm_storage_account" "storageaccount" {
name = var.storageaccountname
resource_group_name = var.resourcegroupname
location = var.location
account_tier = "Standard"
account_replication_type = "LRS"
}
variable.tf
variable "resourcegroupname" {
type = string
description = "The name of the resource group"
}
variable "location" {
type = string
description = "resources should deploy only on 'eastus' as per the policy"
}
variable "storageaccountname" {
type = string
description = "The name of the Storage Account name"
}
output.tf
output "sa_primary_access_key_out"{
value = azurerm_storage_account.storageaccount.primary_access_key
}
output "sa_name_out"{
value = azurerm_storage_account.storageaccount.name
}
Azure Function App Module
main.tf
resource "azurerm_windows_function_app" "win-fn" {
name = var.functionappname
resource_group_name = var.resourcegroupname
location = var.location
storage_account_name = var.storageaccountname
storage_account_access_key = primaryaccesskey
service_plan_id = serviceplanid
site_config {
ftps_state = "FtpsOnly"
application_stack {
node_version = lookup(var.stack_version, "node", null)
java_version = lookup(var.stack_version, "java", null)
}
}
}
variable.tf
variable "resourcegroupname" {
type = string
description = "The name of the resource group"
}
variable "location" {
type = string
description = "resources should deploy only on 'eastus' as per the policy"
}
variable "functionappname" {
type = string
description = "location for the iwallet resources"
}
variable "storageaccountname"{
type = string
description = "The name of the WebApp SKU"
}
variable "stack_version" {
type = map
}
ERROR while executing the terraform plan
╷
│ Error: Unsupported argument
│
│ on main.tf line 55, in module "FunctionApp":
│ 55: service_plan_id = module.ApplicationServicePlan.app_sp_out
│
│ An argument named "service_plan_id" is not expected here.
╵
╷
│ Error: Unsupported argument
│
│ on main.tf line 59, in module "FunctionApp":
│ 59: storage_account_access_key = module.NODE_WA_StorageAccount.sa_primary_access_key_out
│
│ An argument named "storage_account_access_key" is not expected here.
>Solution :
You have to define additional two variables in the FunctionApp module. The root module does not automatically map the values of the variables to the arguments in the child module. In other words, arguments storage_account_access_key
and service_plan_id
are unknown to the root module. To fix this, you just need to define the two variables in the FunctionApp variables.tf
:
variable "service_plan_id" {
type = string
description = "Service Plan ID."
}
variable "storage_account_access_key" {
type = string
description = "Storage account access key."
}
Then, in the child module FunctionApp, change this:
resource "azurerm_windows_function_app" "win-fn" {
name = var.functionappname
resource_group_name = var.resourcegroupname
location = var.location
storage_account_name = var.storageaccountname
storage_account_access_key = var.storage_account_access_key # <--- reference to the new variable
service_plan_id = var.service_plan_id # <--- reference to the new variable
site_config {
ftps_state = "FtpsOnly"
application_stack {
node_version = lookup(var.stack_version, "node", null)
java_version = lookup(var.stack_version, "java", null)
}
}
}
Think of module variables as inputs to functions in programming languages. If you try to pass the value to an undefined variable that will not work. The same logic applies here. Any input you want to provide to a module you have to define. Then, that input must have a value. You can either set it to a default one when defining the variable or leave it undefined and provide it when calling the module.