diff --git a/CHANGELOG.md b/CHANGELOG.md index 320582d454..84bf374b16 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,13 +6,29 @@ NOTES: Prior to this release, MacOS 10.15+ users attemping to run our software [reported](https://github.com/hashicorp/terraform/issues/23033) seeing the error: "'terraform' cannot be opened because the developer cannot be verified." This error affected all MacOS 10.15+ users who downloaded our software directly via web browsers, and was caused by [changes to Apple's third-party software requirements](https://developer.apple.com/news/?id=04102019a). - Users will continue to see an error when attempting to double click on the unzipped binary. This is a bug Apple is working to fix. However, double clicking on the binary is not a recommended way of interacting with our software- users should instead invoke Terraform commands via the command line. [Our recommended approach to install the Terraform CLI can be found here.](https://learn.hashicorp.com/terraform/getting-started/install) + [Our recommended approach to install and interact with the Terraform CLI can be found here](https://learn.hashicorp.com/terraform/getting-started/install). MacOS 10.15+ users should plan to upgrade to 0.12.18+. +UPGRADE NOTES: + +* Inside `provisioner` blocks that have `when = destroy` set, and inside any `connection` blocks that are used by such provisioner blocks, it is now deprecated to refer to any objects other than `self`, `count`, and `each`. + + Terraform has historically allowed this but doing so tends to cause downstream problems with dependency cycles or incorrect destroy ordering because it causes the destroy phase of one resource to depend on the existing state of another. Although this is currently only a warning, we strongly suggest seeking alternative approaches for existing configurations that are hitting this warning in order to avoid the risk of later problems should you need to replace or destroy the related resources. + + This deprecation warning will be promoted to an error in a future release. + +ENHANCEMENTS: + +* provisioners: Warn about the deprecation of non-self references in destroy-time provisioners, both to allow preparation for this later becoming an error and also as an extra hint for the "Cycle" errors that commonly arise when such references are used. [GH-23559] + BUG FIXES: +* cli: Allow moving indexed resource instances to new addresses that that don't yet exist in state [GH-23582] +* cli: Improved heuristics for log level filtering with the `TF_LOG` environment variable, although it is still not 100% reliable for levels other than `TRACE` due to limitations of Terraform's internal logging infrastructure. Because of that, levels other than `TRACE` will now cause the logs to begin with a warning about potential filtering inaccuracy. [GH-23577] +* command/show: Fix panic on show plan [GH-23581] * config: Fixed referencing errors generally involving `for_each` [GH-23475] +* provisioners: The built-in provisioners (`local-exec`, `remote-exec`, `file`, etc) will no longer fail when the `TF_CLI_ARGS` environment variable is set. [GH-17400] ## 0.12.17 (December 02, 2019) diff --git a/addrs/provider.go b/addrs/provider.go index 04fb731bd4..b73cfb5a7f 100644 --- a/addrs/provider.go +++ b/addrs/provider.go @@ -1,6 +1,8 @@ package addrs -import svchost "github.com/hashicorp/terraform-svchost" +import ( + svchost "github.com/hashicorp/terraform-svchost" +) // Provider encapsulates a single provider type. In the future this will be // extended to include additional fields including Namespace and SourceHost diff --git a/addrs/provider_config.go b/addrs/provider_config.go index aaef1d3a4b..6413ed9cfb 100644 --- a/addrs/provider_config.go +++ b/addrs/provider_config.go @@ -11,7 +11,7 @@ import ( // ProviderConfig is the address of a provider configuration. type ProviderConfig struct { - Type string + Type Provider // If not empty, Alias identifies which non-default (aliased) provider // configuration this address refers to. @@ -22,7 +22,7 @@ type ProviderConfig struct { // configuration for the provider with the given type name. func NewDefaultProviderConfig(typeName string) ProviderConfig { return ProviderConfig{ - Type: typeName, + Type: NewLegacyProvider(typeName), } } @@ -41,7 +41,7 @@ func NewDefaultProviderConfig(typeName string) ProviderConfig { func ParseProviderConfigCompact(traversal hcl.Traversal) (ProviderConfig, tfdiags.Diagnostics) { var diags tfdiags.Diagnostics ret := ProviderConfig{ - Type: traversal.RootName(), + Type: NewLegacyProvider(traversal.RootName()), } if len(traversal) < 2 { @@ -114,25 +114,25 @@ func (pc ProviderConfig) Absolute(module ModuleInstance) AbsProviderConfig { } func (pc ProviderConfig) String() string { - if pc.Type == "" { + if pc.Type.LegacyString() == "" { // Should never happen; always indicates a bug return "provider." } if pc.Alias != "" { - return fmt.Sprintf("provider.%s.%s", pc.Type, pc.Alias) + return fmt.Sprintf("provider.%s.%s", pc.Type.LegacyString(), pc.Alias) } - return "provider." + pc.Type + return "provider." + pc.Type.LegacyString() } // StringCompact is an alternative to String that returns the form that can // be parsed by ParseProviderConfigCompact, without the "provider." prefix. func (pc ProviderConfig) StringCompact() string { if pc.Alias != "" { - return fmt.Sprintf("%s.%s", pc.Type, pc.Alias) + return fmt.Sprintf("%s.%s", pc.Type.LegacyString(), pc.Alias) } - return pc.Type + return pc.Type.LegacyString() } // AbsProviderConfig is the absolute address of a provider configuration @@ -181,7 +181,7 @@ func ParseAbsProviderConfig(traversal hcl.Traversal) (AbsProviderConfig, tfdiags } if tt, ok := remain[1].(hcl.TraverseAttr); ok { - ret.ProviderConfig.Type = tt.Name + ret.ProviderConfig.Type = NewLegacyProvider(tt.Name) } else { diags = diags.Append(&hcl.Diagnostic{ Severity: hcl.DiagError, @@ -244,7 +244,7 @@ func (m ModuleInstance) ProviderConfigDefault(name string) AbsProviderConfig { return AbsProviderConfig{ Module: m, ProviderConfig: ProviderConfig{ - Type: name, + Type: NewLegacyProvider(name), }, } } @@ -255,7 +255,7 @@ func (m ModuleInstance) ProviderConfigAliased(name, alias string) AbsProviderCon return AbsProviderConfig{ Module: m, ProviderConfig: ProviderConfig{ - Type: name, + Type: NewLegacyProvider(name), Alias: alias, }, } diff --git a/addrs/provider_config_test.go b/addrs/provider_config_test.go index 1d92a83489..756fa0bb16 100644 --- a/addrs/provider_config_test.go +++ b/addrs/provider_config_test.go @@ -18,14 +18,14 @@ func TestParseProviderConfigCompact(t *testing.T) { { `aws`, ProviderConfig{ - Type: "aws", + Type: NewLegacyProvider("aws"), }, ``, }, { `aws.foo`, ProviderConfig{ - Type: "aws", + Type: NewLegacyProvider("aws"), Alias: "foo", }, ``, @@ -82,7 +82,7 @@ func TestParseAbsProviderConfig(t *testing.T) { AbsProviderConfig{ Module: RootModuleInstance, ProviderConfig: ProviderConfig{ - Type: "aws", + Type: NewLegacyProvider("aws"), }, }, ``, @@ -92,7 +92,7 @@ func TestParseAbsProviderConfig(t *testing.T) { AbsProviderConfig{ Module: RootModuleInstance, ProviderConfig: ProviderConfig{ - Type: "aws", + Type: NewLegacyProvider("aws"), Alias: "foo", }, }, @@ -107,7 +107,7 @@ func TestParseAbsProviderConfig(t *testing.T) { }, }, ProviderConfig: ProviderConfig{ - Type: "aws", + Type: NewLegacyProvider("aws"), }, }, ``, @@ -121,7 +121,7 @@ func TestParseAbsProviderConfig(t *testing.T) { }, }, ProviderConfig: ProviderConfig{ - Type: "aws", + Type: NewLegacyProvider("aws"), Alias: "foo", }, }, @@ -137,7 +137,7 @@ func TestParseAbsProviderConfig(t *testing.T) { }, }, ProviderConfig: ProviderConfig{ - Type: "aws", + Type: NewLegacyProvider("aws"), }, }, ``, @@ -152,7 +152,7 @@ func TestParseAbsProviderConfig(t *testing.T) { }, }, ProviderConfig: ProviderConfig{ - Type: "aws", + Type: NewLegacyProvider("aws"), }, }, ``, @@ -170,7 +170,7 @@ func TestParseAbsProviderConfig(t *testing.T) { }, }, ProviderConfig: ProviderConfig{ - Type: "aws", + Type: NewLegacyProvider("aws"), }, }, ``, diff --git a/addrs/resource.go b/addrs/resource.go index b075a6d1d2..bb4831ea6c 100644 --- a/addrs/resource.go +++ b/addrs/resource.go @@ -65,8 +65,9 @@ func (r Resource) DefaultProviderConfig() ProviderConfig { if under := strings.Index(typeName, "_"); under != -1 { typeName = typeName[:under] } + return ProviderConfig{ - Type: typeName, + Type: NewLegacyProvider(typeName), } } diff --git a/backend/local/backend_plan.go b/backend/local/backend_plan.go index ed51acc986..089453f1dc 100644 --- a/backend/local/backend_plan.go +++ b/backend/local/backend_plan.go @@ -262,7 +262,7 @@ func RenderPlan(plan *plans.Plan, state *states.State, schemas *terraform.Schema if rcs.Action == plans.NoOp { continue } - providerSchema := schemas.ProviderSchema(rcs.ProviderAddr.ProviderConfig.Type) + providerSchema := schemas.ProviderSchema(rcs.ProviderAddr.ProviderConfig.Type.LegacyString()) if providerSchema == nil { // Should never happen ui.Output(fmt.Sprintf("(schema missing for %s)\n", rcs.ProviderAddr)) diff --git a/backend/local/backend_plan_test.go b/backend/local/backend_plan_test.go index 1aa4183a90..898a735fe4 100644 --- a/backend/local/backend_plan_test.go +++ b/backend/local/backend_plan_test.go @@ -216,7 +216,7 @@ func TestLocal_planDeposedOnly(t *testing.T) { }`), }, addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance), ) })) @@ -659,7 +659,7 @@ func testPlanState() *states.State { }`), }, addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance), ) return state @@ -685,7 +685,7 @@ func testPlanState_withDataSource() *states.State { }`), }, addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance), ) rootModule.SetResourceInstanceCurrent( @@ -701,7 +701,7 @@ func testPlanState_withDataSource() *states.State { }`), }, addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance), ) return state @@ -727,7 +727,7 @@ func testPlanState_tainted() *states.State { }`), }, addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance), ) return state diff --git a/backend/remote-state/azure/sender.go b/backend/remote-state/azure/sender.go index 90a2fb5bd8..d2b432a65a 100644 --- a/backend/remote-state/azure/sender.go +++ b/backend/remote-state/azure/sender.go @@ -21,7 +21,7 @@ func withRequestLogging() autorest.SendDecorator { return func(s autorest.Sender) autorest.Sender { return autorest.SenderFunc(func(r *http.Request) (*http.Response, error) { // only log if logging's enabled - logLevel := logging.LogLevel() + logLevel := logging.CurrentLogLevel() if logLevel == "" { return s.Do(r) } diff --git a/backend/testing.go b/backend/testing.go index 1fc081db54..c79a138211 100644 --- a/backend/testing.go +++ b/backend/testing.go @@ -151,7 +151,7 @@ func TestBackendStates(t *testing.T, b Backend) { SchemaVersion: 0, }, addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance), ) diff --git a/command/apply_destroy_test.go b/command/apply_destroy_test.go index 3cdf998f71..c77f627507 100644 --- a/command/apply_destroy_test.go +++ b/command/apply_destroy_test.go @@ -29,7 +29,7 @@ func TestApply_destroy(t *testing.T) { AttrsJSON: []byte(`{"id":"bar"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) }) statePath := testStateFile(t, originalState) @@ -122,7 +122,7 @@ func TestApply_destroyLockedState(t *testing.T) { AttrsJSON: []byte(`{"id":"bar"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) }) statePath := testStateFile(t, originalState) @@ -194,7 +194,7 @@ func TestApply_destroyTargeted(t *testing.T) { AttrsJSON: []byte(`{"id":"i-ab123"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) s.SetResourceInstanceCurrent( addrs.Resource{ @@ -206,7 +206,7 @@ func TestApply_destroyTargeted(t *testing.T) { AttrsJSON: []byte(`{"id":"i-abc123"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) }) statePath := testStateFile(t, originalState) diff --git a/command/apply_test.go b/command/apply_test.go index c15718104e..7a31d71300 100644 --- a/command/apply_test.go +++ b/command/apply_test.go @@ -833,7 +833,7 @@ func TestApply_refresh(t *testing.T) { AttrsJSON: []byte(`{"ami":"bar"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) }) statePath := testStateFile(t, originalState) @@ -987,7 +987,7 @@ func TestApply_state(t *testing.T) { AttrsJSON: []byte(`{"ami":"foo"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) }) statePath := testStateFile(t, originalState) @@ -1351,7 +1351,7 @@ func TestApply_backup(t *testing.T) { AttrsJSON: []byte("{\n \"id\": \"bar\"\n }"), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) }) statePath := testStateFile(t, originalState) @@ -1652,7 +1652,7 @@ func applyFixturePlanFile(t *testing.T) string { Type: "test_instance", Name: "foo", }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), - ProviderAddr: addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + ProviderAddr: addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ChangeSrc: plans.ChangeSrc{ Action: plans.Create, Before: priorValRaw, diff --git a/command/command_test.go b/command/command_test.go index b6c16ea521..4f5acfe381 100644 --- a/command/command_test.go +++ b/command/command_test.go @@ -100,6 +100,12 @@ func tempDir(t *testing.T) string { if err != nil { t.Fatalf("err: %s", err) } + + dir, err = filepath.EvalSymlinks(dir) + if err != nil { + t.Fatal(err) + } + if err := os.RemoveAll(dir); err != nil { t.Fatalf("err: %s", err) } @@ -266,7 +272,7 @@ func testState() *states.State { DependsOn: []addrs.Referenceable{}, }, addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance), ) // DeepCopy is used here to ensure our synthetic state matches exactly @@ -486,6 +492,11 @@ func testTempDir(t *testing.T) string { t.Fatalf("err: %s", err) } + d, err = filepath.EvalSymlinks(d) + if err != nil { + t.Fatal(err) + } + return d } diff --git a/command/format/diff.go b/command/format/diff.go index 8b1a7edf1e..2f2258de0c 100644 --- a/command/format/diff.go +++ b/command/format/diff.go @@ -1014,8 +1014,9 @@ func (p *blockBodyDiffPrinter) writeActionSymbol(action plans.Action) { } func (p *blockBodyDiffPrinter) pathForcesNewResource(path cty.Path) bool { - if !p.action.IsReplace() { - // "requiredReplace" only applies when the instance is being replaced + if !p.action.IsReplace() || p.requiredReplace.Empty() { + // "requiredReplace" only applies when the instance is being replaced, + // and we should only inspect that set if it is not empty return false } return p.requiredReplace.Has(path) diff --git a/command/format/diff_test.go b/command/format/diff_test.go index 96d414cb6b..e1b1d414ad 100644 --- a/command/format/diff_test.go +++ b/command/format/diff_test.go @@ -3157,7 +3157,7 @@ func runTestCases(t *testing.T, testCases map[string]testCase) { Type: "test_instance", Name: "example", }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), - ProviderAddr: addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + ProviderAddr: addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ChangeSrc: plans.ChangeSrc{ Action: tc.Action, Before: before, diff --git a/command/format/state_test.go b/command/format/state_test.go index 2b00da9b84..8f64ba9437 100644 --- a/command/format/state_test.go +++ b/command/format/state_test.go @@ -244,7 +244,7 @@ func basicState(t *testing.T) *states.State { AttrsJSON: []byte(`{"woozles":"confuzles"}`), }, addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance), ) rootModule.SetResourceInstanceCurrent( @@ -259,7 +259,7 @@ func basicState(t *testing.T) *states.State { AttrsJSON: []byte(`{"compute":"sure"}`), }, addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance), ) return state @@ -294,7 +294,7 @@ func stateWithMoreOutputs(t *testing.T) *states.State { AttrsJSON: []byte(`{"woozles":"confuzles"}`), }, addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance), ) return state @@ -320,7 +320,7 @@ func nestedState(t *testing.T) *states.State { AttrsJSON: []byte(`{"woozles":"confuzles","nested": [{"value": "42"}]}`), }, addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance), ) return state @@ -342,7 +342,7 @@ func deposedState(t *testing.T) *states.State { AttrsJSON: []byte(`{"woozles":"confuzles","nested": [{"value": "42"}]}`), }, addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance), ) return state @@ -370,7 +370,7 @@ func onlyDeposedState(t *testing.T) *states.State { AttrsJSON: []byte(`{"woozles":"confuzles","nested": [{"value": "42"}]}`), }, addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance), ) rootModule.SetResourceInstanceDeposed( @@ -386,7 +386,7 @@ func onlyDeposedState(t *testing.T) *states.State { AttrsJSON: []byte(`{"woozles":"confuzles","nested": [{"value": "42"}]}`), }, addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance), ) return state diff --git a/command/graph_test.go b/command/graph_test.go index b8712e6036..13c3bd09f8 100644 --- a/command/graph_test.go +++ b/command/graph_test.go @@ -125,7 +125,7 @@ func TestGraph_plan(t *testing.T) { Before: plans.DynamicValue(`{}`), After: plans.DynamicValue(`null`), }, - ProviderAddr: addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + ProviderAddr: addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), }) emptyConfig, err := plans.NewDynamicValue(cty.EmptyObjectVal, cty.EmptyObject) if err != nil { diff --git a/command/internal_plugin.go b/command/internal_plugin.go index b26ba1df68..33de8569ac 100644 --- a/command/internal_plugin.go +++ b/command/internal_plugin.go @@ -33,7 +33,24 @@ func BuildPluginCommandString(pluginType, pluginName string) (string, error) { return strings.Join(parts, TFSPACE), nil } +// Internal plugins do not support any CLI args, but we do receive flags that +// main.go:mergeEnvArgs has merged in from EnvCLI. Instead of making main.go +// aware of this exception, we strip all flags from our args. Flags are easily +// identified by the '-' prefix, ensured by the cli package used. +func StripArgFlags(args []string) []string { + argsNoFlags := []string{} + for i := range args { + if !strings.HasPrefix(args[i], "-") { + argsNoFlags = append(argsNoFlags, args[i]) + } + } + return argsNoFlags +} + func (c *InternalPluginCommand) Run(args []string) int { + // strip flags from args, only use subcommands. + args = StripArgFlags(args) + if len(args) != 2 { log.Printf("Wrong number of args; expected: terraform internal-plugin pluginType pluginName") return 1 diff --git a/command/internal_plugin_test.go b/command/internal_plugin_test.go index 83a3f844ee..832ec6b154 100644 --- a/command/internal_plugin_test.go +++ b/command/internal_plugin_test.go @@ -46,3 +46,12 @@ func TestInternalPlugin_BuildPluginCommandString(t *testing.T) { t.Errorf("Expected command to end with %s; got:\n%s\n", expected, actual) } } + +func TestInternalPlugin_StripArgFlags(t *testing.T) { + actual := StripArgFlags([]string{"provisioner", "remote-exec", "-var-file=my_vars.tfvars", "-flag"}) + expected := []string{"provisioner", "remote-exec"} + // Must be same length and order. + if len(actual) != len(expected) || expected[0] != actual[0] || actual[1] != actual[1] { + t.Fatalf("Expected args to be exactly '%s', got '%s'", expected, actual) + } +} diff --git a/command/jsonconfig/config.go b/command/jsonconfig/config.go index 0b27c7af4b..4887ed5871 100644 --- a/command/jsonconfig/config.go +++ b/command/jsonconfig/config.go @@ -302,7 +302,7 @@ func marshalResources(resources map[string]*configs.Resource, schemas *terraform } schema, schemaVer := schemas.ResourceTypeConfig( - v.ProviderConfigAddr().Type, + v.ProviderConfigAddr().Type.LegacyString(), v.Mode, v.Type, ) diff --git a/command/jsonplan/plan.go b/command/jsonplan/plan.go index f1563abef3..2659f6deb4 100644 --- a/command/jsonplan/plan.go +++ b/command/jsonplan/plan.go @@ -178,7 +178,7 @@ func (p *plan) marshalResourceChanges(changes *plans.Changes, schemas *terraform } schema, _ := schemas.ResourceTypeConfig( - rc.ProviderAddr.ProviderConfig.Type, + rc.ProviderAddr.ProviderConfig.Type.LegacyString(), addr.Resource.Resource.Mode, addr.Resource.Resource.Type, ) diff --git a/command/jsonplan/values.go b/command/jsonplan/values.go index caa8babf4f..3a3b8f52ec 100644 --- a/command/jsonplan/values.go +++ b/command/jsonplan/values.go @@ -181,7 +181,7 @@ func marshalPlanResources(changes *plans.Changes, ris []addrs.AbsResourceInstanc } schema, schemaVer := schemas.ResourceTypeConfig( - r.ProviderAddr.ProviderConfig.Type, + r.ProviderAddr.ProviderConfig.Type.LegacyString(), r.Addr.Resource.Resource.Mode, resource.Type, ) diff --git a/command/jsonplan/values_test.go b/command/jsonplan/values_test.go index 8395ee0aaf..3716e1b4f5 100644 --- a/command/jsonplan/values_test.go +++ b/command/jsonplan/values_test.go @@ -258,7 +258,7 @@ func TestMarshalPlanResources(t *testing.T) { Type: "test_thing", Name: "example", }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), - ProviderAddr: addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + ProviderAddr: addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ChangeSrc: plans.ChangeSrc{ Action: test.Action, Before: before, diff --git a/command/jsonstate/state.go b/command/jsonstate/state.go index 2fac8fbba6..99b5bdcc8e 100644 --- a/command/jsonstate/state.go +++ b/command/jsonstate/state.go @@ -274,7 +274,7 @@ func marshalResources(resources map[string]*states.Resource, schemas *terraform. } schema, _ := schemas.ResourceTypeConfig( - r.ProviderConfig.ProviderConfig.Type, + r.ProviderConfig.ProviderConfig.Type.LegacyString(), r.Addr.Mode, r.Addr.Type, ) diff --git a/command/jsonstate/state_test.go b/command/jsonstate/state_test.go index e40c123c66..aee5abe127 100644 --- a/command/jsonstate/state_test.go +++ b/command/jsonstate/state_test.go @@ -202,7 +202,7 @@ func TestMarshalResources(t *testing.T) { }, }, ProviderConfig: addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance), }, }, @@ -245,7 +245,7 @@ func TestMarshalResources(t *testing.T) { }, }, ProviderConfig: addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance), }, }, @@ -293,7 +293,7 @@ func TestMarshalResources(t *testing.T) { }, }, ProviderConfig: addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance), }, }, diff --git a/command/meta_config.go b/command/meta_config.go index ec7b3ec16a..2bb104a11a 100644 --- a/command/meta_config.go +++ b/command/meta_config.go @@ -173,10 +173,13 @@ func (m *Meta) dirIsConfigPath(dir string) bool { // directory even if loadBackendConfig succeeded.) func (m *Meta) loadBackendConfig(rootDir string) (*configs.Backend, tfdiags.Diagnostics) { mod, diags := m.loadSingleModule(rootDir) + + // Only return error diagnostics at this point. Any warnings will be caught + // again later and duplicated in the output. if diags.HasErrors() { return nil, diags } - return mod.Backend, diags + return mod.Backend, nil } // loadValuesFile loads a file that defines a single map of key/value pairs. diff --git a/command/plan_test.go b/command/plan_test.go index 6885810d5c..fdac20f01c 100644 --- a/command/plan_test.go +++ b/command/plan_test.go @@ -124,7 +124,7 @@ func TestPlan_destroy(t *testing.T) { AttrsJSON: []byte(`{"id":"bar"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) }) outPath := testTempFile(t) @@ -240,7 +240,7 @@ func TestPlan_outPathNoChange(t *testing.T) { AttrsJSON: []byte(`{"id":"bar","ami":"bar","network_interface":[{"description":"Main network interface","device_index":"0"}]}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) }) statePath := testStateFile(t, originalState) diff --git a/command/show_test.go b/command/show_test.go index 30da8c5724..508f44166e 100644 --- a/command/show_test.go +++ b/command/show_test.go @@ -101,8 +101,34 @@ func TestShow_plan(t *testing.T) { } } +func TestShow_planWithChanges(t *testing.T) { + planPathWithChanges := showFixturePlanFile(t, plans.DeleteThenCreate) + + ui := cli.NewMockUi() + c := &ShowCommand{ + Meta: Meta{ + testingOverrides: metaOverridesForProvider(showFixtureProvider()), + Ui: ui, + }, + } + + args := []string{ + planPathWithChanges, + } + + if code := c.Run(args); code != 0 { + t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) + } + + want := `test_instance.foo must be replaced` + got := ui.OutputWriter.String() + if !strings.Contains(got, want) { + t.Errorf("missing expected output\nwant: %s\ngot:\n%s", want, got) + } +} + func TestShow_plan_json(t *testing.T) { - planPath := showFixturePlanFile(t) + planPath := showFixturePlanFile(t, plans.Create) ui := new(cli.MockUi) c := &ShowCommand{ @@ -377,9 +403,10 @@ func showFixtureProvider() *terraform.MockProvider { } // showFixturePlanFile creates a plan file at a temporary location containing a -// single change to create the test_instance.foo that is included in the "show" +// single change to create or update the test_instance.foo that is included in the "show" // test fixture, returning the location of that plan file. -func showFixturePlanFile(t *testing.T) string { +// `action` is the planned change you would like to elicit +func showFixturePlanFile(t *testing.T, action plans.Action) string { _, snap := testModuleWithSnapshot(t, "show") plannedVal := cty.ObjectVal(map[string]cty.Value{ "id": cty.UnknownVal(cty.String), @@ -400,9 +427,9 @@ func showFixturePlanFile(t *testing.T) string { Type: "test_instance", Name: "foo", }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), - ProviderAddr: addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + ProviderAddr: addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ChangeSrc: plans.ChangeSrc{ - Action: plans.Create, + Action: action, Before: priorValRaw, After: plannedValRaw, }, diff --git a/command/state_mv.go b/command/state_mv.go index 00b48306f0..829ad923bd 100644 --- a/command/state_mv.go +++ b/command/state_mv.go @@ -278,7 +278,9 @@ func (c *StateMvCommand) Run(args []string) int { c.Ui.Output(fmt.Sprintf("%s %q to %q", prefix, addrFrom.String(), args[1])) if !dryRun { fromResourceAddr := addrFrom.ContainingResource() - fromProviderAddr := ssFrom.Resource(fromResourceAddr).ProviderConfig + fromResource := ssFrom.Resource(fromResourceAddr) + fromProviderAddr := fromResource.ProviderConfig + fromEachMode := fromResource.EachMode ssFrom.ForgetResourceInstanceAll(addrFrom) ssFrom.RemoveResourceIfEmpty(fromResourceAddr) @@ -287,22 +289,17 @@ func (c *StateMvCommand) Run(args []string) int { // If we're moving to an address without an index then that // suggests the user's intent is to establish both the // resource and the instance at the same time (since the - // address covers both), but if there's an index in the - // target then the resource must already exist. + // address covers both). If there's an index in the + // target then allow creating the new instance here, + // inferring the mode from how the new address was parsed. if addrTo.Resource.Key != addrs.NoKey { - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Error, - msgInvalidTarget, - fmt.Sprintf("Cannot move to %s: %s does not exist in the current state.", addrTo, addrTo.ContainingResource()), - )) - c.showDiagnostics(diags) - return 1 + fromEachMode = eachModeForInstanceKey(addrTo.Resource.Key) } resourceAddr := addrTo.ContainingResource() stateTo.SyncWrapper().SetResourceMeta( resourceAddr, - states.NoEach, + fromEachMode, fromProviderAddr, // in this case, we bring the provider along as if we were moving the whole resource ) rs = stateTo.Resource(resourceAddr) @@ -358,6 +355,20 @@ func (c *StateMvCommand) Run(args []string) int { return 0 } +func eachModeForInstanceKey(key addrs.InstanceKey) states.EachMode { + switch key.(type) { + case addrs.IntKey: + return states.EachList + case addrs.StringKey: + return states.EachMap + default: + if key == addrs.NoKey { + return states.NoEach + } + panic(fmt.Sprintf("don't know an each mode for instance key %#v", key)) + } +} + // sourceObjectAddrs takes a single source object address and expands it to // potentially multiple objects that need to be handled within it. // diff --git a/command/state_mv_test.go b/command/state_mv_test.go index 504c4fca19..25addaefd5 100644 --- a/command/state_mv_test.go +++ b/command/state_mv_test.go @@ -27,7 +27,7 @@ func TestStateMv(t *testing.T) { AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) s.SetResourceInstanceCurrent( addrs.Resource{ @@ -39,7 +39,7 @@ func TestStateMv(t *testing.T) { AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) }) statePath := testStateFile(t, state) @@ -87,7 +87,7 @@ func TestStateMv_resourceToInstance(t *testing.T) { AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) s.SetResourceInstanceCurrent( addrs.Resource{ @@ -99,7 +99,7 @@ func TestStateMv_resourceToInstance(t *testing.T) { AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) s.SetResourceMeta( addrs.Resource{ @@ -108,7 +108,7 @@ func TestStateMv_resourceToInstance(t *testing.T) { Name: "bar", }.Absolute(addrs.RootModuleInstance), states.EachList, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) }) statePath := testStateFile(t, state) @@ -167,7 +167,7 @@ func TestStateMv_instanceToResource(t *testing.T) { AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) s.SetResourceInstanceCurrent( addrs.Resource{ @@ -179,7 +179,7 @@ func TestStateMv_instanceToResource(t *testing.T) { AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) }) statePath := testStateFile(t, state) @@ -237,6 +237,74 @@ test_instance.foo.0: `) } +func TestStateMv_instanceToNewResource(t *testing.T) { + state := states.BuildState(func(s *states.SyncState) { + s.SetResourceInstanceCurrent( + addrs.Resource{ + Mode: addrs.ManagedResourceMode, + Type: "test_instance", + Name: "foo", + }.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance), + &states.ResourceInstanceObjectSrc{ + AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), + Status: states.ObjectReady, + }, + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), + ) + }) + statePath := testStateFile(t, state) + + p := testProvider() + ui := new(cli.MockUi) + c := &StateMvCommand{ + StateMeta{ + Meta: Meta{ + testingOverrides: metaOverridesForProvider(p), + Ui: ui, + }, + }, + } + + args := []string{ + "-state", statePath, + "test_instance.foo[0]", + "test_instance.bar[\"new\"]", + } + if code := c.Run(args); code != 0 { + t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) + } + + // Test it is correct + testStateOutput(t, statePath, ` +test_instance.bar["new"]: + ID = bar + provider = provider.test + bar = value + foo = value +`) + + // now move the instance to a new resource in a new module + args = []string{ + "-state", statePath, + "test_instance.bar[\"new\"]", + "module.test.test_instance.baz[\"new\"]", + } + if code := c.Run(args); code != 0 { + t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) + } + + // Test it is correct + testStateOutput(t, statePath, ` + +module.test: + test_instance.baz["new"]: + ID = bar + provider = provider.test + bar = value + foo = value +`) +} + func TestStateMv_differentResourceTypes(t *testing.T) { state := states.BuildState(func(s *states.SyncState) { s.SetResourceInstanceCurrent( @@ -249,7 +317,7 @@ func TestStateMv_differentResourceTypes(t *testing.T) { AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) }) statePath := testStateFile(t, state) @@ -299,7 +367,7 @@ func TestStateMv_explicitWithBackend(t *testing.T) { AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) s.SetResourceInstanceCurrent( addrs.Resource{ @@ -311,7 +379,7 @@ func TestStateMv_explicitWithBackend(t *testing.T) { AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) }) statePath := testStateFile(t, state) @@ -368,7 +436,7 @@ func TestStateMv_backupExplicit(t *testing.T) { AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) s.SetResourceInstanceCurrent( addrs.Resource{ @@ -380,7 +448,7 @@ func TestStateMv_backupExplicit(t *testing.T) { AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) }) statePath := testStateFile(t, state) @@ -426,7 +494,7 @@ func TestStateMv_stateOutNew(t *testing.T) { AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) }) statePath := testStateFile(t, state) @@ -477,7 +545,7 @@ func TestStateMv_stateOutExisting(t *testing.T) { AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) }) statePath := testStateFile(t, stateSrc) @@ -493,7 +561,7 @@ func TestStateMv_stateOutExisting(t *testing.T) { AttrsJSON: []byte(`{"id":"bar"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) }) stateOutPath := testStateFile(t, stateDst) @@ -570,7 +638,7 @@ func TestStateMv_stateOutNew_count(t *testing.T) { AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) s.SetResourceInstanceCurrent( addrs.Resource{ @@ -582,7 +650,7 @@ func TestStateMv_stateOutNew_count(t *testing.T) { AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) s.SetResourceInstanceCurrent( addrs.Resource{ @@ -594,7 +662,7 @@ func TestStateMv_stateOutNew_count(t *testing.T) { AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) }) statePath := testStateFile(t, state) @@ -649,7 +717,7 @@ func TestStateMv_stateOutNew_largeCount(t *testing.T) { AttrsJSON: []byte(fmt.Sprintf(`{"id":"foo%d","foo":"value","bar":"value"}`, i)), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) } s.SetResourceInstanceCurrent( @@ -662,7 +730,7 @@ func TestStateMv_stateOutNew_largeCount(t *testing.T) { AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) }) statePath := testStateFile(t, state) @@ -713,7 +781,7 @@ func TestStateMv_stateOutNew_nestedModule(t *testing.T) { AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) s.SetResourceInstanceCurrent( addrs.Resource{ @@ -725,7 +793,7 @@ func TestStateMv_stateOutNew_nestedModule(t *testing.T) { AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) }) @@ -777,7 +845,7 @@ func TestStateMv_toNewModule(t *testing.T) { AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) }) diff --git a/command/state_rm_test.go b/command/state_rm_test.go index a35c247bb3..ed985ff068 100644 --- a/command/state_rm_test.go +++ b/command/state_rm_test.go @@ -25,7 +25,7 @@ func TestStateRm(t *testing.T) { AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) s.SetResourceInstanceCurrent( addrs.Resource{ @@ -37,7 +37,7 @@ func TestStateRm(t *testing.T) { AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) }) statePath := testStateFile(t, state) @@ -84,7 +84,7 @@ func TestStateRmNotChildModule(t *testing.T) { AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) // This second instance has the same local address as the first but // is in a child module. Older versions of Terraform would incorrectly @@ -99,7 +99,7 @@ func TestStateRmNotChildModule(t *testing.T) { AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) }) statePath := testStateFile(t, state) @@ -167,7 +167,7 @@ func TestStateRmNoArgs(t *testing.T) { AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) s.SetResourceInstanceCurrent( addrs.Resource{ @@ -179,7 +179,7 @@ func TestStateRmNoArgs(t *testing.T) { AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) }) statePath := testStateFile(t, state) @@ -220,7 +220,7 @@ func TestStateRmNonExist(t *testing.T) { AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) s.SetResourceInstanceCurrent( addrs.Resource{ @@ -232,7 +232,7 @@ func TestStateRmNonExist(t *testing.T) { AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) }) statePath := testStateFile(t, state) @@ -274,7 +274,7 @@ func TestStateRm_backupExplicit(t *testing.T) { AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) s.SetResourceInstanceCurrent( addrs.Resource{ @@ -286,7 +286,7 @@ func TestStateRm_backupExplicit(t *testing.T) { AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) }) statePath := testStateFile(t, state) @@ -384,7 +384,7 @@ func TestStateRm_backendState(t *testing.T) { AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) s.SetResourceInstanceCurrent( addrs.Resource{ @@ -396,7 +396,7 @@ func TestStateRm_backendState(t *testing.T) { AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) }) diff --git a/command/state_show_test.go b/command/state_show_test.go index e1c574e9aa..17f0365419 100644 --- a/command/state_show_test.go +++ b/command/state_show_test.go @@ -24,7 +24,7 @@ func TestStateShow(t *testing.T) { AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) }) statePath := testStateFile(t, state) @@ -79,7 +79,7 @@ func TestStateShow_multi(t *testing.T) { AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) s.SetResourceInstanceCurrent( addrs.Resource{ @@ -91,7 +91,7 @@ func TestStateShow_multi(t *testing.T) { AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(submod), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(submod), ) }) statePath := testStateFile(t, state) diff --git a/command/taint_test.go b/command/taint_test.go index bcdb76a9c3..b38317d434 100644 --- a/command/taint_test.go +++ b/command/taint_test.go @@ -24,7 +24,7 @@ func TestTaint(t *testing.T) { AttrsJSON: []byte(`{"id":"bar"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) }) statePath := testStateFile(t, state) @@ -59,7 +59,7 @@ func TestTaint_lockedState(t *testing.T) { AttrsJSON: []byte(`{"id":"bar"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) }) statePath := testStateFile(t, state) @@ -245,7 +245,7 @@ func TestTaint_missing(t *testing.T) { AttrsJSON: []byte(`{"id":"bar"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) }) statePath := testStateFile(t, state) @@ -278,7 +278,7 @@ func TestTaint_missingAllow(t *testing.T) { AttrsJSON: []byte(`{"id":"bar"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) }) statePath := testStateFile(t, state) @@ -354,7 +354,7 @@ func TestTaint_module(t *testing.T) { AttrsJSON: []byte(`{"id":"bar"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) s.SetResourceInstanceCurrent( addrs.Resource{ @@ -366,7 +366,7 @@ func TestTaint_module(t *testing.T) { AttrsJSON: []byte(`{"id":"blah"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) }) statePath := testStateFile(t, state) diff --git a/command/untaint_test.go b/command/untaint_test.go index c5f7275f1b..b568c94570 100644 --- a/command/untaint_test.go +++ b/command/untaint_test.go @@ -23,7 +23,7 @@ func TestUntaint(t *testing.T) { AttrsJSON: []byte(`{"id":"bar"}`), Status: states.ObjectTainted, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) }) statePath := testStateFile(t, state) @@ -63,7 +63,7 @@ func TestUntaint_lockedState(t *testing.T) { AttrsJSON: []byte(`{"id":"bar"}`), Status: states.ObjectTainted, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) }) statePath := testStateFile(t, state) @@ -271,7 +271,7 @@ func TestUntaint_missing(t *testing.T) { AttrsJSON: []byte(`{"id":"bar"}`), Status: states.ObjectTainted, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) }) statePath := testStateFile(t, state) @@ -304,7 +304,7 @@ func TestUntaint_missingAllow(t *testing.T) { AttrsJSON: []byte(`{"id":"bar"}`), Status: states.ObjectTainted, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) }) statePath := testStateFile(t, state) @@ -389,7 +389,7 @@ func TestUntaint_module(t *testing.T) { AttrsJSON: []byte(`{"id":"bar"}`), Status: states.ObjectTainted, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) s.SetResourceInstanceCurrent( addrs.Resource{ @@ -401,7 +401,7 @@ func TestUntaint_module(t *testing.T) { AttrsJSON: []byte(`{"id":"bar"}`), Status: states.ObjectTainted, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) }) statePath := testStateFile(t, state) diff --git a/command/workspace_command_test.go b/command/workspace_command_test.go index ea645e0062..2069486c03 100644 --- a/command/workspace_command_test.go +++ b/command/workspace_command_test.go @@ -241,7 +241,7 @@ func TestWorkspace_createWithState(t *testing.T) { AttrsJSON: []byte(`{"id":"bar"}`), Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) }) diff --git a/configs/config.go b/configs/config.go index cc10fb9c4c..cde0014c90 100644 --- a/configs/config.go +++ b/configs/config.go @@ -191,11 +191,11 @@ func (c *Config) gatherProviderTypes(m map[string]struct{}) { } for _, rc := range c.Module.ManagedResources { providerAddr := rc.ProviderConfigAddr() - m[providerAddr.Type] = struct{}{} + m[providerAddr.Type.LegacyString()] = struct{}{} } for _, rc := range c.Module.DataResources { providerAddr := rc.ProviderConfigAddr() - m[providerAddr.Type] = struct{}{} + m[providerAddr.Type.LegacyString()] = struct{}{} } // Must also visit our child modules, recursively. diff --git a/configs/provider.go b/configs/provider.go index 17754a669d..169f897bfb 100644 --- a/configs/provider.go +++ b/configs/provider.go @@ -95,7 +95,7 @@ func decodeProviderBlock(block *hcl.Block) (*Provider, hcl.Diagnostics) { // to its containing module. func (p *Provider) Addr() addrs.ProviderConfig { return addrs.ProviderConfig{ - Type: p.Name, + Type: addrs.NewLegacyProvider(p.Name), Alias: p.Alias, } } diff --git a/configs/provisioner.go b/configs/provisioner.go index 47b6567918..bbc6de993a 100644 --- a/configs/provisioner.go +++ b/configs/provisioner.go @@ -50,6 +50,11 @@ func decodeProvisionerBlock(block *hcl.Block) (*Provisioner, hcl.Diagnostics) { } } + // destroy provisioners can only refer to self + if pv.When == ProvisionerWhenDestroy { + diags = append(diags, onlySelfRefs(config)...) + } + if attr, exists := content.Attributes["on_failure"]; exists { expr, shimDiags := shimTraversalInString(attr.Expr, true) diags = append(diags, shimDiags...) @@ -85,8 +90,11 @@ func decodeProvisionerBlock(block *hcl.Block) (*Provisioner, hcl.Diagnostics) { } seenConnection = block - //conn, connDiags := decodeConnectionBlock(block) - //diags = append(diags, connDiags...) + // destroy provisioners can only refer to self + if pv.When == ProvisionerWhenDestroy { + diags = append(diags, onlySelfRefs(block.Body)...) + } + pv.Connection = &Connection{ Config: block.Body, DeclRange: block.DefRange, @@ -107,6 +115,52 @@ func decodeProvisionerBlock(block *hcl.Block) (*Provisioner, hcl.Diagnostics) { return pv, diags } +func onlySelfRefs(body hcl.Body) hcl.Diagnostics { + var diags hcl.Diagnostics + + // Provisioners currently do not use any blocks in their configuration. + // Blocks are likely to remain solely for meta parameters, but in the case + // that blocks are supported for provisioners, we will want to extend this + // to find variables in nested blocks. + attrs, _ := body.JustAttributes() + for _, attr := range attrs { + for _, v := range attr.Expr.Variables() { + valid := false + switch v.RootName() { + case "self": + valid = true + case "count": + // count must use "index" + if len(v) == 2 { + if t, ok := v[1].(hcl.TraverseAttr); ok && t.Name == "index" { + valid = true + } + } + + case "each": + if len(v) == 2 { + if t, ok := v[1].(hcl.TraverseAttr); ok && t.Name == "key" { + valid = true + } + } + } + + if !valid { + diags = append(diags, &hcl.Diagnostic{ + Severity: hcl.DiagWarning, + Summary: "External references from destroy provisioners are deprecated", + Detail: "Destroy-time provisioners and their connection configurations may only " + + "reference attributes of the related resource, via 'self', 'count.index', " + + "or 'each.key'.\n\nReferences to other resources during the destroy phase " + + "can cause dependency cycles and interact poorly with create_before_destroy.", + Subject: attr.Expr.Range().Ptr(), + }) + } + } + } + return diags +} + // Connection represents a "connection" block when used within either a // "resource" or "provisioner" block in a module or file. type Connection struct { diff --git a/configs/resource.go b/configs/resource.go index 4d5506e293..7ca73ff1ac 100644 --- a/configs/resource.go +++ b/configs/resource.go @@ -70,7 +70,7 @@ func (r *Resource) ProviderConfigAddr() addrs.ProviderConfig { } return addrs.ProviderConfig{ - Type: r.ProviderConfigRef.Name, + Type: addrs.NewLegacyProvider(r.ProviderConfigRef.Name), Alias: r.ProviderConfigRef.Alias, } } @@ -273,6 +273,17 @@ func decodeResourceBlock(block *hcl.Block) (*Resource, hcl.Diagnostics) { } } + // Now we can validate the connection block references if there are any destroy provisioners. + // TODO: should we eliminate standalone connection blocks? + if r.Managed.Connection != nil { + for _, p := range r.Managed.Provisioners { + if p.When == ProvisionerWhenDestroy { + diags = append(diags, onlySelfRefs(r.Managed.Connection.Config)...) + break + } + } + } + return r, diags } @@ -436,7 +447,7 @@ func decodeProviderConfigRef(expr hcl.Expression, argName string) (*ProviderConf // location information and keeping just the addressing information. func (r *ProviderConfigRef) Addr() addrs.ProviderConfig { return addrs.ProviderConfig{ - Type: r.Name, + Type: addrs.NewLegacyProvider(r.Name), Alias: r.Alias, } } diff --git a/configs/testdata/warning-files/destroy-provisioners.tf b/configs/testdata/warning-files/destroy-provisioners.tf new file mode 100644 index 0000000000..ff950bc7fb --- /dev/null +++ b/configs/testdata/warning-files/destroy-provisioners.tf @@ -0,0 +1,40 @@ +locals { + user = "name" +} + +resource "null_resource" "a" { + connection { + host = self.hostname + user = local.user # WARNING: External references from destroy provisioners are deprecated + } + + provisioner "remote-exec" { + when = destroy + index = count.index + key = each.key + + } +} + +resource "null_resource" "b" { + connection { + host = self.hostname + # this is OK since there is no destroy provisioner + user = local.user + } + + provisioner "remote-exec" { + } +} + +resource "null_resource" "b" { + provisioner "remote-exec" { + when = destroy + connection { + host = self.hostname + user = local.user # WARNING: External references from destroy provisioners are deprecated + } + + command = "echo ${local.name}" # WARNING: External references from destroy provisioners are deprecated + } +} diff --git a/go.mod b/go.mod index aa7d2056aa..e3eb4beadc 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,6 @@ require ( cloud.google.com/go v0.45.1 github.com/Azure/azure-sdk-for-go v36.2.0+incompatible github.com/Azure/go-autorest/autorest v0.9.2 - github.com/Azure/go-autorest/autorest/adal v0.8.1-0.20191028180845-3492b2aff503 github.com/Unknwon/com v0.0.0-20151008135407-28b053d5a292 // indirect github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af // indirect github.com/agext/levenshtein v1.2.2 @@ -86,7 +85,6 @@ require ( github.com/keybase/go-crypto v0.0.0-20161004153544-93f5b35093ba // indirect github.com/lib/pq v1.0.0 github.com/lusis/go-artifactory v0.0.0-20160115162124-7e4ce345df82 - github.com/marstr/guid v1.1.0 // indirect github.com/masterzen/winrm v0.0.0-20190223112901-5e5c9a7fe54b github.com/mattn/go-colorable v0.1.1 github.com/mattn/go-shellwords v1.0.4 diff --git a/go.sum b/go.sum index 4508c73528..57054a77c3 100644 --- a/go.sum +++ b/go.sum @@ -7,14 +7,9 @@ cloud.google.com/go v0.45.1 h1:lRi0CHyU+ytlvylOlFKKq0af6JncuyoRh1J+QJBqQx0= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -github.com/Azure/azure-sdk-for-go v21.3.0+incompatible h1:YFvAka2WKAl2xnJkYV1e1b7E2z88AgFszDzWU18ejMY= -github.com/Azure/azure-sdk-for-go v21.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v36.2.0+incompatible h1:09cv2WoH0g6jl6m2iT+R9qcIPZKhXEL0sbmLhxP895s= github.com/Azure/azure-sdk-for-go v36.2.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/go-autorest v10.15.4+incompatible h1:q+DRrRdbCnkY7f2WxQBx58TwCGkEdMAK/hkZ10g0Pzk= -github.com/Azure/go-autorest v10.15.4+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest v13.3.0+incompatible h1:8Ix0VdeOllBx9jEcZ2Wb1uqWUpE1awmJiaHztwaJCPk= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= github.com/Azure/go-autorest/autorest v0.9.2 h1:6AWuh3uWrsZJcNoCHrCF/+g4aKPCU39kaMO6/qrnK/4= github.com/Azure/go-autorest/autorest v0.9.2/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= @@ -30,6 +25,7 @@ github.com/Azure/go-autorest/autorest/date v0.2.0 h1:yW+Zlqf26583pE43KhfnhFcdmSW github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.3.0 h1:qJumjCaCudz+OcqE9/XtEPfvtOjOmKaui4EOpFI6zZc= github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= github.com/Azure/go-autorest/autorest/to v0.3.0 h1:zebkZaadz7+wIQYgC7GXaz3Wb28yKYfVkkBKwc38VF8= github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= @@ -121,8 +117,6 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dimchansky/utfbom v1.0.0 h1:fGC2kkf4qOoKqZ4q7iIh+Vef4ubC1c38UDsEyZynZPc= -github.com/dimchansky/utfbom v1.0.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= github.com/dimchansky/utfbom v1.1.0 h1:FcM3g+nofKgUteL8dm/UpdRXNC9KmADgTpLKsu0TRo4= github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= github.com/dnaeon/go-vcr v0.0.0-20180920040454-5637cf3d8a31 h1:Dzuw9GtbmllUqEcoHfScT9YpKFUssSiZ5PgZkIGf/YQ= @@ -199,8 +193,6 @@ github.com/hashicorp/consul v0.0.0-20171026175957-610f3c86a089/go.mod h1:mFrjN1m github.com/hashicorp/errwrap v0.0.0-20180715044906-d6c0cd880357/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-azure-helpers v0.0.0-20190129193224-166dfd221bb2 h1:VBRx+yPYUZaobnn5ANBcOUf4hhWpTHSQgftG4TcDkhI= -github.com/hashicorp/go-azure-helpers v0.0.0-20190129193224-166dfd221bb2/go.mod h1:lu62V//auUow6k0IykxLK2DCNW8qTmpm8KqhYVWattA= github.com/hashicorp/go-azure-helpers v0.10.0 h1:KhjDnQhCqEMKlt4yH00MCevJQPJ6LkHFdSveXINO6vE= github.com/hashicorp/go-azure-helpers v0.10.0/go.mod h1:YuAtHxm2v74s+IjQwUG88dHBJPd5jL+cXr5BGVzSKhE= github.com/hashicorp/go-checkpoint v0.5.0 h1:MFYpPZCnQqQTE18jFwSII6eUQrD/oxMFp3mlgcqk5mU= @@ -301,8 +293,6 @@ github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lusis/go-artifactory v0.0.0-20160115162124-7e4ce345df82 h1:wnfcqULT+N2seWf6y4yHzmi7GD2kNx4Ute0qArktD48= github.com/lusis/go-artifactory v0.0.0-20160115162124-7e4ce345df82/go.mod h1:y54tfGmO3NKssKveTEFFzH8C/akrSOy/iW9qEAUDV84= -github.com/marstr/guid v1.1.0 h1:/M4H/1G4avsieL6BbUwCOBzulmoeKVP5ux/3mQNnbyI= -github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= github.com/masterzen/simplexml v0.0.0-20160608183007-4572e39b1ab9 h1:SmVbOZFWAlyQshuMfOkiAx1f5oUTsOGG5IXplAEYeeM= github.com/masterzen/simplexml v0.0.0-20160608183007-4572e39b1ab9/go.mod h1:kCEbxUJlNDEBNbdQMkPSp6yaKcRXVI6f4ddk8Riv4bc= github.com/masterzen/winrm v0.0.0-20190223112901-5e5c9a7fe54b h1:/1RFh2SLCJ+tEnT73+Fh5R2AO89sQqs8ba7o+hx1G0Y= @@ -442,7 +432,6 @@ go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/ go.uber.org/zap v1.9.1 h1:XCJQEf3W6eZaVwhRBof6ImoYGJSITeKWsyeh3HFu/5o= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190222235706-ffb98f73852f/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= diff --git a/helper/logging/indent.go b/helper/logging/indent.go new file mode 100644 index 0000000000..e0da0d7c73 --- /dev/null +++ b/helper/logging/indent.go @@ -0,0 +1,23 @@ +package logging + +import ( + "strings" +) + +// Indent adds two spaces to the beginning of each line of the given string, +// with the goal of making the log level filter understand it as a line +// continuation rather than possibly as new log lines. +func Indent(s string) string { + var b strings.Builder + for len(s) > 0 { + end := strings.IndexByte(s, '\n') + if end == -1 { + end = len(s) - 1 + } + var l string + l, s = s[:end+1], s[end+1:] + b.WriteString(" ") + b.WriteString(l) + } + return b.String() +} diff --git a/helper/logging/indent_test.go b/helper/logging/indent_test.go new file mode 100644 index 0000000000..46b12a42ca --- /dev/null +++ b/helper/logging/indent_test.go @@ -0,0 +1,15 @@ +package logging + +import ( + "testing" +) + +func TestIndent(t *testing.T) { + s := "hello\n world\ngoodbye\n moon" + got := Indent(s) + want := " hello\n world\n goodbye\n moon" + + if got != want { + t.Errorf("wrong result\ngot:\n%s\n\nwant:\n%s", got, want) + } +} diff --git a/helper/logging/level.go b/helper/logging/level.go new file mode 100644 index 0000000000..0dc4dfe8d5 --- /dev/null +++ b/helper/logging/level.go @@ -0,0 +1,159 @@ +package logging + +import ( + "bytes" + "io" + "sync" +) + +// LogLevel is a special string, conventionally written all in uppercase, that +// can be used to mark a log line for filtering and to specify filtering +// levels in the LevelFilter type. +type LogLevel string + +// LevelFilter is an io.Writer that can be used with a logger that +// will attempt to filter out log messages that aren't at least a certain +// level. +// +// This filtering is HEURISTIC-BASED, and so will not be 100% reliable. The +// assumptions it makes are: +// +// - Individual log messages are never split across multiple calls to the +// Write method. +// +// - Messages that carry levels are marked by a sequence starting with "[", +// then the level name string, and then "]". Any message without a sequence +// like this is an un-levelled message, and is not subject to filtering. +// +// - Each \n-delimited line in a write is a separate log message, unless a +// line starts with at least one space in which case it is interpreted +// as a continuation of the previous line. +// +// - If a log line starts with a non-whitespace character that isn't a digit +// then it's recognized as a degenerate continuation, because "real" log +// lines should start with a date/time and thus always have a leading +// digit. (This also cleans up after some situations where the assumptuion +// that messages arrive atomically aren't met, which is sadly sometimes +// true for longer messages that trip over some buffering behavior in +// panicwrap.) +// +// Because logging is a cross-cutting concern and not fully under the control +// of Terraform itself, there will certainly be cases where the above +// heuristics will fail. For example, it is likely that LevelFilter will +// occasionally misinterpret a continuation line as a new message because the +// code generating it doesn't know about our indentation convention. +// +// Our goal here is just to make a best effort to reduce the log volume, +// accepting that the results will not be 100% correct. +// +// Logging calls within Terraform Core should follow the above conventions so +// that the log output is broadly correct, however. +// +// Once the filter is in use somewhere, it is not safe to modify +// the structure. +type LevelFilter struct { + // Levels is the list of log levels, in increasing order of + // severity. Example might be: {"DEBUG", "WARN", "ERROR"}. + Levels []LogLevel + + // MinLevel is the minimum level allowed through + MinLevel LogLevel + + // The underlying io.Writer where log messages that pass the filter + // will be set. + Writer io.Writer + + badLevels map[LogLevel]struct{} + show bool + once sync.Once +} + +// Check will check a given line if it would be included in the level +// filter. +func (f *LevelFilter) Check(line []byte) bool { + f.once.Do(f.init) + + // Check for a log level + var level LogLevel + x := bytes.IndexByte(line, '[') + if x >= 0 { + y := bytes.IndexByte(line[x:], ']') + if y >= 0 { + level = LogLevel(line[x+1 : x+y]) + } + } + + //return level == "" + + _, ok := f.badLevels[level] + return !ok +} + +// Write is a specialized implementation of io.Writer suitable for being +// the output of a logger from the "log" package. +// +// This Writer implementation assumes that it will only recieve byte slices +// containing one or more entire lines of log output, each one terminated by +// a newline. This is compatible with the behavior of the "log" package +// directly, and is also tolerant of intermediaries that might buffer multiple +// separate writes together, as long as no individual log line is ever +// split into multiple slices. +// +// Behavior is undefined if any log line is split across multiple writes or +// written without a trailing '\n' delimiter. +func (f *LevelFilter) Write(p []byte) (n int, err error) { + for len(p) > 0 { + // Split at the first \n, inclusive + idx := bytes.IndexByte(p, '\n') + if idx == -1 { + // Invalid, undelimited write. We'll tolerate it assuming that + // our assumptions are being violated, but the results may be + // non-ideal. + idx = len(p) - 1 + break + } + var l []byte + l, p = p[:idx+1], p[idx+1:] + // Lines starting with characters other than decimal digits (including + // whitespace) are assumed to be continuations lines. This is an + // imprecise heuristic, but experimentally it seems to generate + // "good enough" results from Terraform Core's own logging. Its mileage + // may vary with output from other systems. + if l[0] >= '0' && l[0] <= '9' { + f.show = f.Check(l) + } + if f.show { + _, err = f.Writer.Write(l) + if err != nil { + // Technically it's not correct to say we've written the whole + // buffer, but for our purposes here it's good enough as we're + // only implementing io.Writer enough to satisfy logging + // use-cases. + return len(p), err + } + } + } + + // We always behave as if we wrote the whole of the buffer, even if + // we actually skipped some lines. We're only implementiong io.Writer + // enough to satisfy logging use-cases. + return len(p), nil +} + +// SetMinLevel is used to update the minimum log level +func (f *LevelFilter) SetMinLevel(min LogLevel) { + f.MinLevel = min + f.init() +} + +func (f *LevelFilter) init() { + badLevels := make(map[LogLevel]struct{}) + for _, level := range f.Levels { + if level == f.MinLevel { + break + } + badLevels[level] = struct{}{} + } + f.badLevels = badLevels + f.show = true +} diff --git a/helper/logging/level_test.go b/helper/logging/level_test.go new file mode 100644 index 0000000000..baa94748e4 --- /dev/null +++ b/helper/logging/level_test.go @@ -0,0 +1,93 @@ +package logging + +import ( + "bytes" + "io" + "log" + "testing" +) + +func TestLevelFilter_impl(t *testing.T) { + var _ io.Writer = new(LevelFilter) +} + +func TestLevelFilter(t *testing.T) { + buf := new(bytes.Buffer) + filter := &LevelFilter{ + Levels: []LogLevel{"DEBUG", "WARN", "ERROR"}, + MinLevel: "WARN", + Writer: buf, + } + + logger := log.New(filter, "", 0) + logger.Print("2019/01/01 00:00:00 [WARN] foo") + logger.Println("2019/01/01 00:00:00 [ERROR] bar\n2019/01/01 00:00:00 [DEBUG] buzz") + logger.Println("2019/01/01 00:00:00 [DEBUG] baz\n continuation\n2019/01/01 00:00:00 [WARN] buzz\n more\n2019/01/01 00:00:00 [DEBUG] fizz") + + result := buf.String() + expected := "2019/01/01 00:00:00 [WARN] foo\n2019/01/01 00:00:00 [ERROR] bar\n2019/01/01 00:00:00 [WARN] buzz\n more\n" + if result != expected { + t.Fatalf("wrong result\ngot:\n%s\nwant:\n%s", result, expected) + } +} + +func TestLevelFilterCheck(t *testing.T) { + filter := &LevelFilter{ + Levels: []LogLevel{"DEBUG", "WARN", "ERROR"}, + MinLevel: "WARN", + Writer: nil, + } + + testCases := []struct { + line string + check bool + }{ + {"[WARN] foo\n", true}, + {"[ERROR] bar\n", true}, + {"[DEBUG] baz\n", false}, + {"[WARN] buzz\n", true}, + } + + for _, testCase := range testCases { + result := filter.Check([]byte(testCase.line)) + if result != testCase.check { + t.Errorf("Fail: %s", testCase.line) + } + } +} + +func TestLevelFilter_SetMinLevel(t *testing.T) { + filter := &LevelFilter{ + Levels: []LogLevel{"DEBUG", "WARN", "ERROR"}, + MinLevel: "ERROR", + Writer: nil, + } + + testCases := []struct { + line string + checkBefore bool + checkAfter bool + }{ + {"[WARN] foo\n", false, true}, + {"[ERROR] bar\n", true, true}, + {"[DEBUG] baz\n", false, false}, + {"[WARN] buzz\n", false, true}, + } + + for _, testCase := range testCases { + result := filter.Check([]byte(testCase.line)) + if result != testCase.checkBefore { + t.Errorf("Fail: %s", testCase.line) + } + } + + // Update the minimum level to WARN + filter.SetMinLevel("WARN") + + for _, testCase := range testCases { + result := filter.Check([]byte(testCase.line)) + if result != testCase.checkAfter { + t.Errorf("Fail: %s", testCase.line) + } + } +} diff --git a/helper/logging/logging.go b/helper/logging/logging.go index 6bd92f7778..75627cf02e 100644 --- a/helper/logging/logging.go +++ b/helper/logging/logging.go @@ -7,8 +7,6 @@ import ( "os" "strings" "syscall" - - "github.com/hashicorp/logutils" ) // These are the environmental variables that determine if we log, and if @@ -18,13 +16,14 @@ const ( EnvLogFile = "TF_LOG_PATH" // Set to a file ) -var ValidLevels = []logutils.LogLevel{"TRACE", "DEBUG", "INFO", "WARN", "ERROR"} +// ValidLevels are the log level names that Terraform recognizes. +var ValidLevels = []LogLevel{"TRACE", "DEBUG", "INFO", "WARN", "ERROR"} // LogOutput determines where we should send logs (if anywhere) and the log level. func LogOutput() (logOutput io.Writer, err error) { logOutput = ioutil.Discard - logLevel := LogLevel() + logLevel := CurrentLogLevel() if logLevel == "" { return } @@ -38,14 +37,21 @@ func LogOutput() (logOutput io.Writer, err error) { } } - // This was the default since the beginning - logOutput = &logutils.LevelFilter{ + if logLevel == "TRACE" { + // Just pass through logs directly then, without any level filtering at all. + return logOutput, nil + } + + // Otherwise we'll use our level filter, which is a heuristic-based + // best effort thing that is not totally reliable but helps to reduce + // the volume of logs in some cases. + logOutput = &LevelFilter{ Levels: ValidLevels, - MinLevel: logutils.LogLevel(logLevel), + MinLevel: LogLevel(logLevel), Writer: logOutput, } - return + return logOutput, nil } // SetOutput checks for a log destination with LogOutput, and calls @@ -64,8 +70,8 @@ func SetOutput() { log.SetOutput(out) } -// LogLevel returns the current log level string based the environment vars -func LogLevel() string { +// CurrentLogLevel returns the current log level string based the environment vars +func CurrentLogLevel() string { envLevel := os.Getenv(EnvLog) if envLevel == "" { return "" @@ -79,13 +85,16 @@ func LogLevel() string { log.Printf("[WARN] Invalid log level: %q. Defaulting to level: TRACE. Valid levels are: %+v", envLevel, ValidLevels) } + if logLevel != "TRACE" { + log.Printf("[WARN] Log levels other than TRACE are currently unreliable, and are supported only for backward compatibility.\n Use TF_LOG=TRACE to see Terraform's internal logs.\n ----") + } return logLevel } // IsDebugOrHigher returns whether or not the current log level is debug or trace func IsDebugOrHigher() bool { - level := string(LogLevel()) + level := string(CurrentLogLevel()) return level == "DEBUG" || level == "TRACE" } diff --git a/helper/resource/state_shim.go b/helper/resource/state_shim.go index afd60b318a..257109d3b6 100644 --- a/helper/resource/state_shim.go +++ b/helper/resource/state_shim.go @@ -50,7 +50,7 @@ func shimNewState(newState *states.State, providers map[string]terraform.Resourc resType := res.Addr.Type providerType := res.ProviderConfig.ProviderConfig.Type - resource := getResource(providers, providerType, res.Addr) + resource := getResource(providers, providerType.LegacyString(), res.Addr) for key, i := range res.Instances { resState := &terraform.ResourceState{ diff --git a/helper/resource/state_shim_test.go b/helper/resource/state_shim_test.go index a9c101a45c..af85b3906d 100644 --- a/helper/resource/state_shim_test.go +++ b/helper/resource/state_shim_test.go @@ -42,7 +42,7 @@ func TestStateShim(t *testing.T) { }, }, addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance), ) rootModule.SetResourceInstanceCurrent( @@ -57,7 +57,7 @@ func TestStateShim(t *testing.T) { DependsOn: []addrs.Referenceable{}, }, addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance), ) @@ -75,7 +75,7 @@ func TestStateShim(t *testing.T) { DependsOn: []addrs.Referenceable{}, }, addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(childInstance), ) childModule.SetResourceInstanceCurrent( @@ -98,7 +98,7 @@ func TestStateShim(t *testing.T) { }, }, addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(childInstance), ) @@ -123,7 +123,7 @@ func TestStateShim(t *testing.T) { }, }, addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(childInstance), ) @@ -139,7 +139,7 @@ func TestStateShim(t *testing.T) { DependsOn: []addrs.Referenceable{}, }, addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(childInstance), ) childModule.SetResourceInstanceCurrent( @@ -154,7 +154,7 @@ func TestStateShim(t *testing.T) { DependsOn: []addrs.Referenceable{}, }, addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(childInstance), ) @@ -170,7 +170,7 @@ func TestStateShim(t *testing.T) { DependsOn: []addrs.Referenceable{}, }, addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(childInstance), ) diff --git a/helper/resource/testing.go b/helper/resource/testing.go index 26ea72a8df..1119144b4d 100644 --- a/helper/resource/testing.go +++ b/helper/resource/testing.go @@ -18,7 +18,6 @@ import ( "github.com/davecgh/go-spew/spew" "github.com/hashicorp/errwrap" "github.com/hashicorp/go-multierror" - "github.com/hashicorp/logutils" "github.com/mitchellh/colorstring" "github.com/hashicorp/terraform/addrs" @@ -396,7 +395,7 @@ const EnvLogPathMask = "TF_LOG_PATH_MASK" func LogOutput(t TestT) (logOutput io.Writer, err error) { logOutput = ioutil.Discard - logLevel := logging.LogLevel() + logLevel := logging.CurrentLogLevel() if logLevel == "" { return } @@ -424,9 +423,9 @@ func LogOutput(t TestT) (logOutput io.Writer, err error) { } // This was the default since the beginning - logOutput = &logutils.LevelFilter{ + logOutput = &logging.LevelFilter{ Levels: logging.ValidLevels, - MinLevel: logutils.LogLevel(logLevel), + MinLevel: logging.LogLevel(logLevel), Writer: logOutput, } @@ -728,7 +727,7 @@ func testIDOnlyRefresh(c TestCase, opts terraform.ContextOpts, step TestStep, r AttrsFlat: r.Primary.Attributes, Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "placeholder"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("placeholder")}.Absolute(addrs.RootModuleInstance), ) // Create the config module. We use the full config because Refresh diff --git a/helper/resource/testing_import_state.go b/helper/resource/testing_import_state.go index 1f3796176f..9a3ef1be02 100644 --- a/helper/resource/testing_import_state.go +++ b/helper/resource/testing_import_state.go @@ -137,7 +137,7 @@ func testStepImportState( // this shouldn't happen in any reasonable case. var rsrcSchema *schema.Resource if providerAddr, diags := addrs.ParseAbsProviderConfigStr(r.Provider); !diags.HasErrors() { - providerType := providerAddr.ProviderConfig.Type + providerType := providerAddr.ProviderConfig.Type.LegacyString() if provider, ok := step.providers[providerType]; ok { if provider, ok := provider.(*schema.Provider); ok { rsrcSchema = provider.ResourcesMap[r.Type] diff --git a/plans/plan_test.go b/plans/plan_test.go index f68357072f..0fa2361dff 100644 --- a/plans/plan_test.go +++ b/plans/plan_test.go @@ -21,7 +21,7 @@ func TestProviderAddrs(t *testing.T) { Name: "woot", }.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance), ProviderAddr: addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance), }, { @@ -32,7 +32,7 @@ func TestProviderAddrs(t *testing.T) { }.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance), DeposedKey: "foodface", ProviderAddr: addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance), }, { @@ -42,7 +42,7 @@ func TestProviderAddrs(t *testing.T) { Name: "what", }.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance), ProviderAddr: addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance.Child("foo", addrs.NoKey)), }, }, @@ -52,10 +52,10 @@ func TestProviderAddrs(t *testing.T) { got := plan.ProviderAddrs() want := []addrs.AbsProviderConfig{ addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance.Child("foo", addrs.NoKey)), addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance), } diff --git a/plans/planfile/tfplan_test.go b/plans/planfile/tfplan_test.go index 2b49553acd..931e223409 100644 --- a/plans/planfile/tfplan_test.go +++ b/plans/planfile/tfplan_test.go @@ -57,7 +57,7 @@ func TestTFPlanRoundTrip(t *testing.T) { Name: "woot", }.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance), ProviderAddr: addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance), ChangeSrc: plans.ChangeSrc{ Action: plans.DeleteThenCreate, @@ -77,7 +77,7 @@ func TestTFPlanRoundTrip(t *testing.T) { }.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance), DeposedKey: "foodface", ProviderAddr: addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance), ChangeSrc: plans.ChangeSrc{ Action: plans.Delete, @@ -195,7 +195,7 @@ func TestTFPlanRoundTripDestroy(t *testing.T) { Name: "woot", }.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance), ProviderAddr: addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance), ChangeSrc: plans.ChangeSrc{ Action: plans.Delete, diff --git a/providers/addressed_types.go b/providers/addressed_types.go index 7ed523f158..46bb80b602 100644 --- a/providers/addressed_types.go +++ b/providers/addressed_types.go @@ -14,7 +14,7 @@ func AddressedTypes(providerAddrs []addrs.ProviderConfig) []string { } m := map[string]struct{}{} for _, addr := range providerAddrs { - m[addr.Type] = struct{}{} + m[addr.Type.LegacyString()] = struct{}{} } names := make([]string, 0, len(m)) @@ -34,7 +34,7 @@ func AddressedTypesAbs(providerAddrs []addrs.AbsProviderConfig) []string { } m := map[string]struct{}{} for _, addr := range providerAddrs { - m[addr.ProviderConfig.Type] = struct{}{} + m[addr.ProviderConfig.Type.LegacyString()] = struct{}{} } names := make([]string, 0, len(m)) diff --git a/providers/addressed_types_test.go b/providers/addressed_types_test.go index 80915e3e68..407b83510b 100644 --- a/providers/addressed_types_test.go +++ b/providers/addressed_types_test.go @@ -10,11 +10,11 @@ import ( func TestAddressedTypes(t *testing.T) { providerAddrs := []addrs.ProviderConfig{ - {Type: "aws"}, - {Type: "aws", Alias: "foo"}, - {Type: "azure"}, - {Type: "null"}, - {Type: "null"}, + {Type: addrs.NewLegacyProvider("aws")}, + {Type: addrs.NewLegacyProvider("aws"), Alias: "foo"}, + {Type: addrs.NewLegacyProvider("azure")}, + {Type: addrs.NewLegacyProvider("null")}, + {Type: addrs.NewLegacyProvider("null")}, } got := AddressedTypes(providerAddrs) @@ -30,11 +30,11 @@ func TestAddressedTypes(t *testing.T) { func TestAddressedTypesAbs(t *testing.T) { providerAddrs := []addrs.AbsProviderConfig{ - addrs.ProviderConfig{Type: "aws"}.Absolute(addrs.RootModuleInstance), - addrs.ProviderConfig{Type: "aws", Alias: "foo"}.Absolute(addrs.RootModuleInstance), - addrs.ProviderConfig{Type: "azure"}.Absolute(addrs.RootModuleInstance), - addrs.ProviderConfig{Type: "null"}.Absolute(addrs.RootModuleInstance), - addrs.ProviderConfig{Type: "null"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("aws")}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("aws"), Alias: "foo"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("azure")}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("null")}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("null")}.Absolute(addrs.RootModuleInstance), } got := AddressedTypesAbs(providerAddrs) diff --git a/repl/session_test.go b/repl/session_test.go index 0d2f37326d..3ee9bf17a8 100644 --- a/repl/session_test.go +++ b/repl/session_test.go @@ -46,7 +46,7 @@ func TestSession_basicState(t *testing.T) { AttrsJSON: []byte(`{"id":"bar"}`), }, addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance), ) s.SetResourceInstanceCurrent( @@ -60,7 +60,7 @@ func TestSession_basicState(t *testing.T) { AttrsJSON: []byte(`{"id":"bar"}`), }, addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance), ) }) diff --git a/states/state_test.go b/states/state_test.go index 22a43859f1..7b33f034ff 100644 --- a/states/state_test.go +++ b/states/state_test.go @@ -36,7 +36,7 @@ func TestState(t *testing.T) { AttrsJSON: []byte(`{"woozles":"confuzles"}`), }, addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance), ) @@ -79,7 +79,7 @@ func TestState(t *testing.T) { }, }, ProviderConfig: addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance), }, }, @@ -141,7 +141,7 @@ func TestStateDeepCopy(t *testing.T) { Dependencies: []addrs.AbsResource{}, }, addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance), ) rootModule.SetResourceInstanceCurrent( @@ -167,7 +167,7 @@ func TestStateDeepCopy(t *testing.T) { }, }, addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance), ) diff --git a/terraform/context_apply_test.go b/terraform/context_apply_test.go index 7fc9f36821..6c20625725 100644 --- a/terraform/context_apply_test.go +++ b/terraform/context_apply_test.go @@ -1371,7 +1371,7 @@ func TestContext2Apply_destroyDependsOnStateOnly(t *testing.T) { Dependencies: []addrs.AbsResource{}, }, addrs.ProviderConfig{ - Type: "aws", + Type: addrs.NewLegacyProvider("aws"), }.Absolute(addrs.RootModuleInstance), ) root.SetResourceInstanceCurrent( @@ -1395,7 +1395,7 @@ func TestContext2Apply_destroyDependsOnStateOnly(t *testing.T) { }, }, addrs.ProviderConfig{ - Type: "aws", + Type: addrs.NewLegacyProvider("aws"), }.Absolute(addrs.RootModuleInstance), ) @@ -1498,7 +1498,7 @@ func TestContext2Apply_destroyDependsOnStateOnlyModule(t *testing.T) { Dependencies: []addrs.AbsResource{}, }, addrs.ProviderConfig{ - Type: "aws", + Type: addrs.NewLegacyProvider("aws"), }.Absolute(addrs.RootModuleInstance), ) child.SetResourceInstanceCurrent( @@ -1522,7 +1522,7 @@ func TestContext2Apply_destroyDependsOnStateOnlyModule(t *testing.T) { }, }, addrs.ProviderConfig{ - Type: "aws", + Type: addrs.NewLegacyProvider("aws"), }.Absolute(addrs.RootModuleInstance), ) @@ -2145,7 +2145,7 @@ func TestContext2Apply_provisionerDestroyForEach(t *testing.T) { }, ProviderConfig: addrs.AbsProviderConfig{ Module: addrs.ModuleInstance(nil), - ProviderConfig: addrs.ProviderConfig{Type: "aws", Alias: ""}, + ProviderConfig: addrs.ProviderConfig{Type: addrs.NewLegacyProvider("aws"), Alias: ""}, }, }, }, @@ -2966,7 +2966,7 @@ func TestContext2Apply_orphanResource(t *testing.T) { // with the single instance associated with test_thing.one. want := states.BuildState(func(s *states.SyncState) { providerAddr := addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance) zeroAddr := addrs.Resource{ Mode: addrs.ManagedResourceMode, @@ -7386,7 +7386,7 @@ func TestContext2Apply_errorDestroy(t *testing.T) { AttrsJSON: []byte(`{"id":"baz"}`), }, addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance), ) }), @@ -7525,7 +7525,7 @@ func TestContext2Apply_errorUpdateNullNew(t *testing.T) { AttrsJSON: []byte(`{"value":"old"}`), }, addrs.ProviderConfig{ - Type: "aws", + Type: addrs.NewLegacyProvider("aws"), }.Absolute(addrs.RootModuleInstance), ) }), @@ -9188,7 +9188,7 @@ func TestContext2Apply_createBefore_depends(t *testing.T) { AttrsJSON: []byte(`{"id":"bar","require_new":"ami-old"}`), }, addrs.ProviderConfig{ - Type: "aws", + Type: addrs.NewLegacyProvider("aws"), }.Absolute(addrs.RootModuleInstance), ) @@ -9213,7 +9213,7 @@ func TestContext2Apply_createBefore_depends(t *testing.T) { }, }, addrs.ProviderConfig{ - Type: "aws", + Type: addrs.NewLegacyProvider("aws"), }.Absolute(addrs.RootModuleInstance), ) @@ -9319,7 +9319,7 @@ func TestContext2Apply_singleDestroy(t *testing.T) { AttrsJSON: []byte(`{"id":"bar","require_new":"ami-old"}`), }, addrs.ProviderConfig{ - Type: "aws", + Type: addrs.NewLegacyProvider("aws"), }.Absolute(addrs.RootModuleInstance), ) @@ -9344,7 +9344,7 @@ func TestContext2Apply_singleDestroy(t *testing.T) { }, }, addrs.ProviderConfig{ - Type: "aws", + Type: addrs.NewLegacyProvider("aws"), }.Absolute(addrs.RootModuleInstance), ) @@ -10262,7 +10262,7 @@ func TestContext2Apply_destroyWithProviders(t *testing.T) { // correct the state s.Modules["module.mod.module.removed"].Resources["aws_instance.child"].ProviderConfig = addrs.ProviderConfig{ - Type: "aws", + Type: addrs.NewLegacyProvider("aws"), Alias: "bar", }.Absolute(addrs.RootModuleInstance) @@ -10687,7 +10687,7 @@ func TestContext2Apply_issue19908(t *testing.T) { Status: states.ObjectReady, }, addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance), ) }), @@ -10814,7 +10814,7 @@ func TestContext2Apply_moduleReplaceCycle(t *testing.T) { AttrsJSON: []byte(`{"id":"a","require_new":"old"}`), }, addrs.ProviderConfig{ - Type: "aws", + Type: addrs.NewLegacyProvider("aws"), }.Absolute(addrs.RootModuleInstance), ) @@ -10830,7 +10830,7 @@ func TestContext2Apply_moduleReplaceCycle(t *testing.T) { AttrsJSON: []byte(`{"id":"b","require_new":"old"}`), }, addrs.ProviderConfig{ - Type: "aws", + Type: addrs.NewLegacyProvider("aws"), }.Absolute(addrs.RootModuleInstance), ) @@ -10872,7 +10872,7 @@ func TestContext2Apply_moduleReplaceCycle(t *testing.T) { Name: "a", }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance.Child("a", addrs.NoKey)), ProviderAddr: addrs.ProviderConfig{ - Type: "aws", + Type: addrs.NewLegacyProvider("aws"), }.Absolute(addrs.RootModuleInstance), ChangeSrc: plans.ChangeSrc{ Action: aAction, @@ -10887,7 +10887,7 @@ func TestContext2Apply_moduleReplaceCycle(t *testing.T) { Name: "b", }.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance.Child("b", addrs.NoKey)), ProviderAddr: addrs.ProviderConfig{ - Type: "aws", + Type: addrs.NewLegacyProvider("aws"), }.Absolute(addrs.RootModuleInstance), ChangeSrc: plans.ChangeSrc{ Action: plans.DeleteThenCreate, @@ -10937,7 +10937,7 @@ func TestContext2Apply_destroyDataCycle(t *testing.T) { AttrsJSON: []byte(`{"id":"a"}`), }, addrs.ProviderConfig{ - Type: "null", + Type: addrs.NewLegacyProvider("null"), }.Absolute(addrs.RootModuleInstance), ) root.SetResourceInstanceCurrent( @@ -10951,7 +10951,7 @@ func TestContext2Apply_destroyDataCycle(t *testing.T) { AttrsJSON: []byte(`{"id":"data"}`), }, addrs.ProviderConfig{ - Type: "null", + Type: addrs.NewLegacyProvider("null"), }.Absolute(addrs.RootModuleInstance), ) @@ -11025,7 +11025,7 @@ func TestContext2Apply_taintedDestroyFailure(t *testing.T) { AttrsJSON: []byte(`{"id":"a","foo":"a"}`), }, addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance), ) root.SetResourceInstanceCurrent( @@ -11039,7 +11039,7 @@ func TestContext2Apply_taintedDestroyFailure(t *testing.T) { AttrsJSON: []byte(`{"id":"b","foo":"b"}`), }, addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance), ) root.SetResourceInstanceCurrent( @@ -11053,7 +11053,7 @@ func TestContext2Apply_taintedDestroyFailure(t *testing.T) { AttrsJSON: []byte(`{"id":"c","foo":"old"}`), }, addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance), ) @@ -11168,7 +11168,7 @@ func TestContext2Apply_cbdCycle(t *testing.T) { }, }, addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance), ) root.SetResourceInstanceCurrent( @@ -11192,7 +11192,7 @@ func TestContext2Apply_cbdCycle(t *testing.T) { }, }, addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance), ) root.SetResourceInstanceCurrent( @@ -11206,7 +11206,7 @@ func TestContext2Apply_cbdCycle(t *testing.T) { AttrsJSON: []byte(`{"id":"c","require_new":"old"}`), }, addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance), ) diff --git a/terraform/context_components.go b/terraform/context_components.go index e824848f0b..74ab501379 100644 --- a/terraform/context_components.go +++ b/terraform/context_components.go @@ -33,16 +33,15 @@ type basicComponentFactory struct { } func (c *basicComponentFactory) ResourceProviders() []string { - result := make([]string, len(c.providers)) + var result []string for k := range c.providers { result = append(result, k.LegacyString()) } - return result } func (c *basicComponentFactory) ResourceProvisioners() []string { - result := make([]string, len(c.provisioners)) + var result []string for k := range c.provisioners { result = append(result, k) } diff --git a/terraform/context_import_test.go b/terraform/context_import_test.go index 56d60f1b97..1d94264d4b 100644 --- a/terraform/context_import_test.go +++ b/terraform/context_import_test.go @@ -115,7 +115,7 @@ func TestContextImport_collision(t *testing.T) { }, Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "aws"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("aws")}.Absolute(addrs.RootModuleInstance), ) }), }) @@ -601,7 +601,7 @@ func TestContextImport_moduleDiff(t *testing.T) { }, Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "aws"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("aws")}.Absolute(addrs.RootModuleInstance), ) }), }) @@ -659,7 +659,7 @@ func TestContextImport_moduleExisting(t *testing.T) { }, Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "aws"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("aws")}.Absolute(addrs.RootModuleInstance), ) }), }) diff --git a/terraform/context_input.go b/terraform/context_input.go index d24adcb7c2..acc42ae9b8 100644 --- a/terraform/context_input.go +++ b/terraform/context_input.go @@ -96,7 +96,7 @@ func (c *Context) Input(mode InputMode) tfdiags.Diagnostics { UIInput: c.uiInput, } - schema := c.schemas.ProviderConfig(pa.Type) + schema := c.schemas.ProviderConfig(pa.Type.LegacyString()) if schema == nil { // Could either be an incorrect config or just an incomplete // mock in tests. We'll let a later pass decide, and just diff --git a/terraform/context_input_test.go b/terraform/context_input_test.go index 5782184e90..a43b8567ed 100644 --- a/terraform/context_input_test.go +++ b/terraform/context_input_test.go @@ -478,7 +478,7 @@ func TestContext2Input_dataSourceRequiresRefresh(t *testing.T) { }, Status: states.ObjectReady, }, - addrs.ProviderConfig{Type: "null"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("null")}.Absolute(addrs.RootModuleInstance), ) }) diff --git a/terraform/context_plan_test.go b/terraform/context_plan_test.go index b069c3ec62..1710363053 100644 --- a/terraform/context_plan_test.go +++ b/terraform/context_plan_test.go @@ -4976,7 +4976,7 @@ func TestContext2Plan_ignoreChangesInMap(t *testing.T) { AttrsJSON: []byte(`{"tags":{"ignored":"from state","other":"from state"}}`), }, addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance), ) }) diff --git a/terraform/context_refresh_test.go b/terraform/context_refresh_test.go index 65e091e6c3..77c2e9c11c 100644 --- a/terraform/context_refresh_test.go +++ b/terraform/context_refresh_test.go @@ -104,7 +104,7 @@ func TestContext2Refresh_dynamicAttr(t *testing.T) { AttrsJSON: []byte(`{"dynamic":{"type":"string","value":"hello"}}`), }, addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance), ) }) @@ -1739,7 +1739,7 @@ func TestContext2Refresh_schemaUpgradeFlatmap(t *testing.T) { "id": "foo", }, }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) }) @@ -1822,7 +1822,7 @@ func TestContext2Refresh_schemaUpgradeJSON(t *testing.T) { SchemaVersion: 3, AttrsJSON: []byte(`{"id":"foo"}`), }, - addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), + addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance), ) }) @@ -1991,7 +1991,7 @@ func TestRefresh_updateDependencies(t *testing.T) { }, }, addrs.ProviderConfig{ - Type: "aws", + Type: addrs.NewLegacyProvider("aws"), }.Absolute(addrs.RootModuleInstance), ) root.SetResourceInstanceCurrent( @@ -2005,7 +2005,7 @@ func TestRefresh_updateDependencies(t *testing.T) { AttrsJSON: []byte(`{"id":"bar","foo":"foo"}`), }, addrs.ProviderConfig{ - Type: "aws", + Type: addrs.NewLegacyProvider("aws"), }.Absolute(addrs.RootModuleInstance), ) diff --git a/terraform/eval_context_builtin.go b/terraform/eval_context_builtin.go index f6531848ff..f7e9973fee 100644 --- a/terraform/eval_context_builtin.go +++ b/terraform/eval_context_builtin.go @@ -142,7 +142,7 @@ func (ctx *BuiltinEvalContext) Provider(addr addrs.AbsProviderConfig) providers. func (ctx *BuiltinEvalContext) ProviderSchema(addr addrs.AbsProviderConfig) *ProviderSchema { ctx.once.Do(ctx.init) - return ctx.Schemas.ProviderSchema(addr.ProviderConfig.Type) + return ctx.Schemas.ProviderSchema(addr.ProviderConfig.Type.LegacyString()) } func (ctx *BuiltinEvalContext) CloseProvider(addr addrs.ProviderConfig) error { diff --git a/terraform/eval_context_builtin_test.go b/terraform/eval_context_builtin_test.go index 1907d136e3..81c5ffe9cd 100644 --- a/terraform/eval_context_builtin_test.go +++ b/terraform/eval_context_builtin_test.go @@ -24,7 +24,7 @@ func TestBuiltinEvalContextProviderInput(t *testing.T) { ctx2.ProviderInputConfig = cache ctx2.ProviderLock = &lock - providerAddr := addrs.ProviderConfig{Type: "foo"} + providerAddr := addrs.ProviderConfig{Type: addrs.NewLegacyProvider("foo")} expected1 := map[string]cty.Value{"value": cty.StringVal("foo")} ctx1.SetProviderInput(providerAddr, expected1) @@ -57,8 +57,8 @@ func TestBuildingEvalContextInitProvider(t *testing.T) { }, } - providerAddrDefault := addrs.ProviderConfig{Type: "test"} - providerAddrAlias := addrs.ProviderConfig{Type: "test", Alias: "foo"} + providerAddrDefault := addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")} + providerAddrAlias := addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test"), Alias: "foo"} _, err := ctx.InitProvider("test", providerAddrDefault) if err != nil { diff --git a/terraform/eval_diff.go b/terraform/eval_diff.go index b675253e7b..cc9046c20b 100644 --- a/terraform/eval_diff.go +++ b/terraform/eval_diff.go @@ -120,7 +120,7 @@ func (n *EvalDiff) Eval(ctx EvalContext) (interface{}, error) { if providerSchema == nil { return nil, fmt.Errorf("provider schema is unavailable for %s", n.Addr) } - if n.ProviderAddr.ProviderConfig.Type == "" { + if n.ProviderAddr.ProviderConfig.Type.LegacyString() == "" { panic(fmt.Sprintf("EvalDiff for %s does not have ProviderAddr set", n.Addr.Absolute(ctx.Path()))) } @@ -603,7 +603,7 @@ func (n *EvalDiffDestroy) Eval(ctx EvalContext) (interface{}, error) { absAddr := n.Addr.Absolute(ctx.Path()) state := *n.State - if n.ProviderAddr.ProviderConfig.Type == "" { + if n.ProviderAddr.ProviderConfig.Type.LegacyString() == "" { if n.DeposedKey == "" { panic(fmt.Sprintf("EvalDiffDestroy for %s does not have ProviderAddr set", absAddr)) } else { diff --git a/terraform/eval_provider.go b/terraform/eval_provider.go index 1b12b3cc85..2ff3745d12 100644 --- a/terraform/eval_provider.go +++ b/terraform/eval_provider.go @@ -125,7 +125,7 @@ type EvalGetProvider struct { } func (n *EvalGetProvider) Eval(ctx EvalContext) (interface{}, error) { - if n.Addr.ProviderConfig.Type == "" { + if n.Addr.ProviderConfig.Type.LegacyString() == "" { // Should never happen panic("EvalGetProvider used with uninitialized provider configuration address") } diff --git a/terraform/eval_provider_test.go b/terraform/eval_provider_test.go index f71688d37d..5d9a2f61ce 100644 --- a/terraform/eval_provider_test.go +++ b/terraform/eval_provider_test.go @@ -17,7 +17,7 @@ func TestBuildProviderConfig(t *testing.T) { "set_in_config": cty.StringVal("config"), }) providerAddr := addrs.ProviderConfig{ - Type: "foo", + Type: addrs.NewLegacyProvider("foo"), } ctx := &MockEvalContext{ @@ -68,7 +68,7 @@ func TestEvalConfigProvider(t *testing.T) { provider := mockProviderWithConfigSchema(simpleTestSchema()) rp := providers.Interface(provider) n := &EvalConfigProvider{ - Addr: addrs.ProviderConfig{Type: "foo"}, + Addr: addrs.ProviderConfig{Type: addrs.NewLegacyProvider("foo")}, Config: config, Provider: &rp, } @@ -98,7 +98,7 @@ func TestEvalInitProvider_impl(t *testing.T) { func TestEvalInitProvider(t *testing.T) { n := &EvalInitProvider{ - Addr: addrs.ProviderConfig{Type: "foo"}, + Addr: addrs.ProviderConfig{Type: addrs.NewLegacyProvider("foo")}, } provider := &MockProvider{} ctx := &MockEvalContext{InitProviderProvider: provider} @@ -116,7 +116,7 @@ func TestEvalInitProvider(t *testing.T) { func TestEvalCloseProvider(t *testing.T) { n := &EvalCloseProvider{ - Addr: addrs.ProviderConfig{Type: "foo"}, + Addr: addrs.ProviderConfig{Type: addrs.NewLegacyProvider("foo")}, } provider := &MockProvider{} ctx := &MockEvalContext{CloseProviderProvider: provider} diff --git a/terraform/eval_state.go b/terraform/eval_state.go index 0be8775441..fddc62bf23 100644 --- a/terraform/eval_state.go +++ b/terraform/eval_state.go @@ -217,7 +217,7 @@ func (n *EvalWriteState) Eval(ctx EvalContext) (interface{}, error) { absAddr := n.Addr.Absolute(ctx.Path()) state := ctx.State() - if n.ProviderAddr.ProviderConfig.Type == "" { + if n.ProviderAddr.ProviderConfig.Type.LegacyString() == "" { return nil, fmt.Errorf("failed to write state for %s, missing provider type", absAddr) } obj := *n.State diff --git a/terraform/evaltree_provider.go b/terraform/evaltree_provider.go index 6b4df67aaf..f163a727cd 100644 --- a/terraform/evaltree_provider.go +++ b/terraform/evaltree_provider.go @@ -16,7 +16,7 @@ func ProviderEvalTree(n *NodeApplyableProvider, config *configs.Provider) EvalNo seq := make([]EvalNode, 0, 5) seq = append(seq, &EvalInitProvider{ - TypeName: relAddr.Type, + TypeName: relAddr.Type.LegacyString(), Addr: addr.ProviderConfig, }) diff --git a/terraform/evaluate.go b/terraform/evaluate.go index de1fd9a058..ae171ed011 100644 --- a/terraform/evaluate.go +++ b/terraform/evaluate.go @@ -779,7 +779,7 @@ func (d *evaluationStateData) getResourceInstancesAll(addr addrs.Resource, rng t } func (d *evaluationStateData) getResourceSchema(addr addrs.Resource, providerAddr addrs.AbsProviderConfig) *configschema.Block { - providerType := providerAddr.ProviderConfig.Type + providerType := providerAddr.ProviderConfig.Type.LegacyString() schemas := d.Evaluator.Schemas schema, _ := schemas.ResourceTypeConfig(providerType, addr.Mode, addr.Type) return schema diff --git a/terraform/evaluate_valid.go b/terraform/evaluate_valid.go index 9e55b2f996..01f5ca1dba 100644 --- a/terraform/evaluate_valid.go +++ b/terraform/evaluate_valid.go @@ -215,7 +215,7 @@ func (d *evaluationStateData) staticValidateResourceReference(modCfg *configs.Co // Normally accessing this directly is wrong because it doesn't take into // account provider inheritance, etc but it's okay here because we're only // paying attention to the type anyway. - providerType := cfg.ProviderConfigAddr().Type + providerType := cfg.ProviderConfigAddr().Type.LegacyString() schema, _ := d.Evaluator.Schemas.ResourceTypeConfig(providerType, addr.Mode, addr.Type) if schema == nil { diff --git a/terraform/graph_builder.go b/terraform/graph_builder.go index 66b21f300d..71b71b7528 100644 --- a/terraform/graph_builder.go +++ b/terraform/graph_builder.go @@ -5,9 +5,9 @@ import ( "log" "strings" - "github.com/hashicorp/terraform/tfdiags" - "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/helper/logging" + "github.com/hashicorp/terraform/tfdiags" ) // GraphBuilder is an interface that can be implemented and used with @@ -56,7 +56,7 @@ func (b *BasicGraphBuilder) Build(path addrs.ModuleInstance) (*Graph, tfdiags.Di debugOp.End(errMsg) if thisStepStr := g.StringWithNodeTypes(); thisStepStr != lastStepStr { - log.Printf("[TRACE] Completed graph transform %T with new graph:\n%s------", step, thisStepStr) + log.Printf("[TRACE] Completed graph transform %T with new graph:\n%s ------", step, logging.Indent(thisStepStr)) lastStepStr = thisStepStr } else { log.Printf("[TRACE] Completed graph transform %T (no changes)", step) diff --git a/terraform/graph_builder_apply_test.go b/terraform/graph_builder_apply_test.go index 92908e583f..af1aa97791 100644 --- a/terraform/graph_builder_apply_test.go +++ b/terraform/graph_builder_apply_test.go @@ -545,7 +545,7 @@ func TestApplyGraphBuilder_updateFromOrphan(t *testing.T) { AttrsJSON: []byte(`{"id":"a_id"}`), }, addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance), ) root.SetResourceInstanceCurrent( @@ -569,7 +569,7 @@ func TestApplyGraphBuilder_updateFromOrphan(t *testing.T) { }, }, addrs.ProviderConfig{ - Type: "test", + Type: addrs.NewLegacyProvider("test"), }.Absolute(addrs.RootModuleInstance), ) diff --git a/terraform/node_data_refresh_test.go b/terraform/node_data_refresh_test.go index 6b6059fa2b..d4ad1b55af 100644 --- a/terraform/node_data_refresh_test.go +++ b/terraform/node_data_refresh_test.go @@ -130,7 +130,7 @@ func TestNodeRefreshableDataResourceDynamicExpand_scaleIn(t *testing.T) { Config: m.Module.DataResources["data.aws_instance.foo"], ResolvedProvider: addrs.AbsProviderConfig{ ProviderConfig: addrs.ProviderConfig{ - Type: "aws", + Type: addrs.NewLegacyProvider("aws"), }, }, }, @@ -174,7 +174,7 @@ root - terraform.graphNodeRoot t.Fatal("failed to find a destroyableDataResource") } - if destroyableDataResource.ResolvedProvider.ProviderConfig.Type == "" { + if destroyableDataResource.ResolvedProvider.ProviderConfig.Type.LegacyString() == "" { t.Fatal("NodeDestroyableDataResourceInstance missing provider config") } } diff --git a/terraform/node_provider_eval.go b/terraform/node_provider_eval.go index 580e60cb7e..1e4daabb98 100644 --- a/terraform/node_provider_eval.go +++ b/terraform/node_provider_eval.go @@ -14,7 +14,7 @@ func (n *NodeEvalableProvider) EvalTree() EvalNode { relAddr := addr.ProviderConfig return &EvalInitProvider{ - TypeName: relAddr.Type, + TypeName: relAddr.Type.LegacyString(), Addr: addr.ProviderConfig, } } diff --git a/terraform/node_resource_plan_destroy.go b/terraform/node_resource_plan_destroy.go index 38746f0d35..decc372a5c 100644 --- a/terraform/node_resource_plan_destroy.go +++ b/terraform/node_resource_plan_destroy.go @@ -47,7 +47,7 @@ func (n *NodePlanDestroyableResourceInstance) EvalTree() EvalNode { var change *plans.ResourceInstanceChange var state *states.ResourceInstanceObject - if n.ResolvedProvider.ProviderConfig.Type == "" { + if n.ResolvedProvider.ProviderConfig.Type.String() == "" { // Should never happen; indicates that the graph was not constructed // correctly since we didn't get our provider attached. panic(fmt.Sprintf("%T %q was not assigned a resolved provider", n, dag.VertexName(n))) diff --git a/terraform/transform.go b/terraform/transform.go index fd3f5c7daa..d587c89e49 100644 --- a/terraform/transform.go +++ b/terraform/transform.go @@ -4,6 +4,7 @@ import ( "log" "github.com/hashicorp/terraform/dag" + "github.com/hashicorp/terraform/helper/logging" ) // GraphTransformer is the interface that transformers implement. This @@ -45,7 +46,7 @@ func (t *graphTransformerMulti) Transform(g *Graph) error { return err } if thisStepStr := g.StringWithNodeTypes(); thisStepStr != lastStepStr { - log.Printf("[TRACE] (graphTransformerMulti) Completed graph transform %T with new graph:\n%s------", t, thisStepStr) + log.Printf("[TRACE] (graphTransformerMulti) Completed graph transform %T with new graph:\n%s ------", t, logging.Indent(thisStepStr)) lastStepStr = thisStepStr } else { log.Printf("[TRACE] (graphTransformerMulti) Completed graph transform %T (no changes)", t) diff --git a/terraform/transform_attach_schema.go b/terraform/transform_attach_schema.go index c7695dd4ee..2e4c355185 100644 --- a/terraform/transform_attach_schema.go +++ b/terraform/transform_attach_schema.go @@ -59,7 +59,7 @@ func (t *AttachSchemaTransformer) Transform(g *Graph) error { mode := addr.Resource.Mode typeName := addr.Resource.Type providerAddr, _ := tv.ProvidedBy() - providerType := providerAddr.ProviderConfig.Type + providerType := providerAddr.ProviderConfig.Type.LegacyString() schema, version := t.Schemas.ResourceTypeConfig(providerType, mode, typeName) if schema == nil { @@ -72,7 +72,7 @@ func (t *AttachSchemaTransformer) Transform(g *Graph) error { if tv, ok := v.(GraphNodeAttachProviderConfigSchema); ok { providerAddr := tv.ProviderAddr() - schema := t.Schemas.ProviderConfig(providerAddr.ProviderConfig.Type) + schema := t.Schemas.ProviderConfig(providerAddr.ProviderConfig.Type.LegacyString()) if schema == nil { log.Printf("[ERROR] AttachSchemaTransformer: No provider config schema available for %s", providerAddr) continue diff --git a/terraform/transform_diff_test.go b/terraform/transform_diff_test.go index a83a5d75f5..1aced02fbe 100644 --- a/terraform/transform_diff_test.go +++ b/terraform/transform_diff_test.go @@ -44,7 +44,7 @@ func TestDiffTransformer(t *testing.T) { Name: "foo", }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), ProviderAddr: addrs.ProviderConfig{ - Type: "aws", + Type: addrs.NewLegacyProvider("aws"), }.Absolute(addrs.RootModuleInstance), ChangeSrc: plans.ChangeSrc{ Action: plans.Update, diff --git a/terraform/transform_import_state.go b/terraform/transform_import_state.go index ab0ecae0a9..7bda3121f6 100644 --- a/terraform/transform_import_state.go +++ b/terraform/transform_import_state.go @@ -20,7 +20,7 @@ func (t *ImportStateTransformer) Transform(g *Graph) error { // This will be populated if the targets come from the cli, but tests // may not specify implied provider addresses. providerAddr := target.ProviderAddr - if providerAddr.ProviderConfig.Type == "" { + if providerAddr.ProviderConfig.Type.Type == "" { providerAddr = target.Addr.Resource.Resource.DefaultProviderConfig().Absolute(target.Addr.Module) } diff --git a/terraform/transform_orphan_count_test.go b/terraform/transform_orphan_count_test.go index 4853ce831b..94acecfbb9 100644 --- a/terraform/transform_orphan_count_test.go +++ b/terraform/transform_orphan_count_test.go @@ -353,7 +353,7 @@ func TestOrphanResourceCountTransformer_ForEachEdgesAdded(t *testing.T) { Status: states.ObjectReady, }, addrs.ProviderConfig{ - Type: "aws", + Type: addrs.NewLegacyProvider("aws"), }.Absolute(addrs.RootModuleInstance), ) @@ -371,7 +371,7 @@ func TestOrphanResourceCountTransformer_ForEachEdgesAdded(t *testing.T) { Status: states.ObjectReady, }, addrs.ProviderConfig{ - Type: "aws", + Type: addrs.NewLegacyProvider("aws"), }.Absolute(addrs.RootModuleInstance), ) }) diff --git a/terraform/transform_orphan_resource_test.go b/terraform/transform_orphan_resource_test.go index fed351cc1f..1eae68d786 100644 --- a/terraform/transform_orphan_resource_test.go +++ b/terraform/transform_orphan_resource_test.go @@ -27,7 +27,7 @@ func TestOrphanResourceInstanceTransformer(t *testing.T) { Status: states.ObjectReady, }, addrs.ProviderConfig{ - Type: "aws", + Type: addrs.NewLegacyProvider("aws"), }.Absolute(addrs.RootModuleInstance), ) @@ -45,7 +45,7 @@ func TestOrphanResourceInstanceTransformer(t *testing.T) { Status: states.ObjectReady, }, addrs.ProviderConfig{ - Type: "aws", + Type: addrs.NewLegacyProvider("aws"), }.Absolute(addrs.RootModuleInstance), ) }) @@ -93,7 +93,7 @@ func TestOrphanResourceInstanceTransformer_countGood(t *testing.T) { Status: states.ObjectReady, }, addrs.ProviderConfig{ - Type: "aws", + Type: addrs.NewLegacyProvider("aws"), }.Absolute(addrs.RootModuleInstance), ) s.SetResourceInstanceCurrent( @@ -109,7 +109,7 @@ func TestOrphanResourceInstanceTransformer_countGood(t *testing.T) { Status: states.ObjectReady, }, addrs.ProviderConfig{ - Type: "aws", + Type: addrs.NewLegacyProvider("aws"), }.Absolute(addrs.RootModuleInstance), ) }) @@ -156,7 +156,7 @@ func TestOrphanResourceInstanceTransformer_countBad(t *testing.T) { Status: states.ObjectReady, }, addrs.ProviderConfig{ - Type: "aws", + Type: addrs.NewLegacyProvider("aws"), }.Absolute(addrs.RootModuleInstance), ) s.SetResourceInstanceCurrent( @@ -172,7 +172,7 @@ func TestOrphanResourceInstanceTransformer_countBad(t *testing.T) { Status: states.ObjectReady, }, addrs.ProviderConfig{ - Type: "aws", + Type: addrs.NewLegacyProvider("aws"), }.Absolute(addrs.RootModuleInstance), ) }) @@ -219,7 +219,7 @@ func TestOrphanResourceInstanceTransformer_modules(t *testing.T) { Status: states.ObjectReady, }, addrs.ProviderConfig{ - Type: "aws", + Type: addrs.NewLegacyProvider("aws"), }.Absolute(addrs.RootModuleInstance), ) s.SetResourceInstanceCurrent( @@ -235,7 +235,7 @@ func TestOrphanResourceInstanceTransformer_modules(t *testing.T) { Status: states.ObjectReady, }, addrs.ProviderConfig{ - Type: "aws", + Type: addrs.NewLegacyProvider("aws"), }.Absolute(addrs.RootModuleInstance), ) }) diff --git a/terraform/transform_provider.go b/terraform/transform_provider.go index bc86d295fb..8b8dff86fa 100644 --- a/terraform/transform_provider.go +++ b/terraform/transform_provider.go @@ -295,7 +295,7 @@ func (t *MissingProviderTransformer) Transform(g *Graph) error { // We're going to create an implicit _default_ configuration for the // referenced provider type in the _root_ module, ignoring all other // aspects of the resource's declared provider address. - defaultAddr := addrs.RootModuleInstance.ProviderConfigDefault(p.ProviderConfig.Type) + defaultAddr := addrs.RootModuleInstance.ProviderConfigDefault(p.ProviderConfig.Type.LegacyString()) key := defaultAddr.String() provider := m[key] @@ -705,7 +705,7 @@ func (t *ProviderConfigTransformer) attachProviderConfigs(g *Graph) error { // Go through the provider configs to find the matching config for _, p := range mc.Module.ProviderConfigs { - if p.Name == addr.ProviderConfig.Type && p.Alias == addr.ProviderConfig.Alias { + if p.Name == addr.ProviderConfig.Type.LegacyString() && p.Alias == addr.ProviderConfig.Alias { log.Printf("[TRACE] ProviderConfigTransformer: attaching to %q provider configuration from %s", dag.VertexName(v), p.DeclRange) apn.AttachProvider(p) break diff --git a/terraform/transform_provisioner_test.go b/terraform/transform_provisioner_test.go index eecd677888..e96ce22518 100644 --- a/terraform/transform_provisioner_test.go +++ b/terraform/transform_provisioner_test.go @@ -71,7 +71,7 @@ func TestMissingProvisionerTransformer_module(t *testing.T) { Status: states.ObjectReady, }, addrs.ProviderConfig{ - Type: "aws", + Type: addrs.NewLegacyProvider("aws"), }.Absolute(addrs.RootModuleInstance), ) s.SetResourceInstanceCurrent( @@ -87,7 +87,7 @@ func TestMissingProvisionerTransformer_module(t *testing.T) { Status: states.ObjectReady, }, addrs.ProviderConfig{ - Type: "aws", + Type: addrs.NewLegacyProvider("aws"), }.Absolute(addrs.RootModuleInstance), ) }) diff --git a/website/docs/providers/index.html.markdown b/website/docs/providers/index.html.markdown index 1b46aac501..22df0d3154 100644 --- a/website/docs/providers/index.html.markdown +++ b/website/docs/providers/index.html.markdown @@ -125,6 +125,7 @@ down to see all providers. - [Skytap](/docs/providers/skytap/index.html) - [SoftLayer](/docs/providers/softlayer/index.html) - [Spotinst](/docs/providers/spotinst/index.html) +- [StackPath](/docs/providers/stackpath/index.html) - [StatusCake](/docs/providers/statuscake/index.html) - [TelefonicaOpenCloud](/docs/providers/telefonicaopencloud/index.html) - [Template](/docs/providers/template/index.html) diff --git a/website/docs/providers/type/cloud-index.html.markdown b/website/docs/providers/type/cloud-index.html.markdown index 01cc7faebd..62651972b8 100644 --- a/website/docs/providers/type/cloud-index.html.markdown +++ b/website/docs/providers/type/cloud-index.html.markdown @@ -48,6 +48,7 @@ vendor in close collaboration with HashiCorp, and are tested by HashiCorp. - [Skytap](/docs/providers/skytap/index.html) - [Selectel](/docs/providers/selectel/index.html) - [SoftLayer](/docs/providers/softlayer/index.html) +- [StackPath](/docs/providers/stackpath/index.html) - [TelefonicaOpenCloud](/docs/providers/telefonicaopencloud/index.html) - [TencentCloud](/docs/providers/tencentcloud/index.html) - [Triton](/docs/providers/triton/index.html)