terraform: provisioners
This commit is contained in:
parent
f8871917f5
commit
819aed67d4
|
@ -3204,8 +3204,7 @@ func TestContext2Apply_nilDiff(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
func TestContextApply_Provisioner_compute(t *testing.T) {
|
||||
func TestContext2Apply_Provisioner_compute(t *testing.T) {
|
||||
m := testModule(t, "apply-provisioner-compute")
|
||||
p := testProvider("aws")
|
||||
pr := testProvisioner()
|
||||
|
@ -3219,7 +3218,7 @@ func TestContextApply_Provisioner_compute(t *testing.T) {
|
|||
|
||||
return nil
|
||||
}
|
||||
ctx := testContext(t, &ContextOpts{
|
||||
ctx := testContext2(t, &ContextOpts{
|
||||
Module: m,
|
||||
Providers: map[string]ResourceProviderFactory{
|
||||
"aws": testProviderFuncFixed(p),
|
||||
|
@ -3253,6 +3252,7 @@ func TestContextApply_Provisioner_compute(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
func TestContextApply_provisionerCreateFail(t *testing.T) {
|
||||
m := testModule(t, "apply-provisioner-fail-create")
|
||||
p := testProvider("aws")
|
||||
|
|
|
@ -38,7 +38,7 @@ func (EvalEarlyExitError) Error() string { return "early exit" }
|
|||
func Eval(n EvalNode, ctx EvalContext) (interface{}, error) {
|
||||
// Call the lower level eval which doesn't understand early exit,
|
||||
// and if we early exit, it isn't an error.
|
||||
result, err := eval(n, ctx)
|
||||
result, err := EvalRaw(n, ctx)
|
||||
if err != nil {
|
||||
if _, ok := err.(EvalEarlyExitError); ok {
|
||||
return nil, nil
|
||||
|
@ -48,11 +48,13 @@ func Eval(n EvalNode, ctx EvalContext) (interface{}, error) {
|
|||
return result, err
|
||||
}
|
||||
|
||||
func eval(n EvalNode, ctx EvalContext) (interface{}, error) {
|
||||
// EvalRaw is like Eval except that it returns all errors, even if they
|
||||
// signal something normal such as EvalEarlyExitError.
|
||||
func EvalRaw(n EvalNode, ctx EvalContext) (interface{}, error) {
|
||||
argNodes, _ := n.Args()
|
||||
args := make([]interface{}, len(argNodes))
|
||||
for i, n := range argNodes {
|
||||
v, err := eval(n, ctx)
|
||||
v, err := EvalRaw(n, ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package terraform
|
|||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strconv"
|
||||
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/hashicorp/terraform/config"
|
||||
|
@ -16,6 +17,8 @@ type EvalApply struct {
|
|||
Diff **InstanceDiff
|
||||
Provider *ResourceProvider
|
||||
Output **InstanceState
|
||||
Error *error
|
||||
Tainted *bool
|
||||
}
|
||||
|
||||
func (n *EvalApply) Args() ([]EvalNode, []EvalType) {
|
||||
|
@ -81,9 +84,186 @@ func (n *EvalApply) Eval(
|
|||
*n.Output = state
|
||||
}
|
||||
|
||||
// Set the tainted state
|
||||
if n.Tainted != nil {
|
||||
*n.Tainted = err != nil
|
||||
}
|
||||
|
||||
// If there are no errors, then we append it to our output error
|
||||
// if we have one, otherwise we just output it.
|
||||
if err != nil {
|
||||
if n.Error != nil {
|
||||
*n.Error = multierror.Append(*n.Error, err)
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (n *EvalApply) Type() EvalType {
|
||||
return EvalTypeNull
|
||||
}
|
||||
|
||||
// EvalApplyProvisioners is an EvalNode implementation that executes
|
||||
// the provisioners for a resource.
|
||||
//
|
||||
// TODO(mitchellh): This should probably be split up into a more fine-grained
|
||||
// ApplyProvisioner (single) that is looped over.
|
||||
type EvalApplyProvisioners struct {
|
||||
Info *InstanceInfo
|
||||
State **InstanceState
|
||||
Resource *config.Resource
|
||||
InterpResource *Resource
|
||||
Tainted *bool
|
||||
Error *error
|
||||
}
|
||||
|
||||
func (n *EvalApplyProvisioners) Args() ([]EvalNode, []EvalType) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// TODO: test
|
||||
func (n *EvalApplyProvisioners) Eval(
|
||||
ctx EvalContext, args []interface{}) (interface{}, error) {
|
||||
state := *n.State
|
||||
|
||||
if *n.Tainted {
|
||||
// We're already tainted, so just return out
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
{
|
||||
// Call pre hook
|
||||
err := ctx.Hook(func(h Hook) (HookAction, error) {
|
||||
return h.PreProvisionResource(n.Info, state)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// If there are no errors, then we append it to our output error
|
||||
// if we have one, otherwise we just output it.
|
||||
err := n.apply(ctx)
|
||||
if n.Tainted != nil {
|
||||
*n.Tainted = err != nil
|
||||
}
|
||||
if err != nil {
|
||||
if n.Error != nil {
|
||||
*n.Error = multierror.Append(*n.Error, err)
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Call post hook
|
||||
err := ctx.Hook(func(h Hook) (HookAction, error) {
|
||||
return h.PostProvisionResource(n.Info, state)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (n *EvalApplyProvisioners) Type() EvalType {
|
||||
return EvalTypeNull
|
||||
}
|
||||
|
||||
func (n *EvalApplyProvisioners) apply(ctx EvalContext) error {
|
||||
state := *n.State
|
||||
|
||||
// Store the original connection info, restore later
|
||||
origConnInfo := state.Ephemeral.ConnInfo
|
||||
defer func() {
|
||||
state.Ephemeral.ConnInfo = origConnInfo
|
||||
}()
|
||||
|
||||
for _, prov := range n.Resource.Provisioners {
|
||||
// Get the provisioner
|
||||
provisioner := ctx.Provisioner(prov.Type)
|
||||
|
||||
// Interpolate the provisioner config
|
||||
provConfig, err := ctx.Interpolate(prov.RawConfig, n.InterpResource)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Interpolate the conn info, since it may contain variables
|
||||
connInfo, err := ctx.Interpolate(prov.ConnInfo, n.InterpResource)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Merge the connection information
|
||||
overlay := make(map[string]string)
|
||||
if origConnInfo != nil {
|
||||
for k, v := range origConnInfo {
|
||||
overlay[k] = v
|
||||
}
|
||||
}
|
||||
for k, v := range connInfo.Config {
|
||||
switch vt := v.(type) {
|
||||
case string:
|
||||
overlay[k] = vt
|
||||
case int64:
|
||||
overlay[k] = strconv.FormatInt(vt, 10)
|
||||
case int32:
|
||||
overlay[k] = strconv.FormatInt(int64(vt), 10)
|
||||
case int:
|
||||
overlay[k] = strconv.FormatInt(int64(vt), 10)
|
||||
case float32:
|
||||
overlay[k] = strconv.FormatFloat(float64(vt), 'f', 3, 32)
|
||||
case float64:
|
||||
overlay[k] = strconv.FormatFloat(vt, 'f', 3, 64)
|
||||
case bool:
|
||||
overlay[k] = strconv.FormatBool(vt)
|
||||
default:
|
||||
overlay[k] = fmt.Sprintf("%v", vt)
|
||||
}
|
||||
}
|
||||
state.Ephemeral.ConnInfo = overlay
|
||||
|
||||
{
|
||||
// Call pre hook
|
||||
err := ctx.Hook(func(h Hook) (HookAction, error) {
|
||||
return h.PreProvision(n.Info, prov.Type)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// The output function
|
||||
outputFn := func(msg string) {
|
||||
ctx.Hook(func(h Hook) (HookAction, error) {
|
||||
h.ProvisionOutput(n.Info, prov.Type, msg)
|
||||
return HookActionContinue, nil
|
||||
})
|
||||
}
|
||||
|
||||
// Invoke the Provisioner
|
||||
output := CallbackUIOutput{OutputFn: outputFn}
|
||||
if err := provisioner.Apply(&output, state, provConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
{
|
||||
// Call post hook
|
||||
err := ctx.Hook(func(h Hook) (HookAction, error) {
|
||||
return h.PostProvision(n.Info, prov.Type)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
|
|
@ -66,8 +66,9 @@ type EvalWriteState struct {
|
|||
ResourceType string
|
||||
Dependencies []string
|
||||
State **InstanceState
|
||||
Tainted bool
|
||||
Tainted *bool
|
||||
TaintedIndex int
|
||||
TaintedClearPrimary bool
|
||||
}
|
||||
|
||||
func (n *EvalWriteState) Args() ([]EvalNode, []EvalType) {
|
||||
|
@ -102,9 +103,15 @@ func (n *EvalWriteState) Eval(
|
|||
rs.Type = n.ResourceType
|
||||
rs.Dependencies = n.Dependencies
|
||||
|
||||
if n.Tainted {
|
||||
if n.Tainted != nil && *n.Tainted {
|
||||
if n.TaintedIndex != -1 {
|
||||
rs.Tainted[n.TaintedIndex] = *n.State
|
||||
} else {
|
||||
rs.Tainted = append(rs.Tainted, *n.State)
|
||||
}
|
||||
|
||||
if n.TaintedClearPrimary {
|
||||
rs.Primary = nil
|
||||
}
|
||||
} else {
|
||||
// Set the primary state
|
||||
|
|
|
@ -185,9 +185,9 @@ func (n *GraphNodeConfigResource) DependableName() []string {
|
|||
// GraphNodeDependent impl.
|
||||
func (n *GraphNodeConfigResource) DependentOn() []string {
|
||||
result := make([]string, len(n.Resource.DependsOn),
|
||||
len(n.Resource.RawCount.Variables)+
|
||||
(len(n.Resource.RawCount.Variables)+
|
||||
len(n.Resource.RawConfig.Variables)+
|
||||
len(n.Resource.DependsOn))
|
||||
len(n.Resource.DependsOn))*2)
|
||||
copy(result, n.Resource.DependsOn)
|
||||
for _, v := range n.Resource.RawCount.Variables {
|
||||
if vn := varNameForVar(v); vn != "" {
|
||||
|
@ -199,6 +199,18 @@ func (n *GraphNodeConfigResource) DependentOn() []string {
|
|||
result = append(result, vn)
|
||||
}
|
||||
}
|
||||
for _, p := range n.Resource.Provisioners {
|
||||
for _, v := range p.ConnInfo.Variables {
|
||||
if vn := varNameForVar(v); vn != "" {
|
||||
result = append(result, vn)
|
||||
}
|
||||
}
|
||||
for _, v := range p.RawConfig.Variables {
|
||||
if vn := varNameForVar(v); vn != "" {
|
||||
result = append(result, vn)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
|
|
@ -222,6 +222,8 @@ func (n *graphNodeExpandedResource) EvalTree() EvalNode {
|
|||
// Diff the resource for destruction
|
||||
var provider ResourceProvider
|
||||
var diffApply *InstanceDiff
|
||||
var err error
|
||||
var tainted bool
|
||||
seq.Nodes = append(seq.Nodes, &EvalOpFilter{
|
||||
Ops: []walkOperation{walkApply},
|
||||
Node: &EvalSequence{
|
||||
|
@ -262,6 +264,8 @@ func (n *graphNodeExpandedResource) EvalTree() EvalNode {
|
|||
Diff: &diffApply,
|
||||
Provider: &provider,
|
||||
Output: &state,
|
||||
Error: &err,
|
||||
Tainted: &tainted,
|
||||
},
|
||||
&EvalWriteState{
|
||||
Name: n.stateId(),
|
||||
|
@ -269,6 +273,23 @@ func (n *graphNodeExpandedResource) EvalTree() EvalNode {
|
|||
Dependencies: n.DependentOn(),
|
||||
State: &state,
|
||||
},
|
||||
&EvalApplyProvisioners{
|
||||
Info: info,
|
||||
State: &state,
|
||||
Resource: n.Resource,
|
||||
InterpResource: resource,
|
||||
Tainted: &tainted,
|
||||
Error: &err,
|
||||
},
|
||||
&EvalWriteState{
|
||||
Name: n.stateId(),
|
||||
ResourceType: n.Resource.Type,
|
||||
Dependencies: n.DependentOn(),
|
||||
State: &state,
|
||||
Tainted: &tainted,
|
||||
TaintedIndex: -1,
|
||||
TaintedClearPrimary: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
|
@ -66,6 +66,7 @@ func (n *graphNodeTaintedResource) ProvidedBy() []string {
|
|||
// GraphNodeEvalable impl.
|
||||
func (n *graphNodeTaintedResource) EvalTree() EvalNode {
|
||||
var state *InstanceState
|
||||
tainted := true
|
||||
|
||||
seq := &EvalSequence{Nodes: make([]EvalNode, 0, 5)}
|
||||
|
||||
|
@ -95,7 +96,7 @@ func (n *graphNodeTaintedResource) EvalTree() EvalNode {
|
|||
ResourceType: n.ResourceType,
|
||||
Dependencies: n.DependentOn(),
|
||||
State: &state,
|
||||
Tainted: true,
|
||||
Tainted: &tainted,
|
||||
TaintedIndex: n.Index,
|
||||
},
|
||||
},
|
||||
|
@ -140,7 +141,7 @@ func (n *graphNodeTaintedResource) EvalTree() EvalNode {
|
|||
ResourceType: n.ResourceType,
|
||||
Dependencies: n.DependentOn(),
|
||||
State: &state,
|
||||
Tainted: true,
|
||||
Tainted: &tainted,
|
||||
TaintedIndex: n.Index,
|
||||
},
|
||||
},
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
package terraform
|
||||
|
||||
type CallbackUIOutput struct {
|
||||
OutputFun func(string)
|
||||
OutputFn func(string)
|
||||
}
|
||||
|
||||
func (o *CallbackUIOutput) Output(v string) {
|
||||
o.OutputFn(v)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package terraform
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCallbackUIOutput_impl(t *testing.T) {
|
||||
var _ UIOutput = new(CallbackUIOutput)
|
||||
}
|
Loading…
Reference in New Issue