Support for multiple providers of the same type
Adds an "alias" field to the provider which allows creating multiple instances of a provider under different names. This provides support for configurations such as multiple AWS providers for different regions. In each resource, the provider can be set with the "provider" field. (thanks to Cisco Cloud for their support)
This commit is contained in:
parent
ff224dec13
commit
21b0a03d70
|
@ -237,6 +237,38 @@ func TestAccAWSInstance_vpc(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAccAWSInstance_multipleRegions(t *testing.T) {
|
||||||
|
var v ec2.Instance
|
||||||
|
|
||||||
|
// record the initialized providers so that we can use them to
|
||||||
|
// check for the instances in each region
|
||||||
|
var providers []*schema.Provider
|
||||||
|
providerFactories := map[string]terraform.ResourceProviderFactory{
|
||||||
|
"aws": func() (terraform.ResourceProvider, error) {
|
||||||
|
p := Provider()
|
||||||
|
providers = append(providers, p.(*schema.Provider))
|
||||||
|
return p, nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
ProviderFactories: providerFactories,
|
||||||
|
CheckDestroy: testAccCheckInstanceDestroyWithProviders(&providers),
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccInstanceConfigMultipleRegions,
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckInstanceExistsWithProviders(
|
||||||
|
"aws_instance.foo", &v, &providers),
|
||||||
|
testAccCheckInstanceExistsWithProviders(
|
||||||
|
"aws_instance.bar", &v, &providers),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestAccAWSInstance_NetworkInstanceSecurityGroups(t *testing.T) {
|
func TestAccAWSInstance_NetworkInstanceSecurityGroups(t *testing.T) {
|
||||||
var v ec2.Instance
|
var v ec2.Instance
|
||||||
|
|
||||||
|
@ -364,7 +396,25 @@ func TestAccAWSInstance_associatePublicIPAndPrivateIP(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testAccCheckInstanceDestroy(s *terraform.State) error {
|
func testAccCheckInstanceDestroy(s *terraform.State) error {
|
||||||
conn := testAccProvider.Meta().(*AWSClient).ec2conn
|
return testAccCheckInstanceDestroyWithProvider(s, testAccProvider)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckInstanceDestroyWithProviders(providers *[]*schema.Provider) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
for _, provider := range *providers {
|
||||||
|
if provider.Meta() == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err := testAccCheckInstanceDestroyWithProvider(s, provider); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckInstanceDestroyWithProvider(s *terraform.State, provider *schema.Provider) error {
|
||||||
|
conn := provider.Meta().(*AWSClient).ec2conn
|
||||||
|
|
||||||
for _, rs := range s.RootModule().Resources {
|
for _, rs := range s.RootModule().Resources {
|
||||||
if rs.Type != "aws_instance" {
|
if rs.Type != "aws_instance" {
|
||||||
|
@ -397,6 +447,11 @@ func testAccCheckInstanceDestroy(s *terraform.State) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testAccCheckInstanceExists(n string, i *ec2.Instance) resource.TestCheckFunc {
|
func testAccCheckInstanceExists(n string, i *ec2.Instance) resource.TestCheckFunc {
|
||||||
|
providers := []*schema.Provider{testAccProvider}
|
||||||
|
return testAccCheckInstanceExistsWithProviders(n, i, &providers)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckInstanceExistsWithProviders(n string, i *ec2.Instance, providers *[]*schema.Provider) resource.TestCheckFunc {
|
||||||
return func(s *terraform.State) error {
|
return func(s *terraform.State) error {
|
||||||
rs, ok := s.RootModule().Resources[n]
|
rs, ok := s.RootModule().Resources[n]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -406,21 +461,25 @@ func testAccCheckInstanceExists(n string, i *ec2.Instance) resource.TestCheckFun
|
||||||
if rs.Primary.ID == "" {
|
if rs.Primary.ID == "" {
|
||||||
return fmt.Errorf("No ID is set")
|
return fmt.Errorf("No ID is set")
|
||||||
}
|
}
|
||||||
|
for _, provider := range *providers {
|
||||||
conn := testAccProvider.Meta().(*AWSClient).ec2conn
|
conn := provider.Meta().(*AWSClient).ec2conn
|
||||||
resp, err := conn.DescribeInstances(&ec2.DescribeInstancesInput{
|
resp, err := conn.DescribeInstances(&ec2.DescribeInstancesInput{
|
||||||
InstanceIDs: []*string{aws.String(rs.Primary.ID)},
|
InstanceIDs: []*string{aws.String(rs.Primary.ID)},
|
||||||
})
|
})
|
||||||
|
if ec2err, ok := err.(aws.APIError); ok && ec2err.Code == "InvalidInstanceID.NotFound" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if len(resp.Reservations) == 0 {
|
|
||||||
return fmt.Errorf("Instance not found")
|
if len(resp.Reservations) > 0 {
|
||||||
|
*i = *resp.Reservations[0].Instances[0]
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*i = *resp.Reservations[0].Instances[0]
|
return fmt.Errorf("Instance not found")
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -563,6 +622,32 @@ resource "aws_instance" "foo" {
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
const testAccInstanceConfigMultipleRegions = `
|
||||||
|
provider "aws" {
|
||||||
|
alias = "west"
|
||||||
|
region = "us-west-2"
|
||||||
|
}
|
||||||
|
|
||||||
|
provider "aws" {
|
||||||
|
alias = "east"
|
||||||
|
region = "us-east-1"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_instance" "foo" {
|
||||||
|
# us-west-2
|
||||||
|
provider = "aws.west"
|
||||||
|
ami = "ami-4fccb37f"
|
||||||
|
instance_type = "m1.small"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_instance" "bar" {
|
||||||
|
# us-east-1
|
||||||
|
provider = "aws.east"
|
||||||
|
ami = "ami-8c6ea9e4"
|
||||||
|
instance_type = "m1.small"
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
const testAccCheckInstanceConfigTags = `
|
const testAccCheckInstanceConfigTags = `
|
||||||
resource "aws_instance" "foo" {
|
resource "aws_instance" "foo" {
|
||||||
ami = "ami-4fccb37f"
|
ami = "ami-4fccb37f"
|
||||||
|
|
|
@ -63,6 +63,7 @@ type Module struct {
|
||||||
// resource provider.
|
// resource provider.
|
||||||
type ProviderConfig struct {
|
type ProviderConfig struct {
|
||||||
Name string
|
Name string
|
||||||
|
Alias string
|
||||||
RawConfig *RawConfig
|
RawConfig *RawConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,6 +76,7 @@ type Resource struct {
|
||||||
RawCount *RawConfig
|
RawCount *RawConfig
|
||||||
RawConfig *RawConfig
|
RawConfig *RawConfig
|
||||||
Provisioners []*Provisioner
|
Provisioners []*Provisioner
|
||||||
|
Provider string
|
||||||
DependsOn []string
|
DependsOn []string
|
||||||
Lifecycle ResourceLifecycle
|
Lifecycle ResourceLifecycle
|
||||||
}
|
}
|
||||||
|
|
|
@ -325,13 +325,13 @@ func loadOutputsHcl(os *hclobj.Object) ([]*Output, error) {
|
||||||
// LoadProvidersHcl recurses into the given HCL object and turns
|
// LoadProvidersHcl recurses into the given HCL object and turns
|
||||||
// it into a mapping of provider configs.
|
// it into a mapping of provider configs.
|
||||||
func loadProvidersHcl(os *hclobj.Object) ([]*ProviderConfig, error) {
|
func loadProvidersHcl(os *hclobj.Object) ([]*ProviderConfig, error) {
|
||||||
objects := make(map[string]*hclobj.Object)
|
var objects []*hclobj.Object
|
||||||
|
|
||||||
// Iterate over all the "provider" blocks and get the keys along with
|
// Iterate over all the "provider" blocks and get the keys along with
|
||||||
// their raw configuration objects. We'll parse those later.
|
// their raw configuration objects. We'll parse those later.
|
||||||
for _, o1 := range os.Elem(false) {
|
for _, o1 := range os.Elem(false) {
|
||||||
for _, o2 := range o1.Elem(true) {
|
for _, o2 := range o1.Elem(true) {
|
||||||
objects[o2.Key] = o2
|
objects = append(objects, o2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -341,23 +341,38 @@ func loadProvidersHcl(os *hclobj.Object) ([]*ProviderConfig, error) {
|
||||||
|
|
||||||
// Go through each object and turn it into an actual result.
|
// Go through each object and turn it into an actual result.
|
||||||
result := make([]*ProviderConfig, 0, len(objects))
|
result := make([]*ProviderConfig, 0, len(objects))
|
||||||
for n, o := range objects {
|
for _, o := range objects {
|
||||||
var config map[string]interface{}
|
var config map[string]interface{}
|
||||||
|
|
||||||
if err := hcl.DecodeObject(&config, o); err != nil {
|
if err := hcl.DecodeObject(&config, o); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
delete(config, "alias")
|
||||||
|
|
||||||
rawConfig, err := NewRawConfig(config)
|
rawConfig, err := NewRawConfig(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(
|
return nil, fmt.Errorf(
|
||||||
"Error reading config for provider config %s: %s",
|
"Error reading config for provider config %s: %s",
|
||||||
n,
|
o.Key,
|
||||||
err)
|
err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we have an alias field, then add those in
|
||||||
|
var alias string
|
||||||
|
if a := o.Get("alias", false); a != nil {
|
||||||
|
err := hcl.DecodeObject(&alias, a)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"Error reading alias for provider[%s]: %s",
|
||||||
|
o.Key,
|
||||||
|
err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
result = append(result, &ProviderConfig{
|
result = append(result, &ProviderConfig{
|
||||||
Name: n,
|
Name: o.Key,
|
||||||
|
Alias: alias,
|
||||||
RawConfig: rawConfig,
|
RawConfig: rawConfig,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -417,6 +432,7 @@ func loadResourcesHcl(os *hclobj.Object) ([]*Resource, error) {
|
||||||
delete(config, "count")
|
delete(config, "count")
|
||||||
delete(config, "depends_on")
|
delete(config, "depends_on")
|
||||||
delete(config, "provisioner")
|
delete(config, "provisioner")
|
||||||
|
delete(config, "provider")
|
||||||
delete(config, "lifecycle")
|
delete(config, "lifecycle")
|
||||||
|
|
||||||
rawConfig, err := NewRawConfig(config)
|
rawConfig, err := NewRawConfig(config)
|
||||||
|
@ -488,6 +504,19 @@ func loadResourcesHcl(os *hclobj.Object) ([]*Resource, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we have a provider, then parse it out
|
||||||
|
var provider string
|
||||||
|
if o := obj.Get("provider", false); o != nil {
|
||||||
|
err := hcl.DecodeObject(&provider, o)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"Error reading provider for %s[%s]: %s",
|
||||||
|
t.Key,
|
||||||
|
k,
|
||||||
|
err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check if the resource should be re-created before
|
// Check if the resource should be re-created before
|
||||||
// destroying the existing instance
|
// destroying the existing instance
|
||||||
var lifecycle ResourceLifecycle
|
var lifecycle ResourceLifecycle
|
||||||
|
@ -508,6 +537,7 @@ func loadResourcesHcl(os *hclobj.Object) ([]*Resource, error) {
|
||||||
RawCount: countConfig,
|
RawCount: countConfig,
|
||||||
RawConfig: rawConfig,
|
RawConfig: rawConfig,
|
||||||
Provisioners: provisioners,
|
Provisioners: provisioners,
|
||||||
|
Provider: provider,
|
||||||
DependsOn: dependsOn,
|
DependsOn: dependsOn,
|
||||||
Lifecycle: lifecycle,
|
Lifecycle: lifecycle,
|
||||||
})
|
})
|
||||||
|
|
|
@ -36,6 +36,7 @@ type TestCase struct {
|
||||||
|
|
||||||
// Provider is the ResourceProvider that will be under test.
|
// Provider is the ResourceProvider that will be under test.
|
||||||
Providers map[string]terraform.ResourceProvider
|
Providers map[string]terraform.ResourceProvider
|
||||||
|
ProviderFactories map[string]terraform.ResourceProviderFactory
|
||||||
|
|
||||||
// CheckDestroy is called after the resource is finally destroyed
|
// CheckDestroy is called after the resource is finally destroyed
|
||||||
// to allow the tester to test that the resource is truly gone.
|
// to allow the tester to test that the resource is truly gone.
|
||||||
|
@ -102,10 +103,13 @@ func Test(t TestT, c TestCase) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build our context options that we can
|
// Build our context options that we can
|
||||||
ctxProviders := make(map[string]terraform.ResourceProviderFactory)
|
ctxProviders := c.ProviderFactories
|
||||||
|
if ctxProviders == nil {
|
||||||
|
ctxProviders = make(map[string]terraform.ResourceProviderFactory)
|
||||||
for k, p := range c.Providers {
|
for k, p := range c.Providers {
|
||||||
ctxProviders[k] = terraform.ResourceProviderFactoryFixed(p)
|
ctxProviders[k] = terraform.ResourceProviderFactoryFixed(p)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
opts := terraform.ContextOpts{Providers: ctxProviders}
|
opts := terraform.ContextOpts{Providers: ctxProviders}
|
||||||
|
|
||||||
// A single state variable to track the lifecycle, starting with no state
|
// A single state variable to track the lifecycle, starting with no state
|
||||||
|
|
|
@ -3286,6 +3286,39 @@ func TestContext2Apply(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestContext2Apply_providerAlias(t *testing.T) {
|
||||||
|
m := testModule(t, "apply-provider-alias")
|
||||||
|
p := testProvider("aws")
|
||||||
|
p.ApplyFn = testApplyFn
|
||||||
|
p.DiffFn = testDiffFn
|
||||||
|
ctx := testContext2(t, &ContextOpts{
|
||||||
|
Module: m,
|
||||||
|
Providers: map[string]ResourceProviderFactory{
|
||||||
|
"aws": testProviderFuncFixed(p),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if _, err := ctx.Plan(); err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
state, err := ctx.Apply()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mod := state.RootModule()
|
||||||
|
if len(mod.Resources) < 2 {
|
||||||
|
t.Fatalf("bad: %#v", mod.Resources)
|
||||||
|
}
|
||||||
|
|
||||||
|
actual := strings.TrimSpace(state.String())
|
||||||
|
expected := strings.TrimSpace(testTerraformApplyProviderAliasStr)
|
||||||
|
if actual != expected {
|
||||||
|
t.Fatalf("bad: \n%s", actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestContext2Apply_emptyModule(t *testing.T) {
|
func TestContext2Apply_emptyModule(t *testing.T) {
|
||||||
m := testModule(t, "apply-empty-module")
|
m := testModule(t, "apply-empty-module")
|
||||||
p := testProvider("aws")
|
p := testProvider("aws")
|
||||||
|
|
|
@ -3,6 +3,7 @@ package terraform
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/config"
|
"github.com/hashicorp/terraform/config"
|
||||||
|
@ -68,9 +69,11 @@ func (ctx *BuiltinEvalContext) InitProvider(n string) (ResourceProvider, error)
|
||||||
ctx.ProviderLock.Lock()
|
ctx.ProviderLock.Lock()
|
||||||
defer ctx.ProviderLock.Unlock()
|
defer ctx.ProviderLock.Unlock()
|
||||||
|
|
||||||
f, ok := ctx.Providers[n]
|
typeName := strings.SplitN(n, ".", 2)[0]
|
||||||
|
|
||||||
|
f, ok := ctx.Providers[typeName]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("Provider '%s' not found", n)
|
return nil, fmt.Errorf("Provider '%s' not found", typeName)
|
||||||
}
|
}
|
||||||
|
|
||||||
p, err := f()
|
p, err := f()
|
||||||
|
|
|
@ -154,12 +154,13 @@ func (n *EvalUpdateStateHook) Eval(ctx EvalContext) (interface{}, error) {
|
||||||
type EvalWriteState struct {
|
type EvalWriteState struct {
|
||||||
Name string
|
Name string
|
||||||
ResourceType string
|
ResourceType string
|
||||||
|
Provider string
|
||||||
Dependencies []string
|
Dependencies []string
|
||||||
State **InstanceState
|
State **InstanceState
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *EvalWriteState) Eval(ctx EvalContext) (interface{}, error) {
|
func (n *EvalWriteState) Eval(ctx EvalContext) (interface{}, error) {
|
||||||
return writeInstanceToState(ctx, n.Name, n.ResourceType, n.Dependencies,
|
return writeInstanceToState(ctx, n.Name, n.ResourceType, n.Provider, n.Dependencies,
|
||||||
func(rs *ResourceState) error {
|
func(rs *ResourceState) error {
|
||||||
rs.Primary = *n.State
|
rs.Primary = *n.State
|
||||||
return nil
|
return nil
|
||||||
|
@ -172,6 +173,7 @@ func (n *EvalWriteState) Eval(ctx EvalContext) (interface{}, error) {
|
||||||
type EvalWriteStateTainted struct {
|
type EvalWriteStateTainted struct {
|
||||||
Name string
|
Name string
|
||||||
ResourceType string
|
ResourceType string
|
||||||
|
Provider string
|
||||||
Dependencies []string
|
Dependencies []string
|
||||||
State **InstanceState
|
State **InstanceState
|
||||||
// Index indicates which instance in the Tainted list to target, or -1 to append.
|
// Index indicates which instance in the Tainted list to target, or -1 to append.
|
||||||
|
@ -181,7 +183,7 @@ type EvalWriteStateTainted struct {
|
||||||
// EvalWriteStateTainted is an EvalNode implementation that writes the
|
// EvalWriteStateTainted is an EvalNode implementation that writes the
|
||||||
// one of the tainted InstanceStates for a specific resource out of the state.
|
// one of the tainted InstanceStates for a specific resource out of the state.
|
||||||
func (n *EvalWriteStateTainted) Eval(ctx EvalContext) (interface{}, error) {
|
func (n *EvalWriteStateTainted) Eval(ctx EvalContext) (interface{}, error) {
|
||||||
return writeInstanceToState(ctx, n.Name, n.ResourceType, n.Dependencies,
|
return writeInstanceToState(ctx, n.Name, n.ResourceType, n.Provider, n.Dependencies,
|
||||||
func(rs *ResourceState) error {
|
func(rs *ResourceState) error {
|
||||||
if n.Index == -1 {
|
if n.Index == -1 {
|
||||||
rs.Tainted = append(rs.Tainted, *n.State)
|
rs.Tainted = append(rs.Tainted, *n.State)
|
||||||
|
@ -198,6 +200,7 @@ func (n *EvalWriteStateTainted) Eval(ctx EvalContext) (interface{}, error) {
|
||||||
type EvalWriteStateDeposed struct {
|
type EvalWriteStateDeposed struct {
|
||||||
Name string
|
Name string
|
||||||
ResourceType string
|
ResourceType string
|
||||||
|
Provider string
|
||||||
Dependencies []string
|
Dependencies []string
|
||||||
State **InstanceState
|
State **InstanceState
|
||||||
// Index indicates which instance in the Deposed list to target, or -1 to append.
|
// Index indicates which instance in the Deposed list to target, or -1 to append.
|
||||||
|
@ -205,7 +208,7 @@ type EvalWriteStateDeposed struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *EvalWriteStateDeposed) Eval(ctx EvalContext) (interface{}, error) {
|
func (n *EvalWriteStateDeposed) Eval(ctx EvalContext) (interface{}, error) {
|
||||||
return writeInstanceToState(ctx, n.Name, n.ResourceType, n.Dependencies,
|
return writeInstanceToState(ctx, n.Name, n.ResourceType, n.Provider, n.Dependencies,
|
||||||
func(rs *ResourceState) error {
|
func(rs *ResourceState) error {
|
||||||
if n.Index == -1 {
|
if n.Index == -1 {
|
||||||
rs.Deposed = append(rs.Deposed, *n.State)
|
rs.Deposed = append(rs.Deposed, *n.State)
|
||||||
|
@ -225,6 +228,7 @@ func writeInstanceToState(
|
||||||
ctx EvalContext,
|
ctx EvalContext,
|
||||||
resourceName string,
|
resourceName string,
|
||||||
resourceType string,
|
resourceType string,
|
||||||
|
provider string,
|
||||||
dependencies []string,
|
dependencies []string,
|
||||||
writerFn func(*ResourceState) error,
|
writerFn func(*ResourceState) error,
|
||||||
) (*InstanceState, error) {
|
) (*InstanceState, error) {
|
||||||
|
@ -252,6 +256,7 @@ func writeInstanceToState(
|
||||||
}
|
}
|
||||||
rs.Type = resourceType
|
rs.Type = resourceType
|
||||||
rs.Dependencies = dependencies
|
rs.Dependencies = dependencies
|
||||||
|
rs.Provider = provider
|
||||||
|
|
||||||
if err := writerFn(rs); err != nil {
|
if err := writerFn(rs); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -110,7 +110,7 @@ func (n *GraphNodeConfigModule) ProvidedBy() []string {
|
||||||
providers[p.Name] = struct{}{}
|
providers[p.Name] = struct{}{}
|
||||||
}
|
}
|
||||||
for _, r := range config.Resources {
|
for _, r := range config.Resources {
|
||||||
providers[resourceProvider(r.Type)] = struct{}{}
|
providers[resourceProvider(r.Type, r.Provider)] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Turn the map into a string. This makes sure that the list is
|
// Turn the map into a string. This makes sure that the list is
|
||||||
|
@ -176,7 +176,7 @@ type GraphNodeConfigProvider struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *GraphNodeConfigProvider) Name() string {
|
func (n *GraphNodeConfigProvider) Name() string {
|
||||||
return fmt.Sprintf("provider.%s", n.Provider.Name)
|
return fmt.Sprintf("provider.%s", n.ProviderName())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *GraphNodeConfigProvider) ConfigType() GraphNodeConfigType {
|
func (n *GraphNodeConfigProvider) ConfigType() GraphNodeConfigType {
|
||||||
|
@ -201,12 +201,16 @@ func (n *GraphNodeConfigProvider) DependentOn() []string {
|
||||||
|
|
||||||
// GraphNodeEvalable impl.
|
// GraphNodeEvalable impl.
|
||||||
func (n *GraphNodeConfigProvider) EvalTree() EvalNode {
|
func (n *GraphNodeConfigProvider) EvalTree() EvalNode {
|
||||||
return ProviderEvalTree(n.Provider.Name, n.Provider.RawConfig)
|
return ProviderEvalTree(n.ProviderName(), n.Provider.RawConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GraphNodeProvider implementation
|
// GraphNodeProvider implementation
|
||||||
func (n *GraphNodeConfigProvider) ProviderName() string {
|
func (n *GraphNodeConfigProvider) ProviderName() string {
|
||||||
|
if n.Provider.Alias == "" {
|
||||||
return n.Provider.Name
|
return n.Provider.Name
|
||||||
|
} else {
|
||||||
|
return fmt.Sprintf("%s.%s", n.Provider.Name, n.Provider.Alias)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GraphNodeProvider implementation
|
// GraphNodeProvider implementation
|
||||||
|
@ -396,7 +400,7 @@ func (n *GraphNodeConfigResource) EvalTree() EvalNode {
|
||||||
|
|
||||||
// GraphNodeProviderConsumer
|
// GraphNodeProviderConsumer
|
||||||
func (n *GraphNodeConfigResource) ProvidedBy() []string {
|
func (n *GraphNodeConfigResource) ProvidedBy() []string {
|
||||||
return []string{resourceProvider(n.Resource.Type)}
|
return []string{resourceProvider(n.Resource.Type, n.Resource.Provider)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GraphNodeProvisionerConsumer
|
// GraphNodeProvisionerConsumer
|
||||||
|
|
|
@ -58,6 +58,36 @@ func TestGraphNodeConfigProvider_ProviderName(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGraphNodeConfigProvider_ProviderName_alias(t *testing.T) {
|
||||||
|
n := &GraphNodeConfigProvider{
|
||||||
|
Provider: &config.ProviderConfig{Name: "foo", Alias: "bar"},
|
||||||
|
}
|
||||||
|
|
||||||
|
if v := n.ProviderName(); v != "foo.bar" {
|
||||||
|
t.Fatalf("bad: %#v", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGraphNodeConfigProvider_Name(t *testing.T) {
|
||||||
|
n := &GraphNodeConfigProvider{
|
||||||
|
Provider: &config.ProviderConfig{Name: "foo"},
|
||||||
|
}
|
||||||
|
|
||||||
|
if v := n.Name(); v != "provider.foo" {
|
||||||
|
t.Fatalf("bad: %#v", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGraphNodeConfigProvider_Name_alias(t *testing.T) {
|
||||||
|
n := &GraphNodeConfigProvider{
|
||||||
|
Provider: &config.ProviderConfig{Name: "foo", Alias: "bar"},
|
||||||
|
}
|
||||||
|
|
||||||
|
if v := n.Name(); v != "provider.foo.bar" {
|
||||||
|
t.Fatalf("bad: %#v", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestGraphNodeConfigResource_impl(t *testing.T) {
|
func TestGraphNodeConfigResource_impl(t *testing.T) {
|
||||||
var _ dag.Vertex = new(GraphNodeConfigResource)
|
var _ dag.Vertex = new(GraphNodeConfigResource)
|
||||||
var _ dag.NamedVertex = new(GraphNodeConfigResource)
|
var _ dag.NamedVertex = new(GraphNodeConfigResource)
|
||||||
|
@ -76,6 +106,16 @@ func TestGraphNodeConfigResource_ProvidedBy(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGraphNodeConfigResource_ProvidedBy_alias(t *testing.T) {
|
||||||
|
n := &GraphNodeConfigResource{
|
||||||
|
Resource: &config.Resource{Type: "aws_instance", Provider: "aws.bar"},
|
||||||
|
}
|
||||||
|
|
||||||
|
if v := n.ProvidedBy(); v[0] != "aws.bar" {
|
||||||
|
t.Fatalf("bad: %#v", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestGraphNodeConfigResource_ProvisionedBy(t *testing.T) {
|
func TestGraphNodeConfigResource_ProvisionedBy(t *testing.T) {
|
||||||
n := &GraphNodeConfigResource{
|
n := &GraphNodeConfigResource{
|
||||||
Resource: &config.Resource{
|
Resource: &config.Resource{
|
||||||
|
|
|
@ -572,6 +572,9 @@ func (m *ModuleState) String() string {
|
||||||
|
|
||||||
buf.WriteString(fmt.Sprintf("%s:%s%s\n", k, taintStr, deposedStr))
|
buf.WriteString(fmt.Sprintf("%s:%s%s\n", k, taintStr, deposedStr))
|
||||||
buf.WriteString(fmt.Sprintf(" ID = %s\n", id))
|
buf.WriteString(fmt.Sprintf(" ID = %s\n", id))
|
||||||
|
if rs.Provider != "" {
|
||||||
|
buf.WriteString(fmt.Sprintf(" provider = %s\n", rs.Provider))
|
||||||
|
}
|
||||||
|
|
||||||
var attributes map[string]string
|
var attributes map[string]string
|
||||||
if rs.Primary != nil {
|
if rs.Primary != nil {
|
||||||
|
@ -680,6 +683,12 @@ type ResourceState struct {
|
||||||
// similar to Tainted instances in that Terraform is only tracking them in
|
// similar to Tainted instances in that Terraform is only tracking them in
|
||||||
// order to remember to destroy them.
|
// order to remember to destroy them.
|
||||||
Deposed []*InstanceState `json:"deposed,omitempty"`
|
Deposed []*InstanceState `json:"deposed,omitempty"`
|
||||||
|
|
||||||
|
// Provider is used when a resource is connected to a provider with an alias.
|
||||||
|
// If this string is empty, the resource is connected to the default provider,
|
||||||
|
// e.g. "aws_instance" goes with the "aws" provider.
|
||||||
|
// If the resource block contained a "provider" key, that value will be set here.
|
||||||
|
Provider string `json:"provider,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Equal tests whether two ResourceStates are equal.
|
// Equal tests whether two ResourceStates are equal.
|
||||||
|
@ -688,6 +697,10 @@ func (s *ResourceState) Equal(other *ResourceState) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if s.Provider != other.Provider {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// Dependencies must be equal
|
// Dependencies must be equal
|
||||||
sort.Strings(s.Dependencies)
|
sort.Strings(s.Dependencies)
|
||||||
sort.Strings(other.Dependencies)
|
sort.Strings(other.Dependencies)
|
||||||
|
@ -769,6 +782,7 @@ func (r *ResourceState) deepcopy() *ResourceState {
|
||||||
Dependencies: nil,
|
Dependencies: nil,
|
||||||
Primary: r.Primary.deepcopy(),
|
Primary: r.Primary.deepcopy(),
|
||||||
Tainted: nil,
|
Tainted: nil,
|
||||||
|
Provider: r.Provider,
|
||||||
}
|
}
|
||||||
if r.Dependencies != nil {
|
if r.Dependencies != nil {
|
||||||
n.Dependencies = make([]string, len(r.Dependencies))
|
n.Dependencies = make([]string, len(r.Dependencies))
|
||||||
|
|
|
@ -182,6 +182,18 @@ aws_instance.foo:
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
`
|
`
|
||||||
|
|
||||||
|
const testTerraformApplyProviderAliasStr = `
|
||||||
|
aws_instance.bar:
|
||||||
|
ID = foo
|
||||||
|
provider = aws.bar
|
||||||
|
foo = bar
|
||||||
|
type = aws_instance
|
||||||
|
aws_instance.foo:
|
||||||
|
ID = foo
|
||||||
|
num = 2
|
||||||
|
type = aws_instance
|
||||||
|
`
|
||||||
|
|
||||||
const testTerraformApplyEmptyModuleStr = `
|
const testTerraformApplyEmptyModuleStr = `
|
||||||
<no state>
|
<no state>
|
||||||
Outputs:
|
Outputs:
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
provider "aws" {
|
||||||
|
alias = "bar"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_instance" "foo" {
|
||||||
|
num = "2"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_instance" "bar" {
|
||||||
|
foo = "bar"
|
||||||
|
provider = "aws.bar"
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
provider "aws" {
|
||||||
|
}
|
||||||
|
|
||||||
|
provider "aws" {
|
||||||
|
alias = "foo"
|
||||||
|
}
|
||||||
|
|
||||||
|
provider "aws" {
|
||||||
|
alias = "bar"
|
||||||
|
}
|
|
@ -86,6 +86,20 @@ func TestConfigTransformer_outputs(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestConfigTransformer_providerAlias(t *testing.T) {
|
||||||
|
g := Graph{Path: RootModulePath}
|
||||||
|
tf := &ConfigTransformer{Module: testModule(t, "graph-provider-alias")}
|
||||||
|
if err := tf.Transform(&g); err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
actual := strings.TrimSpace(g.String())
|
||||||
|
expected := strings.TrimSpace(testGraphProviderAliasStr)
|
||||||
|
if actual != expected {
|
||||||
|
t.Fatalf("bad:\n\n%s", actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestConfigTransformer_errMissingDeps(t *testing.T) {
|
func TestConfigTransformer_errMissingDeps(t *testing.T) {
|
||||||
g := Graph{Path: RootModulePath}
|
g := Graph{Path: RootModulePath}
|
||||||
tf := &ConfigTransformer{Module: testModule(t, "graph-missing-deps")}
|
tf := &ConfigTransformer{Module: testModule(t, "graph-missing-deps")}
|
||||||
|
@ -126,3 +140,9 @@ aws_instance.foo
|
||||||
output.foo
|
output.foo
|
||||||
aws_instance.foo
|
aws_instance.foo
|
||||||
`
|
`
|
||||||
|
|
||||||
|
const testGraphProviderAliasStr = `
|
||||||
|
provider.aws
|
||||||
|
provider.aws.bar
|
||||||
|
provider.aws.foo
|
||||||
|
`
|
||||||
|
|
|
@ -40,6 +40,7 @@ func (t *DeposedTransformer) Transform(g *Graph) error {
|
||||||
Index: i,
|
Index: i,
|
||||||
ResourceName: k,
|
ResourceName: k,
|
||||||
ResourceType: rs.Type,
|
ResourceType: rs.Type,
|
||||||
|
Provider: rs.Provider,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,6 +53,7 @@ type graphNodeDeposedResource struct {
|
||||||
Index int
|
Index int
|
||||||
ResourceName string
|
ResourceName string
|
||||||
ResourceType string
|
ResourceType string
|
||||||
|
Provider string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *graphNodeDeposedResource) Name() string {
|
func (n *graphNodeDeposedResource) Name() string {
|
||||||
|
@ -59,7 +61,7 @@ func (n *graphNodeDeposedResource) Name() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *graphNodeDeposedResource) ProvidedBy() []string {
|
func (n *graphNodeDeposedResource) ProvidedBy() []string {
|
||||||
return []string{resourceProvider(n.ResourceName)}
|
return []string{resourceProvider(n.ResourceName, n.Provider)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GraphNodeEvalable impl.
|
// GraphNodeEvalable impl.
|
||||||
|
@ -96,6 +98,7 @@ func (n *graphNodeDeposedResource) EvalTree() EvalNode {
|
||||||
&EvalWriteStateDeposed{
|
&EvalWriteStateDeposed{
|
||||||
Name: n.ResourceName,
|
Name: n.ResourceName,
|
||||||
ResourceType: n.ResourceType,
|
ResourceType: n.ResourceType,
|
||||||
|
Provider: n.Provider,
|
||||||
State: &state,
|
State: &state,
|
||||||
Index: n.Index,
|
Index: n.Index,
|
||||||
},
|
},
|
||||||
|
@ -138,6 +141,7 @@ func (n *graphNodeDeposedResource) EvalTree() EvalNode {
|
||||||
&EvalWriteStateDeposed{
|
&EvalWriteStateDeposed{
|
||||||
Name: n.ResourceName,
|
Name: n.ResourceName,
|
||||||
ResourceType: n.ResourceType,
|
ResourceType: n.ResourceType,
|
||||||
|
Provider: n.Provider,
|
||||||
State: &state,
|
State: &state,
|
||||||
Index: n.Index,
|
Index: n.Index,
|
||||||
},
|
},
|
||||||
|
|
|
@ -89,6 +89,7 @@ func (t *OrphanTransformer) Transform(g *Graph) error {
|
||||||
resourceVertexes[i] = g.Add(&graphNodeOrphanResource{
|
resourceVertexes[i] = g.Add(&graphNodeOrphanResource{
|
||||||
ResourceName: k,
|
ResourceName: k,
|
||||||
ResourceType: rs.Type,
|
ResourceType: rs.Type,
|
||||||
|
Provider: rs.Provider,
|
||||||
dependentOn: rs.Dependencies,
|
dependentOn: rs.Dependencies,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -162,6 +163,7 @@ func (n *graphNodeOrphanModule) Expand(b GraphBuilder) (GraphNodeSubgraph, error
|
||||||
type graphNodeOrphanResource struct {
|
type graphNodeOrphanResource struct {
|
||||||
ResourceName string
|
ResourceName string
|
||||||
ResourceType string
|
ResourceType string
|
||||||
|
Provider string
|
||||||
|
|
||||||
dependentOn []string
|
dependentOn []string
|
||||||
}
|
}
|
||||||
|
@ -179,7 +181,7 @@ func (n *graphNodeOrphanResource) Name() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *graphNodeOrphanResource) ProvidedBy() []string {
|
func (n *graphNodeOrphanResource) ProvidedBy() []string {
|
||||||
return []string{resourceProvider(n.ResourceName)}
|
return []string{resourceProvider(n.ResourceName, n.Provider)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GraphNodeEvalable impl.
|
// GraphNodeEvalable impl.
|
||||||
|
@ -215,6 +217,7 @@ func (n *graphNodeOrphanResource) EvalTree() EvalNode {
|
||||||
&EvalWriteState{
|
&EvalWriteState{
|
||||||
Name: n.ResourceName,
|
Name: n.ResourceName,
|
||||||
ResourceType: n.ResourceType,
|
ResourceType: n.ResourceType,
|
||||||
|
Provider: n.Provider,
|
||||||
Dependencies: n.DependentOn(),
|
Dependencies: n.DependentOn(),
|
||||||
State: &state,
|
State: &state,
|
||||||
},
|
},
|
||||||
|
@ -272,6 +275,7 @@ func (n *graphNodeOrphanResource) EvalTree() EvalNode {
|
||||||
&EvalWriteState{
|
&EvalWriteState{
|
||||||
Name: n.ResourceName,
|
Name: n.ResourceName,
|
||||||
ResourceType: n.ResourceType,
|
ResourceType: n.ResourceType,
|
||||||
|
Provider: n.Provider,
|
||||||
Dependencies: n.DependentOn(),
|
Dependencies: n.DependentOn(),
|
||||||
State: &state,
|
State: &state,
|
||||||
},
|
},
|
||||||
|
|
|
@ -342,6 +342,13 @@ func TestGraphNodeOrphanResource_ProvidedBy(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGraphNodeOrphanResource_ProvidedBy_alias(t *testing.T) {
|
||||||
|
n := &graphNodeOrphanResource{ResourceName: "aws_instance.foo", Provider: "aws.bar"}
|
||||||
|
if v := n.ProvidedBy(); v[0] != "aws.bar" {
|
||||||
|
t.Fatalf("bad: %#v", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const testTransformOrphanBasicStr = `
|
const testTransformOrphanBasicStr = `
|
||||||
aws_instance.db (orphan)
|
aws_instance.db (orphan)
|
||||||
aws_instance.web
|
aws_instance.web
|
||||||
|
|
|
@ -140,7 +140,7 @@ func (n *graphNodeExpandedResource) DependentOn() []string {
|
||||||
|
|
||||||
// GraphNodeProviderConsumer
|
// GraphNodeProviderConsumer
|
||||||
func (n *graphNodeExpandedResource) ProvidedBy() []string {
|
func (n *graphNodeExpandedResource) ProvidedBy() []string {
|
||||||
return []string{resourceProvider(n.Resource.Type)}
|
return []string{resourceProvider(n.Resource.Type, n.Resource.Provider)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GraphNodeEvalable impl.
|
// GraphNodeEvalable impl.
|
||||||
|
@ -230,6 +230,7 @@ func (n *graphNodeExpandedResource) EvalTree() EvalNode {
|
||||||
&EvalWriteState{
|
&EvalWriteState{
|
||||||
Name: n.stateId(),
|
Name: n.stateId(),
|
||||||
ResourceType: n.Resource.Type,
|
ResourceType: n.Resource.Type,
|
||||||
|
Provider: n.Resource.Provider,
|
||||||
Dependencies: n.DependentOn(),
|
Dependencies: n.DependentOn(),
|
||||||
State: &state,
|
State: &state,
|
||||||
},
|
},
|
||||||
|
@ -270,6 +271,7 @@ func (n *graphNodeExpandedResource) EvalTree() EvalNode {
|
||||||
&EvalWriteState{
|
&EvalWriteState{
|
||||||
Name: n.stateId(),
|
Name: n.stateId(),
|
||||||
ResourceType: n.Resource.Type,
|
ResourceType: n.Resource.Type,
|
||||||
|
Provider: n.Resource.Provider,
|
||||||
Dependencies: n.DependentOn(),
|
Dependencies: n.DependentOn(),
|
||||||
State: &state,
|
State: &state,
|
||||||
},
|
},
|
||||||
|
@ -416,6 +418,7 @@ func (n *graphNodeExpandedResource) EvalTree() EvalNode {
|
||||||
&EvalWriteState{
|
&EvalWriteState{
|
||||||
Name: n.stateId(),
|
Name: n.stateId(),
|
||||||
ResourceType: n.Resource.Type,
|
ResourceType: n.Resource.Type,
|
||||||
|
Provider: n.Resource.Provider,
|
||||||
Dependencies: n.DependentOn(),
|
Dependencies: n.DependentOn(),
|
||||||
State: &state,
|
State: &state,
|
||||||
},
|
},
|
||||||
|
@ -459,6 +462,7 @@ func (n *graphNodeExpandedResource) EvalTree() EvalNode {
|
||||||
&EvalWriteStateTainted{
|
&EvalWriteStateTainted{
|
||||||
Name: n.stateId(),
|
Name: n.stateId(),
|
||||||
ResourceType: n.Resource.Type,
|
ResourceType: n.Resource.Type,
|
||||||
|
Provider: n.Resource.Provider,
|
||||||
Dependencies: n.DependentOn(),
|
Dependencies: n.DependentOn(),
|
||||||
State: &state,
|
State: &state,
|
||||||
Index: -1,
|
Index: -1,
|
||||||
|
@ -476,6 +480,7 @@ func (n *graphNodeExpandedResource) EvalTree() EvalNode {
|
||||||
Else: &EvalWriteState{
|
Else: &EvalWriteState{
|
||||||
Name: n.stateId(),
|
Name: n.stateId(),
|
||||||
ResourceType: n.Resource.Type,
|
ResourceType: n.Resource.Type,
|
||||||
|
Provider: n.Resource.Provider,
|
||||||
Dependencies: n.DependentOn(),
|
Dependencies: n.DependentOn(),
|
||||||
State: &state,
|
State: &state,
|
||||||
},
|
},
|
||||||
|
@ -586,6 +591,7 @@ func (n *graphNodeExpandedResourceDestroy) EvalTree() EvalNode {
|
||||||
&EvalWriteState{
|
&EvalWriteState{
|
||||||
Name: n.stateId(),
|
Name: n.stateId(),
|
||||||
ResourceType: n.Resource.Type,
|
ResourceType: n.Resource.Type,
|
||||||
|
Provider: n.Resource.Provider,
|
||||||
Dependencies: n.DependentOn(),
|
Dependencies: n.DependentOn(),
|
||||||
State: &state,
|
State: &state,
|
||||||
},
|
},
|
||||||
|
|
|
@ -45,6 +45,7 @@ func (t *TaintedTransformer) Transform(g *Graph) error {
|
||||||
Index: i,
|
Index: i,
|
||||||
ResourceName: k,
|
ResourceName: k,
|
||||||
ResourceType: rs.Type,
|
ResourceType: rs.Type,
|
||||||
|
Provider: rs.Provider,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,6 +58,7 @@ type graphNodeTaintedResource struct {
|
||||||
Index int
|
Index int
|
||||||
ResourceName string
|
ResourceName string
|
||||||
ResourceType string
|
ResourceType string
|
||||||
|
Provider string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *graphNodeTaintedResource) Name() string {
|
func (n *graphNodeTaintedResource) Name() string {
|
||||||
|
@ -64,7 +66,7 @@ func (n *graphNodeTaintedResource) Name() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *graphNodeTaintedResource) ProvidedBy() []string {
|
func (n *graphNodeTaintedResource) ProvidedBy() []string {
|
||||||
return []string{resourceProvider(n.ResourceName)}
|
return []string{resourceProvider(n.ResourceName, n.Provider)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GraphNodeEvalable impl.
|
// GraphNodeEvalable impl.
|
||||||
|
@ -101,6 +103,7 @@ func (n *graphNodeTaintedResource) EvalTree() EvalNode {
|
||||||
&EvalWriteStateTainted{
|
&EvalWriteStateTainted{
|
||||||
Name: n.ResourceName,
|
Name: n.ResourceName,
|
||||||
ResourceType: n.ResourceType,
|
ResourceType: n.ResourceType,
|
||||||
|
Provider: n.Provider,
|
||||||
State: &state,
|
State: &state,
|
||||||
Index: n.Index,
|
Index: n.Index,
|
||||||
},
|
},
|
||||||
|
@ -138,6 +141,7 @@ func (n *graphNodeTaintedResource) EvalTree() EvalNode {
|
||||||
&EvalWriteStateTainted{
|
&EvalWriteStateTainted{
|
||||||
Name: n.ResourceName,
|
Name: n.ResourceName,
|
||||||
ResourceType: n.ResourceType,
|
ResourceType: n.ResourceType,
|
||||||
|
Provider: n.Provider,
|
||||||
State: &state,
|
State: &state,
|
||||||
Index: n.Index,
|
Index: n.Index,
|
||||||
},
|
},
|
||||||
|
|
|
@ -58,6 +58,13 @@ func TestGraphNodeTaintedResource_ProvidedBy(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGraphNodeTaintedResource_ProvidedBy_alias(t *testing.T) {
|
||||||
|
n := &graphNodeTaintedResource{ResourceName: "aws_instance.foo", Provider: "aws.bar"}
|
||||||
|
if v := n.ProvidedBy(); v[0] != "aws.bar" {
|
||||||
|
t.Fatalf("bad: %#v", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const testTransformTaintedBasicStr = `
|
const testTransformTaintedBasicStr = `
|
||||||
aws_instance.web
|
aws_instance.web
|
||||||
aws_instance.web (tainted #1)
|
aws_instance.web (tainted #1)
|
||||||
|
|
|
@ -47,7 +47,11 @@ func (s Semaphore) Release() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// resourceProvider returns the provider name for the given type.
|
// resourceProvider returns the provider name for the given type.
|
||||||
func resourceProvider(t string) string {
|
func resourceProvider(t, alias string) string {
|
||||||
|
if alias != "" {
|
||||||
|
return alias
|
||||||
|
}
|
||||||
|
|
||||||
idx := strings.IndexRune(t, '_')
|
idx := strings.IndexRune(t, '_')
|
||||||
if idx == -1 {
|
if idx == -1 {
|
||||||
return ""
|
return ""
|
||||||
|
|
Loading…
Reference in New Issue