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
}
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 {
return err
}
@ -557,9 +559,14 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc {
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!
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
if applyerr != nil {
@ -614,7 +621,9 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc {
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)
tainted = true
}
@ -654,11 +663,11 @@ func (c *Context) applyWalkFn() depgraph.WalkFunc {
// applyProvisioners is used to run any provisioners a resource has
// 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
origConnInfo := rs.Primary.Ephemeral.ConnInfo
origConnInfo := is.Ephemeral.ConnInfo
defer func() {
rs.Primary.Ephemeral.ConnInfo = origConnInfo
is.Ephemeral.ConnInfo = origConnInfo
}()
for _, prov := range r.Provisioners {
@ -701,14 +710,14 @@ func (c *Context) applyProvisioners(r *Resource, rs *ResourceState) error {
overlay[k] = fmt.Sprintf("%v", vt)
}
}
rs.Primary.Ephemeral.ConnInfo = overlay
is.Ephemeral.ConnInfo = overlay
// Invoke the Provisioner
for _, h := range c.hooks {
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
}
@ -753,7 +762,9 @@ func (c *Context) planWalkFn(result *Plan) depgraph.WalkFunc {
state = new(ResourceState)
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 {
return err
}
@ -797,7 +808,9 @@ func (c *Context) planWalkFn(result *Plan) depgraph.WalkFunc {
// Determine the new state and update variables
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
@ -852,7 +865,12 @@ func (c *Context) refreshWalkFn() depgraph.WalkFunc {
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 {
return err
}

View File

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

View File

@ -13,24 +13,27 @@ type MockResourceProvider struct {
Meta interface{}
ApplyCalled bool
ApplyState *ResourceState
ApplyInfo *InstanceInfo
ApplyState *InstanceState
ApplyDiff *ResourceDiff
ApplyFn func(*ResourceState, *ResourceDiff) (*ResourceState, error)
ApplyReturn *ResourceState
ApplyFn func(*InstanceInfo, *InstanceState, *ResourceDiff) (*InstanceState, error)
ApplyReturn *InstanceState
ApplyReturnError error
ConfigureCalled bool
ConfigureConfig *ResourceConfig
ConfigureReturnError error
DiffCalled bool
DiffState *ResourceState
DiffInfo *InstanceInfo
DiffState *InstanceState
DiffDesired *ResourceConfig
DiffFn func(*ResourceState, *ResourceConfig) (*ResourceDiff, error)
DiffFn func(*InstanceInfo, *InstanceState, *ResourceConfig) (*ResourceDiff, error)
DiffReturn *ResourceDiff
DiffReturnError error
RefreshCalled bool
RefreshState *ResourceState
RefreshFn func(*ResourceState) (*ResourceState, error)
RefreshReturn *ResourceState
RefreshInfo *InstanceInfo
RefreshState *InstanceState
RefreshFn func(*InstanceInfo, *InstanceState) (*InstanceState, error)
RefreshReturn *InstanceState
RefreshReturnError error
ResourcesCalled bool
ResourcesReturn []ResourceType
@ -80,47 +83,53 @@ func (p *MockResourceProvider) Configure(c *ResourceConfig) error {
}
func (p *MockResourceProvider) Apply(
state *ResourceState,
diff *ResourceDiff) (*ResourceState, error) {
info *InstanceInfo,
state *InstanceState,
diff *ResourceDiff) (*InstanceState, error) {
p.Lock()
defer p.Unlock()
p.ApplyCalled = true
p.ApplyInfo = info
p.ApplyState = state
p.ApplyDiff = diff
if p.ApplyFn != nil {
return p.ApplyFn(state, diff)
return p.ApplyFn(info, state, diff)
}
return p.ApplyReturn, p.ApplyReturnError
}
func (p *MockResourceProvider) Diff(
state *ResourceState,
info *InstanceInfo,
state *InstanceState,
desired *ResourceConfig) (*ResourceDiff, error) {
p.Lock()
defer p.Unlock()
p.DiffCalled = true
p.DiffInfo = info
p.DiffState = state
p.DiffDesired = desired
if p.DiffFn != nil {
return p.DiffFn(state, desired)
return p.DiffFn(info, state, desired)
}
return p.DiffReturn, p.DiffReturnError
}
func (p *MockResourceProvider) Refresh(
s *ResourceState) (*ResourceState, error) {
info *InstanceInfo,
s *InstanceState) (*InstanceState, error) {
p.Lock()
defer p.Unlock()
p.RefreshCalled = true
p.RefreshInfo = info
p.RefreshState = s
if p.RefreshFn != nil {
return p.RefreshFn(s)
return p.RefreshFn(info, s)
}
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
// is provided since provisioners only run after a resource has been
// newly created.
Apply(*ResourceState, *ResourceConfig) error
Apply(*InstanceState, *ResourceConfig) error
}
// ResourceProvisionerFactory is a function type that creates a new instance

View File

@ -7,9 +7,9 @@ type MockResourceProvisioner struct {
Meta interface{}
ApplyCalled bool
ApplyState *ResourceState
ApplyState *InstanceState
ApplyConfig *ResourceConfig
ApplyFn func(*ResourceState, *ResourceConfig) error
ApplyFn func(*InstanceState, *ResourceConfig) error
ApplyReturnError error
ValidateCalled bool
@ -28,7 +28,7 @@ func (p *MockResourceProvisioner) Validate(c *ResourceConfig) ([]string, []error
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.ApplyState = state
p.ApplyConfig = c

View File

@ -341,44 +341,6 @@ func (s *ResourceState) GoString() string {
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
// to a given instance.
type InstanceState struct {
@ -425,6 +387,44 @@ func (i *InstanceState) deepcopy() *InstanceState {
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 {
return fmt.Sprintf("*%#v", *i)
}

View File

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