From f3714f1efcbf3d3e7acc69edd86ee8a3a47bc91a Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 13 Feb 2015 17:29:38 -0800 Subject: [PATCH] terraform: start Input --- terraform/context.go | 102 ++++++++++++++++++++++++++++++++++++++ terraform/context_old.go | 16 ------ terraform/context_test.go | 6 +-- 3 files changed, 105 insertions(+), 19 deletions(-) diff --git a/terraform/context.go b/terraform/context.go index dcf72bb2c..bca51d734 100644 --- a/terraform/context.go +++ b/terraform/context.go @@ -2,12 +2,30 @@ package terraform import ( "fmt" + "sort" "sync" "github.com/hashicorp/go-multierror" + "github.com/hashicorp/terraform/config" "github.com/hashicorp/terraform/config/module" ) +// InputMode defines what sort of input will be asked for when Input +// is called on Context. +type InputMode byte + +const ( + // InputModeVar asks for variables + InputModeVar InputMode = 1 << iota + + // InputModeProvider asks for provider variables + InputModeProvider + + // InputModeStd is the standard operating mode and asks for both variables + // and providers. + InputModeStd = InputModeVar | InputModeProvider +) + // ContextOpts are the user-configurable options to create a context with // NewContext. type ContextOpts struct { @@ -36,6 +54,7 @@ type Context2 struct { sh *stopHook state *State stateLock sync.RWMutex + uiInput UIInput variables map[string]string l sync.Mutex // Lock acquired during any task @@ -69,6 +88,7 @@ func NewContext2(opts *ContextOpts) *Context2 { provisioners: opts.Provisioners, sh: sh, state: state, + uiInput: opts.UIInput, variables: opts.Variables, } } @@ -96,6 +116,88 @@ func (c *Context2) GraphBuilder() GraphBuilder { } } +// Input asks for input to fill variables and provider configurations. +// This modifies the configuration in-place, so asking for Input twice +// may result in different UI output showing different current values. +func (c *Context2) Input(mode InputMode) error { + v := c.acquireRun() + defer c.releaseRun(v) + + if mode&InputModeVar != 0 { + // Walk the variables first for the root module. We walk them in + // alphabetical order for UX reasons. + rootConf := c.module.Config() + names := make([]string, len(rootConf.Variables)) + m := make(map[string]*config.Variable) + for i, v := range rootConf.Variables { + names[i] = v.Name + m[v.Name] = v + } + sort.Strings(names) + for _, n := range names { + v := m[n] + switch v.Type() { + case config.VariableTypeMap: + continue + case config.VariableTypeString: + // Good! + default: + panic(fmt.Sprintf("Unknown variable type: %#v", v.Type())) + } + + var defaultString string + if v.Default != nil { + defaultString = v.Default.(string) + } + + // Ask the user for a value for this variable + var value string + for { + var err error + value, err = c.uiInput.Input(&InputOpts{ + Id: fmt.Sprintf("var.%s", n), + Query: fmt.Sprintf("var.%s", n), + Default: defaultString, + Description: v.Description, + }) + if err != nil { + return fmt.Errorf( + "Error asking for %s: %s", n, err) + } + + if value == "" && v.Required() { + // Redo if it is required. + continue + } + + if value == "" { + // No value, just exit the loop. With no value, we just + // use whatever is currently set in variables. + break + } + + break + } + + if value != "" { + c.variables[n] = value + } + } + } + + /* + if mode&InputModeProvider != 0 { + // Create the walk context and walk the inputs, which will gather the + // inputs for any resource providers. + wc := c.walkContext(walkInput, rootModulePath) + wc.Meta = new(walkInputMeta) + return wc.Walk() + } + */ + + return nil +} + // Apply applies the changes represented by this context and returns // the resulting state. // diff --git a/terraform/context_old.go b/terraform/context_old.go index 1a1592b86..cb0ec40ed 100644 --- a/terraform/context_old.go +++ b/terraform/context_old.go @@ -42,22 +42,6 @@ type Context struct { sh *stopHook } -// InputMode defines what sort of input will be asked for when Input -// is called on Context. -type InputMode byte - -const ( - // InputModeVar asks for variables - InputModeVar InputMode = 1 << iota - - // InputModeProvider asks for provider variables - InputModeProvider - - // InputModeStd is the standard operating mode and asks for both variables - // and providers. - InputModeStd = InputModeVar | InputModeProvider -) - // NewContext creates a new context. // // Once a context is created, the pointer values within ContextOpts should diff --git a/terraform/context_test.go b/terraform/context_test.go index 0188e7d95..1e31b5c22 100644 --- a/terraform/context_test.go +++ b/terraform/context_test.go @@ -2382,14 +2382,13 @@ func TestContext2Validate_varRefFilled(t *testing.T) { } } -/* -func TestContextInput(t *testing.T) { +func TestContext2Input(t *testing.T) { input := new(MockUIInput) m := testModule(t, "input-vars") p := testProvider("aws") p.ApplyFn = testApplyFn p.DiffFn = testDiffFn - ctx := testContext(t, &ContextOpts{ + ctx := testContext2(t, &ContextOpts{ Module: m, Providers: map[string]ResourceProviderFactory{ "aws": testProviderFuncFixed(p), @@ -2425,6 +2424,7 @@ func TestContextInput(t *testing.T) { } } +/* func TestContextInput_provider(t *testing.T) { m := testModule(t, "input-provider") p := testProvider("aws")