From 718fb42f4b40bf2b78e7f796db3e07b097db667a Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 24 Sep 2014 14:56:48 -0700 Subject: [PATCH] terraform: Plan should use module.Tree --- config/module/tree_gob.go | 54 ++++++++++++++++++++++++++++++++++ config/module/tree_gob_test.go | 37 +++++++++++++++++++++++ terraform/context.go | 15 +++------- terraform/plan.go | 9 ++---- terraform/plan_test.go | 12 ++++---- 5 files changed, 103 insertions(+), 24 deletions(-) create mode 100644 config/module/tree_gob.go create mode 100644 config/module/tree_gob_test.go diff --git a/config/module/tree_gob.go b/config/module/tree_gob.go new file mode 100644 index 000000000..cbf8a25ed --- /dev/null +++ b/config/module/tree_gob.go @@ -0,0 +1,54 @@ +package module + +import ( + "bytes" + "encoding/gob" + + "github.com/hashicorp/terraform/config" +) + +func (t *Tree) GobDecode(bs []byte) error { + t.lock.Lock() + defer t.lock.Unlock() + + // Decode the gob data + var data treeGob + dec := gob.NewDecoder(bytes.NewReader(bs)) + if err := dec.Decode(&data); err != nil { + return err + } + + // Set the fields + t.name = data.Name + t.config = data.Config + t.children = data.Children + + return nil +} + +func (t *Tree) GobEncode() ([]byte, error) { + data := &treeGob{ + Config: t.config, + Children: t.children, + Name: t.name, + } + + var buf bytes.Buffer + enc := gob.NewEncoder(&buf) + if err := enc.Encode(data); err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +// treeGob is used as a structure to Gob encode a tree. +// +// This structure is private so it can't be referenced but the fields are +// public, allowing Gob to properly encode this. When we decode this, we are +// able to turn it into a Tree. +type treeGob struct { + Config *config.Config + Children map[string]*Tree + Name string +} diff --git a/config/module/tree_gob_test.go b/config/module/tree_gob_test.go new file mode 100644 index 000000000..cee17b42a --- /dev/null +++ b/config/module/tree_gob_test.go @@ -0,0 +1,37 @@ +package module + +import ( + "bytes" + "encoding/gob" + "strings" + "testing" +) + +func TestTreeEncodeDecodeGob(t *testing.T) { + storage := testStorage(t) + tree := NewTree("", testConfig(t, "basic")) + + // This should get things + if err := tree.Load(storage, GetModeGet); err != nil { + t.Fatalf("err: %s", err) + } + + // Encode it. + var buf bytes.Buffer + enc := gob.NewEncoder(&buf) + if err := enc.Encode(tree); err != nil { + t.Fatalf("err: %s", err) + } + + dec := gob.NewDecoder(&buf) + var actual Tree + if err := dec.Decode(&actual); err != nil { + t.Fatalf("err: %s", err) + } + + actualStr := strings.TrimSpace(actual.String()) + expectedStr := strings.TrimSpace(tree.String()) + if actualStr != expectedStr { + t.Fatalf("\n%s\n\nexpected:\n\n%s", actualStr, expectedStr) + } +} diff --git a/terraform/context.go b/terraform/context.go index 92198559b..7ba25cc68 100644 --- a/terraform/context.go +++ b/terraform/context.go @@ -24,7 +24,6 @@ type genericWalkFunc func(*walkContext, *Resource) error // // Additionally, a context can be created from a Plan using Plan.Context. type Context struct { - config *config.Config module *module.Tree diff *Diff hooks []Hook @@ -74,13 +73,7 @@ func NewContext(opts *ContextOpts) *Context { } parCh := make(chan struct{}, par) - var config *config.Config - if opts.Module != nil { - config = opts.Module.Config() - } - return &Context{ - config: config, diff: opts.Diff, hooks: hooks, module: opts.Module, @@ -139,7 +132,7 @@ func (c *Context) Plan(opts *PlanOpts) (*Plan, error) { defer c.releaseRun(v) p := &Plan{ - Config: c.config, + Module: c.module, Vars: c.variables, State: c.state, } @@ -223,12 +216,12 @@ func (c *Context) Validate() ([]string, []error) { var rerr *multierror.Error // Validate the configuration itself - if err := c.config.Validate(); err != nil { + if err := c.module.Config().Validate(); err != nil { rerr = multierror.ErrorAppend(rerr, err) } // Validate the user variables - if errs := smcUserVariables(c.config, c.variables); len(errs) > 0 { + if errs := smcUserVariables(c.module.Config(), c.variables); len(errs) > 0 { rerr = multierror.ErrorAppend(rerr, errs...) } @@ -1260,7 +1253,7 @@ func (c *walkContext) computeResourceMultiVariable( // Get the resource from the configuration so we can know how // many of the resource there is. var cr *config.Resource - for _, r := range c.Context.config.Resources { + for _, r := range c.Context.module.Config().Resources { if r.Id() == v.ResourceId() { cr = r break diff --git a/terraform/plan.go b/terraform/plan.go index 63c6eea1b..e73fde383 100644 --- a/terraform/plan.go +++ b/terraform/plan.go @@ -8,7 +8,6 @@ import ( "io" "sync" - "github.com/hashicorp/terraform/config" "github.com/hashicorp/terraform/config/module" ) @@ -31,8 +30,8 @@ type PlanOpts struct { // Plan represents a single Terraform execution plan, which contains // all the information necessary to make an infrastructure change. type Plan struct { - Config *config.Config Diff *Diff + Module *module.Tree State *State Vars map[string]string @@ -45,7 +44,7 @@ type Plan struct { // Diff, State, Variables. func (p *Plan) Context(opts *ContextOpts) *Context { opts.Diff = p.Diff - opts.Module = module.NewTree("", p.Config) // TODO: compat + opts.Module = p.Module opts.State = p.State opts.Variables = p.Vars return NewContext(opts) @@ -62,10 +61,6 @@ func (p *Plan) String() string { func (p *Plan) init() { p.once.Do(func() { - if p.Config == nil { - p.Config = new(config.Config) - } - if p.Diff == nil { p.Diff = new(Diff) p.Diff.init() diff --git a/terraform/plan_test.go b/terraform/plan_test.go index b63e3706c..8c12b896f 100644 --- a/terraform/plan_test.go +++ b/terraform/plan_test.go @@ -2,14 +2,14 @@ package terraform import ( "bytes" - "reflect" + "strings" "testing" ) func TestReadWritePlan(t *testing.T) { plan := &Plan{ - Config: testConfig(t, "new-good"), + Module: testModule(t, "new-good"), Diff: &Diff{ Modules: []*ModuleDiff{ &ModuleDiff{ @@ -65,9 +65,9 @@ func TestReadWritePlan(t *testing.T) { t.Fatalf("err: %s", err) } - println(reflect.DeepEqual(actual.Config.Resources, plan.Config.Resources)) - - if !reflect.DeepEqual(actual, plan) { - t.Fatalf("bad: %#v", actual) + actualStr := strings.TrimSpace(actual.String()) + expectedStr := strings.TrimSpace(plan.String()) + if actualStr != expectedStr { + t.Fatalf("bad:\n\n%s\n\nexpected:\n\n%s", actualStr, expectedStr) } }