From 95f3e626a51cd75a8373eeead2a11434133494bd Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 16 Sep 2014 16:20:11 -0700 Subject: [PATCH] terraform: modify the ResourceProvider API super hardcore --- terraform/context.go | 40 +++++-- terraform/context_test.go | 156 ++++++++++++------------- terraform/resource_provider.go | 17 ++- terraform/resource_provider_mock.go | 39 ++++--- terraform/resource_provisioner.go | 2 +- terraform/resource_provisioner_mock.go | 6 +- terraform/state.go | 76 ++++++------ terraform/state_test.go | 48 ++++---- 8 files changed, 203 insertions(+), 181 deletions(-) diff --git a/terraform/context.go b/terraform/context.go index da4d707cd..e63f26ae4 100644 --- a/terraform/context.go +++ b/terraform/context.go @@ -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 } diff --git a/terraform/context_test.go b/terraform/context_test.go index fb5bd2f9d..1dbbc7d9b 100644 --- a/terraform/context_test.go +++ b/terraform/context_test.go @@ -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{ diff --git a/terraform/resource_provider.go b/terraform/resource_provider.go index 39942d8a2..2bdf3c238 100644 --- a/terraform/resource_provider.go +++ b/terraform/resource_provider.go @@ -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. diff --git a/terraform/resource_provider_mock.go b/terraform/resource_provider_mock.go index 42faada7c..79c946dc2 100644 --- a/terraform/resource_provider_mock.go +++ b/terraform/resource_provider_mock.go @@ -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 diff --git a/terraform/resource_provisioner.go b/terraform/resource_provisioner.go index 967e0e037..6a749e001 100644 --- a/terraform/resource_provisioner.go +++ b/terraform/resource_provisioner.go @@ -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 diff --git a/terraform/resource_provisioner_mock.go b/terraform/resource_provisioner_mock.go index a6e62a593..f1600784c 100644 --- a/terraform/resource_provisioner_mock.go +++ b/terraform/resource_provisioner_mock.go @@ -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 diff --git a/terraform/state.go b/terraform/state.go index 69e89bac5..f7b3067f4 100644 --- a/terraform/state.go +++ b/terraform/state.go @@ -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) } diff --git a/terraform/state_test.go b/terraform/state_test.go index d11d520dc..13f953e3f 100644 --- a/terraform/state_test.go +++ b/terraform/state_test.go @@ -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) } }