terraform: don't put the ResourceState in Resource
This commit is contained in:
parent
82e92e7024
commit
73e2a43427
|
@ -126,15 +126,14 @@ func (c *Context) Apply() (*State, error) {
|
|||
}
|
||||
c.state.init()
|
||||
|
||||
// Initialize the state with all the resources
|
||||
graphInitState(c.state, g)
|
||||
|
||||
// Walk
|
||||
log.Printf("[INFO] Apply walk starting")
|
||||
err = g.Walk(c.applyWalkFn())
|
||||
log.Printf("[INFO] Apply walk complete")
|
||||
|
||||
// Encode the dependencies, this pushes the logical dependencies
|
||||
// into the state so that we can recover it later.
|
||||
EncodeDependencies(g)
|
||||
|
||||
// Prune the state so that we have as clean a state as possible
|
||||
c.state.prune()
|
||||
|
||||
|
@ -209,6 +208,9 @@ func (c *Context) Plan(opts *PlanOpts) (*Plan, error) {
|
|||
c.state = old
|
||||
}()
|
||||
|
||||
// Initialize the state with all the resources
|
||||
graphInitState(c.state, g)
|
||||
|
||||
walkFn = c.planWalkFn(p)
|
||||
}
|
||||
|
||||
|
@ -244,6 +246,12 @@ func (c *Context) Refresh() (*State, error) {
|
|||
return c.state, err
|
||||
}
|
||||
|
||||
if c.state != nil {
|
||||
// Initialize the state with all the resources
|
||||
graphInitState(c.state, g)
|
||||
}
|
||||
|
||||
// Walk the graph
|
||||
err = g.Walk(c.refreshWalkFn())
|
||||
|
||||
// Prune the state
|
||||
|
@ -529,8 +537,11 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Ensure the state is initialized
|
||||
r.State.init()
|
||||
is := r.State
|
||||
if is == nil {
|
||||
is = new(InstanceState)
|
||||
}
|
||||
is.init()
|
||||
|
||||
if !diff.Destroy {
|
||||
// Since we need the configuration, interpolate the variables
|
||||
|
@ -538,7 +549,7 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc {
|
|||
return err
|
||||
}
|
||||
|
||||
diff, err = r.Provider.Diff(r.Info, r.State.Primary, r.Config)
|
||||
diff, err = r.Provider.Diff(r.Info, is, r.Config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -578,12 +589,12 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc {
|
|||
}
|
||||
|
||||
for _, h := range c.hooks {
|
||||
handleHook(h.PreApply(r.Id, r.State.Primary, diff))
|
||||
handleHook(h.PreApply(r.Id, is, diff))
|
||||
}
|
||||
|
||||
// With the completed diff, apply!
|
||||
log.Printf("[DEBUG] %s: Executing Apply", r.Id)
|
||||
is, applyerr := r.Provider.Apply(r.Info, r.State.Primary, diff)
|
||||
is, applyerr := r.Provider.Apply(r.Info, is, diff)
|
||||
|
||||
var errs []error
|
||||
if applyerr != nil {
|
||||
|
@ -611,25 +622,9 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc {
|
|||
}
|
||||
}
|
||||
|
||||
if r.Flags&FlagTainted != 0 {
|
||||
// Update the tainted resource.
|
||||
r.State.Tainted[r.TaintedIndex] = is
|
||||
} else {
|
||||
// Update the primary resource
|
||||
r.State.Primary = is
|
||||
}
|
||||
|
||||
// Update the resulting diff
|
||||
c.sl.Lock()
|
||||
|
||||
// TODO: Get other modules
|
||||
mod := c.state.RootModule()
|
||||
if is.ID == "" && len(r.State.Tainted) == 0 {
|
||||
delete(mod.Resources, r.Id)
|
||||
} else {
|
||||
mod.Resources[r.Id] = r.State
|
||||
}
|
||||
c.sl.Unlock()
|
||||
// Set the result state
|
||||
r.State = is
|
||||
c.persistState(r)
|
||||
|
||||
// Invoke any provisioners we have defined. This is only done
|
||||
// if the resource was created, as updates or deletes do not
|
||||
|
@ -638,9 +633,9 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc {
|
|||
// Additionally, we need to be careful to not run this if there
|
||||
// was an error during the provider apply.
|
||||
tainted := false
|
||||
if applyerr == nil && r.State.Primary.ID != "" && len(r.Provisioners) > 0 {
|
||||
if applyerr == nil && is.ID != "" && len(r.Provisioners) > 0 {
|
||||
for _, h := range c.hooks {
|
||||
handleHook(h.PreProvisionResource(r.Id, r.State.Primary))
|
||||
handleHook(h.PreProvisionResource(r.Id, is))
|
||||
}
|
||||
|
||||
if err := c.applyProvisioners(r, is); err != nil {
|
||||
|
@ -649,27 +644,21 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc {
|
|||
}
|
||||
|
||||
for _, h := range c.hooks {
|
||||
handleHook(h.PostProvisionResource(r.Id, r.State.Primary))
|
||||
handleHook(h.PostProvisionResource(r.Id, is))
|
||||
}
|
||||
}
|
||||
|
||||
c.sl.Lock()
|
||||
if tainted {
|
||||
log.Printf("[DEBUG] %s: Marking as tainted", r.Id)
|
||||
r.State.Tainted = append(r.State.Tainted, r.State.Primary)
|
||||
r.State.Primary = nil
|
||||
}
|
||||
c.sl.Unlock()
|
||||
|
||||
// Update the state for the resource itself
|
||||
if tainted {
|
||||
// If we're tainted then we need to update some flags
|
||||
if tainted && r.Flags&FlagTainted == 0 {
|
||||
r.Flags &^= FlagPrimary
|
||||
r.Flags &^= FlagHasTainted
|
||||
r.Flags |= FlagTainted
|
||||
r.TaintedIndex = -1
|
||||
c.persistState(r)
|
||||
}
|
||||
|
||||
for _, h := range c.hooks {
|
||||
handleHook(h.PostApply(r.Id, r.State.Primary, applyerr))
|
||||
handleHook(h.PostApply(r.Id, is, applyerr))
|
||||
}
|
||||
|
||||
// Determine the new state and update variables
|
||||
|
@ -766,7 +755,7 @@ func (c *Context) planWalkFn(result *Plan) depgraph.WalkFunc {
|
|||
|
||||
var diff *InstanceDiff
|
||||
|
||||
is := r.State.Primary
|
||||
is := r.State
|
||||
|
||||
for _, h := range c.hooks {
|
||||
handleHook(h.PreDiff(r.Id, is))
|
||||
|
@ -786,14 +775,15 @@ func (c *Context) planWalkFn(result *Plan) depgraph.WalkFunc {
|
|||
// Get a diff from the newest state
|
||||
log.Printf("[DEBUG] %s: Executing diff", r.Id)
|
||||
var err error
|
||||
state := r.State
|
||||
if r.Flags&FlagHasTainted != 0 {
|
||||
|
||||
diffIs := is
|
||||
if diffIs == nil || r.Flags&FlagHasTainted != 0 {
|
||||
// If we're tainted, we pretend to create a new thing.
|
||||
state = new(ResourceState)
|
||||
state.Type = r.State.Type
|
||||
diffIs = new(InstanceState)
|
||||
}
|
||||
state.init()
|
||||
diff, err = r.Provider.Diff(r.Info, state.Primary, r.Config)
|
||||
diffIs.init()
|
||||
|
||||
diff, err = r.Provider.Diff(r.Info, diffIs, r.Config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -846,23 +836,9 @@ func (c *Context) planWalkFn(result *Plan) depgraph.WalkFunc {
|
|||
is = is.MergeDiff(diff)
|
||||
}
|
||||
|
||||
// TODO(mitchellh): do we really need this? I had to do this because
|
||||
// the pointer of r.State is shared with the original c.state
|
||||
// which is now result.State, so modifying this was actually
|
||||
// modifying the plan state, which is not what we want. I *think*
|
||||
// this will be solved if we move to having InstanceState on
|
||||
// type Resource rather than ResourceState, so I'm just going to
|
||||
// keep this in here for now to get tests to work.
|
||||
state := r.State.deepcopy()
|
||||
state.Primary = is
|
||||
|
||||
// Update our internal state so that variable computation works
|
||||
c.sl.Lock()
|
||||
defer c.sl.Unlock()
|
||||
|
||||
// TODO: Handle other modules
|
||||
mod := c.state.RootModule()
|
||||
mod.Resources[r.Id] = state
|
||||
// Set it so that it can be updated
|
||||
r.State = is
|
||||
c.persistState(r)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -883,7 +859,7 @@ func (c *Context) planDestroyWalkFn(result *Plan) depgraph.WalkFunc {
|
|||
}
|
||||
|
||||
r := rn.Resource
|
||||
if r.State.Primary != nil && r.State.Primary.ID != "" {
|
||||
if r.State != nil && r.State.ID != "" {
|
||||
log.Printf("[DEBUG] %s: Making for destroy", r.Id)
|
||||
|
||||
l.Lock()
|
||||
|
@ -899,10 +875,7 @@ func (c *Context) planDestroyWalkFn(result *Plan) depgraph.WalkFunc {
|
|||
|
||||
func (c *Context) refreshWalkFn() depgraph.WalkFunc {
|
||||
cb := func(r *Resource) error {
|
||||
is := r.State.Primary
|
||||
if r.Flags&FlagTainted != 0 {
|
||||
is = r.State.Tainted[r.TaintedIndex]
|
||||
}
|
||||
is := r.State
|
||||
|
||||
if is == nil || is.ID == "" {
|
||||
log.Printf("[DEBUG] %s: Not refreshing, ID is empty", r.Id)
|
||||
|
@ -922,17 +895,9 @@ func (c *Context) refreshWalkFn() depgraph.WalkFunc {
|
|||
is.init()
|
||||
}
|
||||
|
||||
if r.Flags&FlagTainted != 0 {
|
||||
r.State.Tainted[r.TaintedIndex] = is
|
||||
} else {
|
||||
r.State.Primary = is
|
||||
}
|
||||
|
||||
// TODO: Handle other modules
|
||||
c.sl.Lock()
|
||||
mod := c.state.RootModule()
|
||||
mod.Resources[r.Id] = r.State
|
||||
c.sl.Unlock()
|
||||
// Set the updated state
|
||||
r.State = is
|
||||
c.persistState(r)
|
||||
|
||||
for _, h := range c.hooks {
|
||||
handleHook(h.PostRefresh(r.Id, is))
|
||||
|
@ -1111,3 +1076,43 @@ func (c *Context) genericWalkFn(cb genericWalkFunc) depgraph.WalkFunc {
|
|||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Context) persistState(r *Resource) {
|
||||
// Acquire a state lock around this whole thing since we're updating that
|
||||
c.sl.Lock()
|
||||
defer c.sl.Unlock()
|
||||
|
||||
// If we have no state, then we don't persist.
|
||||
if c.state == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Get the state for this resource. The resource state should always
|
||||
// exist because we call graphInitState before anything that could
|
||||
// potentially call this.
|
||||
module := c.state.RootModule()
|
||||
rs := module.Resources[r.Id]
|
||||
if rs == nil {
|
||||
panic(fmt.Sprintf("nil ResourceState for ID: %s", r.Id))
|
||||
}
|
||||
|
||||
// Assign the instance state to the proper location
|
||||
if r.Flags&FlagTainted != 0 {
|
||||
if r.TaintedIndex >= 0 {
|
||||
// Tainted with a pre-existing index, just update that spot
|
||||
rs.Tainted[r.TaintedIndex] = r.State
|
||||
} else {
|
||||
// Newly tainted, so append it to the list, update the
|
||||
// index, and remove the primary.
|
||||
rs.Tainted = append(rs.Tainted, r.State)
|
||||
rs.Primary = nil
|
||||
r.TaintedIndex = len(rs.Tainted) - 1
|
||||
}
|
||||
} else {
|
||||
// The primary instance, so just set it directly
|
||||
rs.Primary = r.State
|
||||
}
|
||||
|
||||
// Do a pruning so that empty resources are not saved
|
||||
rs.prune()
|
||||
}
|
||||
|
|
|
@ -172,24 +172,28 @@ func Graph(opts *GraphOpts) (*depgraph.Graph, error) {
|
|||
return g, nil
|
||||
}
|
||||
|
||||
// EncodeDependencies is used to walk the graph and encode the
|
||||
// logical dependency information into the resource state. This
|
||||
// allows the dependency tree to be recovered from the state file
|
||||
// such that orphaned resources will still be destroyed in the
|
||||
// proper order.
|
||||
func EncodeDependencies(g *depgraph.Graph) {
|
||||
// graphInitState is used to initialize a State with a ResourceState
|
||||
// for every resource.
|
||||
//
|
||||
// This method is very important to call because it will properly setup
|
||||
// the ResourceState dependency information with data from the graph. This
|
||||
// allows orphaned resources to be destroyed in the proper order.
|
||||
func graphInitState(s *State, g *depgraph.Graph) {
|
||||
// TODO: other modules
|
||||
mod := s.RootModule()
|
||||
|
||||
for _, n := range g.Nouns {
|
||||
// Ignore any non-resource nodes
|
||||
rn, ok := n.Meta.(*GraphNodeResource)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
// Skip only if the resource has state
|
||||
rs := rn.Resource
|
||||
state := rs.State
|
||||
if state == nil {
|
||||
continue
|
||||
r := rn.Resource
|
||||
rs := mod.Resources[r.Id]
|
||||
if rs == nil {
|
||||
rs = new(ResourceState)
|
||||
rs.init()
|
||||
mod.Resources[r.Id] = rs
|
||||
}
|
||||
|
||||
// Update the dependencies
|
||||
|
@ -197,7 +201,7 @@ func EncodeDependencies(g *depgraph.Graph) {
|
|||
for _, dep := range n.Deps {
|
||||
switch target := dep.Target.Meta.(type) {
|
||||
case *GraphNodeResource:
|
||||
if target.Resource.Id == rs.Id {
|
||||
if target.Resource.Id == r.Id {
|
||||
continue
|
||||
}
|
||||
inject = append(inject, target.Resource.Id)
|
||||
|
@ -212,7 +216,7 @@ func EncodeDependencies(g *depgraph.Graph) {
|
|||
}
|
||||
|
||||
// Update the dependencies
|
||||
state.Dependencies = inject
|
||||
rs.Dependencies = inject
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -275,7 +279,7 @@ func graphAddConfigResources(
|
|||
Resource: &Resource{
|
||||
Id: name,
|
||||
Info: &InstanceInfo{Type: r.Type},
|
||||
State: state,
|
||||
State: state.Primary,
|
||||
Config: NewResourceConfig(r.RawConfig),
|
||||
Flags: flags,
|
||||
},
|
||||
|
@ -604,7 +608,7 @@ func graphAddOrphans(g *depgraph.Graph, c *config.Config, s *State) {
|
|||
Resource: &Resource{
|
||||
Id: k,
|
||||
Info: &InstanceInfo{Type: rs.Type},
|
||||
State: rs,
|
||||
State: rs.Primary,
|
||||
Config: NewResourceConfig(nil),
|
||||
Flags: FlagOrphan,
|
||||
},
|
||||
|
@ -625,8 +629,8 @@ func graphAddOrphans(g *depgraph.Graph, c *config.Config, s *State) {
|
|||
rn := n.Meta.(*GraphNodeResource)
|
||||
|
||||
// If we have no dependencies, then just continue
|
||||
deps := rn.Resource.State.Dependencies
|
||||
if len(deps) == 0 {
|
||||
rs := mod.Resources[n.Name]
|
||||
if len(rs.Dependencies) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -641,7 +645,7 @@ func graphAddOrphans(g *depgraph.Graph, c *config.Config, s *State) {
|
|||
continue
|
||||
}
|
||||
|
||||
for _, depName := range rn.Resource.State.Dependencies {
|
||||
for _, depName := range rs.Dependencies {
|
||||
if rn2.Resource.Id != depName {
|
||||
continue
|
||||
}
|
||||
|
@ -800,7 +804,7 @@ func graphAddTainted(g *depgraph.Graph, s *State) {
|
|||
}
|
||||
}
|
||||
|
||||
for i, _ := range rs.Tainted {
|
||||
for i, is := range rs.Tainted {
|
||||
name := fmt.Sprintf("%s (tainted #%d)", k, i+1)
|
||||
|
||||
// Add each of the tainted resources to the graph, and encode
|
||||
|
@ -813,7 +817,7 @@ func graphAddTainted(g *depgraph.Graph, s *State) {
|
|||
Resource: &Resource{
|
||||
Id: k,
|
||||
Info: &InstanceInfo{Type: rs.Type},
|
||||
State: rs,
|
||||
State: is,
|
||||
Config: NewResourceConfig(nil),
|
||||
Diff: &InstanceDiff{Destroy: true},
|
||||
Flags: FlagTainted,
|
||||
|
|
|
@ -79,7 +79,7 @@ func graphDotAddResources(buf *bytes.Buffer, g *depgraph.Graph) {
|
|||
// green = create. Destroy is in the next section.
|
||||
var color, fillColor string
|
||||
if rn.Resource.Diff != nil && !rn.Resource.Diff.Empty() {
|
||||
if rn.Resource.State != nil && rn.Resource.State.Primary.ID != "" {
|
||||
if rn.Resource.State != nil && rn.Resource.State.ID != "" {
|
||||
color = "#FFFF00"
|
||||
fillColor = "#FFFF94"
|
||||
} else {
|
||||
|
|
|
@ -516,7 +516,7 @@ func TestGraphAddDiff_destroy_counts(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestEncodeDependencies(t *testing.T) {
|
||||
func TestGraphInitState(t *testing.T) {
|
||||
config := testConfig(t, "graph-basic")
|
||||
state := &State{
|
||||
Modules: []*ModuleState{
|
||||
|
@ -546,7 +546,7 @@ func TestEncodeDependencies(t *testing.T) {
|
|||
}
|
||||
|
||||
// This should encode the dependency information into the state
|
||||
EncodeDependencies(g)
|
||||
graphInitState(state, g)
|
||||
|
||||
root := state.RootModule()
|
||||
web := root.Resources["aws_instance.web"]
|
||||
|
@ -560,7 +560,7 @@ func TestEncodeDependencies(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestEncodeDependencies_Count(t *testing.T) {
|
||||
func TestGraphInitState_Count(t *testing.T) {
|
||||
config := testConfig(t, "graph-count")
|
||||
state := &State{
|
||||
Modules: []*ModuleState{
|
||||
|
@ -590,7 +590,7 @@ func TestEncodeDependencies_Count(t *testing.T) {
|
|||
}
|
||||
|
||||
// This should encode the dependency information into the state
|
||||
EncodeDependencies(g)
|
||||
graphInitState(state, g)
|
||||
|
||||
root := state.RootModule()
|
||||
web := root.Resources["aws_instance.web.0"]
|
||||
|
|
|
@ -31,7 +31,7 @@ type Resource struct {
|
|||
Config *ResourceConfig
|
||||
Diff *InstanceDiff
|
||||
Provider ResourceProvider
|
||||
State *ResourceState
|
||||
State *InstanceState
|
||||
Provisioners []*ResourceProvisionerConfig
|
||||
Flags ResourceFlag
|
||||
TaintedIndex int
|
||||
|
@ -56,7 +56,7 @@ func (r *Resource) Vars() map[string]string {
|
|||
}
|
||||
|
||||
vars := make(map[string]string)
|
||||
for ak, av := range r.State.Primary.Attributes {
|
||||
for ak, av := range r.State.Attributes {
|
||||
vars[fmt.Sprintf("%s.%s", r.Id, ak)] = av
|
||||
}
|
||||
|
||||
|
|
|
@ -16,11 +16,9 @@ func TestResource_Vars(t *testing.T) {
|
|||
|
||||
r = &Resource{
|
||||
Id: "key",
|
||||
State: &ResourceState{
|
||||
Primary: &InstanceState{
|
||||
Attributes: map[string]string{
|
||||
"foo": "bar",
|
||||
},
|
||||
State: &InstanceState{
|
||||
Attributes: map[string]string{
|
||||
"foo": "bar",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue