terraform: start Input

This commit is contained in:
Mitchell Hashimoto 2015-02-13 17:29:38 -08:00
parent 7b305d1f41
commit f3714f1efc
3 changed files with 105 additions and 19 deletions

View File

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

View File

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

View File

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