From 927999a820eebb34b077736b4fc6c7984ed63007 Mon Sep 17 00:00:00 2001 From: Kristin Laemmert Date: Tue, 4 Feb 2020 12:07:59 -0500 Subject: [PATCH] command/state show: use configured provider (#24027) The `state show` command was not checking if a given resource had a configured provider, and instead was only using the default provider config. This PR checks for a configured provider, using the default provider if one is not set. Fixes #22010 --- command/format/state.go | 5 ++-- command/state_show.go | 6 +++- command/state_show_test.go | 61 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 3 deletions(-) diff --git a/command/format/state.go b/command/format/state.go index 749dffbe4b..3c1b695d12 100644 --- a/command/format/state.go +++ b/command/format/state.go @@ -141,13 +141,14 @@ func formatStateModule(p blockBodyDiffPrinter, m *states.Module, schemas *terraf var schema *configschema.Block // TODO: Get the provider FQN when it is available from the AbsoluteProviderConfig, in state - provider := addr.DefaultProvider() + // check if the resource has a configured provider, otherwise use the default provider + provider := addrs.NewLegacyProvider(m.Resources[key].ProviderConfig.ProviderConfig.LocalName) if _, exists := schemas.Providers[provider]; !exists { // This should never happen in normal use because we should've // loaded all of the schemas and checked things prior to this // point. We can't return errors here, but since this is UI code // we will try to do _something_ reasonable. - p.buf.WriteString(fmt.Sprintf("# missing schema for provider %q\n\n", provider)) + p.buf.WriteString(fmt.Sprintf("# missing schema for provider %q\n\n", provider.LegacyString())) continue } diff --git a/command/state_show.go b/command/state_show.go index 318db7bcdd..de3d48d449 100644 --- a/command/state_show.go +++ b/command/state_show.go @@ -115,11 +115,15 @@ func (c *StateShowCommand) Run(args []string) int { return 1 } + // check if the resource has a configured provider, otherwise this will use the default provider + rs := state.Resource(addr.ContainingResource()) + absPc := rs.ProviderConfig.ProviderConfig.Absolute(addrs.RootModuleInstance) + singleInstance := states.NewState() singleInstance.EnsureModule(addr.Module).SetResourceInstanceCurrent( addr.Resource, is.Current, - addrs.NewDefaultLocalProviderConfig(addr.Resource.Resource.DefaultProvider().LegacyString()).Absolute(addr.Module), + absPc, ) output := format.State(&format.StateOpts{ diff --git a/command/state_show_test.go b/command/state_show_test.go index e684a1ed7d..26f18c9e11 100644 --- a/command/state_show_test.go +++ b/command/state_show_test.go @@ -6,6 +6,7 @@ import ( "github.com/hashicorp/terraform/addrs" "github.com/hashicorp/terraform/configs/configschema" + "github.com/hashicorp/terraform/providers" "github.com/hashicorp/terraform/states" "github.com/hashicorp/terraform/terraform" "github.com/mitchellh/cli" @@ -182,6 +183,66 @@ func TestStateShow_emptyState(t *testing.T) { } } +func TestStateShow_configured_provider(t *testing.T) { + state := states.BuildState(func(s *states.SyncState) { + s.SetResourceInstanceCurrent( + addrs.Resource{ + Mode: addrs.ManagedResourceMode, + Type: "test_instance", + Name: "foo", + }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), + &states.ResourceInstanceObjectSrc{ + AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`), + Status: states.ObjectReady, + }, + addrs.LocalProviderConfig{LocalName: "test-beta"}.Absolute(addrs.RootModuleInstance), + ) + }) + statePath := testStateFile(t, state) + + p := testProvider() + p.GetSchemaReturn = &terraform.ProviderSchema{ + ResourceTypes: map[string]*configschema.Block{ + "test_instance": { + Attributes: map[string]*configschema.Attribute{ + "id": {Type: cty.String, Optional: true, Computed: true}, + "foo": {Type: cty.String, Optional: true}, + "bar": {Type: cty.String, Optional: true}, + }, + }, + }, + } + + ui := new(cli.MockUi) + c := &StateShowCommand{ + Meta: Meta{ + testingOverrides: &testingOverrides{ + ProviderResolver: providers.ResolverFixed( + map[addrs.Provider]providers.Factory{ + addrs.NewLegacyProvider("test-beta"): providers.FactoryFixed(p), + }, + ), + }, + Ui: ui, + }, + } + + args := []string{ + "-state", statePath, + "test_instance.foo", + } + if code := c.Run(args); code != 0 { + t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) + } + + // Test that outputs were displayed + expected := strings.TrimSpace(testStateShowOutput) + "\n" + actual := ui.OutputWriter.String() + if actual != expected { + t.Fatalf("Expected:\n%q\n\nTo equal:\n%q", actual, expected) + } +} + const testStateShowOutput = ` # test_instance.foo: resource "test_instance" "foo" {