4
votes

Is it still not possible to use variable provider in Terraform v0.12.6 ? In *.tfvars I have list variable supplier

supplier = ["azurerm.core-prod","azurerm.core-nonprod"]

and providers defined in provider.tf:

provider "azurerm" {
  ...
  alias           = "core-prod"
}

provider "azurerm" {
  ...
  alias = "core-nonprod"

then I want to reference it in *.tf . Below example is with 'data', but same applies to 'resource'

data "azurerm_public_ip" "pip" {
  count = "${var.count}"
   ....
   provider = "${var.supplier[count.index]}"
} 

What is workaround ? Error: Invalid provider configuration reference, showing that The provider argument requires a provider type name, optionally followed by a period and then a configuration alias.

1
You need to setup a provider alias for this. Documentation is here: terraform.io/docs/configuration/…. There are also answers on Stack Overflow about how to use these that you can reference. Also this has been possible since at least 0.11.Matt Schuchard
Sorry, I updated my question with provider.tf , of course I have it setupirom

1 Answers

5
votes

It is not possible to dynamically associate a resource with a provider. Similar to how in statically-typed programming languages you typically can't dynamically switch a particular symbol to refer to a different library at runtime, Terraform needs to bind resource blocks to provider configurations before expression evaluation is possible.

What you can do is write a module that expects to receive a provider configuration from its caller and then statically select a provider configuration per instance of that module:

provider "azurerm" {
  # ...

  alias = "core-prod"
}

module "provider-agnostic-example" {
  source = "./modules/provider-agnostic-example"

  providers = {
    # This means that the default configuration for "azurerm" in the
    # child module is the same as the "core-prod" alias configuration
    # in this parent module.
    azurerm = azurerm.core-prod
  }
}

In this case, the module itself is provider agnostic, and so it can be used in both your production and non-production settings, but any particular use of the module must specify which it is for.

A common approach is to have a separate configuration for each environment, with shared modules representing any characteristics the environments have in common but giving the opportunity for representing any differences that might need to exist between them. In the simplest case, this might just be two configurations that consist only of a single module block and a single provider block, each with some different arguments representing the configuration for that environment, and with the shared module containing all of the resource and data blocks. In more complex systems there might be multiple modules integrated together using module composition techniques.