Push plugin discovery down into command package

Previously we did plugin discovery in the main package, but as we move
towards versioned plugins we need more information available in order to
resolve plugins, so we move this responsibility into the command package
itself.

For the moment this is just preserving the existing behavior as long as
there are only internal and unversioned plugins present. This is the
final state for provisioners in 0.10, since we don't want to support
versioned provisioners yet. For providers this is just a checkpoint along
the way, since further work is required to apply version constraints from
configuration and support additional plugin search directories.

The automatic plugin discovery behavior is not desirable for tests because
we want to mock the plugins there, so we add a new backdoor for the tests
to use to skip the plugin discovery and just provide their own mock
implementations. Most of this diff is thus noisy rework of the tests to
use this new mechanism.
This commit is contained in:
Martin Atkins 2017-04-13 18:05:58 -07:00
parent bcd395e6bd
commit 8364383c35
28 changed files with 611 additions and 657 deletions

View File

@ -33,7 +33,7 @@ func TestApply_destroy(t *testing.T) {
c := &ApplyCommand{ c := &ApplyCommand{
Destroy: true, Destroy: true,
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -123,7 +123,7 @@ func TestApply_destroyLockedState(t *testing.T) {
c := &ApplyCommand{ c := &ApplyCommand{
Destroy: true, Destroy: true,
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -155,7 +155,7 @@ func TestApply_destroyPlan(t *testing.T) {
c := &ApplyCommand{ c := &ApplyCommand{
Destroy: true, Destroy: true,
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -199,7 +199,7 @@ func TestApply_destroyTargeted(t *testing.T) {
c := &ApplyCommand{ c := &ApplyCommand{
Destroy: true, Destroy: true,
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }

View File

@ -28,7 +28,7 @@ func TestApply(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ApplyCommand{ c := &ApplyCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -74,7 +74,7 @@ func TestApply_lockedState(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ApplyCommand{ c := &ApplyCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -112,7 +112,7 @@ func TestApply_lockedStateWait(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ApplyCommand{ c := &ApplyCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -188,7 +188,7 @@ func TestApply_parallelism(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ApplyCommand{ c := &ApplyCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(provider), testingOverrides: metaOverridesForProvider(provider),
Ui: ui, Ui: ui,
}, },
} }
@ -241,7 +241,7 @@ func TestApply_configInvalid(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ApplyCommand{ c := &ApplyCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -276,7 +276,7 @@ func TestApply_defaultState(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ApplyCommand{ c := &ApplyCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -314,7 +314,7 @@ func TestApply_error(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ApplyCommand{ c := &ApplyCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -403,7 +403,7 @@ func TestApply_init(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ApplyCommand{ c := &ApplyCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -460,7 +460,7 @@ func TestApply_input(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ApplyCommand{ c := &ApplyCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -495,7 +495,7 @@ func TestApply_inputPartial(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ApplyCommand{ c := &ApplyCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -535,7 +535,7 @@ func TestApply_noArgs(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ApplyCommand{ c := &ApplyCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -584,7 +584,7 @@ func TestApply_plan(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ApplyCommand{ c := &ApplyCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -630,7 +630,7 @@ func TestApply_plan_backup(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ApplyCommand{ c := &ApplyCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -672,7 +672,7 @@ func TestApply_plan_noBackup(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ApplyCommand{ c := &ApplyCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -729,7 +729,7 @@ func TestApply_plan_remoteState(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ApplyCommand{ c := &ApplyCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -782,7 +782,7 @@ func TestApply_planWithVarFile(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ApplyCommand{ c := &ApplyCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -824,7 +824,7 @@ func TestApply_planVars(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ApplyCommand{ c := &ApplyCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -855,11 +855,9 @@ func TestApply_planNoModuleFiles(t *testing.T) {
Module: testModule(t, "apply-plan-no-module"), Module: testModule(t, "apply-plan-no-module"),
}) })
contextOpts := testCtxConfig(p)
apply := &ApplyCommand{ apply := &ApplyCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: contextOpts, testingOverrides: metaOverridesForProvider(p),
Ui: new(cli.MockUi), Ui: new(cli.MockUi),
}, },
} }
@ -895,7 +893,7 @@ func TestApply_refresh(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ApplyCommand{ c := &ApplyCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -961,7 +959,7 @@ func TestApply_shutdown(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ApplyCommand{ c := &ApplyCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
@ -1072,7 +1070,7 @@ func TestApply_state(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ApplyCommand{ c := &ApplyCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -1145,7 +1143,7 @@ func TestApply_stateNoExist(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ApplyCommand{ c := &ApplyCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -1164,7 +1162,7 @@ func TestApply_sensitiveOutput(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ApplyCommand{ c := &ApplyCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -1198,7 +1196,7 @@ func TestApply_stateFuture(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ApplyCommand{ c := &ApplyCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -1239,7 +1237,7 @@ func TestApply_statePast(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ApplyCommand{ c := &ApplyCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -1260,7 +1258,7 @@ func TestApply_vars(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ApplyCommand{ c := &ApplyCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -1303,7 +1301,7 @@ func TestApply_varFile(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ApplyCommand{ c := &ApplyCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -1356,7 +1354,7 @@ func TestApply_varFileDefault(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ApplyCommand{ c := &ApplyCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -1408,7 +1406,7 @@ func TestApply_varFileDefaultJSON(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ApplyCommand{ c := &ApplyCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -1471,7 +1469,7 @@ func TestApply_backup(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ApplyCommand{ c := &ApplyCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -1540,7 +1538,7 @@ func TestApply_disableBackup(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ApplyCommand{ c := &ApplyCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -1608,7 +1606,7 @@ func TestApply_terraformEnv(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ApplyCommand{ c := &ApplyCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -1663,7 +1661,7 @@ func TestApply_terraformEnvNonDefault(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ApplyCommand{ c := &ApplyCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }

View File

@ -69,8 +69,8 @@ func testFixturePath(name string) string {
return filepath.Join(fixtureDir, name) return filepath.Join(fixtureDir, name)
} }
func testCtxConfig(p terraform.ResourceProvider) *terraform.ContextOpts { func metaOverridesForProvider(p terraform.ResourceProvider) *testingOverrides {
return &terraform.ContextOpts{ return &testingOverrides{
Providers: map[string]terraform.ResourceProviderFactory{ Providers: map[string]terraform.ResourceProviderFactory{
"test": func() (terraform.ResourceProvider, error) { "test": func() (terraform.ResourceProvider, error) {
return p, nil return p, nil
@ -79,8 +79,8 @@ func testCtxConfig(p terraform.ResourceProvider) *terraform.ContextOpts {
} }
} }
func testCtxConfigWithShell(p terraform.ResourceProvider, pr terraform.ResourceProvisioner) *terraform.ContextOpts { func metaOverridesForProviderAndProvisioner(p terraform.ResourceProvider, pr terraform.ResourceProvisioner) *testingOverrides {
return &terraform.ContextOpts{ return &testingOverrides{
Providers: map[string]terraform.ResourceProviderFactory{ Providers: map[string]terraform.ResourceProviderFactory{
"test": func() (terraform.ResourceProvider, error) { "test": func() (terraform.ResourceProvider, error) {
return p, nil return p, nil

View File

@ -25,7 +25,7 @@ func TestConsole_basic(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ConsoleCommand{ c := &ConsoleCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -61,7 +61,7 @@ func TestConsole_tfvars(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ConsoleCommand{ c := &ConsoleCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }

View File

@ -30,7 +30,7 @@ func TestDebugJSON2Dot(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &DebugJSON2DotCommand{ c := &DebugJSON2DotCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }

View File

@ -22,7 +22,7 @@ func TestFmt_errorReporting(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &FmtCommand{ c := &FmtCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -43,7 +43,7 @@ func TestFmt_tooManyArgs(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &FmtCommand{ c := &FmtCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -82,7 +82,7 @@ func TestFmt_workingDirectory(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &FmtCommand{ c := &FmtCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -108,7 +108,7 @@ func TestFmt_directoryArg(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &FmtCommand{ c := &FmtCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -131,7 +131,7 @@ func TestFmt_stdinArg(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &FmtCommand{ c := &FmtCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
input: input, input: input,
@ -158,7 +158,7 @@ func TestFmt_nonDefaultOptions(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &FmtCommand{ c := &FmtCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }

View File

@ -15,7 +15,7 @@ func TestGet(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &GetCommand{ c := &GetCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
dataDir: tempDir(t), dataDir: tempDir(t),
}, },
@ -41,7 +41,7 @@ func TestGet_multipleArgs(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &GetCommand{ c := &GetCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
dataDir: tempDir(t), dataDir: tempDir(t),
}, },
@ -69,7 +69,7 @@ func TestGet_noArgs(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &GetCommand{ c := &GetCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
dataDir: tempDir(t), dataDir: tempDir(t),
}, },
@ -96,7 +96,7 @@ func TestGet_update(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &GetCommand{ c := &GetCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
dataDir: tempDir(t), dataDir: tempDir(t),
}, },

View File

@ -16,7 +16,7 @@ func TestGraph(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &GraphCommand{ c := &GraphCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -38,7 +38,7 @@ func TestGraph_multipleArgs(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &GraphCommand{ c := &GraphCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -65,7 +65,7 @@ func TestGraph_noArgs(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &GraphCommand{ c := &GraphCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -105,7 +105,7 @@ func TestGraph_plan(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &GraphCommand{ c := &GraphCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }

View File

@ -15,7 +15,7 @@ func TestImport(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ImportCommand{ c := &ImportCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -55,7 +55,7 @@ func TestImport_providerConfig(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ImportCommand{ c := &ImportCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -111,7 +111,7 @@ func TestImport_providerConfigDisable(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ImportCommand{ c := &ImportCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -168,7 +168,7 @@ func TestImport_providerConfigWithVar(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ImportCommand{ c := &ImportCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -225,7 +225,7 @@ func TestImport_providerConfigWithVarDefault(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ImportCommand{ c := &ImportCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -281,7 +281,7 @@ func TestImport_providerConfigWithVarFile(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ImportCommand{ c := &ImportCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -335,7 +335,7 @@ func TestRefresh_badState(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &RefreshCommand{ c := &RefreshCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -366,7 +366,7 @@ func TestRefresh_cwd(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &RefreshCommand{ c := &RefreshCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -438,7 +438,7 @@ func TestRefresh_defaultState(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &RefreshCommand{ c := &RefreshCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -510,7 +510,7 @@ func TestRefresh_futureState(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &RefreshCommand{ c := &RefreshCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -553,7 +553,7 @@ func TestRefresh_pastState(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &RefreshCommand{ c := &RefreshCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -612,7 +612,7 @@ func TestRefresh_outPath(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &RefreshCommand{ c := &RefreshCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -687,7 +687,7 @@ func TestRefresh_var(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &RefreshCommand{ c := &RefreshCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -717,7 +717,7 @@ func TestRefresh_varFile(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &RefreshCommand{ c := &RefreshCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -752,7 +752,7 @@ func TestRefresh_varFileDefault(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &RefreshCommand{ c := &RefreshCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -802,7 +802,7 @@ func TestRefresh_varsUnset(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &RefreshCommand{ c := &RefreshCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -842,7 +842,7 @@ func TestRefresh_backup(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &RefreshCommand{ c := &RefreshCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -927,7 +927,7 @@ func TestRefresh_disableBackup(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &RefreshCommand{ c := &RefreshCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -992,7 +992,7 @@ func TestRefresh_displaysOutputs(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &RefreshCommand{ c := &RefreshCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -1021,7 +1021,7 @@ func TestImport_customProvider(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ImportCommand{ c := &ImportCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }

View File

@ -17,7 +17,7 @@ func TestInit(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &InitCommand{ c := &InitCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -54,7 +54,7 @@ func TestInit_cwd(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &InitCommand{ c := &InitCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -81,7 +81,7 @@ func TestInit_empty(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &InitCommand{ c := &InitCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -96,7 +96,7 @@ func TestInit_multipleArgs(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &InitCommand{ c := &InitCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -134,7 +134,7 @@ func TestInit_dstInSrc(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &InitCommand{ c := &InitCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -162,7 +162,7 @@ func TestInit_get(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &InitCommand{ c := &InitCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -189,7 +189,7 @@ func TestInit_copyGet(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &InitCommand{ c := &InitCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -222,7 +222,7 @@ func TestInit_backend(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &InitCommand{ c := &InitCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -248,7 +248,7 @@ func TestInit_backendUnset(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &InitCommand{ c := &InitCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -273,7 +273,7 @@ func TestInit_backendUnset(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &InitCommand{ c := &InitCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -301,7 +301,7 @@ func TestInit_backendConfigFile(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &InitCommand{ c := &InitCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -333,7 +333,7 @@ func TestInit_backendConfigFileChange(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &InitCommand{ c := &InitCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -360,7 +360,7 @@ func TestInit_backendConfigKV(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &InitCommand{ c := &InitCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -387,7 +387,7 @@ func TestInit_copyBackendDst(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &InitCommand{ c := &InitCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -426,7 +426,7 @@ func TestInit_backendReinitWithExtra(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &InitCommand{ c := &InitCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -474,7 +474,7 @@ func TestInit_backendReinitConfigToExtra(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &InitCommand{ c := &InitCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -518,7 +518,7 @@ func TestInit_inputFalse(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &InitCommand{ c := &InitCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -546,7 +546,7 @@ func TestInit_remoteState(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &InitCommand{ c := &InitCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -582,7 +582,7 @@ func TestInit_remoteStateSubdir(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &InitCommand{ c := &InitCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -626,7 +626,7 @@ func TestInit_remoteStateWithLocal(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &InitCommand{ c := &InitCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -664,7 +664,7 @@ func TestInit_remoteStateWithRemote(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &InitCommand{ c := &InitCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }

View File

@ -33,7 +33,8 @@ type Meta struct {
// (not from within the command itself). // (not from within the command itself).
Color bool // True if output should be colored Color bool // True if output should be colored
ContextOpts *terraform.ContextOpts // Opts copied to initialize GlobalPluginDirs []string // Additional paths to search for plugins
PluginOverrides *PluginOverrides // legacy overrides from .terraformrc file
Ui cli.Ui // Ui for output Ui cli.Ui // Ui for output
// ExtraHooks are extra hooks to add to the context. // ExtraHooks are extra hooks to add to the context.
@ -46,6 +47,9 @@ type Meta struct {
// Modify the data directory location. Defaults to DefaultDataDir // Modify the data directory location. Defaults to DefaultDataDir
dataDir string dataDir string
// Override certain behavior for tests within this package
testingOverrides *testingOverrides
//---------------------------------------------------------- //----------------------------------------------------------
// Private: do not set these // Private: do not set these
//---------------------------------------------------------- //----------------------------------------------------------
@ -109,6 +113,16 @@ type Meta struct {
reconfigure bool reconfigure bool
} }
type PluginOverrides struct {
Providers map[string]string
Provisioners map[string]string
}
type testingOverrides struct {
Providers map[string]terraform.ResourceProviderFactory
Provisioners map[string]terraform.ResourceProvisionerFactory
}
// initStatePaths is used to initialize the default values for // initStatePaths is used to initialize the default values for
// statePath, stateOutPath, and backupPath // statePath, stateOutPath, and backupPath
func (m *Meta) initStatePaths() { func (m *Meta) initStatePaths() {
@ -199,14 +213,7 @@ func (m *Meta) StdinPiped() bool {
// context with the settings from this Meta. // context with the settings from this Meta.
func (m *Meta) contextOpts() *terraform.ContextOpts { func (m *Meta) contextOpts() *terraform.ContextOpts {
var opts terraform.ContextOpts var opts terraform.ContextOpts
if v := m.ContextOpts; v != nil {
opts = *v
}
opts.Hooks = []terraform.Hook{m.uiHook(), &terraform.DebugHook{}} opts.Hooks = []terraform.Hook{m.uiHook(), &terraform.DebugHook{}}
if m.ContextOpts != nil {
opts.Hooks = append(opts.Hooks, m.ContextOpts.Hooks...)
}
opts.Hooks = append(opts.Hooks, m.ExtraHooks...) opts.Hooks = append(opts.Hooks, m.ExtraHooks...)
vs := make(map[string]interface{}) vs := make(map[string]interface{})
@ -226,6 +233,17 @@ func (m *Meta) contextOpts() *terraform.ContextOpts {
opts.Parallelism = m.parallelism opts.Parallelism = m.parallelism
opts.Shadow = m.shadow opts.Shadow = m.shadow
// If testingOverrides are set, we'll skip the plugin discovery process
// and just work with what we've been given, thus allowing the tests
// to provide mock providers and provisioners.
if m.testingOverrides != nil {
opts.Providers = m.testingOverrides.Providers
opts.Provisioners = m.testingOverrides.Provisioners
} else {
opts.Providers = m.providerFactories()
opts.Provisioners = m.provisionerFactories()
}
opts.Meta = &terraform.ContextMeta{ opts.Meta = &terraform.ContextMeta{
Env: m.Env(), Env: m.Env(),
} }

View File

@ -31,7 +31,7 @@ func TestOutput(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &OutputCommand{ c := &OutputCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -79,7 +79,7 @@ func TestModuleOutput(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &OutputCommand{ c := &OutputCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -129,7 +129,7 @@ func TestModuleOutputs(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &OutputCommand{ c := &OutputCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -177,7 +177,7 @@ func TestOutput_nestedListAndMap(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &OutputCommand{ c := &OutputCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -216,7 +216,7 @@ func TestOutput_json(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &OutputCommand{ c := &OutputCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -256,7 +256,7 @@ func TestMissingModuleOutput(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &OutputCommand{ c := &OutputCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -292,7 +292,7 @@ func TestOutput_badVar(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &OutputCommand{ c := &OutputCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -330,7 +330,7 @@ func TestOutput_blank(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &OutputCommand{ c := &OutputCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -355,7 +355,7 @@ func TestOutput_manyArgs(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &OutputCommand{ c := &OutputCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -373,7 +373,7 @@ func TestOutput_noArgs(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &OutputCommand{ c := &OutputCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -391,7 +391,7 @@ func TestOutput_noState(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &OutputCommand{ c := &OutputCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -420,7 +420,7 @@ func TestOutput_noVars(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &OutputCommand{ c := &OutputCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -480,7 +480,7 @@ func TestOutput_stateDefault(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &OutputCommand{ c := &OutputCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }

View File

@ -28,7 +28,7 @@ func TestPlan(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &PlanCommand{ c := &PlanCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -61,7 +61,7 @@ func TestPlan_lockedState(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &PlanCommand{ c := &PlanCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -89,7 +89,7 @@ func TestPlan_plan(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &PlanCommand{ c := &PlanCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -128,7 +128,7 @@ func TestPlan_destroy(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &PlanCommand{ c := &PlanCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -165,7 +165,7 @@ func TestPlan_noState(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &PlanCommand{ c := &PlanCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -205,7 +205,7 @@ func TestPlan_outPath(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &PlanCommand{ c := &PlanCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -262,7 +262,7 @@ func TestPlan_outPathNoChange(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &PlanCommand{ c := &PlanCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -318,7 +318,7 @@ func TestPlan_outBackend(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &PlanCommand{ c := &PlanCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -382,7 +382,7 @@ func TestPlan_outBackendLegacy(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &PlanCommand{ c := &PlanCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -412,7 +412,7 @@ func TestPlan_refresh(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &PlanCommand{ c := &PlanCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -450,7 +450,7 @@ func TestPlan_state(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &PlanCommand{ c := &PlanCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -506,7 +506,7 @@ func TestPlan_stateDefault(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &PlanCommand{ c := &PlanCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -535,7 +535,7 @@ func TestPlan_stateFuture(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &PlanCommand{ c := &PlanCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -576,7 +576,7 @@ func TestPlan_statePast(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &PlanCommand{ c := &PlanCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -608,7 +608,7 @@ func TestPlan_validate(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &PlanCommand{ c := &PlanCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -632,7 +632,7 @@ func TestPlan_vars(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &PlanCommand{ c := &PlanCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -676,7 +676,7 @@ func TestPlan_varsUnset(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &PlanCommand{ c := &PlanCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -702,7 +702,7 @@ func TestPlan_varFile(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &PlanCommand{ c := &PlanCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -752,7 +752,7 @@ func TestPlan_varFileDefault(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &PlanCommand{ c := &PlanCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -795,7 +795,7 @@ func TestPlan_detailedExitcode(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &PlanCommand{ c := &PlanCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -820,7 +820,7 @@ func TestPlan_detailedExitcode_emptyDiff(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &PlanCommand{ c := &PlanCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }

163
command/plugins.go Normal file
View File

@ -0,0 +1,163 @@
package command
import (
"log"
"os/exec"
"strings"
plugin "github.com/hashicorp/go-plugin"
tfplugin "github.com/hashicorp/terraform/plugin"
"github.com/hashicorp/terraform/plugin/discovery"
"github.com/hashicorp/terraform/terraform"
)
func (m *Meta) providerFactories() map[string]terraform.ResourceProviderFactory {
var dirs []string
// When searching the following directories, earlier entries get precedence
// if the same plugin version is found twice, but newer versions will
// always get preference below regardless of where they are coming from.
// TODO: Add auto-install dir, default vendor dir and optional override
// vendor dir(s).
dirs = append(dirs, ".")
dirs = append(dirs, m.GlobalPluginDirs...)
plugins := discovery.FindPlugins("provider", dirs)
plugins, _ = plugins.ValidateVersions()
// For now our goal is to just find the latest version of each plugin
// we have on the system, emulating our pre-versioning behavior.
// TODO: Reorganize how providers are handled so that we can use
// version constraints from configuration to select which plugins
// we will use when multiple are available.
factories := make(map[string]terraform.ResourceProviderFactory)
// Wire up the internal provisioners first. These might be overridden
// by discovered providers below.
for name := range InternalProviders {
client, err := internalPluginClient("provider", name)
if err != nil {
log.Printf("[WARN] failed to build command line for internal plugin %q: %s", name, err)
continue
}
factories[name] = providerFactory(client)
}
byName := plugins.ByName()
for name, metas := range byName {
// Since we validated versions above and we partitioned the sets
// by name, we're guaranteed that the metas in our set all have
// valid versions and that there's at least one meta.
newest := metas.Newest()
client := newest.Client()
factories[name] = providerFactory(client)
}
return factories
}
func (m *Meta) provisionerFactories() map[string]terraform.ResourceProvisionerFactory {
var dirs []string
// When searching the following directories, earlier entries get precedence
// if the same plugin version is found twice, but newer versions will
// always get preference below regardless of where they are coming from.
//
// NOTE: Currently we don't use versioning for provisioners, so the
// version handling here is just the minimum required to be able to use
// the plugin discovery package. All provisioner plugins should always
// be versionless, which we treat as version 0.0.0 here.
dirs = append(dirs, ".")
dirs = append(dirs, m.GlobalPluginDirs...)
plugins := discovery.FindPlugins("provisioner", dirs)
plugins, _ = plugins.ValidateVersions()
// For now our goal is to just find the latest version of each plugin
// we have on the system. All provisioners should be at version 0.0.0
// currently, so there should actually only be one instance of each plugin
// name here, even though the discovery interface forces us to pretend
// that might not be true.
factories := make(map[string]terraform.ResourceProvisionerFactory)
// Wire up the internal provisioners first. These might be overridden
// by discovered provisioners below.
for name := range InternalProvisioners {
client, err := internalPluginClient("provisioner", name)
if err != nil {
log.Printf("[WARN] failed to build command line for internal plugin %q: %s", name, err)
continue
}
factories[name] = provisionerFactory(client)
}
byName := plugins.ByName()
for name, metas := range byName {
// Since we validated versions above and we partitioned the sets
// by name, we're guaranteed that the metas in our set all have
// valid versions and that there's at least one meta.
newest := metas.Newest()
client := newest.Client()
factories[name] = provisionerFactory(client)
}
return factories
}
func internalPluginClient(kind, name string) (*plugin.Client, error) {
cmdLine, err := BuildPluginCommandString(kind, name)
if err != nil {
return nil, err
}
// See the docstring for BuildPluginCommandString for why we need to do
// this split here.
cmdArgv := strings.Split(cmdLine, TFSPACE)
cfg := &plugin.ClientConfig{
Cmd: exec.Command(cmdArgv[0], cmdArgv[1:]...),
HandshakeConfig: tfplugin.Handshake,
Managed: true,
Plugins: tfplugin.PluginMap,
}
return plugin.NewClient(cfg), nil
}
func providerFactory(client *plugin.Client) terraform.ResourceProviderFactory {
return func() (terraform.ResourceProvider, error) {
// Request the RPC client so we can get the provider
// so we can build the actual RPC-implemented provider.
rpcClient, err := client.Client()
if err != nil {
return nil, err
}
raw, err := rpcClient.Dispense(tfplugin.ProviderPluginName)
if err != nil {
return nil, err
}
return raw.(terraform.ResourceProvider), nil
}
}
func provisionerFactory(client *plugin.Client) terraform.ResourceProvisionerFactory {
return func() (terraform.ResourceProvisioner, error) {
// Request the RPC client so we can get the provisioner
// so we can build the actual RPC-implemented provisioner.
rpcClient, err := client.Client()
if err != nil {
return nil, err
}
raw, err := rpcClient.Dispense(tfplugin.ProvisionerPluginName)
if err != nil {
return nil, err
}
return raw.(terraform.ResourceProvisioner), nil
}
}

View File

@ -40,7 +40,7 @@ func TestPush_good(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &PushCommand{ c := &PushCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
@ -101,7 +101,7 @@ func TestPush_goodBackendInit(t *testing.T) {
ui = new(cli.MockUi) ui = new(cli.MockUi)
c := &PushCommand{ c := &PushCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
@ -148,7 +148,7 @@ func TestPush_noUploadModules(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &PushCommand{ c := &PushCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
@ -168,7 +168,7 @@ func TestPush_noUploadModules(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &GetCommand{ c := &GetCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -238,7 +238,7 @@ func TestPush_input(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &PushCommand{ c := &PushCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
@ -297,7 +297,7 @@ func TestPush_inputPartial(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &PushCommand{ c := &PushCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
@ -367,7 +367,7 @@ func TestPush_localOverride(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &PushCommand{ c := &PushCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
@ -446,7 +446,7 @@ func TestPush_remoteOverride(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &PushCommand{ c := &PushCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
@ -537,7 +537,7 @@ func TestPush_preferAtlas(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &PushCommand{ c := &PushCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
@ -613,7 +613,7 @@ func TestPush_tfvars(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &PushCommand{ c := &PushCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
@ -688,7 +688,7 @@ func TestPush_name(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &PushCommand{ c := &PushCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
@ -716,7 +716,7 @@ func TestPush_noState(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &PushCommand{ c := &PushCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -801,7 +801,7 @@ func TestPush_plan(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &PushCommand{ c := &PushCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }

View File

@ -22,7 +22,7 @@ func TestRefresh(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &RefreshCommand{ c := &RefreshCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -71,7 +71,7 @@ func TestRefresh_empty(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &RefreshCommand{ c := &RefreshCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -105,7 +105,7 @@ func TestRefresh_lockedState(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &RefreshCommand{ c := &RefreshCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -145,7 +145,7 @@ func TestRefresh_cwd(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &RefreshCommand{ c := &RefreshCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -217,7 +217,7 @@ func TestRefresh_defaultState(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &RefreshCommand{ c := &RefreshCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -290,7 +290,7 @@ func TestRefresh_futureState(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &RefreshCommand{ c := &RefreshCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -333,7 +333,7 @@ func TestRefresh_pastState(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &RefreshCommand{ c := &RefreshCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -392,7 +392,7 @@ func TestRefresh_outPath(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &RefreshCommand{ c := &RefreshCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -467,7 +467,7 @@ func TestRefresh_var(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &RefreshCommand{ c := &RefreshCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -497,7 +497,7 @@ func TestRefresh_varFile(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &RefreshCommand{ c := &RefreshCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -532,7 +532,7 @@ func TestRefresh_varFileDefault(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &RefreshCommand{ c := &RefreshCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -582,7 +582,7 @@ func TestRefresh_varsUnset(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &RefreshCommand{ c := &RefreshCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -622,7 +622,7 @@ func TestRefresh_backup(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &RefreshCommand{ c := &RefreshCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -707,7 +707,7 @@ func TestRefresh_disableBackup(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &RefreshCommand{ c := &RefreshCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -776,7 +776,7 @@ func TestRefresh_displaysOutputs(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &RefreshCommand{ c := &RefreshCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }

View File

@ -16,7 +16,7 @@ func TestShow(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ShowCommand{ c := &ShowCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -61,7 +61,7 @@ func TestShow_noArgs(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ShowCommand{ c := &ShowCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -93,7 +93,7 @@ func TestShow_noArgsNoState(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ShowCommand{ c := &ShowCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -112,7 +112,7 @@ func TestShow_plan(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ShowCommand{ c := &ShowCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -138,7 +138,7 @@ func TestShow_noArgsRemoteState(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ShowCommand{ c := &ShowCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }
@ -162,7 +162,7 @@ func TestShow_state(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ShowCommand{ c := &ShowCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
}, },
} }

View File

@ -17,7 +17,7 @@ func TestStateList(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &StateListCommand{ c := &StateListCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -48,7 +48,7 @@ func TestStateList_backendState(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &StateListCommand{ c := &StateListCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -74,7 +74,7 @@ func TestStateList_noState(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &StateListCommand{ c := &StateListCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }

View File

@ -47,7 +47,7 @@ func TestStateMv(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &StateMvCommand{ c := &StateMvCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -114,7 +114,7 @@ func TestStateMv_backupExplicit(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &StateMvCommand{ c := &StateMvCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -169,7 +169,7 @@ func TestStateMv_stateOutNew(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &StateMvCommand{ c := &StateMvCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -241,7 +241,7 @@ func TestStateMv_stateOutExisting(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &StateMvCommand{ c := &StateMvCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -282,7 +282,7 @@ func TestStateMv_noState(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &StateMvCommand{ c := &StateMvCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -343,7 +343,7 @@ func TestStateMv_stateOutNew_count(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &StateMvCommand{ c := &StateMvCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -521,7 +521,7 @@ func TestStateMv_stateOutNew_largeCount(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &StateMvCommand{ c := &StateMvCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -602,7 +602,7 @@ func TestStateMv_stateOutNew_nestedModule(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &StateMvCommand{ c := &StateMvCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }

View File

@ -21,7 +21,7 @@ func TestStatePull(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &StatePullCommand{ c := &StatePullCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -46,7 +46,7 @@ func TestStatePull_noState(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &StatePullCommand{ c := &StatePullCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }

View File

@ -23,7 +23,7 @@ func TestStatePush_empty(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &StatePushCommand{ c := &StatePushCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -52,7 +52,7 @@ func TestStatePush_replaceMatch(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &StatePushCommand{ c := &StatePushCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -88,7 +88,7 @@ func TestStatePush_replaceMatchStdin(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &StatePushCommand{ c := &StatePushCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -117,7 +117,7 @@ func TestStatePush_lineageMismatch(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &StatePushCommand{ c := &StatePushCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -146,7 +146,7 @@ func TestStatePush_serialNewer(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &StatePushCommand{ c := &StatePushCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -175,7 +175,7 @@ func TestStatePush_serialOlder(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &StatePushCommand{ c := &StatePushCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }

View File

@ -47,7 +47,7 @@ func TestStateRm(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &StateRmCommand{ c := &StateRmCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -113,7 +113,7 @@ func TestStateRm_backupExplicit(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &StateRmCommand{ c := &StateRmCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -147,7 +147,7 @@ func TestStateRm_noState(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &StateRmCommand{ c := &StateRmCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }

View File

@ -35,7 +35,7 @@ func TestStateShow(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &StateShowCommand{ c := &StateShowCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -93,7 +93,7 @@ func TestStateShow_multi(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &StateShowCommand{ c := &StateShowCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -115,7 +115,7 @@ func TestStateShow_noState(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &StateShowCommand{ c := &StateShowCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -135,7 +135,7 @@ func TestStateShow_emptyState(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &StateShowCommand{ c := &StateShowCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }
@ -164,7 +164,7 @@ func TestStateShow_emptyStateWithModule(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &StateShowCommand{ c := &StateShowCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }

View File

@ -35,7 +35,7 @@ func TestUnlock(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &UnlockCommand{ c := &UnlockCommand{
Meta: Meta{ Meta: Meta{
ContextOpts: testCtxConfig(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
}, },
} }

View File

@ -31,7 +31,8 @@ func init() {
meta := command.Meta{ meta := command.Meta{
Color: true, Color: true,
ContextOpts: &ContextOpts, GlobalPluginDirs: globalPluginDirs(),
PluginOverrides: &PluginOverrides,
Ui: Ui, Ui: Ui,
} }

265
config.go
View File

@ -6,17 +6,9 @@ import (
"io/ioutil" "io/ioutil"
"log" "log"
"os" "os"
"os/exec"
"path/filepath"
"strings"
"github.com/hashicorp/go-plugin"
"github.com/hashicorp/hcl" "github.com/hashicorp/hcl"
"github.com/hashicorp/terraform/command" "github.com/hashicorp/terraform/command"
tfplugin "github.com/hashicorp/terraform/plugin"
"github.com/hashicorp/terraform/terraform"
"github.com/kardianos/osext"
"github.com/mitchellh/cli"
) )
// Config is the structure of the configuration for the Terraform CLI. // Config is the structure of the configuration for the Terraform CLI.
@ -35,8 +27,9 @@ type Config struct {
// can be overridden by user configurations. // can be overridden by user configurations.
var BuiltinConfig Config var BuiltinConfig Config
// ContextOpts are the global ContextOpts we use to initialize the CLI. // PluginOverrides are paths that override discovered plugins, set from
var ContextOpts terraform.ContextOpts // the config file.
var PluginOverrides command.PluginOverrides
// ConfigFile returns the default path to the configuration file. // ConfigFile returns the default path to the configuration file.
// //
@ -85,88 +78,6 @@ func LoadConfig(path string) (*Config, error) {
return &result, nil return &result, nil
} }
// Discover plugins located on disk, and fall back on plugins baked into the
// Terraform binary.
//
// We look in the following places for plugins:
//
// 1. Terraform configuration path
// 2. Path where Terraform is installed
// 3. Path where Terraform is invoked
//
// Whichever file is discoverd LAST wins.
//
// Finally, we look at the list of plugins compiled into Terraform. If any of
// them has not been found on disk we use the internal version. This allows
// users to add / replace plugins without recompiling the main binary.
func (c *Config) Discover(ui cli.Ui) error {
// Look in ~/.terraform.d/plugins/
dir, err := ConfigDir()
if err != nil {
log.Printf("[ERR] Error loading config directory: %s", err)
} else {
if err := c.discover(filepath.Join(dir, "plugins")); err != nil {
return err
}
}
// Next, look in the same directory as the Terraform executable, usually
// /usr/local/bin. If found, this replaces what we found in the config path.
exePath, err := osext.Executable()
if err != nil {
log.Printf("[ERR] Error loading exe directory: %s", err)
} else {
if err := c.discover(filepath.Dir(exePath)); err != nil {
return err
}
}
// Finally look in the cwd (where we are invoke Terraform). If found, this
// replaces anything we found in the config / install paths.
if err := c.discover("."); err != nil {
return err
}
// Finally, if we have a plugin compiled into Terraform and we didn't find
// a replacement on disk, we'll just use the internal version. Only do this
// from the main process, or the log output will break the plugin handshake.
if os.Getenv("TF_PLUGIN_MAGIC_COOKIE") == "" {
for name, _ := range command.InternalProviders {
if path, found := c.Providers[name]; found {
// Allow these warnings to be suppressed via TF_PLUGIN_DEV=1 or similar
if os.Getenv("TF_PLUGIN_DEV") == "" {
ui.Warn(fmt.Sprintf("[WARN] %s overrides an internal plugin for %s-provider.\n"+
" If you did not expect to see this message you will need to remove the old plugin.\n"+
" See https://www.terraform.io/docs/internals/internal-plugins.html", path, name))
}
} else {
cmd, err := command.BuildPluginCommandString("provider", name)
if err != nil {
return err
}
c.Providers[name] = cmd
}
}
for name, _ := range command.InternalProvisioners {
if path, found := c.Provisioners[name]; found {
if os.Getenv("TF_PLUGIN_DEV") == "" {
ui.Warn(fmt.Sprintf("[WARN] %s overrides an internal plugin for %s-provisioner.\n"+
" If you did not expect to see this message you will need to remove the old plugin.\n"+
" See https://www.terraform.io/docs/internals/internal-plugins.html", path, name))
}
} else {
cmd, err := command.BuildPluginCommandString("provisioner", name)
if err != nil {
return err
}
c.Provisioners[name] = cmd
}
}
}
return nil
}
// Merge merges two configurations and returns a third entirely // Merge merges two configurations and returns a third entirely
// new configuration with the two merged. // new configuration with the two merged.
func (c1 *Config) Merge(c2 *Config) *Config { func (c1 *Config) Merge(c2 *Config) *Config {
@ -196,173 +107,3 @@ func (c1 *Config) Merge(c2 *Config) *Config {
return &result return &result
} }
func (c *Config) discover(path string) error {
var err error
if !filepath.IsAbs(path) {
path, err = filepath.Abs(path)
if err != nil {
return err
}
}
err = c.discoverSingle(
filepath.Join(path, "terraform-provider-*"), &c.Providers)
if err != nil {
return err
}
err = c.discoverSingle(
filepath.Join(path, "terraform-provisioner-*"), &c.Provisioners)
if err != nil {
return err
}
return nil
}
func (c *Config) discoverSingle(glob string, m *map[string]string) error {
matches, err := filepath.Glob(glob)
if err != nil {
return err
}
if *m == nil {
*m = make(map[string]string)
}
for _, match := range matches {
file := filepath.Base(match)
// If the filename has a ".", trim up to there
if idx := strings.Index(file, "."); idx >= 0 {
file = file[:idx]
}
// Look for foo-bar-baz. The plugin name is "baz"
parts := strings.SplitN(file, "-", 3)
if len(parts) != 3 {
continue
}
log.Printf("[DEBUG] Discovered plugin: %s = %s", parts[2], match)
(*m)[parts[2]] = match
}
return nil
}
// ProviderFactories returns the mapping of prefixes to
// ResourceProviderFactory that can be used to instantiate a
// binary-based plugin.
func (c *Config) ProviderFactories() map[string]terraform.ResourceProviderFactory {
result := make(map[string]terraform.ResourceProviderFactory)
for k, v := range c.Providers {
result[k] = c.providerFactory(v)
}
return result
}
func (c *Config) providerFactory(path string) terraform.ResourceProviderFactory {
// Build the plugin client configuration and init the plugin
var config plugin.ClientConfig
config.Cmd = pluginCmd(path)
config.HandshakeConfig = tfplugin.Handshake
config.Managed = true
config.Plugins = tfplugin.PluginMap
client := plugin.NewClient(&config)
return func() (terraform.ResourceProvider, error) {
// Request the RPC client so we can get the provider
// so we can build the actual RPC-implemented provider.
rpcClient, err := client.Client()
if err != nil {
return nil, err
}
raw, err := rpcClient.Dispense(tfplugin.ProviderPluginName)
if err != nil {
return nil, err
}
return raw.(terraform.ResourceProvider), nil
}
}
// ProvisionerFactories returns the mapping of prefixes to
// ResourceProvisionerFactory that can be used to instantiate a
// binary-based plugin.
func (c *Config) ProvisionerFactories() map[string]terraform.ResourceProvisionerFactory {
result := make(map[string]terraform.ResourceProvisionerFactory)
for k, v := range c.Provisioners {
result[k] = c.provisionerFactory(v)
}
return result
}
func (c *Config) provisionerFactory(path string) terraform.ResourceProvisionerFactory {
// Build the plugin client configuration and init the plugin
var config plugin.ClientConfig
config.HandshakeConfig = tfplugin.Handshake
config.Cmd = pluginCmd(path)
config.Managed = true
config.Plugins = tfplugin.PluginMap
client := plugin.NewClient(&config)
return func() (terraform.ResourceProvisioner, error) {
rpcClient, err := client.Client()
if err != nil {
return nil, err
}
raw, err := rpcClient.Dispense(tfplugin.ProvisionerPluginName)
if err != nil {
return nil, err
}
return raw.(terraform.ResourceProvisioner), nil
}
}
func pluginCmd(path string) *exec.Cmd {
cmdPath := ""
// If the path doesn't contain a separator, look in the same
// directory as the Terraform executable first.
if !strings.ContainsRune(path, os.PathSeparator) {
exePath, err := osext.Executable()
if err == nil {
temp := filepath.Join(
filepath.Dir(exePath),
filepath.Base(path))
if _, err := os.Stat(temp); err == nil {
cmdPath = temp
}
}
// If we still haven't found the executable, look for it
// in the PATH.
if v, err := exec.LookPath(path); err == nil {
cmdPath = v
}
}
// No plugin binary found, so try to use an internal plugin.
if strings.Contains(path, command.TFSPACE) {
parts := strings.Split(path, command.TFSPACE)
return exec.Command(parts[0], parts[1:]...)
}
// If we still don't have a path, then just set it to the original
// given path.
if cmdPath == "" {
cmdPath = path
}
// Build the command to execute the plugin
return exec.Command(cmdPath)
}

10
main.go
View File

@ -108,10 +108,6 @@ func wrappedMain() int {
// Load the configuration // Load the configuration
config := BuiltinConfig config := BuiltinConfig
if err := config.Discover(Ui); err != nil {
Ui.Error(fmt.Sprintf("Error discovering plugins: %s", err))
return 1
}
// Load the configuration file if we have one, that can be used to // Load the configuration file if we have one, that can be used to
// define extra providers and provisioners. // define extra providers and provisioners.
@ -185,9 +181,9 @@ func wrappedMain() int {
HelpWriter: os.Stdout, HelpWriter: os.Stdout,
} }
// Initialize the TFConfig settings for the commands... // Pass in the overriding plugin paths from config
ContextOpts.Providers = config.ProviderFactories() PluginOverrides.Providers = config.Providers
ContextOpts.Provisioners = config.ProvisionerFactories() PluginOverrides.Provisioners = config.Provisioners
exitCode, err := cliRunner.Run() exitCode, err := cliRunner.Run()
if err != nil { if err != nil {

37
plugins.go Normal file
View File

@ -0,0 +1,37 @@
package main
import (
"log"
"path/filepath"
"github.com/kardianos/osext"
)
// globalPluginDirs returns directories that should be searched for
// globally-installed plugins (not specific to the current configuration).
//
// Earlier entries in this slice get priority over later when multiple copies
// of the same plugin version are found, but newer versions always override
// older versions where both satisfy the provider version constraints.
func globalPluginDirs() []string {
var ret []string
// Look in the same directory as the Terraform executable.
// If found, this replaces what we found in the config path.
exePath, err := osext.Executable()
if err != nil {
log.Printf("[ERROR] Error discovering exe directory: %s", err)
} else {
ret = append(ret, filepath.Dir(exePath))
}
// Look in ~/.terraform.d/plugins/ , or its equivalent on non-UNIX
dir, err := ConfigDir()
if err != nil {
log.Printf("[ERROR] Error finding global config directory: %s", err)
} else {
ret = append(ret, filepath.Join(dir, "plugins"))
}
return ret
}