terraform: Plan should use module.Tree

This commit is contained in:
Mitchell Hashimoto 2014-09-24 14:56:48 -07:00
parent 672bf58337
commit 718fb42f4b
5 changed files with 103 additions and 24 deletions

54
config/module/tree_gob.go Normal file
View File

@ -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
}

View File

@ -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)
}
}

View File

@ -24,7 +24,6 @@ type genericWalkFunc func(*walkContext, *Resource) error
// //
// Additionally, a context can be created from a Plan using Plan.Context. // Additionally, a context can be created from a Plan using Plan.Context.
type Context struct { type Context struct {
config *config.Config
module *module.Tree module *module.Tree
diff *Diff diff *Diff
hooks []Hook hooks []Hook
@ -74,13 +73,7 @@ func NewContext(opts *ContextOpts) *Context {
} }
parCh := make(chan struct{}, par) parCh := make(chan struct{}, par)
var config *config.Config
if opts.Module != nil {
config = opts.Module.Config()
}
return &Context{ return &Context{
config: config,
diff: opts.Diff, diff: opts.Diff,
hooks: hooks, hooks: hooks,
module: opts.Module, module: opts.Module,
@ -139,7 +132,7 @@ func (c *Context) Plan(opts *PlanOpts) (*Plan, error) {
defer c.releaseRun(v) defer c.releaseRun(v)
p := &Plan{ p := &Plan{
Config: c.config, Module: c.module,
Vars: c.variables, Vars: c.variables,
State: c.state, State: c.state,
} }
@ -223,12 +216,12 @@ func (c *Context) Validate() ([]string, []error) {
var rerr *multierror.Error var rerr *multierror.Error
// Validate the configuration itself // Validate the configuration itself
if err := c.config.Validate(); err != nil { if err := c.module.Config().Validate(); err != nil {
rerr = multierror.ErrorAppend(rerr, err) rerr = multierror.ErrorAppend(rerr, err)
} }
// Validate the user variables // 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...) rerr = multierror.ErrorAppend(rerr, errs...)
} }
@ -1260,7 +1253,7 @@ func (c *walkContext) computeResourceMultiVariable(
// Get the resource from the configuration so we can know how // Get the resource from the configuration so we can know how
// many of the resource there is. // many of the resource there is.
var cr *config.Resource var cr *config.Resource
for _, r := range c.Context.config.Resources { for _, r := range c.Context.module.Config().Resources {
if r.Id() == v.ResourceId() { if r.Id() == v.ResourceId() {
cr = r cr = r
break break

View File

@ -8,7 +8,6 @@ import (
"io" "io"
"sync" "sync"
"github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/config/module" "github.com/hashicorp/terraform/config/module"
) )
@ -31,8 +30,8 @@ type PlanOpts struct {
// Plan represents a single Terraform execution plan, which contains // Plan represents a single Terraform execution plan, which contains
// all the information necessary to make an infrastructure change. // all the information necessary to make an infrastructure change.
type Plan struct { type Plan struct {
Config *config.Config
Diff *Diff Diff *Diff
Module *module.Tree
State *State State *State
Vars map[string]string Vars map[string]string
@ -45,7 +44,7 @@ type Plan struct {
// Diff, State, Variables. // Diff, State, Variables.
func (p *Plan) Context(opts *ContextOpts) *Context { func (p *Plan) Context(opts *ContextOpts) *Context {
opts.Diff = p.Diff opts.Diff = p.Diff
opts.Module = module.NewTree("", p.Config) // TODO: compat opts.Module = p.Module
opts.State = p.State opts.State = p.State
opts.Variables = p.Vars opts.Variables = p.Vars
return NewContext(opts) return NewContext(opts)
@ -62,10 +61,6 @@ func (p *Plan) String() string {
func (p *Plan) init() { func (p *Plan) init() {
p.once.Do(func() { p.once.Do(func() {
if p.Config == nil {
p.Config = new(config.Config)
}
if p.Diff == nil { if p.Diff == nil {
p.Diff = new(Diff) p.Diff = new(Diff)
p.Diff.init() p.Diff.init()

View File

@ -2,14 +2,14 @@ package terraform
import ( import (
"bytes" "bytes"
"reflect" "strings"
"testing" "testing"
) )
func TestReadWritePlan(t *testing.T) { func TestReadWritePlan(t *testing.T) {
plan := &Plan{ plan := &Plan{
Config: testConfig(t, "new-good"), Module: testModule(t, "new-good"),
Diff: &Diff{ Diff: &Diff{
Modules: []*ModuleDiff{ Modules: []*ModuleDiff{
&ModuleDiff{ &ModuleDiff{
@ -65,9 +65,9 @@ func TestReadWritePlan(t *testing.T) {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
} }
println(reflect.DeepEqual(actual.Config.Resources, plan.Config.Resources)) actualStr := strings.TrimSpace(actual.String())
expectedStr := strings.TrimSpace(plan.String())
if !reflect.DeepEqual(actual, plan) { if actualStr != expectedStr {
t.Fatalf("bad: %#v", actual) t.Fatalf("bad:\n\n%s\n\nexpected:\n\n%s", actualStr, expectedStr)
} }
} }