diff --git a/command/apply.go b/command/apply.go index e8e14940b..da5499970 100644 --- a/command/apply.go +++ b/command/apply.go @@ -13,9 +13,9 @@ import ( // ApplyCommand is a Command implementation that applies a Terraform // configuration and actually builds or changes infrastructure. type ApplyCommand struct { - ShutdownCh <-chan struct{} - TFConfig *terraform.Config - Ui cli.Ui + ShutdownCh <-chan struct{} + ContextOpts *terraform.ContextOpts + Ui cli.Ui } func (c *ApplyCommand) Run(args []string) int { @@ -44,21 +44,14 @@ func (c *ApplyCommand) Run(args []string) int { stateOutPath = statePath } - // Initialize Terraform right away - c.TFConfig.Hooks = append(c.TFConfig.Hooks, &UiHook{Ui: c.Ui}) - tf, err := terraform.New(c.TFConfig) - if err != nil { - c.Ui.Error(fmt.Sprintf("Error initializing Terraform: %s", err)) - return 1 - } - - // Attempt to read a plan from the path given. This is how we test that - // it is a plan or not (kind of jank, but if it quacks like a duck...) planStatePath := statePath if init { planStatePath = "" } - plan, err := PlanArg(configPath, planStatePath, tf) + + // Initialize Terraform right away + c.ContextOpts.Hooks = append(c.ContextOpts.Hooks, &UiHook{Ui: c.Ui}) + ctx, err := ContextArg(configPath, planStatePath, c.ContextOpts) if err != nil { c.Ui.Error(err.Error()) return 1 @@ -67,7 +60,7 @@ func (c *ApplyCommand) Run(args []string) int { errCh := make(chan error) stateCh := make(chan *terraform.State) go func() { - state, err := tf.Apply(plan) + state, err := ctx.Apply() if err != nil { errCh <- err return @@ -83,7 +76,7 @@ func (c *ApplyCommand) Run(args []string) int { c.Ui.Output("Interrupt received. Gracefully shutting down...") // Stop execution - tf.Stop() + ctx.Stop() // Still get the result, since there is still one select { diff --git a/command/apply_test.go b/command/apply_test.go index 163ac9121..8f89f8221 100644 --- a/command/apply_test.go +++ b/command/apply_test.go @@ -6,6 +6,7 @@ import ( "testing" "time" + "github.com/hashicorp/terraform/config" "github.com/hashicorp/terraform/terraform" "github.com/mitchellh/cli" ) @@ -16,8 +17,8 @@ func TestApply(t *testing.T) { p := testProvider() ui := new(cli.MockUi) c := &ApplyCommand{ - TFConfig: testTFConfig(p), - Ui: ui, + ContextOpts: testCtxConfig(p), + Ui: ui, } args := []string{ @@ -52,8 +53,8 @@ func TestApply_configInvalid(t *testing.T) { p := testProvider() ui := new(cli.MockUi) c := &ApplyCommand{ - TFConfig: testTFConfig(p), - Ui: ui, + ContextOpts: testCtxConfig(p), + Ui: ui, } args := []string{ @@ -67,14 +68,16 @@ func TestApply_configInvalid(t *testing.T) { } func TestApply_plan(t *testing.T) { - planPath := testPlanFile(t, new(terraform.Plan)) + planPath := testPlanFile(t, &terraform.Plan{ + Config: new(config.Config), + }) statePath := testTempFile(t) p := testProvider() ui := new(cli.MockUi) c := &ApplyCommand{ - TFConfig: testTFConfig(p), - Ui: ui, + ContextOpts: testCtxConfig(p), + Ui: ui, } args := []string{ @@ -115,9 +118,9 @@ func TestApply_shutdown(t *testing.T) { shutdownCh := make(chan struct{}) ui := new(cli.MockUi) c := &ApplyCommand{ - ShutdownCh: shutdownCh, - TFConfig: testTFConfig(p), - Ui: ui, + ContextOpts: testCtxConfig(p), + ShutdownCh: shutdownCh, + Ui: ui, } p.DiffFn = func( @@ -215,8 +218,8 @@ func TestApply_state(t *testing.T) { ui := new(cli.MockUi) c := &ApplyCommand{ - TFConfig: testTFConfig(p), - Ui: ui, + ContextOpts: testCtxConfig(p), + Ui: ui, } // Run the apply command pointing to our existing state @@ -262,8 +265,8 @@ func TestApply_stateNoExist(t *testing.T) { p := testProvider() ui := new(cli.MockUi) c := &ApplyCommand{ - TFConfig: testTFConfig(p), - Ui: ui, + ContextOpts: testCtxConfig(p), + Ui: ui, } args := []string{ diff --git a/command/command.go b/command/command.go index 0805202b2..f87ed0787 100644 --- a/command/command.go +++ b/command/command.go @@ -8,17 +8,17 @@ import ( "github.com/hashicorp/terraform/terraform" ) -func PlanArg( +func ContextArg( path string, statePath string, - tf *terraform.Terraform) (*terraform.Plan, error) { + opts *terraform.ContextOpts) (*terraform.Context, error) { // First try to just read the plan directly from the path given. f, err := os.Open(path) if err == nil { plan, err := terraform.ReadPlan(f) f.Close() if err == nil { - return plan, nil + return plan.Context(opts), nil } } @@ -59,13 +59,13 @@ func PlanArg( return nil, fmt.Errorf("Error validating config: %s", err) } - plan, err := tf.Plan(&terraform.PlanOpts{ - Config: config, - State: state, - }) - if err != nil { + opts.Config = config + opts.State = state + ctx := terraform.NewContext(opts) + + if _, err := ctx.Plan(nil); err != nil { return nil, fmt.Errorf("Error running plan: %s", err) } - return plan, nil + return ctx, nil } diff --git a/command/command_test.go b/command/command_test.go index 074db94b8..2f3207aa7 100644 --- a/command/command_test.go +++ b/command/command_test.go @@ -16,8 +16,8 @@ func testFixturePath(name string) string { return filepath.Join(fixtureDir, name, "main.tf") } -func testTFConfig(p terraform.ResourceProvider) *terraform.Config { - return &terraform.Config{ +func testCtxConfig(p terraform.ResourceProvider) *terraform.ContextOpts { + return &terraform.ContextOpts{ Providers: map[string]terraform.ResourceProviderFactory{ "test": func() (terraform.ResourceProvider, error) { return p, nil diff --git a/command/graph.go b/command/graph.go index bca522e9d..0d36166cd 100644 --- a/command/graph.go +++ b/command/graph.go @@ -15,8 +15,8 @@ import ( // GraphCommand is a Command implementation that takes a Terraform // configuration and outputs the dependency tree in graphical form. type GraphCommand struct { - TFConfig *terraform.Config - Ui cli.Ui + ContextOpts *terraform.ContextOpts + Ui cli.Ui } func (c *GraphCommand) Run(args []string) int { @@ -41,7 +41,7 @@ func (c *GraphCommand) Run(args []string) int { g, err := terraform.Graph(&terraform.GraphOpts{ Config: conf, - Providers: c.TFConfig.Providers, + Providers: c.ContextOpts.Providers, }) if err != nil { c.Ui.Error(fmt.Sprintf("Error creating graph: %s", err)) diff --git a/command/plan.go b/command/plan.go index 5781f0156..7f729a62d 100644 --- a/command/plan.go +++ b/command/plan.go @@ -15,8 +15,8 @@ import ( // PlanCommand is a Command implementation that compares a Terraform // configuration to an actual infrastructure and shows the differences. type PlanCommand struct { - TFConfig *terraform.Config - Ui cli.Ui + ContextOpts *terraform.ContextOpts + Ui cli.Ui } func (c *PlanCommand) Run(args []string) int { @@ -65,26 +65,19 @@ func (c *PlanCommand) Run(args []string) int { return 1 } - c.TFConfig.Hooks = append(c.TFConfig.Hooks, &UiHook{Ui: c.Ui}) - tf, err := terraform.New(c.TFConfig) - if err != nil { - c.Ui.Error(fmt.Sprintf("Error initializing Terraform: %s", err)) - return 1 - } + c.ContextOpts.Config = b + c.ContextOpts.Hooks = append(c.ContextOpts.Hooks, &UiHook{Ui: c.Ui}) + c.ContextOpts.State = state + ctx := terraform.NewContext(c.ContextOpts) if refresh { - state, err = tf.Refresh(b, state) - if err != nil { + if _, err := ctx.Refresh(); err != nil { c.Ui.Error(fmt.Sprintf("Error refreshing state: %s", err)) return 1 } } - plan, err := tf.Plan(&terraform.PlanOpts{ - Config: b, - Destroy: destroy, - State: state, - }) + plan, err := ctx.Plan(&terraform.PlanOpts{Destroy: destroy}) if err != nil { c.Ui.Error(fmt.Sprintf("Error running plan: %s", err)) return 1 diff --git a/command/plan_test.go b/command/plan_test.go index 4ef71cb2e..948cd73d9 100644 --- a/command/plan_test.go +++ b/command/plan_test.go @@ -26,8 +26,8 @@ func TestPlan_destroy(t *testing.T) { p := testProvider() ui := new(cli.MockUi) c := &PlanCommand{ - TFConfig: testTFConfig(p), - Ui: ui, + ContextOpts: testCtxConfig(p), + Ui: ui, } args := []string{ @@ -51,8 +51,8 @@ func TestPlan_noState(t *testing.T) { p := testProvider() ui := new(cli.MockUi) c := &PlanCommand{ - TFConfig: testTFConfig(p), - Ui: ui, + ContextOpts: testCtxConfig(p), + Ui: ui, } args := []string{ @@ -87,8 +87,8 @@ func TestPlan_outPath(t *testing.T) { p := testProvider() ui := new(cli.MockUi) c := &PlanCommand{ - TFConfig: testTFConfig(p), - Ui: ui, + ContextOpts: testCtxConfig(p), + Ui: ui, } p.DiffReturn = &terraform.ResourceDiff{ @@ -118,8 +118,8 @@ func TestPlan_refresh(t *testing.T) { p := testProvider() ui := new(cli.MockUi) c := &PlanCommand{ - TFConfig: testTFConfig(p), - Ui: ui, + ContextOpts: testCtxConfig(p), + Ui: ui, } args := []string{ @@ -162,8 +162,8 @@ func TestPlan_state(t *testing.T) { p := testProvider() ui := new(cli.MockUi) c := &PlanCommand{ - TFConfig: testTFConfig(p), - Ui: ui, + ContextOpts: testCtxConfig(p), + Ui: ui, } args := []string{ diff --git a/command/refresh.go b/command/refresh.go index b3c9f4bb1..7bec37034 100644 --- a/command/refresh.go +++ b/command/refresh.go @@ -15,8 +15,8 @@ import ( // RefreshCommand is a cli.Command implementation that refreshes the state // file. type RefreshCommand struct { - TFConfig *terraform.Config - Ui cli.Ui + ContextOpts *terraform.ContextOpts + Ui cli.Ui } func (c *RefreshCommand) Run(args []string) int { @@ -66,14 +66,11 @@ func (c *RefreshCommand) Run(args []string) int { return 1 } - c.TFConfig.Hooks = append(c.TFConfig.Hooks, &UiHook{Ui: c.Ui}) - tf, err := terraform.New(c.TFConfig) - if err != nil { - c.Ui.Error(fmt.Sprintf("Error initializing Terraform: %s", err)) - return 1 - } + c.ContextOpts.Config = b + c.ContextOpts.Hooks = append(c.ContextOpts.Hooks, &UiHook{Ui: c.Ui}) + ctx := terraform.NewContext(c.ContextOpts) - state, err = tf.Refresh(b, state) + state, err = ctx.Refresh() if err != nil { c.Ui.Error(fmt.Sprintf("Error refreshing state: %s", err)) return 1 diff --git a/command/refresh_test.go b/command/refresh_test.go index 192f42137..9f65e92c1 100644 --- a/command/refresh_test.go +++ b/command/refresh_test.go @@ -30,8 +30,8 @@ func TestRefresh(t *testing.T) { p := testProvider() ui := new(cli.MockUi) c := &RefreshCommand{ - TFConfig: testTFConfig(p), - Ui: ui, + ContextOpts: testCtxConfig(p), + Ui: ui, } p.RefreshFn = nil @@ -96,8 +96,8 @@ func TestRefresh_outPath(t *testing.T) { p := testProvider() ui := new(cli.MockUi) c := &RefreshCommand{ - TFConfig: testTFConfig(p), - Ui: ui, + ContextOpts: testCtxConfig(p), + Ui: ui, } p.RefreshFn = nil diff --git a/config.go b/config.go index d0085ab91..10749aab4 100644 --- a/config.go +++ b/config.go @@ -11,12 +11,6 @@ import ( "github.com/mitchellh/osext" ) -// TFConfig is the global base configuration that has the -// basic providers registered. Users of this configuration -// should copy it (call the Copy method) before using it so -// that it isn't corrupted. -var TFConfig terraform.Config - // Config is the structure of the configuration for the Terraform CLI. // // This is not the configuration for Terraform itself. That is in the diff --git a/terraform/context.go b/terraform/context.go index 49463e575..0e7194e58 100644 --- a/terraform/context.go +++ b/terraform/context.go @@ -66,7 +66,7 @@ func NewContext(opts *ContextOpts) *Context { providers: opts.Providers, variables: opts.Variables, - sh: sh, + sh: sh, } }