terraform: provisioners
This commit is contained in:
parent
f8871917f5
commit
819aed67d4
|
@ -3204,8 +3204,7 @@ func TestContext2Apply_nilDiff(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
func TestContext2Apply_Provisioner_compute(t *testing.T) {
|
||||||
func TestContextApply_Provisioner_compute(t *testing.T) {
|
|
||||||
m := testModule(t, "apply-provisioner-compute")
|
m := testModule(t, "apply-provisioner-compute")
|
||||||
p := testProvider("aws")
|
p := testProvider("aws")
|
||||||
pr := testProvisioner()
|
pr := testProvisioner()
|
||||||
|
@ -3219,7 +3218,7 @@ func TestContextApply_Provisioner_compute(t *testing.T) {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
ctx := testContext(t, &ContextOpts{
|
ctx := testContext2(t, &ContextOpts{
|
||||||
Module: m,
|
Module: m,
|
||||||
Providers: map[string]ResourceProviderFactory{
|
Providers: map[string]ResourceProviderFactory{
|
||||||
"aws": testProviderFuncFixed(p),
|
"aws": testProviderFuncFixed(p),
|
||||||
|
@ -3253,6 +3252,7 @@ func TestContextApply_Provisioner_compute(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
func TestContextApply_provisionerCreateFail(t *testing.T) {
|
func TestContextApply_provisionerCreateFail(t *testing.T) {
|
||||||
m := testModule(t, "apply-provisioner-fail-create")
|
m := testModule(t, "apply-provisioner-fail-create")
|
||||||
p := testProvider("aws")
|
p := testProvider("aws")
|
||||||
|
|
|
@ -38,7 +38,7 @@ func (EvalEarlyExitError) Error() string { return "early exit" }
|
||||||
func Eval(n EvalNode, ctx EvalContext) (interface{}, error) {
|
func Eval(n EvalNode, ctx EvalContext) (interface{}, error) {
|
||||||
// Call the lower level eval which doesn't understand early exit,
|
// Call the lower level eval which doesn't understand early exit,
|
||||||
// and if we early exit, it isn't an error.
|
// and if we early exit, it isn't an error.
|
||||||
result, err := eval(n, ctx)
|
result, err := EvalRaw(n, ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if _, ok := err.(EvalEarlyExitError); ok {
|
if _, ok := err.(EvalEarlyExitError); ok {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
@ -48,11 +48,13 @@ func Eval(n EvalNode, ctx EvalContext) (interface{}, error) {
|
||||||
return result, err
|
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()
|
argNodes, _ := n.Args()
|
||||||
args := make([]interface{}, len(argNodes))
|
args := make([]interface{}, len(argNodes))
|
||||||
for i, n := range argNodes {
|
for i, n := range argNodes {
|
||||||
v, err := eval(n, ctx)
|
v, err := EvalRaw(n, ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package terraform
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/hashicorp/go-multierror"
|
"github.com/hashicorp/go-multierror"
|
||||||
"github.com/hashicorp/terraform/config"
|
"github.com/hashicorp/terraform/config"
|
||||||
|
@ -16,6 +17,8 @@ type EvalApply struct {
|
||||||
Diff **InstanceDiff
|
Diff **InstanceDiff
|
||||||
Provider *ResourceProvider
|
Provider *ResourceProvider
|
||||||
Output **InstanceState
|
Output **InstanceState
|
||||||
|
Error *error
|
||||||
|
Tainted *bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *EvalApply) Args() ([]EvalNode, []EvalType) {
|
func (n *EvalApply) Args() ([]EvalNode, []EvalType) {
|
||||||
|
@ -81,9 +84,186 @@ func (n *EvalApply) Eval(
|
||||||
*n.Output = state
|
*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
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *EvalApply) Type() EvalType {
|
func (n *EvalApply) Type() EvalType {
|
||||||
return EvalTypeNull
|
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
|
ResourceType string
|
||||||
Dependencies []string
|
Dependencies []string
|
||||||
State **InstanceState
|
State **InstanceState
|
||||||
Tainted bool
|
Tainted *bool
|
||||||
TaintedIndex int
|
TaintedIndex int
|
||||||
|
TaintedClearPrimary bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *EvalWriteState) Args() ([]EvalNode, []EvalType) {
|
func (n *EvalWriteState) Args() ([]EvalNode, []EvalType) {
|
||||||
|
@ -102,9 +103,15 @@ func (n *EvalWriteState) Eval(
|
||||||
rs.Type = n.ResourceType
|
rs.Type = n.ResourceType
|
||||||
rs.Dependencies = n.Dependencies
|
rs.Dependencies = n.Dependencies
|
||||||
|
|
||||||
if n.Tainted {
|
if n.Tainted != nil && *n.Tainted {
|
||||||
if n.TaintedIndex != -1 {
|
if n.TaintedIndex != -1 {
|
||||||
rs.Tainted[n.TaintedIndex] = *n.State
|
rs.Tainted[n.TaintedIndex] = *n.State
|
||||||
|
} else {
|
||||||
|
rs.Tainted = append(rs.Tainted, *n.State)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n.TaintedClearPrimary {
|
||||||
|
rs.Primary = nil
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Set the primary state
|
// Set the primary state
|
||||||
|
|
|
@ -185,9 +185,9 @@ func (n *GraphNodeConfigResource) DependableName() []string {
|
||||||
// GraphNodeDependent impl.
|
// GraphNodeDependent impl.
|
||||||
func (n *GraphNodeConfigResource) DependentOn() []string {
|
func (n *GraphNodeConfigResource) DependentOn() []string {
|
||||||
result := make([]string, len(n.Resource.DependsOn),
|
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.RawConfig.Variables)+
|
||||||
len(n.Resource.DependsOn))
|
len(n.Resource.DependsOn))*2)
|
||||||
copy(result, n.Resource.DependsOn)
|
copy(result, n.Resource.DependsOn)
|
||||||
for _, v := range n.Resource.RawCount.Variables {
|
for _, v := range n.Resource.RawCount.Variables {
|
||||||
if vn := varNameForVar(v); vn != "" {
|
if vn := varNameForVar(v); vn != "" {
|
||||||
|
@ -199,6 +199,18 @@ func (n *GraphNodeConfigResource) DependentOn() []string {
|
||||||
result = append(result, vn)
|
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
|
return result
|
||||||
}
|
}
|
||||||
|
|
|
@ -222,6 +222,8 @@ func (n *graphNodeExpandedResource) EvalTree() EvalNode {
|
||||||
// Diff the resource for destruction
|
// Diff the resource for destruction
|
||||||
var provider ResourceProvider
|
var provider ResourceProvider
|
||||||
var diffApply *InstanceDiff
|
var diffApply *InstanceDiff
|
||||||
|
var err error
|
||||||
|
var tainted bool
|
||||||
seq.Nodes = append(seq.Nodes, &EvalOpFilter{
|
seq.Nodes = append(seq.Nodes, &EvalOpFilter{
|
||||||
Ops: []walkOperation{walkApply},
|
Ops: []walkOperation{walkApply},
|
||||||
Node: &EvalSequence{
|
Node: &EvalSequence{
|
||||||
|
@ -262,6 +264,8 @@ func (n *graphNodeExpandedResource) EvalTree() EvalNode {
|
||||||
Diff: &diffApply,
|
Diff: &diffApply,
|
||||||
Provider: &provider,
|
Provider: &provider,
|
||||||
Output: &state,
|
Output: &state,
|
||||||
|
Error: &err,
|
||||||
|
Tainted: &tainted,
|
||||||
},
|
},
|
||||||
&EvalWriteState{
|
&EvalWriteState{
|
||||||
Name: n.stateId(),
|
Name: n.stateId(),
|
||||||
|
@ -269,6 +273,23 @@ func (n *graphNodeExpandedResource) EvalTree() EvalNode {
|
||||||
Dependencies: n.DependentOn(),
|
Dependencies: n.DependentOn(),
|
||||||
State: &state,
|
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.
|
// GraphNodeEvalable impl.
|
||||||
func (n *graphNodeTaintedResource) EvalTree() EvalNode {
|
func (n *graphNodeTaintedResource) EvalTree() EvalNode {
|
||||||
var state *InstanceState
|
var state *InstanceState
|
||||||
|
tainted := true
|
||||||
|
|
||||||
seq := &EvalSequence{Nodes: make([]EvalNode, 0, 5)}
|
seq := &EvalSequence{Nodes: make([]EvalNode, 0, 5)}
|
||||||
|
|
||||||
|
@ -95,7 +96,7 @@ func (n *graphNodeTaintedResource) EvalTree() EvalNode {
|
||||||
ResourceType: n.ResourceType,
|
ResourceType: n.ResourceType,
|
||||||
Dependencies: n.DependentOn(),
|
Dependencies: n.DependentOn(),
|
||||||
State: &state,
|
State: &state,
|
||||||
Tainted: true,
|
Tainted: &tainted,
|
||||||
TaintedIndex: n.Index,
|
TaintedIndex: n.Index,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -140,7 +141,7 @@ func (n *graphNodeTaintedResource) EvalTree() EvalNode {
|
||||||
ResourceType: n.ResourceType,
|
ResourceType: n.ResourceType,
|
||||||
Dependencies: n.DependentOn(),
|
Dependencies: n.DependentOn(),
|
||||||
State: &state,
|
State: &state,
|
||||||
Tainted: true,
|
Tainted: &tainted,
|
||||||
TaintedIndex: n.Index,
|
TaintedIndex: n.Index,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
package terraform
|
package terraform
|
||||||
|
|
||||||
type CallbackUIOutput struct {
|
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