diff --git a/terraform/state.go b/terraform/state.go index 933ab264d9..4ac4d09b2c 100644 --- a/terraform/state.go +++ b/terraform/state.go @@ -16,8 +16,7 @@ import ( // can use to keep track of what real world resources it is actually // managing. type State struct { - Dependencies map[string][][]string - Resources map[string]*ResourceState + Resources map[string]*ResourceState once sync.Once } @@ -75,6 +74,13 @@ func (s *State) String() string { for ak, av := range rs.Attributes { buf.WriteString(fmt.Sprintf(" %s = %s\n", ak, av)) } + + if len(rs.Dependencies) > 0 { + buf.WriteString(fmt.Sprintf("\n Dependencies:\n")) + for _, dep := range rs.Dependencies { + buf.WriteString(fmt.Sprintf(" %s\n", dep.ID)) + } + } } return buf.String() @@ -135,10 +141,43 @@ func WriteState(d *State, dst io.Writer) error { // Extra is just extra data that a provider can return that we store // for later, but is not exposed in any way to the user. type ResourceState struct { - ID string - Type string + // This is filled in and managed by Terraform, and is the resource + // type itself such as "mycloud_instance". If a resource provider sets + // this value, it won't be persisted. + Type string + + // The attributes below are all meant to be filled in by the + // resource providers themselves. Documentation for each are above + // each element. + + // A unique ID for this resource. This is opaque to Terraform + // and is only meant as a lookup mechanism for the providers. + ID string + + // Attributes are basic information about the resource. Any keys here + // are accessible in variable format within Terraform configurations: + // ${resourcetype.name.attribute}. Attributes map[string]string - Extra map[string]interface{} + + // Extra information that the provider can store about a resource. + // This data is opaque, never shown to the user, and is sent back to + // the provider as-is for whatever purpose appropriate. + Extra map[string]interface{} + + // Dependencies are a list of things that this resource relies on + // existing to remain intact. For example: an AWS instance might + // depend on a subnet (which itself might depend on a VPC, and so + // on). + // + // Terraform uses this information to build valid destruction + // orders and to warn the user if they're destroying a resource that + // another resource depends on. + // + // Things can be put into this list that may not be managed by + // Terraform. If Terraform doesn't find a matching ID in the + // overall state, then it assumes it isn't managed and doesn't + // worry about it. + Dependencies []ResourceDependency } // MergeDiff takes a ResourceDiff and merges the attributes into @@ -174,3 +213,11 @@ func (s *ResourceState) MergeDiff(d *ResourceDiff) *ResourceState { return &result } + +// ResourceDependency maps a resource to another resource that it +// depends on to remain intact and uncorrupted. +type ResourceDependency struct { + // ID of the resource that we depend on. This ID should map + // directly to another ResourceState's ID. + ID string +} diff --git a/terraform/terraform.go b/terraform/terraform.go index f16155c610..384b9e7d17 100644 --- a/terraform/terraform.go +++ b/terraform/terraform.go @@ -104,6 +104,10 @@ func (t *Terraform) apply( p *Plan) (*State, error) { s := new(State) err := g.Walk(t.applyWalkFn(s, p)) + + // Now that we've built the state and have the graph, re-calculate + // the dependencies for our state based on what we did. + return s, err } diff --git a/terraform/terraform_test.go b/terraform/terraform_test.go index ad1c0ab15a..df62962d05 100644 --- a/terraform/terraform_test.go +++ b/terraform/terraform_test.go @@ -492,15 +492,27 @@ func testProviderFunc(n string, rs []string) ResourceProviderFactory { return nil, nil } + id := "foo" + if idAttr, ok := d.Attributes["id"]; ok { + id = idAttr.New + } + result := &ResourceState{ - ID: "foo", - Attributes: make(map[string]string), + ID: id, } if d != nil { result = result.MergeDiff(d) } + if depAttr, ok := d.Attributes["dep"]; ok { + result.Dependencies = []ResourceDependency{ + ResourceDependency{ + ID: depAttr.New, + }, + } + } + return result, nil } diff --git a/terraform/test-fixtures/apply-destroy/main.tf b/terraform/test-fixtures/apply-destroy/main.tf index e0eeec4507..63c561692a 100644 --- a/terraform/test-fixtures/apply-destroy/main.tf +++ b/terraform/test-fixtures/apply-destroy/main.tf @@ -1,7 +1,10 @@ resource "aws_instance" "foo" { + id = "foo" num = "2" } resource "aws_instance" "bar" { + id = "bar" foo = "{aws_instance.foo.num}" + dep = "foo" }