terraform: provider input
This commit is contained in:
parent
f3714f1efc
commit
7c78a3749e
|
@ -57,8 +57,9 @@ type Context2 struct {
|
|||
uiInput UIInput
|
||||
variables map[string]string
|
||||
|
||||
l sync.Mutex // Lock acquired during any task
|
||||
runCh <-chan struct{}
|
||||
l sync.Mutex // Lock acquired during any task
|
||||
providerInputConfig map[string]map[string]interface{}
|
||||
runCh <-chan struct{}
|
||||
}
|
||||
|
||||
// NewContext creates a new Context structure.
|
||||
|
@ -81,15 +82,16 @@ func NewContext2(opts *ContextOpts) *Context2 {
|
|||
}
|
||||
|
||||
return &Context2{
|
||||
diff: opts.Diff,
|
||||
hooks: hooks,
|
||||
module: opts.Module,
|
||||
providers: opts.Providers,
|
||||
provisioners: opts.Provisioners,
|
||||
sh: sh,
|
||||
state: state,
|
||||
uiInput: opts.UIInput,
|
||||
variables: opts.Variables,
|
||||
diff: opts.Diff,
|
||||
hooks: hooks,
|
||||
module: opts.Module,
|
||||
providers: opts.Providers,
|
||||
providerInputConfig: make(map[string]map[string]interface{}),
|
||||
provisioners: opts.Provisioners,
|
||||
sh: sh,
|
||||
state: state,
|
||||
uiInput: opts.UIInput,
|
||||
variables: opts.Variables,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -185,15 +187,12 @@ func (c *Context2) Input(mode InputMode) error {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
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()
|
||||
if mode&InputModeProvider != 0 {
|
||||
// Do the walk
|
||||
if _, err := c.walk(walkInput); err != nil {
|
||||
return err
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -2424,13 +2424,12 @@ func TestContext2Input(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
func TestContextInput_provider(t *testing.T) {
|
||||
func TestContext2Input_provider(t *testing.T) {
|
||||
m := testModule(t, "input-provider")
|
||||
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),
|
||||
|
@ -2464,6 +2463,7 @@ func TestContextInput_provider(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
func TestContextInput_providerId(t *testing.T) {
|
||||
input := new(MockUIInput)
|
||||
m := testModule(t, "input-provider")
|
||||
|
|
|
@ -15,6 +15,9 @@ type EvalContext interface {
|
|||
// hook and should return the hook action to take and the error.
|
||||
Hook(func(Hook) (HookAction, error)) error
|
||||
|
||||
// Input is the UIInput object for interacting with the UI.
|
||||
Input() UIInput
|
||||
|
||||
// InitProvider initializes the provider with the given name and
|
||||
// returns the implementation of the resource provider or an error.
|
||||
//
|
||||
|
@ -32,6 +35,11 @@ type EvalContext interface {
|
|||
ConfigureProvider(string, *ResourceConfig) error
|
||||
ParentProviderConfig(string) *ResourceConfig
|
||||
|
||||
// ProviderInput and SetProviderInput are used to configure providers
|
||||
// from user input.
|
||||
ProviderInput(string) map[string]interface{}
|
||||
SetProviderInput(string, map[string]interface{})
|
||||
|
||||
// InitProvisioner initializes the provisioner with the given name and
|
||||
// returns the implementation of the resource provisioner or an error.
|
||||
//
|
||||
|
@ -69,6 +77,9 @@ type MockEvalContext struct {
|
|||
HookCalled bool
|
||||
HookError error
|
||||
|
||||
InputCalled bool
|
||||
InputInput UIInput
|
||||
|
||||
InitProviderCalled bool
|
||||
InitProviderName string
|
||||
InitProviderProvider ResourceProvider
|
||||
|
@ -78,6 +89,14 @@ type MockEvalContext struct {
|
|||
ProviderName string
|
||||
ProviderProvider ResourceProvider
|
||||
|
||||
ProviderInputCalled bool
|
||||
ProviderInputName string
|
||||
ProviderInputConfig map[string]interface{}
|
||||
|
||||
SetProviderInputCalled bool
|
||||
SetProviderInputName string
|
||||
SetProviderInputConfig map[string]interface{}
|
||||
|
||||
ConfigureProviderCalled bool
|
||||
ConfigureProviderName string
|
||||
ConfigureProviderConfig *ResourceConfig
|
||||
|
@ -122,6 +141,11 @@ func (c *MockEvalContext) Hook(fn func(Hook) (HookAction, error)) error {
|
|||
return c.HookError
|
||||
}
|
||||
|
||||
func (c *MockEvalContext) Input() UIInput {
|
||||
c.InputCalled = true
|
||||
return c.InputInput
|
||||
}
|
||||
|
||||
func (c *MockEvalContext) InitProvider(n string) (ResourceProvider, error) {
|
||||
c.InitProviderCalled = true
|
||||
c.InitProviderName = n
|
||||
|
@ -147,6 +171,18 @@ func (c *MockEvalContext) ParentProviderConfig(n string) *ResourceConfig {
|
|||
return c.ParentProviderConfigConfig
|
||||
}
|
||||
|
||||
func (c *MockEvalContext) ProviderInput(n string) map[string]interface{} {
|
||||
c.ProviderInputCalled = true
|
||||
c.ProviderInputName = n
|
||||
return c.ProviderInputConfig
|
||||
}
|
||||
|
||||
func (c *MockEvalContext) SetProviderInput(n string, cfg map[string]interface{}) {
|
||||
c.SetProviderInputCalled = true
|
||||
c.SetProviderInputName = n
|
||||
c.SetProviderInputConfig = cfg
|
||||
}
|
||||
|
||||
func (c *MockEvalContext) InitProvisioner(n string) (ResourceProvisioner, error) {
|
||||
c.InitProvisionerCalled = true
|
||||
c.InitProvisionerName = n
|
||||
|
|
|
@ -14,9 +14,11 @@ type BuiltinEvalContext struct {
|
|||
PathValue []string
|
||||
Interpolater *Interpolater
|
||||
Hooks []Hook
|
||||
InputValue UIInput
|
||||
Providers map[string]ResourceProviderFactory
|
||||
ProviderCache map[string]ResourceProvider
|
||||
ProviderConfigCache map[string]*ResourceConfig
|
||||
ProviderInputConfig map[string]map[string]interface{}
|
||||
ProviderLock *sync.Mutex
|
||||
Provisioners map[string]ResourceProvisionerFactory
|
||||
ProvisionerCache map[string]ResourceProvisioner
|
||||
|
@ -49,6 +51,10 @@ func (ctx *BuiltinEvalContext) Hook(fn func(Hook) (HookAction, error)) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (ctx *BuiltinEvalContext) Input() UIInput {
|
||||
return ctx.InputValue
|
||||
}
|
||||
|
||||
func (ctx *BuiltinEvalContext) InitProvider(n string) (ResourceProvider, error) {
|
||||
ctx.once.Do(ctx.init)
|
||||
|
||||
|
@ -100,6 +106,20 @@ func (ctx *BuiltinEvalContext) ConfigureProvider(
|
|||
return p.Configure(cfg)
|
||||
}
|
||||
|
||||
func (ctx *BuiltinEvalContext) ProviderInput(n string) map[string]interface{} {
|
||||
ctx.ProviderLock.Lock()
|
||||
defer ctx.ProviderLock.Unlock()
|
||||
|
||||
return ctx.ProviderInputConfig[n]
|
||||
}
|
||||
|
||||
func (ctx *BuiltinEvalContext) SetProviderInput(n string, c map[string]interface{}) {
|
||||
ctx.ProviderLock.Lock()
|
||||
defer ctx.ProviderLock.Unlock()
|
||||
|
||||
ctx.ProviderInputConfig[n] = c
|
||||
}
|
||||
|
||||
func (ctx *BuiltinEvalContext) ParentProviderConfig(n string) *ResourceConfig {
|
||||
ctx.ProviderLock.Lock()
|
||||
defer ctx.ProviderLock.Unlock()
|
||||
|
|
|
@ -2,6 +2,8 @@ package terraform
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/terraform/config"
|
||||
)
|
||||
|
||||
// EvalConfigProvider is an EvalNode implementation that configures
|
||||
|
@ -17,15 +19,26 @@ func (n *EvalConfigProvider) Args() ([]EvalNode, []EvalType) {
|
|||
|
||||
func (n *EvalConfigProvider) Eval(
|
||||
ctx EvalContext, args []interface{}) (interface{}, error) {
|
||||
config := args[0].(*ResourceConfig)
|
||||
cfg := args[0].(*ResourceConfig)
|
||||
|
||||
// If we have a configuration set, then use that
|
||||
if input := ctx.ProviderInput(n.Provider); input != nil {
|
||||
rc, err := config.NewRawConfig(input)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
merged := cfg.raw.Merge(rc)
|
||||
cfg = NewResourceConfig(merged)
|
||||
}
|
||||
|
||||
// Get the parent configuration if there is one
|
||||
if parent := ctx.ParentProviderConfig(n.Provider); parent != nil {
|
||||
merged := config.raw.Merge(parent.raw)
|
||||
config = NewResourceConfig(merged)
|
||||
merged := cfg.raw.Merge(parent.raw)
|
||||
cfg = NewResourceConfig(merged)
|
||||
}
|
||||
|
||||
return nil, ctx.ConfigureProvider(n.Provider, config)
|
||||
return nil, ctx.ConfigureProvider(n.Provider, cfg)
|
||||
}
|
||||
|
||||
func (n *EvalConfigProvider) Type() EvalType {
|
||||
|
@ -80,3 +93,52 @@ func (n *EvalGetProvider) Eval(
|
|||
func (n *EvalGetProvider) Type() EvalType {
|
||||
return EvalTypeResourceProvider
|
||||
}
|
||||
|
||||
// EvalInputProvider is an EvalNode implementation that asks for input
|
||||
// for the given provider configurations.
|
||||
type EvalInputProvider struct {
|
||||
Name string
|
||||
Provider *ResourceProvider
|
||||
Config *config.RawConfig
|
||||
}
|
||||
|
||||
func (n *EvalInputProvider) Args() ([]EvalNode, []EvalType) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (n *EvalInputProvider) Eval(
|
||||
ctx EvalContext, args []interface{}) (interface{}, error) {
|
||||
// If we already configured this provider, then don't do this again
|
||||
if v := ctx.ProviderInput(n.Name); v != nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
rc := NewResourceConfig(n.Config)
|
||||
rc.Config = make(map[string]interface{})
|
||||
|
||||
// Wrap the input into a namespace
|
||||
input := &PrefixUIInput{
|
||||
IdPrefix: fmt.Sprintf("provider.%s", n.Name),
|
||||
QueryPrefix: fmt.Sprintf("provider.%s.", n.Name),
|
||||
UIInput: ctx.Input(),
|
||||
}
|
||||
|
||||
// Go through each provider and capture the input necessary
|
||||
// to satisfy it.
|
||||
config, err := (*n.Provider).Input(input, rc)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"Error configuring %s: %s", n.Name, err)
|
||||
}
|
||||
|
||||
if config != nil && len(config.Config) > 0 {
|
||||
// Set the configuration
|
||||
ctx.SetProviderInput(n.Name, config.Config)
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (n *EvalInputProvider) Type() EvalType {
|
||||
return EvalTypeNull
|
||||
}
|
||||
|
|
|
@ -7,18 +7,45 @@ import (
|
|||
// ProviderEvalTree returns the evaluation tree for initializing and
|
||||
// configuring providers.
|
||||
func ProviderEvalTree(n string, config *config.RawConfig) EvalNode {
|
||||
return &EvalSequence{
|
||||
Nodes: []EvalNode{
|
||||
&EvalInitProvider{Name: n},
|
||||
&EvalValidateProvider{
|
||||
ProviderName: n,
|
||||
Provider: &EvalGetProvider{Name: n},
|
||||
Config: &EvalInterpolate{Config: config},
|
||||
},
|
||||
&EvalConfigProvider{
|
||||
Provider: n,
|
||||
Config: &EvalInterpolate{Config: config},
|
||||
seq := make([]EvalNode, 0, 5)
|
||||
seq = append(seq, &EvalInitProvider{Name: n})
|
||||
|
||||
// Input stuff
|
||||
var provider ResourceProvider
|
||||
seq = append(seq, &EvalOpFilter{
|
||||
Ops: []walkOperation{walkInput},
|
||||
Node: &EvalSequence{
|
||||
Nodes: []EvalNode{
|
||||
&EvalGetProvider{
|
||||
Name: n,
|
||||
Output: &provider,
|
||||
},
|
||||
&EvalInputProvider{
|
||||
Name: n,
|
||||
Provider: &provider,
|
||||
Config: config,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
// Apply stuff
|
||||
seq = append(seq, &EvalOpFilter{
|
||||
Ops: []walkOperation{walkValidate, walkRefresh, walkPlan, walkApply},
|
||||
Node: &EvalSequence{
|
||||
Nodes: []EvalNode{
|
||||
&EvalValidateProvider{
|
||||
ProviderName: n,
|
||||
Provider: &EvalGetProvider{Name: n},
|
||||
Config: &EvalInterpolate{Config: config},
|
||||
},
|
||||
&EvalConfigProvider{
|
||||
Provider: n,
|
||||
Config: &EvalInterpolate{Config: config},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
return &EvalSequence{Nodes: seq}
|
||||
}
|
||||
|
|
|
@ -55,9 +55,11 @@ func (w *ContextGraphWalker) EnterGraph(g *Graph) EvalContext {
|
|||
ctx := &BuiltinEvalContext{
|
||||
PathValue: g.Path,
|
||||
Hooks: w.Context.hooks,
|
||||
InputValue: w.Context.uiInput,
|
||||
Providers: w.Context.providers,
|
||||
ProviderCache: w.providerCache,
|
||||
ProviderConfigCache: w.providerConfigCache,
|
||||
ProviderInputConfig: w.Context.providerInputConfig,
|
||||
ProviderLock: &w.providerLock,
|
||||
Provisioners: w.Context.provisioners,
|
||||
ProvisionerCache: w.provisionerCache,
|
||||
|
|
Loading…
Reference in New Issue