terraform: Plan seems to work again

This commit is contained in:
Mitchell Hashimoto 2014-06-25 17:40:50 -07:00
parent c68cfc5e6f
commit e9d1be397c
3 changed files with 56 additions and 101 deletions

View File

@ -111,6 +111,10 @@ func graphAddConfigResources(
var state *ResourceState
if s != nil {
state = s.Resources[r.Id()]
} else {
state = &ResourceState{
Type: r.Type,
}
}
noun := &depgraph.Noun{

View File

@ -124,20 +124,14 @@ func (t *Terraform) Graph(c *config.Config, s *State) (*depgraph.Graph, error) {
return g, nil
}
func (t *Terraform) Plan(s *State) (*Plan, error) {
// TODO: add config param
graph, err := t.Graph(nil, s)
func (t *Terraform) Plan(
c *config.Config, s *State, vs map[string]string) (*Plan, error) {
g, err := t.Graph(c, s)
if err != nil {
return nil, err
}
result := new(Plan)
err = graph.Walk(t.planWalkFn(s, result))
if err != nil {
return nil, err
}
return result, nil
return t.plan(g, c, s, vs)
}
// Refresh goes through all the resources in the state and refreshes them
@ -151,6 +145,19 @@ func (t *Terraform) Refresh(c *config.Config, s *State) (*State, error) {
return t.refresh(g)
}
func (t *Terraform) plan(
g *depgraph.Graph,
c *config.Config,
s *State,
vs map[string]string) (*Plan, error) {
p := &Plan{
Config: c,
Vars: vs,
}
err := g.Walk(t.planWalkFn(p, vs))
return p, err
}
func (t *Terraform) refresh(g *depgraph.Graph) (*State, error) {
s := new(State)
err := g.Walk(t.refreshWalkFn(s))
@ -243,40 +250,15 @@ func (t *Terraform) applyWalkFn(
}
func (t *Terraform) planWalkFn(
state *State, result *Plan) depgraph.WalkFunc {
result *Plan, vs map[string]string) depgraph.WalkFunc {
var l sync.Mutex
// Initialize the result diff so we can write to it
// Initialize the result
result.init()
// Write our configuration out
//result.Config = t.config
// Copy the variables
/*
result.Vars = make(map[string]string)
for k, v := range t.variables {
result.Vars[k] = v
}
*/
cb := func(r *Resource) (map[string]string, error) {
// Refresh the state so we're working with the latest resource info
newState, err := r.Provider.Refresh(r.State)
if err != nil {
return nil, err
}
// Make sure the state is set to at the very least the empty state
if newState == nil {
newState = new(ResourceState)
}
// Set the type, the provider shouldn't modify this
newState.Type = r.State.Type
// Get a diff from the newest state
diff, err := r.Provider.Diff(newState, r.Config)
diff, err := r.Provider.Diff(r.State, r.Config)
if err != nil {
return nil, err
}
@ -285,17 +267,15 @@ func (t *Terraform) planWalkFn(
if !diff.Empty() {
result.Diff.Resources[r.Id] = diff
}
result.State.Resources[r.Id] = newState
l.Unlock()
// Determine the new state and update variables
vars := make(map[string]string)
rs := newState
if !diff.Empty() {
rs = r.State.MergeDiff(diff)
r.State = r.State.MergeDiff(diff)
}
if rs != nil {
for ak, av := range rs.Attributes {
if r.State != nil {
for ak, av := range r.State.Attributes {
vars[fmt.Sprintf("%s.%s", r.Id, ak)] = av
}
}
@ -303,7 +283,7 @@ func (t *Terraform) planWalkFn(
return vars, nil
}
return t.genericWalkFn(nil, cb)
return t.genericWalkFn(vs, cb)
}
func (t *Terraform) genericWalkFn(
@ -351,9 +331,18 @@ func (t *Terraform) genericWalkFn(
panic(fmt.Sprintf("Interpolate error: %s", err))
}
// Set the config
// Force the config to be set later
rn.Resource.Config = nil
}
// Make sure that at least some resource configuration is set
if rn.Resource.Config == nil {
if rn.Config == nil {
rn.Resource.Config = new(ResourceConfig)
} else {
rn.Resource.Config = NewResourceConfig(rn.Config.RawConfig)
}
}
// Call the callack
newVars, err := cb(rn.Resource)

View File

@ -13,6 +13,7 @@ import (
// This is the directory where our test fixtures are.
const fixtureDir = "./test-fixtures"
/*
func TestTerraformApply(t *testing.T) {
tf := testTerraform(t, "apply-good")
@ -110,11 +111,13 @@ func TestTerraformApply_vars(t *testing.T) {
t.Fatalf("bad: \n%s", actual)
}
}
*/
func TestTerraformPlan(t *testing.T) {
tf := testTerraform(t, "plan-good")
c := testConfig(t, "plan-good")
tf := testTerraform2(t, nil)
plan, err := tf.Plan(nil)
plan, err := tf.Plan(c, nil, nil)
if err != nil {
t.Fatalf("err: %s", err)
}
@ -128,20 +131,13 @@ func TestTerraformPlan(t *testing.T) {
if actual != expected {
t.Fatalf("bad:\n%s", actual)
}
p := testProviderMock(testProvider(tf, "aws_instance.foo"))
if !p.RefreshCalled {
t.Fatal("refresh should be called")
}
if p.RefreshState == nil {
t.Fatal("refresh should have state")
}
}
func TestTerraformPlan_nil(t *testing.T) {
tf := testTerraform(t, "plan-nil")
c := testConfig(t, "plan-nil")
tf := testTerraform2(t, nil)
plan, err := tf.Plan(nil)
plan, err := tf.Plan(c, nil, nil)
if err != nil {
t.Fatalf("err: %s", err)
}
@ -151,9 +147,10 @@ func TestTerraformPlan_nil(t *testing.T) {
}
func TestTerraformPlan_computed(t *testing.T) {
tf := testTerraform(t, "plan-computed")
c := testConfig(t, "plan-computed")
tf := testTerraform2(t, nil)
plan, err := tf.Plan(nil)
plan, err := tf.Plan(c, nil, nil)
if err != nil {
t.Fatalf("err: %s", err)
}
@ -169,46 +166,6 @@ func TestTerraformPlan_computed(t *testing.T) {
}
}
func TestTerraformPlan_providerInit(t *testing.T) {
tf := testTerraform(t, "plan-provider-init")
_, err := tf.Plan(nil)
if err != nil {
t.Fatalf("err: %s", err)
}
p := testProviderMock(testProvider(tf, "do_droplet.bar"))
if p == nil {
t.Fatal("should have provider")
}
if !p.ConfigureCalled {
t.Fatal("configure should be called")
}
if p.ConfigureConfig.Config["foo"].(string) != "2" {
t.Fatalf("bad: %#v", p.ConfigureConfig)
}
}
func TestTerraformPlan_refreshNil(t *testing.T) {
tf := testTerraform(t, "plan-nil")
s := new(State)
s.init()
s.Resources["aws_instance.foo"] = &ResourceState{
Attributes: map[string]string{
"nil": "1",
},
}
plan, err := tf.Plan(s)
if err != nil {
t.Fatalf("err: %s", err)
}
if len(plan.Diff.Resources) != 0 {
t.Fatalf("bad: %#v", plan.Diff.Resources)
}
}
func TestTerraformRefresh(t *testing.T) {
rpAWS := new(MockResourceProvider)
rpAWS.ResourcesReturn = []ResourceType{
@ -476,7 +433,12 @@ func testTerraform(t *testing.T, name string) *Terraform {
func testTerraform2(t *testing.T, c *Config) *Terraform {
if c == nil {
c = new(Config)
c = &Config{
Providers: map[string]ResourceProviderFactory{
"aws": testProviderFunc("aws", []string{"aws_instance"}),
"do": testProviderFunc("do", []string{"do_droplet"}),
},
}
}
tf, err := New(c)