command: use new API

This commit is contained in:
Mitchell Hashimoto 2014-07-03 11:46:40 -07:00
parent adcd6486a2
commit a6ae7230d1
11 changed files with 69 additions and 89 deletions

View File

@ -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 {

View File

@ -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{

View File

@ -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
}

View File

@ -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

View File

@ -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))

View File

@ -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

View File

@ -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{

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -66,7 +66,7 @@ func NewContext(opts *ContextOpts) *Context {
providers: opts.Providers,
variables: opts.Variables,
sh: sh,
sh: sh,
}
}