0

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?

1
  • Which version of Terraform are you using? The below answer is related to 0.12.x. I am assuming you are using. Commented Nov 21, 2019 at 20:20

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

Comments

1

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}"
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.