github.com/pulumi/terraform@v1.4.0/pkg/terraform/transform_provider_test.go (about)

     1  package terraform
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  	"testing"
     7  
     8  	"github.com/pulumi/terraform/pkg/addrs"
     9  	"github.com/pulumi/terraform/pkg/configs"
    10  	"github.com/pulumi/terraform/pkg/dag"
    11  )
    12  
    13  func testProviderTransformerGraph(t *testing.T, cfg *configs.Config) *Graph {
    14  	t.Helper()
    15  
    16  	g := &Graph{Path: addrs.RootModuleInstance}
    17  	ct := &ConfigTransformer{Config: cfg}
    18  	if err := ct.Transform(g); err != nil {
    19  		t.Fatal(err)
    20  	}
    21  	arct := &AttachResourceConfigTransformer{Config: cfg}
    22  	if err := arct.Transform(g); err != nil {
    23  		t.Fatal(err)
    24  	}
    25  
    26  	return g
    27  }
    28  
    29  func TestProviderTransformer(t *testing.T) {
    30  	mod := testModule(t, "transform-provider-basic")
    31  
    32  	g := testProviderTransformerGraph(t, mod)
    33  	{
    34  		transform := &MissingProviderTransformer{}
    35  		if err := transform.Transform(g); err != nil {
    36  			t.Fatalf("err: %s", err)
    37  		}
    38  	}
    39  
    40  	transform := &ProviderTransformer{}
    41  	if err := transform.Transform(g); err != nil {
    42  		t.Fatalf("err: %s", err)
    43  	}
    44  
    45  	actual := strings.TrimSpace(g.String())
    46  	expected := strings.TrimSpace(testTransformProviderBasicStr)
    47  	if actual != expected {
    48  		t.Fatalf("bad:\n\n%s", actual)
    49  	}
    50  }
    51  
    52  // Test providers with FQNs that do not match the typeName
    53  func TestProviderTransformer_fqns(t *testing.T) {
    54  	for _, mod := range []string{"fqns", "fqns-module"} {
    55  		mod := testModule(t, fmt.Sprintf("transform-provider-%s", mod))
    56  
    57  		g := testProviderTransformerGraph(t, mod)
    58  		{
    59  			transform := &MissingProviderTransformer{Config: mod}
    60  			if err := transform.Transform(g); err != nil {
    61  				t.Fatalf("err: %s", err)
    62  			}
    63  		}
    64  
    65  		transform := &ProviderTransformer{Config: mod}
    66  		if err := transform.Transform(g); err != nil {
    67  			t.Fatalf("err: %s", err)
    68  		}
    69  
    70  		actual := strings.TrimSpace(g.String())
    71  		expected := strings.TrimSpace(testTransformProviderBasicStr)
    72  		if actual != expected {
    73  			t.Fatalf("bad:\n\n%s", actual)
    74  		}
    75  	}
    76  }
    77  
    78  func TestCloseProviderTransformer(t *testing.T) {
    79  	mod := testModule(t, "transform-provider-basic")
    80  	g := testProviderTransformerGraph(t, mod)
    81  
    82  	{
    83  		transform := &MissingProviderTransformer{}
    84  		if err := transform.Transform(g); err != nil {
    85  			t.Fatalf("err: %s", err)
    86  		}
    87  	}
    88  
    89  	{
    90  		transform := &ProviderTransformer{}
    91  		if err := transform.Transform(g); err != nil {
    92  			t.Fatalf("err: %s", err)
    93  		}
    94  	}
    95  
    96  	{
    97  		transform := &CloseProviderTransformer{}
    98  		if err := transform.Transform(g); err != nil {
    99  			t.Fatalf("err: %s", err)
   100  		}
   101  	}
   102  
   103  	actual := strings.TrimSpace(g.String())
   104  	expected := strings.TrimSpace(testTransformCloseProviderBasicStr)
   105  	if actual != expected {
   106  		t.Fatalf("bad:\n\n%s", actual)
   107  	}
   108  }
   109  
   110  func TestCloseProviderTransformer_withTargets(t *testing.T) {
   111  	mod := testModule(t, "transform-provider-basic")
   112  
   113  	g := testProviderTransformerGraph(t, mod)
   114  	transforms := []GraphTransformer{
   115  		&MissingProviderTransformer{},
   116  		&ProviderTransformer{},
   117  		&CloseProviderTransformer{},
   118  		&TargetsTransformer{
   119  			Targets: []addrs.Targetable{
   120  				addrs.RootModuleInstance.Resource(
   121  					addrs.ManagedResourceMode, "something", "else",
   122  				),
   123  			},
   124  		},
   125  	}
   126  
   127  	for _, tr := range transforms {
   128  		if err := tr.Transform(g); err != nil {
   129  			t.Fatalf("err: %s", err)
   130  		}
   131  	}
   132  
   133  	actual := strings.TrimSpace(g.String())
   134  	expected := strings.TrimSpace(``)
   135  	if actual != expected {
   136  		t.Fatalf("expected:%s\n\ngot:\n\n%s", expected, actual)
   137  	}
   138  }
   139  
   140  func TestMissingProviderTransformer(t *testing.T) {
   141  	mod := testModule(t, "transform-provider-missing")
   142  
   143  	g := testProviderTransformerGraph(t, mod)
   144  	{
   145  		transform := &MissingProviderTransformer{}
   146  		if err := transform.Transform(g); err != nil {
   147  			t.Fatalf("err: %s", err)
   148  		}
   149  	}
   150  
   151  	{
   152  		transform := &ProviderTransformer{}
   153  		if err := transform.Transform(g); err != nil {
   154  			t.Fatalf("err: %s", err)
   155  		}
   156  	}
   157  
   158  	{
   159  		transform := &CloseProviderTransformer{}
   160  		if err := transform.Transform(g); err != nil {
   161  			t.Fatalf("err: %s", err)
   162  		}
   163  	}
   164  
   165  	actual := strings.TrimSpace(g.String())
   166  	expected := strings.TrimSpace(testTransformMissingProviderBasicStr)
   167  	if actual != expected {
   168  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
   169  	}
   170  }
   171  
   172  func TestMissingProviderTransformer_grandchildMissing(t *testing.T) {
   173  	mod := testModule(t, "transform-provider-missing-grandchild")
   174  
   175  	concrete := func(a *NodeAbstractProvider) dag.Vertex { return a }
   176  
   177  	g := testProviderTransformerGraph(t, mod)
   178  	{
   179  		transform := transformProviders(concrete, mod)
   180  		if err := transform.Transform(g); err != nil {
   181  			t.Fatalf("err: %s", err)
   182  		}
   183  	}
   184  	{
   185  		transform := &TransitiveReductionTransformer{}
   186  		if err := transform.Transform(g); err != nil {
   187  			t.Fatalf("err: %s", err)
   188  		}
   189  	}
   190  
   191  	actual := strings.TrimSpace(g.String())
   192  	expected := strings.TrimSpace(testTransformMissingGrandchildProviderStr)
   193  	if actual != expected {
   194  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
   195  	}
   196  }
   197  
   198  func TestPruneProviderTransformer(t *testing.T) {
   199  	mod := testModule(t, "transform-provider-prune")
   200  
   201  	g := testProviderTransformerGraph(t, mod)
   202  	{
   203  		transform := &MissingProviderTransformer{}
   204  		if err := transform.Transform(g); err != nil {
   205  			t.Fatalf("err: %s", err)
   206  		}
   207  	}
   208  
   209  	{
   210  		transform := &ProviderTransformer{}
   211  		if err := transform.Transform(g); err != nil {
   212  			t.Fatalf("err: %s", err)
   213  		}
   214  	}
   215  
   216  	{
   217  		transform := &CloseProviderTransformer{}
   218  		if err := transform.Transform(g); err != nil {
   219  			t.Fatalf("err: %s", err)
   220  		}
   221  	}
   222  
   223  	{
   224  		transform := &PruneProviderTransformer{}
   225  		if err := transform.Transform(g); err != nil {
   226  			t.Fatalf("err: %s", err)
   227  		}
   228  	}
   229  
   230  	actual := strings.TrimSpace(g.String())
   231  	expected := strings.TrimSpace(testTransformPruneProviderBasicStr)
   232  	if actual != expected {
   233  		t.Fatalf("bad:\n\n%s", actual)
   234  	}
   235  }
   236  
   237  // the child module resource is attached to the configured parent provider
   238  func TestProviderConfigTransformer_parentProviders(t *testing.T) {
   239  	mod := testModule(t, "transform-provider-inherit")
   240  	concrete := func(a *NodeAbstractProvider) dag.Vertex { return a }
   241  
   242  	g := testProviderTransformerGraph(t, mod)
   243  	{
   244  		tf := transformProviders(concrete, mod)
   245  		if err := tf.Transform(g); err != nil {
   246  			t.Fatalf("err: %s", err)
   247  		}
   248  	}
   249  
   250  	actual := strings.TrimSpace(g.String())
   251  	expected := strings.TrimSpace(testTransformModuleProviderConfigStr)
   252  	if actual != expected {
   253  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
   254  	}
   255  }
   256  
   257  // the child module resource is attached to the configured grand-parent provider
   258  func TestProviderConfigTransformer_grandparentProviders(t *testing.T) {
   259  	mod := testModule(t, "transform-provider-grandchild-inherit")
   260  	concrete := func(a *NodeAbstractProvider) dag.Vertex { return a }
   261  
   262  	g := testProviderTransformerGraph(t, mod)
   263  	{
   264  		tf := transformProviders(concrete, mod)
   265  		if err := tf.Transform(g); err != nil {
   266  			t.Fatalf("err: %s", err)
   267  		}
   268  	}
   269  
   270  	actual := strings.TrimSpace(g.String())
   271  	expected := strings.TrimSpace(testTransformModuleProviderGrandparentStr)
   272  	if actual != expected {
   273  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
   274  	}
   275  }
   276  
   277  func TestProviderConfigTransformer_inheritOldSkool(t *testing.T) {
   278  	mod := testModuleInline(t, map[string]string{
   279  		"main.tf": `
   280  provider "test" {
   281    test_string = "config"
   282  }
   283  
   284  module "moda" {
   285    source = "./moda"
   286  }
   287  `,
   288  
   289  		"moda/main.tf": `
   290  resource "test_object" "a" {
   291  }
   292  `,
   293  	})
   294  	concrete := func(a *NodeAbstractProvider) dag.Vertex { return a }
   295  
   296  	g := testProviderTransformerGraph(t, mod)
   297  	{
   298  		tf := transformProviders(concrete, mod)
   299  		if err := tf.Transform(g); err != nil {
   300  			t.Fatalf("err: %s", err)
   301  		}
   302  	}
   303  
   304  	expected := `module.moda.test_object.a
   305    provider["registry.terraform.io/hashicorp/test"]
   306  provider["registry.terraform.io/hashicorp/test"]`
   307  
   308  	actual := strings.TrimSpace(g.String())
   309  	if actual != expected {
   310  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
   311  	}
   312  }
   313  
   314  // Verify that configurations which are not recommended yet supported still work
   315  func TestProviderConfigTransformer_nestedModuleProviders(t *testing.T) {
   316  	mod := testModuleInline(t, map[string]string{
   317  		"main.tf": `
   318  terraform {
   319    required_providers {
   320      test = {
   321        source = "registry.terraform.io/hashicorp/test"
   322  	}
   323    }
   324  }
   325  
   326  provider "test" {
   327    alias = "z"
   328    test_string = "config"
   329  }
   330  
   331  module "moda" {
   332    source = "./moda"
   333    providers = {
   334      test.x = test.z
   335    }
   336  }
   337  `,
   338  
   339  		"moda/main.tf": `
   340  terraform {
   341    required_providers {
   342      test = {
   343        source = "registry.terraform.io/hashicorp/test"
   344        configuration_aliases = [ test.x ]
   345  	}
   346    }
   347  }
   348  
   349  provider "test" {
   350    test_string = "config"
   351  }
   352  
   353  // this should connect to this module's provider
   354  resource "test_object" "a" {
   355  }
   356  
   357  resource "test_object" "x" {
   358    provider = test.x
   359  }
   360  
   361  module "modb" {
   362    source = "./modb"
   363  }
   364  `,
   365  
   366  		"moda/modb/main.tf": `
   367  # this should end up with the provider from the parent module
   368  resource "test_object" "a" {
   369  }
   370  `,
   371  	})
   372  	concrete := func(a *NodeAbstractProvider) dag.Vertex { return a }
   373  
   374  	g := testProviderTransformerGraph(t, mod)
   375  	{
   376  		tf := transformProviders(concrete, mod)
   377  		if err := tf.Transform(g); err != nil {
   378  			t.Fatalf("err: %s", err)
   379  		}
   380  	}
   381  
   382  	expected := `module.moda.module.modb.test_object.a
   383    module.moda.provider["registry.terraform.io/hashicorp/test"]
   384  module.moda.provider["registry.terraform.io/hashicorp/test"]
   385  module.moda.test_object.a
   386    module.moda.provider["registry.terraform.io/hashicorp/test"]
   387  module.moda.test_object.x
   388    provider["registry.terraform.io/hashicorp/test"].z
   389  provider["registry.terraform.io/hashicorp/test"].z`
   390  
   391  	actual := strings.TrimSpace(g.String())
   392  	if actual != expected {
   393  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
   394  	}
   395  }
   396  
   397  func TestProviderConfigTransformer_duplicateLocalName(t *testing.T) {
   398  	mod := testModuleInline(t, map[string]string{
   399  		"main.tf": `
   400  terraform {
   401    required_providers {
   402  	# We have to allow this since it wasn't previously prevented. If the
   403  	# default config is equivalent to the provider config, the user may never
   404  	# see an error.
   405      dupe = {
   406        source = "registry.terraform.io/hashicorp/test"
   407      }
   408    }
   409  }
   410  
   411  provider "test" {
   412  }
   413  `})
   414  	concrete := func(a *NodeAbstractProvider) dag.Vertex { return a }
   415  
   416  	g := testProviderTransformerGraph(t, mod)
   417  	tf := ProviderConfigTransformer{
   418  		Config:   mod,
   419  		Concrete: concrete,
   420  	}
   421  	if err := tf.Transform(g); err != nil {
   422  		t.Fatalf("err: %s", err)
   423  	}
   424  
   425  	expected := `provider["registry.terraform.io/hashicorp/test"]`
   426  
   427  	actual := strings.TrimSpace(g.String())
   428  	if actual != expected {
   429  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
   430  	}
   431  }
   432  
   433  const testTransformProviderBasicStr = `
   434  aws_instance.web
   435    provider["registry.terraform.io/hashicorp/aws"]
   436  provider["registry.terraform.io/hashicorp/aws"]
   437  `
   438  
   439  const testTransformCloseProviderBasicStr = `
   440  aws_instance.web
   441    provider["registry.terraform.io/hashicorp/aws"]
   442  provider["registry.terraform.io/hashicorp/aws"]
   443  provider["registry.terraform.io/hashicorp/aws"] (close)
   444    aws_instance.web
   445    provider["registry.terraform.io/hashicorp/aws"]
   446  `
   447  
   448  const testTransformMissingProviderBasicStr = `
   449  aws_instance.web
   450    provider["registry.terraform.io/hashicorp/aws"]
   451  foo_instance.web
   452    provider["registry.terraform.io/hashicorp/foo"]
   453  provider["registry.terraform.io/hashicorp/aws"]
   454  provider["registry.terraform.io/hashicorp/aws"] (close)
   455    aws_instance.web
   456    provider["registry.terraform.io/hashicorp/aws"]
   457  provider["registry.terraform.io/hashicorp/foo"]
   458  provider["registry.terraform.io/hashicorp/foo"] (close)
   459    foo_instance.web
   460    provider["registry.terraform.io/hashicorp/foo"]
   461  `
   462  
   463  const testTransformMissingGrandchildProviderStr = `
   464  module.sub.module.subsub.bar_instance.two
   465    provider["registry.terraform.io/hashicorp/bar"]
   466  module.sub.module.subsub.foo_instance.one
   467    module.sub.provider["registry.terraform.io/hashicorp/foo"]
   468  module.sub.provider["registry.terraform.io/hashicorp/foo"]
   469  provider["registry.terraform.io/hashicorp/bar"]
   470  `
   471  
   472  const testTransformPruneProviderBasicStr = `
   473  foo_instance.web
   474    provider["registry.terraform.io/hashicorp/foo"]
   475  provider["registry.terraform.io/hashicorp/foo"]
   476  provider["registry.terraform.io/hashicorp/foo"] (close)
   477    foo_instance.web
   478    provider["registry.terraform.io/hashicorp/foo"]
   479  `
   480  
   481  const testTransformModuleProviderConfigStr = `
   482  module.child.aws_instance.thing
   483    provider["registry.terraform.io/hashicorp/aws"].foo
   484  provider["registry.terraform.io/hashicorp/aws"].foo
   485  `
   486  
   487  const testTransformModuleProviderGrandparentStr = `
   488  module.child.module.grandchild.aws_instance.baz
   489    provider["registry.terraform.io/hashicorp/aws"].foo
   490  provider["registry.terraform.io/hashicorp/aws"].foo
   491  `