terraform: starting up the plans
This commit is contained in:
parent
a78fe784b8
commit
aae2d4c780
|
@ -26,6 +26,7 @@ type ContextOpts struct {
|
||||||
// perform operations on infrastructure. This structure is built using
|
// perform operations on infrastructure. This structure is built using
|
||||||
// NewContext. See the documentation for that.
|
// NewContext. See the documentation for that.
|
||||||
type Context2 struct {
|
type Context2 struct {
|
||||||
|
diff *Diff
|
||||||
hooks []Hook
|
hooks []Hook
|
||||||
module *module.Tree
|
module *module.Tree
|
||||||
providers map[string]ResourceProviderFactory
|
providers map[string]ResourceProviderFactory
|
||||||
|
@ -41,12 +42,19 @@ type Context2 struct {
|
||||||
// should not be mutated in any way, since the pointers are copied, not
|
// should not be mutated in any way, since the pointers are copied, not
|
||||||
// the values themselves.
|
// the values themselves.
|
||||||
func NewContext2(opts *ContextOpts) *Context2 {
|
func NewContext2(opts *ContextOpts) *Context2 {
|
||||||
|
state := opts.State
|
||||||
|
if state == nil {
|
||||||
|
state = new(State)
|
||||||
|
state.init()
|
||||||
|
}
|
||||||
|
|
||||||
return &Context2{
|
return &Context2{
|
||||||
|
diff: opts.Diff,
|
||||||
hooks: opts.Hooks,
|
hooks: opts.Hooks,
|
||||||
module: opts.Module,
|
module: opts.Module,
|
||||||
providers: opts.Providers,
|
providers: opts.Providers,
|
||||||
provisioners: opts.Provisioners,
|
provisioners: opts.Provisioners,
|
||||||
state: opts.State,
|
state: state,
|
||||||
variables: opts.Variables,
|
variables: opts.Variables,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,6 +81,51 @@ func (c *Context2) GraphBuilder() GraphBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Plan generates an execution plan for the given context.
|
||||||
|
//
|
||||||
|
// The execution plan encapsulates the context and can be stored
|
||||||
|
// in order to reinstantiate a context later for Apply.
|
||||||
|
//
|
||||||
|
// Plan also updates the diff of this context to be the diff generated
|
||||||
|
// by the plan, so Apply can be called after.
|
||||||
|
func (c *Context2) Plan(opts *PlanOpts) (*Plan, error) {
|
||||||
|
p := &Plan{
|
||||||
|
Module: c.module,
|
||||||
|
Vars: c.variables,
|
||||||
|
State: c.state,
|
||||||
|
}
|
||||||
|
|
||||||
|
var operation walkOperation
|
||||||
|
if opts != nil && opts.Destroy {
|
||||||
|
operation = walkPlanDestroy
|
||||||
|
} else {
|
||||||
|
// Set our state to be something temporary. We do this so that
|
||||||
|
// the plan can update a fake state so that variables work, then
|
||||||
|
// we replace it back with our old state.
|
||||||
|
old := c.state
|
||||||
|
if old == nil {
|
||||||
|
c.state = &State{}
|
||||||
|
c.state.init()
|
||||||
|
} else {
|
||||||
|
c.state = old.deepcopy()
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
c.state = old
|
||||||
|
}()
|
||||||
|
|
||||||
|
operation = walkPlan
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do the walk
|
||||||
|
walker, err := c.walk(operation)
|
||||||
|
p.Diff = walker.Diff
|
||||||
|
|
||||||
|
// Update the diff so that our context is up-to-date
|
||||||
|
c.diff = p.Diff
|
||||||
|
|
||||||
|
return p, err
|
||||||
|
}
|
||||||
|
|
||||||
// Refresh goes through all the resources in the state and refreshes them
|
// Refresh goes through all the resources in the state and refreshes them
|
||||||
// to their latest state. This will update the state that this context
|
// to their latest state. This will update the state that this context
|
||||||
// works with, along with returning it.
|
// works with, along with returning it.
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -49,6 +49,10 @@ type EvalContext interface {
|
||||||
// that is currently being acted upon.
|
// that is currently being acted upon.
|
||||||
Interpolate(*config.RawConfig, *Resource) (*ResourceConfig, error)
|
Interpolate(*config.RawConfig, *Resource) (*ResourceConfig, error)
|
||||||
|
|
||||||
|
// Diff returns the global diff as well as the lock that should
|
||||||
|
// be used to modify that diff.
|
||||||
|
Diff() (*Diff, *sync.RWMutex)
|
||||||
|
|
||||||
// State returns the global state as well as the lock that should
|
// State returns the global state as well as the lock that should
|
||||||
// be used to modify that state.
|
// be used to modify that state.
|
||||||
State() (*State, *sync.RWMutex)
|
State() (*State, *sync.RWMutex)
|
||||||
|
@ -96,6 +100,10 @@ type MockEvalContext struct {
|
||||||
PathCalled bool
|
PathCalled bool
|
||||||
PathPath []string
|
PathPath []string
|
||||||
|
|
||||||
|
DiffCalled bool
|
||||||
|
DiffDiff *Diff
|
||||||
|
DiffLock *sync.RWMutex
|
||||||
|
|
||||||
StateCalled bool
|
StateCalled bool
|
||||||
StateState *State
|
StateState *State
|
||||||
StateLock *sync.RWMutex
|
StateLock *sync.RWMutex
|
||||||
|
@ -156,6 +164,11 @@ func (c *MockEvalContext) Path() []string {
|
||||||
return c.PathPath
|
return c.PathPath
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *MockEvalContext) Diff() (*Diff, *sync.RWMutex) {
|
||||||
|
c.DiffCalled = true
|
||||||
|
return c.DiffDiff, c.DiffLock
|
||||||
|
}
|
||||||
|
|
||||||
func (c *MockEvalContext) State() (*State, *sync.RWMutex) {
|
func (c *MockEvalContext) State() (*State, *sync.RWMutex) {
|
||||||
c.StateCalled = true
|
c.StateCalled = true
|
||||||
return c.StateState, c.StateLock
|
return c.StateState, c.StateLock
|
||||||
|
|
|
@ -22,6 +22,8 @@ type BuiltinEvalContext struct {
|
||||||
Provisioners map[string]ResourceProvisionerFactory
|
Provisioners map[string]ResourceProvisionerFactory
|
||||||
ProvisionerCache map[string]ResourceProvisioner
|
ProvisionerCache map[string]ResourceProvisioner
|
||||||
ProvisionerLock *sync.Mutex
|
ProvisionerLock *sync.Mutex
|
||||||
|
DiffValue *Diff
|
||||||
|
DiffLock *sync.RWMutex
|
||||||
StateValue *State
|
StateValue *State
|
||||||
StateLock *sync.RWMutex
|
StateLock *sync.RWMutex
|
||||||
|
|
||||||
|
@ -177,6 +179,10 @@ func (ctx *BuiltinEvalContext) Path() []string {
|
||||||
return ctx.PathValue
|
return ctx.PathValue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ctx *BuiltinEvalContext) Diff() (*Diff, *sync.RWMutex) {
|
||||||
|
return ctx.DiffValue, ctx.DiffLock
|
||||||
|
}
|
||||||
|
|
||||||
func (ctx *BuiltinEvalContext) State() (*State, *sync.RWMutex) {
|
func (ctx *BuiltinEvalContext) State() (*State, *sync.RWMutex) {
|
||||||
return ctx.StateValue, ctx.StateLock
|
return ctx.StateValue, ctx.StateLock
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,131 @@
|
||||||
|
package terraform
|
||||||
|
|
||||||
|
// EvalDiff is an EvalNode implementation that does a refresh for
|
||||||
|
// a resource.
|
||||||
|
type EvalDiff struct {
|
||||||
|
Info *InstanceInfo
|
||||||
|
Config EvalNode
|
||||||
|
Provider EvalNode
|
||||||
|
State EvalNode
|
||||||
|
Output *InstanceDiff
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *EvalDiff) Args() ([]EvalNode, []EvalType) {
|
||||||
|
return []EvalNode{n.Config, n.Provider, n.State},
|
||||||
|
[]EvalType{EvalTypeConfig, EvalTypeResourceProvider,
|
||||||
|
EvalTypeInstanceState}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: test
|
||||||
|
func (n *EvalDiff) Eval(
|
||||||
|
ctx EvalContext, args []interface{}) (interface{}, error) {
|
||||||
|
// Extract our arguments
|
||||||
|
var state *InstanceState
|
||||||
|
config := args[0].(*ResourceConfig)
|
||||||
|
provider := args[1].(ResourceProvider)
|
||||||
|
if args[2] != nil {
|
||||||
|
state = args[2].(*InstanceState)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call pre-diff hook
|
||||||
|
err := ctx.Hook(func(h Hook) (HookAction, error) {
|
||||||
|
return h.PreDiff(n.Info, state)
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// The state for the diff must never be nil
|
||||||
|
diffState := state
|
||||||
|
if diffState == nil {
|
||||||
|
diffState = new(InstanceState)
|
||||||
|
}
|
||||||
|
diffState.init()
|
||||||
|
|
||||||
|
// Diff!
|
||||||
|
diff, err := provider.Diff(n.Info, diffState, config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if diff == nil {
|
||||||
|
diff = new(InstanceDiff)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Require a destroy if there is no ID and it requires new.
|
||||||
|
if diff.RequiresNew() && state != nil && state.ID != "" {
|
||||||
|
diff.Destroy = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we're creating a new resource, compute its ID
|
||||||
|
if diff.RequiresNew() || state == nil || state.ID == "" {
|
||||||
|
var oldID string
|
||||||
|
if state != nil {
|
||||||
|
oldID = state.Attributes["id"]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add diff to compute new ID
|
||||||
|
diff.init()
|
||||||
|
diff.Attributes["id"] = &ResourceAttrDiff{
|
||||||
|
Old: oldID,
|
||||||
|
NewComputed: true,
|
||||||
|
RequiresNew: true,
|
||||||
|
Type: DiffAttrOutput,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call post-refresh hook
|
||||||
|
err = ctx.Hook(func(h Hook) (HookAction, error) {
|
||||||
|
return h.PostDiff(n.Info, diff)
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update our output
|
||||||
|
*n.Output = *diff
|
||||||
|
|
||||||
|
// Merge our state so that the state is updated with our plan
|
||||||
|
if !diff.Empty() {
|
||||||
|
state = state.MergeDiff(diff)
|
||||||
|
}
|
||||||
|
|
||||||
|
return state, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *EvalDiff) Type() EvalType {
|
||||||
|
return EvalTypeInstanceState
|
||||||
|
}
|
||||||
|
|
||||||
|
// EvalWriteDiff is an EvalNode implementation that writes the diff to
|
||||||
|
// the full diff.
|
||||||
|
type EvalWriteDiff struct {
|
||||||
|
Name string
|
||||||
|
Diff *InstanceDiff
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *EvalWriteDiff) Args() ([]EvalNode, []EvalType) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: test
|
||||||
|
func (n *EvalWriteDiff) Eval(
|
||||||
|
ctx EvalContext, args []interface{}) (interface{}, error) {
|
||||||
|
diff, lock := ctx.Diff()
|
||||||
|
|
||||||
|
// Acquire the lock so that we can do this safely concurrently
|
||||||
|
lock.Lock()
|
||||||
|
defer lock.Unlock()
|
||||||
|
|
||||||
|
// Write the diff
|
||||||
|
modDiff := diff.ModuleByPath(ctx.Path())
|
||||||
|
if modDiff == nil {
|
||||||
|
modDiff = diff.AddModule(ctx.Path())
|
||||||
|
}
|
||||||
|
modDiff.Resources[n.Name] = n.Diff
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *EvalWriteDiff) Type() EvalType {
|
||||||
|
return EvalTypeNull
|
||||||
|
}
|
|
@ -17,5 +17,6 @@ const (
|
||||||
EvalTypeConfig // *ResourceConfig
|
EvalTypeConfig // *ResourceConfig
|
||||||
EvalTypeResourceProvider // ResourceProvider
|
EvalTypeResourceProvider // ResourceProvider
|
||||||
EvalTypeResourceProvisioner // ResourceProvisioner
|
EvalTypeResourceProvisioner // ResourceProvisioner
|
||||||
|
EvalTypeInstanceDiff // *InstanceDiff
|
||||||
EvalTypeInstanceState // *InstanceState
|
EvalTypeInstanceState // *InstanceState
|
||||||
)
|
)
|
||||||
|
|
|
@ -10,7 +10,8 @@ const (
|
||||||
_EvalType_name_2 = "EvalTypeConfig"
|
_EvalType_name_2 = "EvalTypeConfig"
|
||||||
_EvalType_name_3 = "EvalTypeResourceProvider"
|
_EvalType_name_3 = "EvalTypeResourceProvider"
|
||||||
_EvalType_name_4 = "EvalTypeResourceProvisioner"
|
_EvalType_name_4 = "EvalTypeResourceProvisioner"
|
||||||
_EvalType_name_5 = "EvalTypeInstanceState"
|
_EvalType_name_5 = "EvalTypeInstanceDiff"
|
||||||
|
_EvalType_name_6 = "EvalTypeInstanceState"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -19,7 +20,8 @@ var (
|
||||||
_EvalType_index_2 = [...]uint8{0, 14}
|
_EvalType_index_2 = [...]uint8{0, 14}
|
||||||
_EvalType_index_3 = [...]uint8{0, 24}
|
_EvalType_index_3 = [...]uint8{0, 24}
|
||||||
_EvalType_index_4 = [...]uint8{0, 27}
|
_EvalType_index_4 = [...]uint8{0, 27}
|
||||||
_EvalType_index_5 = [...]uint8{0, 21}
|
_EvalType_index_5 = [...]uint8{0, 20}
|
||||||
|
_EvalType_index_6 = [...]uint8{0, 21}
|
||||||
)
|
)
|
||||||
|
|
||||||
func (i EvalType) String() string {
|
func (i EvalType) String() string {
|
||||||
|
@ -36,6 +38,8 @@ func (i EvalType) String() string {
|
||||||
return _EvalType_name_4
|
return _EvalType_name_4
|
||||||
case i == 32:
|
case i == 32:
|
||||||
return _EvalType_name_5
|
return _EvalType_name_5
|
||||||
|
case i == 64:
|
||||||
|
return _EvalType_name_6
|
||||||
default:
|
default:
|
||||||
return fmt.Sprintf("EvalType(%d)", i)
|
return fmt.Sprintf("EvalType(%d)", i)
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,11 +19,13 @@ type ContextGraphWalker struct {
|
||||||
// Outputs, do not set these. Do not read these while the graph
|
// Outputs, do not set these. Do not read these while the graph
|
||||||
// is being walked.
|
// is being walked.
|
||||||
EvalError error
|
EvalError error
|
||||||
|
Diff *Diff
|
||||||
ValidationWarnings []string
|
ValidationWarnings []string
|
||||||
ValidationErrors []error
|
ValidationErrors []error
|
||||||
|
|
||||||
errorLock sync.Mutex
|
errorLock sync.Mutex
|
||||||
once sync.Once
|
once sync.Once
|
||||||
|
diffLock sync.RWMutex
|
||||||
providerCache map[string]ResourceProvider
|
providerCache map[string]ResourceProvider
|
||||||
providerConfigCache map[string]*ResourceConfig
|
providerConfigCache map[string]*ResourceConfig
|
||||||
providerLock sync.Mutex
|
providerLock sync.Mutex
|
||||||
|
@ -44,6 +46,8 @@ func (w *ContextGraphWalker) EnterGraph(g *Graph) EvalContext {
|
||||||
Provisioners: w.Context.provisioners,
|
Provisioners: w.Context.provisioners,
|
||||||
ProvisionerCache: w.provisionerCache,
|
ProvisionerCache: w.provisionerCache,
|
||||||
ProvisionerLock: &w.provisionerLock,
|
ProvisionerLock: &w.provisionerLock,
|
||||||
|
DiffValue: w.Diff,
|
||||||
|
DiffLock: &w.diffLock,
|
||||||
StateValue: w.Context.state,
|
StateValue: w.Context.state,
|
||||||
StateLock: &w.Context.stateLock,
|
StateLock: &w.Context.stateLock,
|
||||||
Interpolater: &Interpolater{
|
Interpolater: &Interpolater{
|
||||||
|
@ -87,6 +91,9 @@ func (w *ContextGraphWalker) ExitEvalTree(
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *ContextGraphWalker) init() {
|
func (w *ContextGraphWalker) init() {
|
||||||
|
w.Diff = new(Diff)
|
||||||
|
w.Diff.init()
|
||||||
|
|
||||||
w.providerCache = make(map[string]ResourceProvider, 5)
|
w.providerCache = make(map[string]ResourceProvider, 5)
|
||||||
w.providerConfigCache = make(map[string]*ResourceConfig, 5)
|
w.providerConfigCache = make(map[string]*ResourceConfig, 5)
|
||||||
w.provisionerCache = make(map[string]ResourceProvisioner, 5)
|
w.provisionerCache = make(map[string]ResourceProvisioner, 5)
|
||||||
|
|
|
@ -115,6 +115,32 @@ func (n *graphNodeExpandedResource) EvalTree() EvalNode {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Diff the resource
|
||||||
|
var diff InstanceDiff
|
||||||
|
seq.Nodes = append(seq.Nodes, &EvalOpFilter{
|
||||||
|
Ops: []walkOperation{walkPlan},
|
||||||
|
Node: &EvalSequence{
|
||||||
|
Nodes: []EvalNode{
|
||||||
|
&EvalWriteState{
|
||||||
|
Name: n.stateId(),
|
||||||
|
ResourceType: n.Resource.Type,
|
||||||
|
Dependencies: n.DependentOn(),
|
||||||
|
State: &EvalDiff{
|
||||||
|
Info: info,
|
||||||
|
Config: &EvalInterpolate{Config: n.Resource.RawConfig},
|
||||||
|
Provider: &EvalGetProvider{Name: n.ProvidedBy()[0]},
|
||||||
|
State: &EvalReadState{Name: n.stateId()},
|
||||||
|
Output: &diff,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&EvalWriteDiff{
|
||||||
|
Name: n.stateId(),
|
||||||
|
Diff: &diff,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
return seq
|
return seq
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue