terraform: add ID to diff implicitly

This commit is contained in:
Mitchell Hashimoto 2014-07-08 16:58:31 -07:00
parent 2fd5b36550
commit 251790f05a
8 changed files with 112 additions and 26 deletions

View File

@ -4,9 +4,9 @@ import (
"fmt"
"log"
"github.com/hashicorp/terraform/flatmap"
"github.com/hashicorp/terraform/helper/diff"
"github.com/hashicorp/terraform/terraform"
"github.com/hashicorp/terraform/flatmap"
"github.com/mitchellh/goamz/ec2"
)

View File

@ -532,6 +532,26 @@ func (c *Context) planWalkFn(result *Plan) depgraph.WalkFunc {
}
}
if diff == nil {
diff = new(ResourceDiff)
}
if diff.RequiresNew() && r.State.ID != "" {
// This will also require a destroy
diff.Destroy = true
}
if diff.RequiresNew() || r.State.ID == "" {
// Add diff to compute new ID
diff.init()
diff.Attributes["id"] = &ResourceAttrDiff{
Old: r.State.Attributes["id"],
NewComputed: true,
RequiresNew: true,
Type: DiffAttrOutput,
}
}
l.Lock()
if !diff.Empty() {
result.Diff.Resources[r.Id] = diff
@ -752,7 +772,10 @@ func (c *Context) genericWalkFn(cb genericWalkFunc) depgraph.WalkFunc {
}()
// Call the callack
log.Printf("[INFO] Walking: %s", rn.Resource.Id)
log.Printf(
"[INFO] Walking: %s (Graph node: %s)",
rn.Resource.Id,
n.Name)
if err := cb(rn.Resource); err != nil {
log.Printf("[ERROR] Error walking '%s': %s", rn.Resource.Id, err)
return err

View File

@ -180,8 +180,6 @@ func TestContextApply_Minimal(t *testing.T) {
t.Fatalf("err: %s", err)
}
ctx.variables = map[string]string{"value": "1"}
state, err := ctx.Apply()
if err != nil {
t.Fatalf("err: %s", err)
@ -242,7 +240,9 @@ func TestContextApply_cancel(t *testing.T) {
// Start the Apply in a goroutine
stateCh := make(chan *State)
go func() {
println("START")
state, err := ctx.Apply()
println("STOP")
if err != nil {
panic(err)
}
@ -714,6 +714,29 @@ func TestContextPlan(t *testing.T) {
}
}
func TestContextPlan_minimal(t *testing.T) {
c := testConfig(t, "plan-empty")
p := testProvider("aws")
p.DiffFn = testDiffFn
ctx := testContext(t, &ContextOpts{
Config: c,
Providers: map[string]ResourceProviderFactory{
"aws": testProviderFuncFixed(p),
},
})
plan, err := ctx.Plan(nil)
if err != nil {
t.Fatalf("err: %s", err)
}
actual := strings.TrimSpace(plan.String())
expected := strings.TrimSpace(testTerraformPlanEmptyStr)
if actual != expected {
t.Fatalf("bad:\n%s", actual)
}
}
func TestContextPlan_nil(t *testing.T) {
c := testConfig(t, "plan-nil")
p := testProvider("aws")
@ -723,6 +746,14 @@ func TestContextPlan_nil(t *testing.T) {
Providers: map[string]ResourceProviderFactory{
"aws": testProviderFuncFixed(p),
},
State: &State{
Resources: map[string]*ResourceState{
"aws_instance.foo": &ResourceState{
ID: "bar",
Type: "aws_instance",
},
},
},
})
plan, err := ctx.Plan(nil)

View File

@ -115,6 +115,10 @@ func (d *Diff) String() string {
keyLen := 0
keys := make([]string, 0, len(rdiff.Attributes))
for key, _ := range rdiff.Attributes {
if key == "id" {
continue
}
keys = append(keys, key)
if len(key) > keyLen {
keyLen = len(key)
@ -152,6 +156,8 @@ func (d *Diff) String() string {
type ResourceDiff struct {
Attributes map[string]*ResourceAttrDiff
Destroy bool
once sync.Once
}
// ResourceAttrDiff is the diff of a single attribute of a resource.
@ -177,6 +183,14 @@ const (
DiffAttrOutput
)
func (d *ResourceDiff) init() {
d.once.Do(func() {
if d.Attributes == nil {
d.Attributes = make(map[string]*ResourceAttrDiff)
}
})
}
// Empty returns true if this diff encapsulates no changes.
func (d *ResourceDiff) Empty() bool {
if d == nil {

View File

@ -273,7 +273,7 @@ func graphAddDiff(g *depgraph.Graph, d *Diff) error {
continue
}
if rd.Destroy || rd.RequiresNew() {
if rd.Destroy {
// If we're destroying, we create a new destroy node with
// the proper dependencies. Perform a dirty copy operation.
newNode := new(GraphNodeResource)

View File

@ -129,6 +129,10 @@ func (c *ResourceConfig) IsSet(k string) bool {
}
func (c *ResourceConfig) interpolate(ctx *Context) error {
if c == nil {
return nil
}
if ctx != nil {
if err := ctx.computeVars(c.raw); err != nil {
return err

View File

@ -110,10 +110,8 @@ aws_instance.foo:
const testTerraformApplyMinimalStr = `
aws_instance.bar:
ID = foo
type = aws_instance
aws_instance.foo:
ID = foo
type = aws_instance
`
const testTerraformApplyDestroyStr = `
@ -216,10 +214,10 @@ aws_instance.foo:
const testTerraformPlanStr = `
DIFF:
UPDATE: aws_instance.bar
CREATE: aws_instance.bar
foo: "" => "2"
type: "" => "aws_instance"
UPDATE: aws_instance.foo
CREATE: aws_instance.foo
num: "" => "2"
type: "" => "aws_instance"
@ -231,10 +229,10 @@ STATE:
const testTerraformPlanComputedStr = `
DIFF:
UPDATE: aws_instance.bar
CREATE: aws_instance.bar
foo: "" => "<computed>"
type: "" => "aws_instance"
UPDATE: aws_instance.foo
CREATE: aws_instance.foo
foo: "" => "<computed>"
num: "" => "2"
type: "" => "aws_instance"
@ -247,10 +245,10 @@ STATE:
const testTerraformPlanComputedIdStr = `
DIFF:
UPDATE: aws_instance.bar
CREATE: aws_instance.bar
foo: "" => "<computed>"
type: "" => "aws_instance"
UPDATE: aws_instance.foo
CREATE: aws_instance.foo
foo: "" => "<computed>"
num: "" => "2"
type: "" => "aws_instance"
@ -263,22 +261,22 @@ STATE:
const testTerraformPlanCountStr = `
DIFF:
UPDATE: aws_instance.bar
CREATE: aws_instance.bar
foo: "" => "foo,foo,foo,foo,foo"
type: "" => "aws_instance"
UPDATE: aws_instance.foo.0
CREATE: aws_instance.foo.0
foo: "" => "foo"
type: "" => "aws_instance"
UPDATE: aws_instance.foo.1
CREATE: aws_instance.foo.1
foo: "" => "foo"
type: "" => "aws_instance"
UPDATE: aws_instance.foo.2
CREATE: aws_instance.foo.2
foo: "" => "foo"
type: "" => "aws_instance"
UPDATE: aws_instance.foo.3
CREATE: aws_instance.foo.3
foo: "" => "foo"
type: "" => "aws_instance"
UPDATE: aws_instance.foo.4
CREATE: aws_instance.foo.4
foo: "" => "foo"
type: "" => "aws_instance"
@ -290,7 +288,7 @@ STATE:
const testTerraformPlanCountDecreaseStr = `
DIFF:
UPDATE: aws_instance.bar
CREATE: aws_instance.bar
foo: "" => "bar"
type: "" => "aws_instance"
DESTROY: aws_instance.foo.1
@ -311,13 +309,13 @@ aws_instance.foo.2:
const testTerraformPlanCountIncreaseStr = `
DIFF:
UPDATE: aws_instance.bar
CREATE: aws_instance.bar
foo: "" => "bar"
type: "" => "aws_instance"
UPDATE: aws_instance.foo.1
CREATE: aws_instance.foo.1
foo: "" => "foo"
type: "" => "aws_instance"
UPDATE: aws_instance.foo.2
CREATE: aws_instance.foo.2
foo: "" => "foo"
type: "" => "aws_instance"
@ -343,11 +341,22 @@ aws_instance.two:
ID = baz
`
const testTerraformPlanEmptyStr = `
DIFF:
CREATE: aws_instance.bar
CREATE: aws_instance.foo
STATE:
<no state>
`
const testTerraformPlanOrphanStr = `
DIFF:
DESTROY: aws_instance.baz
UPDATE: aws_instance.foo
CREATE: aws_instance.foo
num: "" => "2"
type: "" => "aws_instance"
@ -360,7 +369,7 @@ aws_instance.baz:
const testTerraformPlanStateStr = `
DIFF:
UPDATE: aws_instance.bar
CREATE: aws_instance.bar
foo: "" => "2"
type: "" => "aws_instance"
UPDATE: aws_instance.foo

View File

@ -0,0 +1,5 @@
resource "aws_instance" "foo" {
}
resource "aws_instance" "bar" {
}