terraform: modify the ResourceProvider API super hardcore

This commit is contained in:
Mitchell Hashimoto 2014-09-16 16:20:11 -07:00
parent 4b0f970659
commit 95f3e626a5
8 changed files with 203 additions and 181 deletions

View File

@ -514,7 +514,9 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc {
return err return err
} }
diff, err = r.Provider.Diff(r.State, r.Config) is := new(InstanceState) // TODO(armon): completely broken
info := new(InstanceInfo)
diff, err = r.Provider.Diff(info, is, r.Config)
if err != nil { if err != nil {
return err return err
} }
@ -557,9 +559,14 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc {
handleHook(h.PreApply(r.Id, r.State, diff)) handleHook(h.PreApply(r.Id, r.State, diff))
} }
// TODO(armon): completely broken, added to compile
var rs *ResourceState
is := new(InstanceState)
info := new(InstanceInfo)
// With the completed diff, apply! // With the completed diff, apply!
log.Printf("[DEBUG] %s: Executing Apply", r.Id) log.Printf("[DEBUG] %s: Executing Apply", r.Id)
rs, applyerr := r.Provider.Apply(r.State, diff) is, applyerr := r.Provider.Apply(info, is, diff)
var errs []error var errs []error
if applyerr != nil { if applyerr != nil {
@ -614,7 +621,9 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc {
handleHook(h.PreProvisionResource(r.Id, r.State)) handleHook(h.PreProvisionResource(r.Id, r.State))
} }
if err := c.applyProvisioners(r, rs); err != nil { // TODO(armon): I renamed "rs" to "is" to get things to
// compile.
if err := c.applyProvisioners(r, is); err != nil {
errs = append(errs, err) errs = append(errs, err)
tainted = true tainted = true
} }
@ -654,11 +663,11 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc {
// applyProvisioners is used to run any provisioners a resource has // applyProvisioners is used to run any provisioners a resource has
// defined after the resource creation has already completed. // defined after the resource creation has already completed.
func (c *Context) applyProvisioners(r *Resource, rs *ResourceState) error { func (c *Context) applyProvisioners(r *Resource, is *InstanceState) error {
// Store the original connection info, restore later // Store the original connection info, restore later
origConnInfo := rs.Primary.Ephemeral.ConnInfo origConnInfo := is.Ephemeral.ConnInfo
defer func() { defer func() {
rs.Primary.Ephemeral.ConnInfo = origConnInfo is.Ephemeral.ConnInfo = origConnInfo
}() }()
for _, prov := range r.Provisioners { for _, prov := range r.Provisioners {
@ -701,14 +710,14 @@ func (c *Context) applyProvisioners(r *Resource, rs *ResourceState) error {
overlay[k] = fmt.Sprintf("%v", vt) overlay[k] = fmt.Sprintf("%v", vt)
} }
} }
rs.Primary.Ephemeral.ConnInfo = overlay is.Ephemeral.ConnInfo = overlay
// Invoke the Provisioner // Invoke the Provisioner
for _, h := range c.hooks { for _, h := range c.hooks {
handleHook(h.PreProvision(r.Id, prov.Type)) handleHook(h.PreProvision(r.Id, prov.Type))
} }
if err := prov.Provisioner.Apply(rs, prov.Config); err != nil { if err := prov.Provisioner.Apply(is, prov.Config); err != nil {
return err return err
} }
@ -753,7 +762,9 @@ func (c *Context) planWalkFn(result *Plan) depgraph.WalkFunc {
state = new(ResourceState) state = new(ResourceState)
state.Type = r.State.Type state.Type = r.State.Type
} }
diff, err = r.Provider.Diff(state, r.Config) is := new(InstanceState) // TODO(armon): completely broken
info := new(InstanceInfo) // TODO(armon): completely broken
diff, err = r.Provider.Diff(info, is, r.Config)
if err != nil { if err != nil {
return err return err
} }
@ -797,7 +808,9 @@ func (c *Context) planWalkFn(result *Plan) depgraph.WalkFunc {
// Determine the new state and update variables // Determine the new state and update variables
if !diff.Empty() { if !diff.Empty() {
r.State = r.State.MergeDiff(diff) // TODO(armon): commented to compile, this is important
// but needs to be fixed to work with InstanceState
//r.State = r.State.MergeDiff(diff)
} }
// Update our internal state so that variable computation works // Update our internal state so that variable computation works
@ -852,7 +865,12 @@ func (c *Context) refreshWalkFn() depgraph.WalkFunc {
handleHook(h.PreRefresh(r.Id, r.State)) handleHook(h.PreRefresh(r.Id, r.State))
} }
rs, err := r.Provider.Refresh(r.State) // TODO(armon): completely broken
var rs *ResourceState
is := new(InstanceState)
info := new(InstanceInfo)
is, err := r.Provider.Refresh(info, is)
if err != nil { if err != nil {
return err return err
} }

View File

@ -411,7 +411,7 @@ func TestContextApply_badDiff(t *testing.T) {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
} }
p.DiffFn = func(*ResourceState, *ResourceConfig) (*ResourceDiff, error) { p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*ResourceDiff, error) {
return &ResourceDiff{ return &ResourceDiff{
Attributes: map[string]*ResourceAttrDiff{ Attributes: map[string]*ResourceAttrDiff{
"newp": nil, "newp": nil,
@ -436,7 +436,7 @@ func TestContextApply_cancel(t *testing.T) {
}, },
}) })
p.ApplyFn = func(*ResourceState, *ResourceDiff) (*ResourceState, error) { p.ApplyFn = func(*InstanceInfo, *InstanceState, *ResourceDiff) (*InstanceState, error) {
if !stopped { if !stopped {
stopped = true stopped = true
go ctx.Stop() go ctx.Stop()
@ -448,16 +448,14 @@ func TestContextApply_cancel(t *testing.T) {
} }
} }
return &ResourceState{ return &InstanceState{
Primary: &InstanceState{ ID: "foo",
ID: "foo", Attributes: map[string]string{
Attributes: map[string]string{ "num": "2",
"num": "2",
},
}, },
}, nil }, nil
} }
p.DiffFn = func(*ResourceState, *ResourceConfig) (*ResourceDiff, error) { p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*ResourceDiff, error) {
return &ResourceDiff{ return &ResourceDiff{
Attributes: map[string]*ResourceAttrDiff{ Attributes: map[string]*ResourceAttrDiff{
"num": &ResourceAttrDiff{ "num": &ResourceAttrDiff{
@ -542,7 +540,7 @@ func TestContextApply_nilDiff(t *testing.T) {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
} }
p.DiffFn = func(*ResourceState, *ResourceConfig) (*ResourceDiff, error) { p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*ResourceDiff, error) {
return nil, nil return nil, nil
} }
@ -557,7 +555,7 @@ func TestContextApply_Provisioner_compute(t *testing.T) {
pr := testProvisioner() pr := testProvisioner()
p.ApplyFn = testApplyFn p.ApplyFn = testApplyFn
p.DiffFn = testDiffFn p.DiffFn = testDiffFn
pr.ApplyFn = func(rs *ResourceState, c *ResourceConfig) error { pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error {
val, ok := c.Config["foo"] val, ok := c.Config["foo"]
if !ok || val != "computed_dynamical" { if !ok || val != "computed_dynamical" {
t.Fatalf("bad value for foo: %v %#v", val, c) t.Fatalf("bad value for foo: %v %#v", val, c)
@ -606,7 +604,7 @@ func TestContextApply_provisionerFail(t *testing.T) {
p.ApplyFn = testApplyFn p.ApplyFn = testApplyFn
p.DiffFn = testDiffFn p.DiffFn = testDiffFn
pr.ApplyFn = func(*ResourceState, *ResourceConfig) error { pr.ApplyFn = func(*InstanceState, *ResourceConfig) error {
return fmt.Errorf("EXPLOSION") return fmt.Errorf("EXPLOSION")
} }
@ -645,7 +643,7 @@ func TestContextApply_provisionerResourceRef(t *testing.T) {
pr := testProvisioner() pr := testProvisioner()
p.ApplyFn = testApplyFn p.ApplyFn = testApplyFn
p.DiffFn = testDiffFn p.DiffFn = testDiffFn
pr.ApplyFn = func(rs *ResourceState, c *ResourceConfig) error { pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error {
val, ok := c.Config["foo"] val, ok := c.Config["foo"]
if !ok || val != "2" { if !ok || val != "2" {
t.Fatalf("bad value for foo: %v %#v", val, c) t.Fatalf("bad value for foo: %v %#v", val, c)
@ -711,7 +709,7 @@ func TestContextApply_outputDiffVars(t *testing.T) {
State: s, State: s,
}) })
p.ApplyFn = func(s *ResourceState, d *ResourceDiff) (*ResourceState, error) { p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *ResourceDiff) (*InstanceState, error) {
for k, ad := range d.Attributes { for k, ad := range d.Attributes {
if ad.NewComputed { if ad.NewComputed {
return nil, fmt.Errorf("%s: computed", k) return nil, fmt.Errorf("%s: computed", k)
@ -719,10 +717,10 @@ func TestContextApply_outputDiffVars(t *testing.T) {
} }
result := s.MergeDiff(d) result := s.MergeDiff(d)
result.Primary.ID = "foo" result.ID = "foo"
return result, nil return result, nil
} }
p.DiffFn = func(*ResourceState, *ResourceConfig) (*ResourceDiff, error) { p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*ResourceDiff, error) {
return &ResourceDiff{ return &ResourceDiff{
Attributes: map[string]*ResourceAttrDiff{ Attributes: map[string]*ResourceAttrDiff{
"foo": &ResourceAttrDiff{ "foo": &ResourceAttrDiff{
@ -749,13 +747,13 @@ func TestContextApply_Provisioner_ConnInfo(t *testing.T) {
p := testProvider("aws") p := testProvider("aws")
pr := testProvisioner() pr := testProvisioner()
p.ApplyFn = func(s *ResourceState, d *ResourceDiff) (*ResourceState, error) { p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *ResourceDiff) (*InstanceState, error) {
if s.Primary.Ephemeral.ConnInfo == nil { if s.Ephemeral.ConnInfo == nil {
t.Fatalf("ConnInfo not initialized") t.Fatalf("ConnInfo not initialized")
} }
result, _ := testApplyFn(s, d) result, _ := testApplyFn(info, s, d)
result.Primary.Ephemeral.ConnInfo = map[string]string{ result.Ephemeral.ConnInfo = map[string]string{
"type": "ssh", "type": "ssh",
"host": "127.0.0.1", "host": "127.0.0.1",
"port": "22", "port": "22",
@ -764,8 +762,8 @@ func TestContextApply_Provisioner_ConnInfo(t *testing.T) {
} }
p.DiffFn = testDiffFn p.DiffFn = testDiffFn
pr.ApplyFn = func(rs *ResourceState, c *ResourceConfig) error { pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error {
conn := rs.Primary.Ephemeral.ConnInfo conn := rs.Ephemeral.ConnInfo
if conn["type"] != "telnet" { if conn["type"] != "telnet" {
t.Fatalf("Bad: %#v", conn) t.Fatalf("Bad: %#v", conn)
} }
@ -937,16 +935,16 @@ func TestContextApply_destroyOrphan(t *testing.T) {
State: s, State: s,
}) })
p.ApplyFn = func(s *ResourceState, d *ResourceDiff) (*ResourceState, error) { p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *ResourceDiff) (*InstanceState, error) {
if d.Destroy { if d.Destroy {
return nil, nil return nil, nil
} }
result := s.MergeDiff(d) result := s.MergeDiff(d)
result.Primary.ID = "foo" result.ID = "foo"
return result, nil return result, nil
} }
p.DiffFn = func(*ResourceState, *ResourceConfig) (*ResourceDiff, error) { p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*ResourceDiff, error) {
return &ResourceDiff{ return &ResourceDiff{
Attributes: map[string]*ResourceAttrDiff{ Attributes: map[string]*ResourceAttrDiff{
"num": &ResourceAttrDiff{ "num": &ResourceAttrDiff{
@ -983,27 +981,23 @@ func TestContextApply_error(t *testing.T) {
}, },
}) })
p.ApplyFn = func(*ResourceState, *ResourceDiff) (*ResourceState, error) { p.ApplyFn = func(*InstanceInfo, *InstanceState, *ResourceDiff) (*InstanceState, error) {
if errored { if errored {
state := &ResourceState{ state := &InstanceState{
Primary: &InstanceState{ ID: "bar",
ID: "bar",
},
} }
return state, fmt.Errorf("error") return state, fmt.Errorf("error")
} }
errored = true errored = true
return &ResourceState{ return &InstanceState{
Primary: &InstanceState{ ID: "foo",
ID: "foo", Attributes: map[string]string{
Attributes: map[string]string{ "num": "2",
"num": "2",
},
}, },
}, nil }, nil
} }
p.DiffFn = func(*ResourceState, *ResourceConfig) (*ResourceDiff, error) { p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*ResourceDiff, error) {
return &ResourceDiff{ return &ResourceDiff{
Attributes: map[string]*ResourceAttrDiff{ Attributes: map[string]*ResourceAttrDiff{
"num": &ResourceAttrDiff{ "num": &ResourceAttrDiff{
@ -1057,22 +1051,20 @@ func TestContextApply_errorPartial(t *testing.T) {
State: s, State: s,
}) })
p.ApplyFn = func(s *ResourceState, d *ResourceDiff) (*ResourceState, error) { p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *ResourceDiff) (*InstanceState, error) {
if errored { if errored {
return s, fmt.Errorf("error") return s, fmt.Errorf("error")
} }
errored = true errored = true
return &ResourceState{ return &InstanceState{
Primary: &InstanceState{ ID: "foo",
ID: "foo", Attributes: map[string]string{
Attributes: map[string]string{ "num": "2",
"num": "2",
},
}, },
}, nil }, nil
} }
p.DiffFn = func(*ResourceState, *ResourceConfig) (*ResourceDiff, error) { p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*ResourceDiff, error) {
return &ResourceDiff{ return &ResourceDiff{
Attributes: map[string]*ResourceAttrDiff{ Attributes: map[string]*ResourceAttrDiff{
"num": &ResourceAttrDiff{ "num": &ResourceAttrDiff{
@ -1143,16 +1135,16 @@ func TestContextApply_idAttr(t *testing.T) {
}, },
}) })
p.ApplyFn = func(s *ResourceState, d *ResourceDiff) (*ResourceState, error) { p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *ResourceDiff) (*InstanceState, error) {
result := s.MergeDiff(d) result := s.MergeDiff(d)
result.Primary.ID = "foo" result.ID = "foo"
result.Primary.Attributes = map[string]string{ result.Attributes = map[string]string{
"id": "bar", "id": "bar",
} }
return result, nil return result, nil
} }
p.DiffFn = func(*ResourceState, *ResourceConfig) (*ResourceDiff, error) { p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*ResourceDiff, error) {
return &ResourceDiff{ return &ResourceDiff{
Attributes: map[string]*ResourceAttrDiff{ Attributes: map[string]*ResourceAttrDiff{
"num": &ResourceAttrDiff{ "num": &ResourceAttrDiff{
@ -1762,9 +1754,11 @@ func TestContextPlan_diffVar(t *testing.T) {
}) })
p.DiffFn = func( p.DiffFn = func(
s *ResourceState, c *ResourceConfig) (*ResourceDiff, error) { info *InstanceInfo,
if s.Primary.ID != "bar" { s *InstanceState,
return testDiffFn(s, c) c *ResourceConfig) (*ResourceDiff, error) {
if s.ID != "bar" {
return testDiffFn(info, s, c)
} }
return &ResourceDiff{ return &ResourceDiff{
@ -1993,10 +1987,8 @@ func TestContextRefresh(t *testing.T) {
}) })
p.RefreshFn = nil p.RefreshFn = nil
p.RefreshReturn = &ResourceState{ p.RefreshReturn = &InstanceState{
Primary: &InstanceState{ ID: "foo",
ID: "foo",
},
} }
s, err := ctx.Refresh() s, err := ctx.Refresh()
@ -2007,7 +1999,7 @@ func TestContextRefresh(t *testing.T) {
if !p.RefreshCalled { if !p.RefreshCalled {
t.Fatal("refresh should be called") t.Fatal("refresh should be called")
} }
if p.RefreshState.Primary.ID != "foo" { if p.RefreshState.ID != "foo" {
t.Fatalf("bad: %#v", p.RefreshState) t.Fatalf("bad: %#v", p.RefreshState)
} }
if !reflect.DeepEqual(mod.Resources["aws_instance.web"], p.RefreshReturn) { if !reflect.DeepEqual(mod.Resources["aws_instance.web"], p.RefreshReturn) {
@ -2072,10 +2064,8 @@ func TestContextRefresh_ignoreUncreated(t *testing.T) {
}) })
p.RefreshFn = nil p.RefreshFn = nil
p.RefreshReturn = &ResourceState{ p.RefreshReturn = &InstanceState{
Primary: &InstanceState{ ID: "foo",
ID: "foo",
},
} }
_, err := ctx.Refresh() _, err := ctx.Refresh()
@ -2157,10 +2147,8 @@ func TestContextRefresh_state(t *testing.T) {
}) })
p.RefreshFn = nil p.RefreshFn = nil
p.RefreshReturn = &ResourceState{ p.RefreshReturn = &InstanceState{
Primary: &InstanceState{ ID: "foo",
ID: "foo",
},
} }
s, err := ctx.Refresh() s, err := ctx.Refresh()
@ -2206,10 +2194,8 @@ func TestContextRefresh_vars(t *testing.T) {
}) })
p.RefreshFn = nil p.RefreshFn = nil
p.RefreshReturn = &ResourceState{ p.RefreshReturn = &InstanceState{
Primary: &InstanceState{ ID: "foo",
ID: "foo",
},
} }
s, err := ctx.Refresh() s, err := ctx.Refresh()
@ -2220,7 +2206,7 @@ func TestContextRefresh_vars(t *testing.T) {
if !p.RefreshCalled { if !p.RefreshCalled {
t.Fatal("refresh should be called") t.Fatal("refresh should be called")
} }
if p.RefreshState.Primary.ID != "foo" { if p.RefreshState.ID != "foo" {
t.Fatalf("bad: %#v", p.RefreshState) t.Fatalf("bad: %#v", p.RefreshState)
} }
if !reflect.DeepEqual(mod.Resources["aws_instance.web"], p.RefreshReturn) { if !reflect.DeepEqual(mod.Resources["aws_instance.web"], p.RefreshReturn) {
@ -2239,8 +2225,9 @@ func testContext(t *testing.T, opts *ContextOpts) *Context {
} }
func testApplyFn( func testApplyFn(
s *ResourceState, info *InstanceInfo,
d *ResourceDiff) (*ResourceState, error) { s *InstanceState,
d *ResourceDiff) (*InstanceState, error) {
if d.Destroy { if d.Destroy {
return nil, nil return nil, nil
} }
@ -2250,25 +2237,28 @@ func testApplyFn(
id = idAttr.New id = idAttr.New
} }
result := &ResourceState{ result := &InstanceState{
Primary: &InstanceState{ ID: id,
ID: id,
},
} }
if d != nil { if d != nil {
result = result.MergeDiff(d) result = result.MergeDiff(d)
} }
if depAttr, ok := d.Attributes["dep"]; ok { // TODO(armon): commenting this out to compile, but you're in the
result.Dependencies = []string{depAttr.New} // process of removing this, too anyways. Remove when safe.
} /*
if depAttr, ok := d.Attributes["dep"]; ok {
result.Dependencies = []string{depAttr.New}
}
*/
return result, nil return result, nil
} }
func testDiffFn( func testDiffFn(
s *ResourceState, info *InstanceInfo,
s *InstanceState,
c *ResourceConfig) (*ResourceDiff, error) { c *ResourceConfig) (*ResourceDiff, error) {
var diff ResourceDiff var diff ResourceDiff
diff.Attributes = make(map[string]*ResourceAttrDiff) diff.Attributes = make(map[string]*ResourceAttrDiff)
@ -2338,7 +2328,7 @@ func testDiffFn(
continue continue
} }
old, ok := s.Primary.Attributes[k] old, ok := s.Attributes[k]
if !ok { if !ok {
continue continue
} }
@ -2350,7 +2340,7 @@ func testDiffFn(
if !diff.Empty() { if !diff.Empty() {
diff.Attributes["type"] = &ResourceAttrDiff{ diff.Attributes["type"] = &ResourceAttrDiff{
Old: "", Old: "",
New: s.Type, New: info.Type,
} }
} }
@ -2359,7 +2349,7 @@ func testDiffFn(
func testProvider(prefix string) *MockResourceProvider { func testProvider(prefix string) *MockResourceProvider {
p := new(MockResourceProvider) p := new(MockResourceProvider)
p.RefreshFn = func(s *ResourceState) (*ResourceState, error) { p.RefreshFn = func(info *InstanceInfo, s *InstanceState) (*InstanceState, error) {
return s, nil return s, nil
} }
p.ResourcesReturn = []ResourceType{ p.ResourcesReturn = []ResourceType{

View File

@ -46,18 +46,27 @@ type ResourceProvider interface {
// If the resource state given has an empty ID, then a new resource // If the resource state given has an empty ID, then a new resource
// is expected to be created. // is expected to be created.
Apply( Apply(
*ResourceState, *InstanceInfo,
*ResourceDiff) (*ResourceState, error) *InstanceState,
*ResourceDiff) (*InstanceState, error)
// Diff diffs a resource versus a desired state and returns // Diff diffs a resource versus a desired state and returns
// a diff. // a diff.
Diff( Diff(
*ResourceState, *InstanceInfo,
*InstanceState,
*ResourceConfig) (*ResourceDiff, error) *ResourceConfig) (*ResourceDiff, error)
// Refresh refreshes a resource and updates all of its attributes // Refresh refreshes a resource and updates all of its attributes
// with the latest information. // with the latest information.
Refresh(*ResourceState) (*ResourceState, error) Refresh(*InstanceInfo, *InstanceState) (*InstanceState, error)
}
// InstanceInfo is used to hold information about the instance and/or
// resource being modified.
type InstanceInfo struct {
// Type is the resource type of this instance
Type string
} }
// ResourceType is a type of resource that a resource provider can manage. // ResourceType is a type of resource that a resource provider can manage.

View File

@ -13,24 +13,27 @@ type MockResourceProvider struct {
Meta interface{} Meta interface{}
ApplyCalled bool ApplyCalled bool
ApplyState *ResourceState ApplyInfo *InstanceInfo
ApplyState *InstanceState
ApplyDiff *ResourceDiff ApplyDiff *ResourceDiff
ApplyFn func(*ResourceState, *ResourceDiff) (*ResourceState, error) ApplyFn func(*InstanceInfo, *InstanceState, *ResourceDiff) (*InstanceState, error)
ApplyReturn *ResourceState ApplyReturn *InstanceState
ApplyReturnError error ApplyReturnError error
ConfigureCalled bool ConfigureCalled bool
ConfigureConfig *ResourceConfig ConfigureConfig *ResourceConfig
ConfigureReturnError error ConfigureReturnError error
DiffCalled bool DiffCalled bool
DiffState *ResourceState DiffInfo *InstanceInfo
DiffState *InstanceState
DiffDesired *ResourceConfig DiffDesired *ResourceConfig
DiffFn func(*ResourceState, *ResourceConfig) (*ResourceDiff, error) DiffFn func(*InstanceInfo, *InstanceState, *ResourceConfig) (*ResourceDiff, error)
DiffReturn *ResourceDiff DiffReturn *ResourceDiff
DiffReturnError error DiffReturnError error
RefreshCalled bool RefreshCalled bool
RefreshState *ResourceState RefreshInfo *InstanceInfo
RefreshFn func(*ResourceState) (*ResourceState, error) RefreshState *InstanceState
RefreshReturn *ResourceState RefreshFn func(*InstanceInfo, *InstanceState) (*InstanceState, error)
RefreshReturn *InstanceState
RefreshReturnError error RefreshReturnError error
ResourcesCalled bool ResourcesCalled bool
ResourcesReturn []ResourceType ResourcesReturn []ResourceType
@ -80,47 +83,53 @@ func (p *MockResourceProvider) Configure(c *ResourceConfig) error {
} }
func (p *MockResourceProvider) Apply( func (p *MockResourceProvider) Apply(
state *ResourceState, info *InstanceInfo,
diff *ResourceDiff) (*ResourceState, error) { state *InstanceState,
diff *ResourceDiff) (*InstanceState, error) {
p.Lock() p.Lock()
defer p.Unlock() defer p.Unlock()
p.ApplyCalled = true p.ApplyCalled = true
p.ApplyInfo = info
p.ApplyState = state p.ApplyState = state
p.ApplyDiff = diff p.ApplyDiff = diff
if p.ApplyFn != nil { if p.ApplyFn != nil {
return p.ApplyFn(state, diff) return p.ApplyFn(info, state, diff)
} }
return p.ApplyReturn, p.ApplyReturnError return p.ApplyReturn, p.ApplyReturnError
} }
func (p *MockResourceProvider) Diff( func (p *MockResourceProvider) Diff(
state *ResourceState, info *InstanceInfo,
state *InstanceState,
desired *ResourceConfig) (*ResourceDiff, error) { desired *ResourceConfig) (*ResourceDiff, error) {
p.Lock() p.Lock()
defer p.Unlock() defer p.Unlock()
p.DiffCalled = true p.DiffCalled = true
p.DiffInfo = info
p.DiffState = state p.DiffState = state
p.DiffDesired = desired p.DiffDesired = desired
if p.DiffFn != nil { if p.DiffFn != nil {
return p.DiffFn(state, desired) return p.DiffFn(info, state, desired)
} }
return p.DiffReturn, p.DiffReturnError return p.DiffReturn, p.DiffReturnError
} }
func (p *MockResourceProvider) Refresh( func (p *MockResourceProvider) Refresh(
s *ResourceState) (*ResourceState, error) { info *InstanceInfo,
s *InstanceState) (*InstanceState, error) {
p.Lock() p.Lock()
defer p.Unlock() defer p.Unlock()
p.RefreshCalled = true p.RefreshCalled = true
p.RefreshInfo = info
p.RefreshState = s p.RefreshState = s
if p.RefreshFn != nil { if p.RefreshFn != nil {
return p.RefreshFn(s) return p.RefreshFn(info, s)
} }
return p.RefreshReturn, p.RefreshReturnError return p.RefreshReturn, p.RefreshReturnError

View File

@ -20,7 +20,7 @@ type ResourceProvisioner interface {
// resource state along with an error. Instead of a diff, the ResourceConfig // resource state along with an error. Instead of a diff, the ResourceConfig
// is provided since provisioners only run after a resource has been // is provided since provisioners only run after a resource has been
// newly created. // newly created.
Apply(*ResourceState, *ResourceConfig) error Apply(*InstanceState, *ResourceConfig) error
} }
// ResourceProvisionerFactory is a function type that creates a new instance // ResourceProvisionerFactory is a function type that creates a new instance

View File

@ -7,9 +7,9 @@ type MockResourceProvisioner struct {
Meta interface{} Meta interface{}
ApplyCalled bool ApplyCalled bool
ApplyState *ResourceState ApplyState *InstanceState
ApplyConfig *ResourceConfig ApplyConfig *ResourceConfig
ApplyFn func(*ResourceState, *ResourceConfig) error ApplyFn func(*InstanceState, *ResourceConfig) error
ApplyReturnError error ApplyReturnError error
ValidateCalled bool ValidateCalled bool
@ -28,7 +28,7 @@ func (p *MockResourceProvisioner) Validate(c *ResourceConfig) ([]string, []error
return p.ValidateReturnWarns, p.ValidateReturnErrors return p.ValidateReturnWarns, p.ValidateReturnErrors
} }
func (p *MockResourceProvisioner) Apply(state *ResourceState, c *ResourceConfig) error { func (p *MockResourceProvisioner) Apply(state *InstanceState, c *ResourceConfig) error {
p.ApplyCalled = true p.ApplyCalled = true
p.ApplyState = state p.ApplyState = state
p.ApplyConfig = c p.ApplyConfig = c

View File

@ -341,44 +341,6 @@ func (s *ResourceState) GoString() string {
return fmt.Sprintf("*%#v", *s) return fmt.Sprintf("*%#v", *s)
} }
// MergeDiff takes a ResourceDiff and merges the attributes into
// this resource state in order to generate a new state. This new
// state can be used to provide updated attribute lookups for
// variable interpolation.
//
// If the diff attribute requires computing the value, and hence
// won't be available until apply, the value is replaced with the
// computeID.
func (s *ResourceState) MergeDiff(d *ResourceDiff) *ResourceState {
var result ResourceState
if s != nil {
result = *s
}
result.init()
if s != nil {
for k, v := range s.Primary.Attributes {
result.Primary.Attributes[k] = v
}
}
if d != nil {
for k, diff := range d.Attributes {
if diff.NewRemoved {
delete(result.Primary.Attributes, k)
continue
}
if diff.NewComputed {
result.Primary.Attributes[k] = config.UnknownVariableValue
continue
}
result.Primary.Attributes[k] = diff.New
}
}
return &result
}
// 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 {
@ -425,6 +387,44 @@ func (i *InstanceState) deepcopy() *InstanceState {
return n return n
} }
// MergeDiff takes a ResourceDiff and merges the attributes into
// this resource state in order to generate a new state. This new
// state can be used to provide updated attribute lookups for
// variable interpolation.
//
// If the diff attribute requires computing the value, and hence
// won't be available until apply, the value is replaced with the
// computeID.
func (s *InstanceState) MergeDiff(d *ResourceDiff) *InstanceState {
var result InstanceState
if s != nil {
result = *s
}
result.init()
if s != nil {
for k, v := range s.Attributes {
result.Attributes[k] = v
}
}
if d != nil {
for k, diff := range d.Attributes {
if diff.NewRemoved {
delete(result.Attributes, k)
continue
}
if diff.NewComputed {
result.Attributes[k] = config.UnknownVariableValue
continue
}
result.Attributes[k] = diff.New
}
}
return &result
}
func (i *InstanceState) GoString() string { func (i *InstanceState) GoString() string {
return fmt.Sprintf("*%#v", *i) return fmt.Sprintf("*%#v", *i)
} }

View File

@ -12,14 +12,12 @@ import (
"github.com/hashicorp/terraform/config" "github.com/hashicorp/terraform/config"
) )
func TestResourceState_MergeDiff(t *testing.T) { func TestInstanceState_MergeDiff(t *testing.T) {
rs := ResourceState{ is := InstanceState{
Primary: &InstanceState{ ID: "foo",
ID: "foo", Attributes: map[string]string{
Attributes: map[string]string{ "foo": "bar",
"foo": "bar", "port": "8000",
"port": "8000",
},
}, },
} }
@ -44,7 +42,7 @@ func TestResourceState_MergeDiff(t *testing.T) {
}, },
} }
rs2 := rs.MergeDiff(diff) is2 := is.MergeDiff(diff)
expected := map[string]string{ expected := map[string]string{
"foo": "baz", "foo": "baz",
@ -52,13 +50,13 @@ func TestResourceState_MergeDiff(t *testing.T) {
"baz": config.UnknownVariableValue, "baz": config.UnknownVariableValue,
} }
if !reflect.DeepEqual(expected, rs2.Primary.Attributes) { if !reflect.DeepEqual(expected, is2.Attributes) {
t.Fatalf("bad: %#v", rs2.Primary.Attributes) t.Fatalf("bad: %#v", is2.Attributes)
} }
} }
func TestResourceState_MergeDiff_nil(t *testing.T) { func TestInstanceState_MergeDiff_nil(t *testing.T) {
var rs *ResourceState = nil var is *InstanceState = nil
diff := &ResourceDiff{ diff := &ResourceDiff{
Attributes: map[string]*ResourceAttrDiff{ Attributes: map[string]*ResourceAttrDiff{
@ -69,35 +67,33 @@ func TestResourceState_MergeDiff_nil(t *testing.T) {
}, },
} }
rs2 := rs.MergeDiff(diff) is2 := is.MergeDiff(diff)
expected := map[string]string{ expected := map[string]string{
"foo": "baz", "foo": "baz",
} }
if !reflect.DeepEqual(expected, rs2.Primary.Attributes) { if !reflect.DeepEqual(expected, is2.Attributes) {
t.Fatalf("bad: %#v", rs2.Primary.Attributes) t.Fatalf("bad: %#v", is2.Attributes)
} }
} }
func TestResourceState_MergeDiff_nilDiff(t *testing.T) { func TestInstanceState_MergeDiff_nilDiff(t *testing.T) {
rs := ResourceState{ is := InstanceState{
Primary: &InstanceState{ ID: "foo",
ID: "foo", Attributes: map[string]string{
Attributes: map[string]string{ "foo": "bar",
"foo": "bar",
},
}, },
} }
rs2 := rs.MergeDiff(nil) is2 := is.MergeDiff(nil)
expected := map[string]string{ expected := map[string]string{
"foo": "bar", "foo": "bar",
} }
if !reflect.DeepEqual(expected, rs2.Primary.Attributes) { if !reflect.DeepEqual(expected, is2.Attributes) {
t.Fatalf("bad: %#v", rs2.Primary.Attributes) t.Fatalf("bad: %#v", is2.Attributes)
} }
} }