How to avoid reading data source before it is created during plan or defer the read?

I have an issue with one module requiring data from a resource which does not yet exist when I run plan (we have multiple modules and none were yet run, I am attempting to run at root level using terragrunt).

As you can see the role of the failing module is to create a service principal in azure and assign roles binding storage account to the roles using the service principal so we need information about both storage account and service principal in one place.

I am probably missing some basic way of decomposing code in terraform (I am quite new to it) so please explain.

This is the module main.tf that fails because azurerm_storage_account does not exist (it is created in another module).

When we run apply all works - terraform knows that it has to create storage account first, then goes and runs the module that creates the role assignments…

main.tf which fails (only for plan, works for apply)

data "azurerm_storage_account" "main" {
  name                = var.storage_account_name
  resource_group_name = var.resource_group_name
}

module "platform_service_app" {
  source                   = "../ad-application"
  name                     = "svc_${var.release_id}_platform_service"
  generate_password        = true
  create_service_principal = true
}

resource "azurerm_role_definition" "platform_service_role" {
  name        = "${var.release_id}-webservices-servicerole"
  scope       = "/subscriptions/${data.azurerm_subscription.current.subscription_id}"
  description = "Provides read/write/delete access to Azure Blob Storage."

  permissions {
    actions = [
      "Microsoft.Storage/storageAccounts/blobServices/containers/read",
      "Microsoft.Storage/storageAccounts/blobServices/generateUserDelegationKey/action"
    ]
    data_actions = [
      "Microsoft.Storage/storageAccounts/blobServices/containers/blobs/delete",
      "Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read",
      "Microsoft.Storage/storageAccounts/blobServices/containers/blobs/move/action",
      "Microsoft.Storage/storageAccounts/blobServices/containers/blobs/write"
    ]
  }
  assignable_scopes = [
    data.azurerm_subscription.current.id,
    data.azurerm_storage_account.main.id
  ]
}

resource "azurerm_role_assignment" "platform_service_to_storage_account" {
  scope              = data.azurerm_storage_account.main.id
  role_definition_id = azurerm_role_definition.platform_service_role.role_definition_resource_id
  principal_id       = module.platform_service_app.service_principal_id
}

And the error:

Error: Storage Account: (Name "some name here" / Resource Group "some resource group") was not found
│   with data.azurerm_storage_account.main,
│   on main.tf line 1, in data "azurerm_storage_account" "main":
│    1: data "azurerm_storage_account" "main" {

Hi @Tomasz-Kluczkowski,

If another part of your configuration (including other modules you’re using together with this one) is responsible for managing that object then it’s typically better to pass the necessary information about that object between your modules using input variables and output values, so that the module which uses the object will refer directly to the result of the other module rather than re-reading what was only just written elsewhere in the same configuration.

A data resource like this is intended to represent a dependency on an object managed in some other Terraform configuration, or by some other process outside of Terraform, and so the error you saw is intended to prompt you to run that other external process first in order to prepare what this configuration needs. In your case that isn’t possible because the “external process” is actually a different part of the same Terraform configuration.

1 Like

Thx a lot for such a speedy reply.
Looks like we have a few places in our code where this issue exists (and we were lucky that stuff was created in correct order and we did not see this problem).

I will refactor to follow your advice.