Terraform - use resource name and string for name - terraform

strange question. Can I, instead of using a variable, also use the resource property of an resource + a string to construct a name:
For example:
resource "azurerm_network_security_group" "nsgvmss" {
name = **"NSG - azurerm_resource_virtual_machine_scale_set.vmss.name"**
location = azurerm_resource_group.rgapp.location
resource_group_name = azurerm_resource_group.rgapp.name
}
this works of course with variables like "NSG, ${var.vssname}" but again,
was wondering if i can use the resource name of the object in TF as well
Thanks

This is called string interpolation. Also see expressions (which isn't as pre-0.12-centric)
...
name = "NSG - ${azurerm_resource_virtual_machine_scale_set.vmss.name}"
...

Related

how do i substitute text for a variable in a terraform?

I'm new to terraform and wanted to substitute the value devcert below for a variable value called env, how do i format the below to include the variable value instead of devcert?
pfx_blob = data.azurerm_key_vault_secret.devcert.value
// Get Certificate from External KeyVault
resource "azurerm_app_service_certificate" "cert" {
name = "sslCertificate"
resource_group_name = "rg1"
location = "uk west"
pfx_blob = data.azurerm_key_vault_secret.devcert.value
You can't do that. Such operation is not supported in terraform. Instead you should use for_each to create multiple instances of azurerm_key_vault_secret, rather then fully separate data sources. Then you can reference it using:
pfx_blob = data.azurerm_key_vault_secret.devcert["myinstance"].value

Terraform count length of variables

we have a standard naming convention within azure, but in order to sometimes be able to make an exception, it must be possible to provide a name yourself when calling the module
How can be indicated within count which variable Var.Log Name or Local.ComponetName should be used and how can we pass this to the name of the resource
resource "azurerm_log_analytics_workspace" "LOG" {
count = length(var.LOG_Name) == "" ? length(local.ComponentNames) : null
name = var.LOG_Name[count.index] == "" ? local.ComponentNames[count.index] : null
resource_group_name = element(var.resourcegroup_name[*], count.index)
location = var.location
sku = var.LOG_Sku
retention_in_days = var.LOG_RetentionPeriod
}
What you are actually looking for are loops. Within loops you can reference the name of the resource and in case there is no such resource available it won't create them, which seems to be what you tried to indicate when mentioning null.
Here is a great link regarding loops in terraform that thoroughly explains the different types of loops and how to use them: https://blog.gruntwork.io/terraform-tips-tricks-loops-if-statements-and-gotchas-f739bbae55f9

Terraform - Variable name for CosmosDB

I'm using Terraform to create the resources in Azure and have split the files as main.tf, variables.tf and terraform.tfvars
In order to have a standard naming convention, I'm following the process below when naming the resources.
prefix-environment-resourcename
For example, in main.tf I'm creating it as below:
resource "azurerm_resource_group" "rg" {
name = "${var.prefix}-${var.environment}-${var.resource_group_name}"
location = "westus"
}
The variables will be declared in variables.tf and the terraform.tfvars will contain
prefix = "sample"
environment = "dev"
resource_group_name = "rg"
and when the Terraform is executed, I'll get the resource name created as "sample-dev-rg"
This will come in handy when I'm creating other resources or deploy the code to other environments. Since I just need to modify the tfvars alone.
Another example:
resource "azurerm_app_service" "example" {
name = "${var.prefix}-${var.environment_name}-${var.appservice_name}"
}
My issue is:
How do I use the logic above for CosmosDb? I need the name in the main.tf to be
created without special characters.
How do I create something like
this: sampledevcosmosdbname
If you're using Terraform 0.13 and above, you can make use of regex validation for each of the variables that make up your resource names, and ensure that none of them use special/unusual characters. Here's an example prefix variable that can only use A-Z, a-z, 0-9, and - characters:
variable "prefix" {
type = string
description = "Prefix ID"
validation {
condition = can(regex("^[A-Za-z0-9-]*$", var.prefix))
error_message = "The prefix cannot use special characters."
}
}
To create something like sampledevcosmosdbname (prefix, environment, dbname), you can just place several interpolations next to one another like so - no separation is needed:
resource "azurerm_cosmosdb_sql_database" "example" {
...
name = "${var.prefix}${var.environment}${var.dbname}"
}

Terraform looking local vars that are calculated using mapping when using count to create multiple resources

I’m using mapped variables in order to create local vars based on longer variable names, I'm using them where we would have abbreviations or where the resource wants a sanitized or shortened version of a value used elsewhere.
Eg
variable "env-short" {
description = "create a shortened version of the name of use in resource naming"
type = "map"
default = {
"Proof Of Concept" = "poc"
"User Acceptance Testing" = "uat"
"Production" = "prd"
}
}
variable "org-short" {
description = "create a shortened version of the name of use in resource naming"
type = map(string)
default = {
"My Big Company" = "MBC"
"My Little Company" = "MLC"
}
}
variable "loc-short" {
description = "create a shortened version of the name of use in resource naming"
type = map(string)
default = {
"UK South" = "UKS"
"UK West" = "UKW"
"North Europe" = "NEU"
"West Europe" = "WEU"
}
}
And use corresponding variables for their full length mapping equiverlants.
Now I could use as is within a resource block by something like
Name = “${lower(“${var.loc-short[$var.location]}”)-${lower(“${var.org-short[$var.organisation]}”)-${lower(“${var.env-short[$var.environment]}”)-myresource”
But like all good coders I like to keep things neat and readable by declaring local variables that I can then refer to.
locals {
org-short = "${lower("${var.org-short["${var.organisation}"]}")}"
loc-short = "${lower("${var.loc-short["${var.location}"]}")}"
env-short = "${lower("${var.env-short["${var.environment}"]}")}"
# I also create additional for commonly used configurations of them
name-prefix = "${lower("${var.org-short["${var.organisation}"]}")}-${lower("${var.loc-short["${var.location}"]}")}"
name-prefix-storage = "${lower("${var.org-short["${var.organisation}"]}")}${lower("${var.loc-short["${var.location}"]}")}"
}
This works really great and keeps things neat tidy and readable.
resource "provisioner_example" "test" {
location = var.location
name = “${local.loc-short}-${local.env-short}-my resource”
I would like however to be able to use this format when I start creating multiple resources using the count functionality.
resource "provisioner_example" "test" {
count = length(var.location)
location = var.location[count.index]
name = “${local.loc-short[count.index]}-${local.env-short}-my resource”
Terraform then complains that the index is invalid in the locals lookup, varlocation is tuple with 2 elements,| var.loc-short is map of string with 4 elements. The given key does not identify an element in this collection value: string required.
Now I know I can work around this by getting rid of the locals variables andincluding the variable calculation directly
name =”${lower("${var.loc-short["${var.locations[count.index]}"]}")}-${local.env-short}-my resource"
But to me it then makes the code seem more messy and less structured.
Any ideas on how I can pass the count index value to the map lookup?

proper way to use nested variables in terraform

In my terraform script, I have
resource "azuread_application" "main" {
count = "${length(var.sp_names)}"
name = "${sp_prefix}-${var.sp_names[count.index]}"
available_to_other_tenants = false
}
resource "azuread_service_principal" "main" {
count = "${length(var.sp_names)}"
application_id = "${azuread_application.main.["${sp_prefix}"-"${var.sp_names[count.index]}"].application_id}"
}
when I ran terraform init I get the following error:
An attribute name is required after a dot.
what is the right way to use nested variables and a list object?
In order for a resource to be represented as a map of instances rather than a list of instances, you need to use for_each instead of count:
resource "azuread_application" "main" {
for_each = { for n in var.sp_names : n => "${var.sp_prefix}-${n}" }
name = each.value
available_to_other_tenants = false
}
The for_each expression above is a for expression that transforms your list or set of names into a mapping from the given names to the prefixed names. In the other expressions in that block, each.key would therefore produce the original given name and each.value the prefixed name.
You can then similarly use for_each to declare the intent "create one service principal per application" by using the application resource's map itself as the for_each expression for the service principal resource:
resource "azuread_service_principal" "main" {
for_each = azuread_application.main
application_id = each.value.application_id
}
In this case, the azuread_application.main value is a map from unprefixed names to objects representing each of the declared applications. Therefore each.key in this block is the unprefixed name again, but each.value is the corresponding application object from which we can access the application_id value.
If your var.sp_names had a string "example" in it, then Terraform would interpret the above as a request to create two objects named azuread_application.main["example"] and azuread_service_principal.main["example"], identifying these instances by the var.sp_names values. This is different to count where the instances would have addresses like azuread_application.main[0] and azuread_service_principal.main[0]. By using for_each, we ensure that adding and removing items from var.sp_names will add and remove corresponding instances from those resources, rather than updating existing ones that happen to share the same numeric indices.
I am assuming you are using a version older that 0.12.x. If not the answer from Martin is the best one.
You need to leverage the splatting.
resource "azuread_service_principal" "main" {
count = "${length(var.sp_names)}"
application_id = "${azuread_application.main.*.application_id}"
}

Resources