Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provider inheritance in modules #3285

Closed
jen20 opened this issue Sep 19, 2015 · 6 comments
Closed

Provider inheritance in modules #3285

jen20 opened this issue Sep 19, 2015 · 6 comments

Comments

@jen20
Copy link
Contributor

jen20 commented Sep 19, 2015

I'm opening this issue as per @mitchellh's recommendation on Twitter to discuss changes in the module system which might support multi-region infrastructure and more effective module reuse.

Problem

At the moment in order to build multi-region infrastructure in AWS (and I assume other providers too, if they require a provider connection per region in the same manner as AWS), there appear to be a few options:

  1. Make region a variable, and use the -state option on the apply command to apply the same configuration to multiple regions. Though this is straightforward, I see the following downsides:
    • it requires multiple Terraform runs in order to provision infrastructure
    • is only capable of provisioning basically the same basic infrastructure in each region (short of lots of additional variables and parameterization)
    • resources within one region cannot refer easily to resources in another region in a straightforward manner
    • (unconfirmed) it may not work well with Atlas
  2. Use provider aliases in order to build multiple AWS providers, and then use the provider field on each resource. This allows for creating infrastructure for more than one region simultaneously, and allows cross-region references, while not requiring the same sets of infrastructure to be created per region. However, it has the downside that it gets very verbose, and modules must all be parameterized with the provider name.

Effectively what I am looking for is a way to be able to build up an entire AWS account worth of resources from a single Terraform configuration and state (potentially managable via Atlas) but without requiring explicit markup of which resource goes with which provider.

Proposal

Taking inspiration from #1819, #3160 and #3072, I believe the following solution may work, and will also retain backwards compatibility with existing configurations and modules.

Modules which declare their own providers should not inherit providers from the parent context. In order to maintain backwards compatbility and not increase verbosity for those not using Terraform in this manner, modules which do not declare their own providers should inherit providers from the parent context as is currently the case.

In the case that providers are declared in a module, resources within that module should default to the provider(s) declared in the module unless explicitly marked otherwise.

Example

The following example is non-functional but should be enought to discuss:

vpc/variables.tf:

varible "region" {}

vpc/main.tf:

provider "aws" {
    //Omit the keys, take them from the envvars
    region = "${var.region}"
}

resource "aws_vpc" "mod" {
    //This uses the provider declared within the module instance since 
    //not marked explicitly otherwise
    cidr_block = "..."
}

main.tf:

provider "dnsimple" {
    token = "${var.dnsimple_token}"
    email = "${var.dnsimple_email}"
}

module "us_east_1_vpc" {
    source = "./vpc"

    region = "us-east-1"
}

module "us_west_2_vpc" {
    source = "./vpc"

    region = "us-west-1"
}

resource "dnsimple_record" "www" {
    //This uses the provider declared in this context
}

If the provider in vpc/main.tf were moved to main.tf instead, the provider from the main.tf context would be inherited by the VPC module, thus maintaining backward compatibility with existing modules.

Does this sound like a reasonable course of action? (I am happy to look at implementing this if so).

@josephholsten
Copy link
Contributor

@jen20 we've gone through all our current issues, this sounds like it would fix them.

At the moment, we're working around it my treating providers as global, so each different region gets its own .tfstate. It would be lovely to be able to trust the providers to be scoped properly.

What do you need to spike an implementation, or at least a test case?

@mtougeron
Copy link
Contributor

I would also love to be able to utilize providers defined (and aliases) in modules in the parent files. This would allow me to have a module that sets up all of our VPCs (both AWS & OpenStack) in an included module and be able to use them in the base server definition.

@farridav
Copy link

I have had the same problem, and have a working solution with one state file, and a module used multiple times passing region through and instantiating an aliased provider (@jen20's option #2) though I get a weird graph that splits out my top level provider from my module specific providers.. e.g:-

Top provider               sub resource                   sub resource
      |                          |                               |
Core resource              module resource              module resource
                                 |                               |
                   module provider (region specific) module provider (region specific)

Forgive my markdown graphing skills :)

@rvangundy
Copy link

@farridav I managed to get things working using the same approach you took. Have you encountered the issue where if you remove a module and run apply again, it loses the provider region for that module (not surprising since provider data is not stored in the tfstate file)? In my case, I'm prompted for the provider region, and on entering it still encounter the following error:

module.vpc_admin_west.provider.aws.default: "region": required field is not set

If I've only removed resources for a particular region, I can get around this by setting the AWS_REGION variable; though this would not work if I wished to remove resources from multiple regions.

@apparentlymart
Copy link
Contributor

Hello!

I'm just working through some of these older issues that use an outdated labeling scheme and so got missed on previous issue gardening passes.

We did some work in this area back in the v0.11 major release. The upgrade guide covers this in a "what changed" sort of way, but the effect is to allow providers to be passed explicitly between modules where needed while retaining the default inheritance behavior in the normal case.

Since I think that change addressed the problem statement here, I'm going to close this out. Sorry for letting this sit here so long!

@ghost
Copy link

ghost commented Mar 31, 2020

I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues.

If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

@ghost ghost locked and limited conversation to collaborators Mar 31, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

7 participants