terraform: add ID to diff implicitly
This commit is contained in:
parent
2fd5b36550
commit
251790f05a
|
@ -4,9 +4,9 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/flatmap"
|
||||||
"github.com/hashicorp/terraform/helper/diff"
|
"github.com/hashicorp/terraform/helper/diff"
|
||||||
"github.com/hashicorp/terraform/terraform"
|
"github.com/hashicorp/terraform/terraform"
|
||||||
"github.com/hashicorp/terraform/flatmap"
|
|
||||||
"github.com/mitchellh/goamz/ec2"
|
"github.com/mitchellh/goamz/ec2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -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()
|
l.Lock()
|
||||||
if !diff.Empty() {
|
if !diff.Empty() {
|
||||||
result.Diff.Resources[r.Id] = diff
|
result.Diff.Resources[r.Id] = diff
|
||||||
|
@ -752,7 +772,10 @@ func (c *Context) genericWalkFn(cb genericWalkFunc) depgraph.WalkFunc {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Call the callack
|
// 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 {
|
if err := cb(rn.Resource); err != nil {
|
||||||
log.Printf("[ERROR] Error walking '%s': %s", rn.Resource.Id, err)
|
log.Printf("[ERROR] Error walking '%s': %s", rn.Resource.Id, err)
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -180,8 +180,6 @@ func TestContextApply_Minimal(t *testing.T) {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.variables = map[string]string{"value": "1"}
|
|
||||||
|
|
||||||
state, err := ctx.Apply()
|
state, err := ctx.Apply()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
|
@ -242,7 +240,9 @@ func TestContextApply_cancel(t *testing.T) {
|
||||||
// Start the Apply in a goroutine
|
// Start the Apply in a goroutine
|
||||||
stateCh := make(chan *State)
|
stateCh := make(chan *State)
|
||||||
go func() {
|
go func() {
|
||||||
|
println("START")
|
||||||
state, err := ctx.Apply()
|
state, err := ctx.Apply()
|
||||||
|
println("STOP")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
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) {
|
func TestContextPlan_nil(t *testing.T) {
|
||||||
c := testConfig(t, "plan-nil")
|
c := testConfig(t, "plan-nil")
|
||||||
p := testProvider("aws")
|
p := testProvider("aws")
|
||||||
|
@ -723,6 +746,14 @@ func TestContextPlan_nil(t *testing.T) {
|
||||||
Providers: map[string]ResourceProviderFactory{
|
Providers: map[string]ResourceProviderFactory{
|
||||||
"aws": testProviderFuncFixed(p),
|
"aws": testProviderFuncFixed(p),
|
||||||
},
|
},
|
||||||
|
State: &State{
|
||||||
|
Resources: map[string]*ResourceState{
|
||||||
|
"aws_instance.foo": &ResourceState{
|
||||||
|
ID: "bar",
|
||||||
|
Type: "aws_instance",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
plan, err := ctx.Plan(nil)
|
plan, err := ctx.Plan(nil)
|
||||||
|
|
|
@ -115,6 +115,10 @@ func (d *Diff) String() string {
|
||||||
keyLen := 0
|
keyLen := 0
|
||||||
keys := make([]string, 0, len(rdiff.Attributes))
|
keys := make([]string, 0, len(rdiff.Attributes))
|
||||||
for key, _ := range rdiff.Attributes {
|
for key, _ := range rdiff.Attributes {
|
||||||
|
if key == "id" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
keys = append(keys, key)
|
keys = append(keys, key)
|
||||||
if len(key) > keyLen {
|
if len(key) > keyLen {
|
||||||
keyLen = len(key)
|
keyLen = len(key)
|
||||||
|
@ -152,6 +156,8 @@ func (d *Diff) String() string {
|
||||||
type ResourceDiff struct {
|
type ResourceDiff struct {
|
||||||
Attributes map[string]*ResourceAttrDiff
|
Attributes map[string]*ResourceAttrDiff
|
||||||
Destroy bool
|
Destroy bool
|
||||||
|
|
||||||
|
once sync.Once
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResourceAttrDiff is the diff of a single attribute of a resource.
|
// ResourceAttrDiff is the diff of a single attribute of a resource.
|
||||||
|
@ -177,6 +183,14 @@ const (
|
||||||
DiffAttrOutput
|
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.
|
// Empty returns true if this diff encapsulates no changes.
|
||||||
func (d *ResourceDiff) Empty() bool {
|
func (d *ResourceDiff) Empty() bool {
|
||||||
if d == nil {
|
if d == nil {
|
||||||
|
|
|
@ -273,7 +273,7 @@ func graphAddDiff(g *depgraph.Graph, d *Diff) error {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if rd.Destroy || rd.RequiresNew() {
|
if rd.Destroy {
|
||||||
// If we're destroying, we create a new destroy node with
|
// If we're destroying, we create a new destroy node with
|
||||||
// the proper dependencies. Perform a dirty copy operation.
|
// the proper dependencies. Perform a dirty copy operation.
|
||||||
newNode := new(GraphNodeResource)
|
newNode := new(GraphNodeResource)
|
||||||
|
|
|
@ -129,6 +129,10 @@ func (c *ResourceConfig) IsSet(k string) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ResourceConfig) interpolate(ctx *Context) error {
|
func (c *ResourceConfig) interpolate(ctx *Context) error {
|
||||||
|
if c == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
if ctx != nil {
|
if ctx != nil {
|
||||||
if err := ctx.computeVars(c.raw); err != nil {
|
if err := ctx.computeVars(c.raw); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -110,10 +110,8 @@ aws_instance.foo:
|
||||||
const testTerraformApplyMinimalStr = `
|
const testTerraformApplyMinimalStr = `
|
||||||
aws_instance.bar:
|
aws_instance.bar:
|
||||||
ID = foo
|
ID = foo
|
||||||
type = aws_instance
|
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
type = aws_instance
|
|
||||||
`
|
`
|
||||||
|
|
||||||
const testTerraformApplyDestroyStr = `
|
const testTerraformApplyDestroyStr = `
|
||||||
|
@ -216,10 +214,10 @@ aws_instance.foo:
|
||||||
const testTerraformPlanStr = `
|
const testTerraformPlanStr = `
|
||||||
DIFF:
|
DIFF:
|
||||||
|
|
||||||
UPDATE: aws_instance.bar
|
CREATE: aws_instance.bar
|
||||||
foo: "" => "2"
|
foo: "" => "2"
|
||||||
type: "" => "aws_instance"
|
type: "" => "aws_instance"
|
||||||
UPDATE: aws_instance.foo
|
CREATE: aws_instance.foo
|
||||||
num: "" => "2"
|
num: "" => "2"
|
||||||
type: "" => "aws_instance"
|
type: "" => "aws_instance"
|
||||||
|
|
||||||
|
@ -231,10 +229,10 @@ STATE:
|
||||||
const testTerraformPlanComputedStr = `
|
const testTerraformPlanComputedStr = `
|
||||||
DIFF:
|
DIFF:
|
||||||
|
|
||||||
UPDATE: aws_instance.bar
|
CREATE: aws_instance.bar
|
||||||
foo: "" => "<computed>"
|
foo: "" => "<computed>"
|
||||||
type: "" => "aws_instance"
|
type: "" => "aws_instance"
|
||||||
UPDATE: aws_instance.foo
|
CREATE: aws_instance.foo
|
||||||
foo: "" => "<computed>"
|
foo: "" => "<computed>"
|
||||||
num: "" => "2"
|
num: "" => "2"
|
||||||
type: "" => "aws_instance"
|
type: "" => "aws_instance"
|
||||||
|
@ -247,10 +245,10 @@ STATE:
|
||||||
const testTerraformPlanComputedIdStr = `
|
const testTerraformPlanComputedIdStr = `
|
||||||
DIFF:
|
DIFF:
|
||||||
|
|
||||||
UPDATE: aws_instance.bar
|
CREATE: aws_instance.bar
|
||||||
foo: "" => "<computed>"
|
foo: "" => "<computed>"
|
||||||
type: "" => "aws_instance"
|
type: "" => "aws_instance"
|
||||||
UPDATE: aws_instance.foo
|
CREATE: aws_instance.foo
|
||||||
foo: "" => "<computed>"
|
foo: "" => "<computed>"
|
||||||
num: "" => "2"
|
num: "" => "2"
|
||||||
type: "" => "aws_instance"
|
type: "" => "aws_instance"
|
||||||
|
@ -263,22 +261,22 @@ STATE:
|
||||||
const testTerraformPlanCountStr = `
|
const testTerraformPlanCountStr = `
|
||||||
DIFF:
|
DIFF:
|
||||||
|
|
||||||
UPDATE: aws_instance.bar
|
CREATE: aws_instance.bar
|
||||||
foo: "" => "foo,foo,foo,foo,foo"
|
foo: "" => "foo,foo,foo,foo,foo"
|
||||||
type: "" => "aws_instance"
|
type: "" => "aws_instance"
|
||||||
UPDATE: aws_instance.foo.0
|
CREATE: aws_instance.foo.0
|
||||||
foo: "" => "foo"
|
foo: "" => "foo"
|
||||||
type: "" => "aws_instance"
|
type: "" => "aws_instance"
|
||||||
UPDATE: aws_instance.foo.1
|
CREATE: aws_instance.foo.1
|
||||||
foo: "" => "foo"
|
foo: "" => "foo"
|
||||||
type: "" => "aws_instance"
|
type: "" => "aws_instance"
|
||||||
UPDATE: aws_instance.foo.2
|
CREATE: aws_instance.foo.2
|
||||||
foo: "" => "foo"
|
foo: "" => "foo"
|
||||||
type: "" => "aws_instance"
|
type: "" => "aws_instance"
|
||||||
UPDATE: aws_instance.foo.3
|
CREATE: aws_instance.foo.3
|
||||||
foo: "" => "foo"
|
foo: "" => "foo"
|
||||||
type: "" => "aws_instance"
|
type: "" => "aws_instance"
|
||||||
UPDATE: aws_instance.foo.4
|
CREATE: aws_instance.foo.4
|
||||||
foo: "" => "foo"
|
foo: "" => "foo"
|
||||||
type: "" => "aws_instance"
|
type: "" => "aws_instance"
|
||||||
|
|
||||||
|
@ -290,7 +288,7 @@ STATE:
|
||||||
const testTerraformPlanCountDecreaseStr = `
|
const testTerraformPlanCountDecreaseStr = `
|
||||||
DIFF:
|
DIFF:
|
||||||
|
|
||||||
UPDATE: aws_instance.bar
|
CREATE: aws_instance.bar
|
||||||
foo: "" => "bar"
|
foo: "" => "bar"
|
||||||
type: "" => "aws_instance"
|
type: "" => "aws_instance"
|
||||||
DESTROY: aws_instance.foo.1
|
DESTROY: aws_instance.foo.1
|
||||||
|
@ -311,13 +309,13 @@ aws_instance.foo.2:
|
||||||
const testTerraformPlanCountIncreaseStr = `
|
const testTerraformPlanCountIncreaseStr = `
|
||||||
DIFF:
|
DIFF:
|
||||||
|
|
||||||
UPDATE: aws_instance.bar
|
CREATE: aws_instance.bar
|
||||||
foo: "" => "bar"
|
foo: "" => "bar"
|
||||||
type: "" => "aws_instance"
|
type: "" => "aws_instance"
|
||||||
UPDATE: aws_instance.foo.1
|
CREATE: aws_instance.foo.1
|
||||||
foo: "" => "foo"
|
foo: "" => "foo"
|
||||||
type: "" => "aws_instance"
|
type: "" => "aws_instance"
|
||||||
UPDATE: aws_instance.foo.2
|
CREATE: aws_instance.foo.2
|
||||||
foo: "" => "foo"
|
foo: "" => "foo"
|
||||||
type: "" => "aws_instance"
|
type: "" => "aws_instance"
|
||||||
|
|
||||||
|
@ -343,11 +341,22 @@ aws_instance.two:
|
||||||
ID = baz
|
ID = baz
|
||||||
`
|
`
|
||||||
|
|
||||||
|
const testTerraformPlanEmptyStr = `
|
||||||
|
DIFF:
|
||||||
|
|
||||||
|
CREATE: aws_instance.bar
|
||||||
|
CREATE: aws_instance.foo
|
||||||
|
|
||||||
|
STATE:
|
||||||
|
|
||||||
|
<no state>
|
||||||
|
`
|
||||||
|
|
||||||
const testTerraformPlanOrphanStr = `
|
const testTerraformPlanOrphanStr = `
|
||||||
DIFF:
|
DIFF:
|
||||||
|
|
||||||
DESTROY: aws_instance.baz
|
DESTROY: aws_instance.baz
|
||||||
UPDATE: aws_instance.foo
|
CREATE: aws_instance.foo
|
||||||
num: "" => "2"
|
num: "" => "2"
|
||||||
type: "" => "aws_instance"
|
type: "" => "aws_instance"
|
||||||
|
|
||||||
|
@ -360,7 +369,7 @@ aws_instance.baz:
|
||||||
const testTerraformPlanStateStr = `
|
const testTerraformPlanStateStr = `
|
||||||
DIFF:
|
DIFF:
|
||||||
|
|
||||||
UPDATE: aws_instance.bar
|
CREATE: aws_instance.bar
|
||||||
foo: "" => "2"
|
foo: "" => "2"
|
||||||
type: "" => "aws_instance"
|
type: "" => "aws_instance"
|
||||||
UPDATE: aws_instance.foo
|
UPDATE: aws_instance.foo
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
resource "aws_instance" "foo" {
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_instance" "bar" {
|
||||||
|
}
|
Loading…
Reference in New Issue