From 9c434316a0c90a30f52d057f67533e610ea30ce1 Mon Sep 17 00:00:00 2001 From: Kristin Laemmert Date: Mon, 13 Jan 2020 10:41:13 -0500 Subject: [PATCH] command/show: fix issue with show and aliased provider The formatter in `command/format/state.go`, when formatting a resource with an aliased provider, was looking for a schema with the alias (ie, test.foo), but the schemas are only listed by provider type (test). Update the state formatter to lookup schemas by provider type only. Some of the show tests (and a couple others) were not properly cleaning up the created tmpdirs, so I fixed those. Also, the show tests are using a statefile named `state.tfstate`, but were not passing that path to the show command, so we were getting some false positives (a `show` command that returns `no state` exits 0). Fixes part of #21462 (aliased providers) --- command/format/state.go | 2 +- command/init_test.go | 1 + command/plugins_test.go | 1 + command/show_test.go | 70 ++++++++++++++++++++++++++++++++++++++--- 4 files changed, 69 insertions(+), 5 deletions(-) diff --git a/command/format/state.go b/command/format/state.go index be1ea24de96e..143edc9e1489 100644 --- a/command/format/state.go +++ b/command/format/state.go @@ -139,7 +139,7 @@ func formatStateModule(p blockBodyDiffPrinter, m *states.Module, schemas *terraf } var schema *configschema.Block - provider := m.Resources[key].ProviderConfig.ProviderConfig.StringCompact() + provider := addr.DefaultProviderConfig().Absolute(m.Addr).ProviderConfig.StringCompact() 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 diff --git a/command/init_test.go b/command/init_test.go index e0054d88fd48..9cbdeb158edb 100644 --- a/command/init_test.go +++ b/command/init_test.go @@ -1237,6 +1237,7 @@ func TestInit_providerLockFile(t *testing.T) { func TestInit_pluginDirReset(t *testing.T) { td := testTempDir(t) + defer os.RemoveAll(td) defer testChdir(t, td)() ui := new(cli.MockUi) diff --git a/command/plugins_test.go b/command/plugins_test.go index 5b3c40cf2284..19eaf5964235 100644 --- a/command/plugins_test.go +++ b/command/plugins_test.go @@ -99,6 +99,7 @@ func TestMultiVersionProviderResolver(t *testing.T) { func TestPluginPath(t *testing.T) { td := testTempDir(t) + defer os.RemoveAll(td) defer testChdir(t, td)() pluginPath := []string{"a", "b", "c"} diff --git a/command/show_test.go b/command/show_test.go index 508f44166eef..3e48d49d5c24 100644 --- a/command/show_test.go +++ b/command/show_test.go @@ -2,6 +2,7 @@ package command import ( "encoding/json" + "fmt" "io/ioutil" "os" "path/filepath" @@ -41,7 +42,9 @@ func TestShow(t *testing.T) { func TestShow_noArgs(t *testing.T) { // Create the default state statePath := testStateFile(t, testState()) - defer testChdir(t, filepath.Dir(statePath))() + stateDir := filepath.Dir(statePath) + defer os.RemoveAll(stateDir) + defer testChdir(t, stateDir)() ui := new(cli.MockUi) c := &ShowCommand{ @@ -51,16 +54,73 @@ func TestShow_noArgs(t *testing.T) { }, } - args := []string{} + // the statefile created by testStateFile is named state.tfstate + // so one arg is required + args := []string{"state.tfstate"} if code := c.Run(args); code != 0 { t.Fatalf("bad: \n%s", ui.OutputWriter.String()) } + + if !strings.Contains(ui.OutputWriter.String(), "# test_instance.foo:") { + t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) + } +} + +// https://github.com/hashicorp/terraform/issues/21462 +func TestShow_aliasedProvider(t *testing.T) { + // Create the default state with aliased resource + testState := 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{ + // The weird whitespace here is reflective of how this would + // get written out in a real state file, due to the indentation + // of all of the containing wrapping objects and arrays. + AttrsJSON: []byte("{\n \"id\": \"bar\"\n }"), + Status: states.ObjectReady, + Dependencies: []addrs.AbsResource{}, + DependsOn: []addrs.Referenceable{}, + }, + addrs.RootModuleInstance.ProviderConfigAliased("test", "alias"), + ) + }) + + statePath := testStateFile(t, testState) + stateDir := filepath.Dir(statePath) + defer os.RemoveAll(stateDir) + defer testChdir(t, stateDir)() + + ui := new(cli.MockUi) + c := &ShowCommand{ + Meta: Meta{ + testingOverrides: metaOverridesForProvider(testProvider()), + Ui: ui, + }, + } + + fmt.Println(os.Getwd()) + + // the statefile created by testStateFile is named state.tfstate + args := []string{"state.tfstate"} + if code := c.Run(args); code != 0 { + t.Fatalf("bad exit code: \n%s", ui.OutputWriter.String()) + } + + if strings.Contains(ui.OutputWriter.String(), "# missing schema for provider \"test.alias\"") { + t.Fatalf("bad output: \n%s", ui.OutputWriter.String()) + } } func TestShow_noArgsNoState(t *testing.T) { // Create the default state statePath := testStateFile(t, testState()) - defer testChdir(t, filepath.Dir(statePath))() + stateDir := filepath.Dir(statePath) + defer os.RemoveAll(stateDir) + defer testChdir(t, stateDir)() ui := new(cli.MockUi) c := &ShowCommand{ @@ -70,7 +130,8 @@ func TestShow_noArgsNoState(t *testing.T) { }, } - args := []string{} + // the statefile created by testStateFile is named state.tfstate + args := []string{"state.tfstate"} if code := c.Run(args); code != 0 { t.Fatalf("bad: \n%s", ui.OutputWriter.String()) } @@ -150,6 +211,7 @@ func TestShow_plan_json(t *testing.T) { func TestShow_state(t *testing.T) { originalState := testState() statePath := testStateFile(t, originalState) + defer os.RemoveAll(filepath.Dir(statePath)) ui := new(cli.MockUi) c := &ShowCommand{