terraform: refreshing tainted resources works

This commit is contained in:
Mitchell Hashimoto 2014-09-19 22:28:13 -06:00
parent f89c2c5ff0
commit 157843725d
3 changed files with 34 additions and 16 deletions

View File

@ -893,19 +893,23 @@ func (c *Context) planDestroyWalkFn(result *Plan) depgraph.WalkFunc {
} }
func (c *Context) refreshWalkFn() depgraph.WalkFunc { func (c *Context) refreshWalkFn() depgraph.WalkFunc {
cb := func(r *Resource, tainted bool, inst **InstanceState) error { cb := func(r *Resource) error {
if *inst == nil || (*inst).ID == "" { is := r.State.Primary
if r.Tainted {
is = r.State.Tainted[r.TaintedIndex]
}
if is == nil || is.ID == "" {
log.Printf("[DEBUG] %s: Not refreshing, ID is empty", r.Id) log.Printf("[DEBUG] %s: Not refreshing, ID is empty", r.Id)
return nil return nil
} }
state := *inst
for _, h := range c.hooks { for _, h := range c.hooks {
handleHook(h.PreRefresh(r.Id, state)) handleHook(h.PreRefresh(r.Id, is))
} }
info := &InstanceInfo{Type: r.State.Type} info := &InstanceInfo{Type: r.State.Type}
is, err := r.Provider.Refresh(info, state) is, err := r.Provider.Refresh(info, is)
if err != nil { if err != nil {
return err return err
} }
@ -914,8 +918,11 @@ func (c *Context) refreshWalkFn() depgraph.WalkFunc {
is.init() is.init()
} }
// Update the state if r.Tainted {
*inst = is r.State.Tainted[r.TaintedIndex] = is
} else {
r.State.Primary = is
}
// TODO: Handle other modules // TODO: Handle other modules
c.sl.Lock() c.sl.Lock()
@ -930,7 +937,7 @@ func (c *Context) refreshWalkFn() depgraph.WalkFunc {
return nil return nil
} }
return c.genericWalkFn(instanceWalk(cb)) return c.genericWalkFn(cb)
} }
func (c *Context) validateWalkFn(rws *[]string, res *[]error) depgraph.WalkFunc { func (c *Context) validateWalkFn(rws *[]string, res *[]error) depgraph.WalkFunc {

View File

@ -2235,6 +2235,7 @@ func TestContextRefresh_tainted(t *testing.T) {
Path: rootModulePath, Path: rootModulePath,
Resources: map[string]*ResourceState{ Resources: map[string]*ResourceState{
"aws_instance.web": &ResourceState{ "aws_instance.web": &ResourceState{
Type: "aws_instance",
Tainted: []*InstanceState{ Tainted: []*InstanceState{
&InstanceState{ &InstanceState{
ID: "bar", ID: "bar",
@ -2262,16 +2263,14 @@ func TestContextRefresh_tainted(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
} }
originalMod := state.RootModule()
mod := s.RootModule()
if !p.RefreshCalled { if !p.RefreshCalled {
t.Fatal("refresh should be called") t.Fatal("refresh should be called")
} }
if !reflect.DeepEqual(p.RefreshState, originalMod.Resources["aws_instance.web"].Tainted[0]) {
t.Fatalf("bad: %#v %#v", p.RefreshState, originalMod.Resources["aws_instance.web"].Tainted[0]) actual := strings.TrimSpace(s.String())
} expected := strings.TrimSpace(testContextRefreshTaintedStr)
if !reflect.DeepEqual(mod.Resources["aws_instance.web"].Tainted[0], p.RefreshReturn) { if actual != expected {
t.Fatalf("bad: %#v", mod.Resources) t.Fatalf("bad:\n\n%s\n\n%s", actual, expected)
} }
} }
@ -2476,3 +2475,9 @@ root
root -> aws_instance.bar root -> aws_instance.bar
root -> aws_instance.foo root -> aws_instance.foo
` `
const testContextRefreshTaintedStr = `
aws_instance.web: (1 tainted)
ID = <not created>
Tainted ID 1 = foo
`

View File

@ -364,6 +364,12 @@ func (s *ResourceState) GoString() string {
return fmt.Sprintf("*%#v", *s) return fmt.Sprintf("*%#v", *s)
} }
func (s *ResourceState) String() string {
var buf bytes.Buffer
buf.WriteString(fmt.Sprintf("Type = %s", s.Type))
return buf.String()
}
// InstanceState is used to track the unique state information belonging // InstanceState is used to track the unique state information belonging
// to a given instance. // to a given instance.
type InstanceState struct { type InstanceState struct {
@ -451,7 +457,7 @@ func (i *InstanceState) GoString() string {
func (i *InstanceState) String() string { func (i *InstanceState) String() string {
var buf bytes.Buffer var buf bytes.Buffer
if i.ID == "" { if i == nil || i.ID == "" {
return "<not created>" return "<not created>"
} }