diff --git a/addrs/resource.go b/addrs/resource.go index 56b2e5119..bce96183a 100644 --- a/addrs/resource.go +++ b/addrs/resource.go @@ -135,6 +135,14 @@ func (r AbsResource) Instance(key InstanceKey) AbsResourceInstance { } } +// Config returns the unexpanded ConfigResource for this AbsResource. +func (r AbsResource) Config() ConfigResource { + return ConfigResource{ + Module: r.Module.Module(), + Resource: r.Resource, + } +} + // TargetContains implements Targetable by returning true if the given other // address is either equal to the receiver or is an instance of the // receiver. @@ -300,7 +308,7 @@ func (r ConfigResource) TargetContains(other Targetable) bool { // We'll use our stringification as a cheat-ish way to test for equality. return to.String() == r.String() case AbsResource: - return r.TargetContains(ConfigResource{Module: to.Module.Module(), Resource: to.Resource}) + return r.TargetContains(to.Config()) case AbsResourceInstance: return r.TargetContains(to.ContainingResource()) default: diff --git a/command/format/state.go b/command/format/state.go index 31616c9cf..949fc6e17 100644 --- a/command/format/state.go +++ b/command/format/state.go @@ -107,6 +107,7 @@ func formatStateModule(p blockBodyDiffPrinter, m *states.Module, schemas *terraf instances := []obj{} addr := m.Resources[key].Addr + resAddr := addr.Resource taintStr := "" if v.Current != nil && v.Current.Status == 'T' { @@ -114,11 +115,11 @@ func formatStateModule(p blockBodyDiffPrinter, m *states.Module, schemas *terraf } instances = append(instances, - obj{fmt.Sprintf("# %s:%s\n", addr.Absolute(m.Addr).Instance(k), taintStr), v.Current}) + obj{fmt.Sprintf("# %s:%s\n", addr.Instance(k), taintStr), v.Current}) for dk, v := range v.Deposed { instances = append(instances, - obj{fmt.Sprintf("# %s: (deposed object %s)\n", addr.Absolute(m.Addr).Instance(k), dk), v}) + obj{fmt.Sprintf("# %s: (deposed object %s)\n", addr.Instance(k), dk), v}) } // Sort the instances for consistent output. @@ -150,44 +151,44 @@ func formatStateModule(p blockBodyDiffPrinter, m *states.Module, schemas *terraf continue } - switch addr.Mode { + switch resAddr.Mode { case addrs.ManagedResourceMode: schema, _ = schemas.ResourceTypeConfig( provider, - addr.Mode, - addr.Type, + resAddr.Mode, + resAddr.Type, ) if schema == nil { p.buf.WriteString(fmt.Sprintf( - "# missing schema for provider %q resource type %s\n\n", provider, addr.Type)) + "# missing schema for provider %q resource type %s\n\n", provider, resAddr.Type)) continue } p.buf.WriteString(fmt.Sprintf( "resource %q %q {", - addr.Type, - addr.Name, + resAddr.Type, + resAddr.Name, )) case addrs.DataResourceMode: schema, _ = schemas.ResourceTypeConfig( provider, - addr.Mode, - addr.Type, + resAddr.Mode, + resAddr.Type, ) if schema == nil { p.buf.WriteString(fmt.Sprintf( - "# missing schema for provider %q data source %s\n\n", provider, addr.Type)) + "# missing schema for provider %q data source %s\n\n", provider, resAddr.Type)) continue } p.buf.WriteString(fmt.Sprintf( "data %q %q {", - addr.Type, - addr.Name, + resAddr.Type, + resAddr.Name, )) default: // should never happen, since the above is exhaustive - p.buf.WriteString(addr.String()) + p.buf.WriteString(resAddr.String()) } val, err := instance.Decode(schema.ImpliedType()) diff --git a/command/jsonstate/state.go b/command/jsonstate/state.go index bf9a6f872..b2432e6e6 100644 --- a/command/jsonstate/state.go +++ b/command/jsonstate/state.go @@ -255,22 +255,24 @@ func marshalResources(resources map[string]*states.Resource, module addrs.Module for _, r := range resources { for k, ri := range r.Instances { + resAddr := r.Addr.Resource + current := resource{ - Address: r.Addr.Absolute(module).Instance(k).String(), - Type: r.Addr.Type, - Name: r.Addr.Name, + Address: r.Addr.Instance(k).String(), + Type: resAddr.Type, + Name: resAddr.Name, ProviderName: r.ProviderConfig.Provider.LegacyString(), } - switch r.Addr.Mode { + switch resAddr.Mode { case addrs.ManagedResourceMode: current.Mode = "managed" case addrs.DataResourceMode: current.Mode = "data" default: return ret, fmt.Errorf("resource %s has an unsupported mode %s", - r.Addr.String(), - r.Addr.Mode.String(), + resAddr.String(), + resAddr.Mode.String(), ) } @@ -280,8 +282,8 @@ func marshalResources(resources map[string]*states.Resource, module addrs.Module schema, _ := schemas.ResourceTypeConfig( r.ProviderConfig.Provider, - r.Addr.Mode, - r.Addr.Type, + resAddr.Mode, + resAddr.Type, ) // It is possible that the only instance is deposed @@ -289,7 +291,7 @@ func marshalResources(resources map[string]*states.Resource, module addrs.Module current.SchemaVersion = ri.Current.SchemaVersion if schema == nil { - return nil, fmt.Errorf("no schema found for %s", r.Addr.String()) + return nil, fmt.Errorf("no schema found for %s", resAddr.String()) } riObj, err := ri.Current.Decode(schema.ImpliedType()) if err != nil { diff --git a/command/jsonstate/state_test.go b/command/jsonstate/state_test.go index c1b16c8c2..6d9e87ede 100644 --- a/command/jsonstate/state_test.go +++ b/command/jsonstate/state_test.go @@ -186,10 +186,12 @@ func TestMarshalResources(t *testing.T) { "single resource": { map[string]*states.Resource{ "test_thing.baz": { - Addr: addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_thing", - Name: "bar", + Addr: addrs.AbsResource{ + Resource: addrs.Resource{ + Mode: addrs.ManagedResourceMode, + Type: "test_thing", + Name: "bar", + }, }, EachMode: states.NoEach, Instances: map[addrs.InstanceKey]*states.ResourceInstance{ @@ -228,10 +230,12 @@ func TestMarshalResources(t *testing.T) { "resource with count": { map[string]*states.Resource{ "test_thing.bar": { - Addr: addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_thing", - Name: "bar", + Addr: addrs.AbsResource{ + Resource: addrs.Resource{ + Mode: addrs.ManagedResourceMode, + Type: "test_thing", + Name: "bar", + }, }, EachMode: states.EachList, Instances: map[addrs.InstanceKey]*states.ResourceInstance{ @@ -270,10 +274,12 @@ func TestMarshalResources(t *testing.T) { "resource with for_each": { map[string]*states.Resource{ "test_thing.bar": { - Addr: addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_thing", - Name: "bar", + Addr: addrs.AbsResource{ + Resource: addrs.Resource{ + Mode: addrs.ManagedResourceMode, + Type: "test_thing", + Name: "bar", + }, }, EachMode: states.EachMap, Instances: map[addrs.InstanceKey]*states.ResourceInstance{ @@ -312,10 +318,12 @@ func TestMarshalResources(t *testing.T) { "deposed resource": { map[string]*states.Resource{ "test_thing.baz": { - Addr: addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_thing", - Name: "bar", + Addr: addrs.AbsResource{ + Resource: addrs.Resource{ + Mode: addrs.ManagedResourceMode, + Type: "test_thing", + Name: "bar", + }, }, EachMode: states.NoEach, Instances: map[addrs.InstanceKey]*states.ResourceInstance{ @@ -356,10 +364,12 @@ func TestMarshalResources(t *testing.T) { "deposed and current resource": { map[string]*states.Resource{ "test_thing.baz": { - Addr: addrs.Resource{ - Mode: addrs.ManagedResourceMode, - Type: "test_thing", - Name: "bar", + Addr: addrs.AbsResource{ + Resource: addrs.Resource{ + Mode: addrs.ManagedResourceMode, + Type: "test_thing", + Name: "bar", + }, }, EachMode: states.NoEach, Instances: map[addrs.InstanceKey]*states.ResourceInstance{ diff --git a/command/state_meta.go b/command/state_meta.go index 25c17bdb7..b94ffd4c9 100644 --- a/command/state_meta.go +++ b/command/state_meta.go @@ -192,7 +192,7 @@ func (c *StateMeta) collectModuleResourceInstances(ms *states.Module) []addrs.Ab func (c *StateMeta) collectResourceInstances(moduleAddr addrs.ModuleInstance, rs *states.Resource) []addrs.AbsResourceInstance { var ret []addrs.AbsResourceInstance for key := range rs.Instances { - ret = append(ret, rs.Addr.Instance(key).Absolute(moduleAddr)) + ret = append(ret, rs.Addr.Instance(key)) } return ret } diff --git a/command/state_mv.go b/command/state_mv.go index b4dc14321..096fa1b1f 100644 --- a/command/state_mv.go +++ b/command/state_mv.go @@ -226,7 +226,7 @@ func (c *StateMvCommand) Run(args []string) int { ssFrom.RemoveResource(addrFrom) // Update the address before adding it to the state. - rs.Addr = addrTo.Resource + rs.Addr = addrTo stateTo.Module(addrTo.Module).Resources[addrTo.Resource.String()] = rs } diff --git a/helper/resource/state_shim.go b/helper/resource/state_shim.go index fb7ed4ad0..fdb1db687 100644 --- a/helper/resource/state_shim.go +++ b/helper/resource/state_shim.go @@ -47,10 +47,10 @@ func shimNewState(newState *states.State, providers map[string]terraform.Resourc } for _, res := range newMod.Resources { - resType := res.Addr.Type + resType := res.Addr.Resource.Type providerType := res.ProviderConfig.Provider.Type - resource := getResource(providers, providerType, res.Addr) + resource := getResource(providers, providerType, res.Addr.Resource) for key, i := range res.Instances { resState := &terraform.ResourceState{ @@ -103,7 +103,7 @@ func shimNewState(newState *states.State, providers map[string]terraform.Resourc idx = "." + key.String() } - mod.Resources[res.Addr.String()+idx] = resState + mod.Resources[res.Addr.Resource.String()+idx] = resState } // add any deposed instances diff --git a/states/module.go b/states/module.go index ec177edf3..acce10129 100644 --- a/states/module.go +++ b/states/module.go @@ -58,7 +58,7 @@ func (ms *Module) SetResourceMeta(addr addrs.Resource, eachMode EachMode, provid rs := ms.Resource(addr) if rs == nil { rs = &Resource{ - Addr: addr, + Addr: addr.Absolute(ms.Addr), Instances: map[addrs.InstanceKey]*ResourceInstance{}, } ms.Resources[addr.String()] = rs @@ -295,7 +295,7 @@ func (ms *Module) RemoveLocalValue(name string) { func (ms *Module) PruneResourceHusks() { for _, rs := range ms.Resources { if len(rs.Instances) == 0 { - ms.RemoveResource(rs.Addr) + ms.RemoveResource(rs.Addr.Resource) } } } diff --git a/states/resource.go b/states/resource.go index da883ddab..fc9f0b49a 100644 --- a/states/resource.go +++ b/states/resource.go @@ -10,9 +10,9 @@ import ( // Resource represents the state of a resource. type Resource struct { - // Addr is the module-relative address for the resource this state object + // Addr is the absolute address for the resource this state object // belongs to. - Addr addrs.Resource + Addr addrs.AbsResource // EachMode is the multi-instance mode currently in use for this resource, // or NoEach if this is a single-instance resource. This dictates what diff --git a/states/state.go b/states/state.go index 1f842359e..7777b9144 100644 --- a/states/state.go +++ b/states/state.go @@ -70,6 +70,17 @@ func (s *State) Module(addr addrs.ModuleInstance) *Module { return s.Modules[addr.String()] } +// ModuleInstances returns the set of Module states that matches the given path. +func (s *State) ModuleInstances(addr addrs.Module) []*Module { + var ms []*Module + for _, m := range s.Modules { + if m.Addr.Module().Equal(addr) { + ms = append(ms, m) + } + } + return ms +} + // RemoveModule removes the module with the given address from the state, // unless it is the root module. The root module cannot be deleted, and so // this method will panic if that is attempted. @@ -133,6 +144,18 @@ func (s *State) Resource(addr addrs.AbsResource) *Resource { return ms.Resource(addr.Resource) } +// Resources returns the set of resources that match the given configuration path. +func (s *State) Resources(addr addrs.ConfigResource) []*Resource { + var ret []*Resource + for _, m := range s.ModuleInstances(addr.Module) { + r := m.Resource(addr.Resource) + if r != nil { + ret = append(ret, r) + } + } + return ret +} + // ResourceInstance returns the state for the resource instance with the given // address, or nil if no such resource is tracked in the state. func (s *State) ResourceInstance(addr addrs.AbsResourceInstance) *ResourceInstance { diff --git a/states/state_string.go b/states/state_string.go index 8be3d01a0..1c326ece9 100644 --- a/states/state_string.go +++ b/states/state_string.go @@ -91,7 +91,7 @@ func (m *Module) testString() string { addrsOrder := make([]addrs.AbsResourceInstance, 0, len(m.Resources)) for _, rs := range m.Resources { for ik := range rs.Instances { - addrsOrder = append(addrsOrder, rs.Addr.Instance(ik).Absolute(addrs.RootModuleInstance)) + addrsOrder = append(addrsOrder, rs.Addr.Instance(ik)) } } diff --git a/states/state_test.go b/states/state_test.go index 7feb252a4..bff8c4c15 100644 --- a/states/state_test.go +++ b/states/state_test.go @@ -67,7 +67,8 @@ func TestState(t *testing.T) { Mode: addrs.ManagedResourceMode, Type: "test_thing", Name: "baz", - }, + }.Absolute(addrs.RootModuleInstance), + EachMode: EachList, Instances: map[addrs.InstanceKey]*ResourceInstance{ addrs.IntKey(0): { diff --git a/states/statefile/version4.go b/states/statefile/version4.go index adde804f1..050be0ac9 100644 --- a/states/statefile/version4.go +++ b/states/statefile/version4.go @@ -371,7 +371,7 @@ func writeStateV4(file *File, w io.Writer) tfdiags.Diagnostics { for _, ms := range file.State.Modules { moduleAddr := ms.Addr for _, rs := range ms.Resources { - resourceAddr := rs.Addr + resourceAddr := rs.Addr.Resource var mode string switch resourceAddr.Mode { diff --git a/states/sync.go b/states/sync.go index 47fb16d6e..af391e55f 100644 --- a/states/sync.go +++ b/states/sync.go @@ -246,40 +246,48 @@ func (s *SyncState) RemoveResourceIfEmpty(addr addrs.AbsResource) bool { // The state is modified in-place if necessary, moving a resource instance // between the two addresses. The return value is true if a change was made, // and false otherwise. -func (s *SyncState) MaybeFixUpResourceInstanceAddressForCount(addr addrs.AbsResource, countEnabled bool) bool { +func (s *SyncState) MaybeFixUpResourceInstanceAddressForCount(addr addrs.ConfigResource, countEnabled bool) bool { s.lock.Lock() defer s.lock.Unlock() - ms := s.state.Module(addr.Module) - if ms == nil { + // get all modules instances that may match this state + modules := s.state.ModuleInstances(addr.Module) + if len(modules) == 0 { return false } - relAddr := addr.Resource - rs := ms.Resource(relAddr) - if rs == nil { - return false - } - huntKey := addrs.NoKey - replaceKey := addrs.InstanceKey(addrs.IntKey(0)) - if !countEnabled { - huntKey, replaceKey = replaceKey, huntKey + changed := false + + for _, ms := range modules { + relAddr := addr.Resource + rs := ms.Resource(relAddr) + if rs == nil { + continue + } + + huntKey := addrs.NoKey + replaceKey := addrs.InstanceKey(addrs.IntKey(0)) + if !countEnabled { + huntKey, replaceKey = replaceKey, huntKey + } + + is, exists := rs.Instances[huntKey] + if !exists { + continue + } + + if _, exists := rs.Instances[replaceKey]; exists { + // If the replacement key also exists then we'll do nothing and keep both. + continue + } + + // If we get here then we need to "rename" from hunt to replace + rs.Instances[replaceKey] = is + delete(rs.Instances, huntKey) + changed = true } - is, exists := rs.Instances[huntKey] - if !exists { - return false - } - - if _, exists := rs.Instances[replaceKey]; exists { - // If the replacement key also exists then we'll do nothing and keep both. - return false - } - - // If we get here then we need to "rename" from hunt to replace - rs.Instances[replaceKey] = is - delete(rs.Instances, huntKey) - return true + return changed } // SetResourceInstanceCurrent saves the given instance object as the current @@ -464,7 +472,7 @@ func (s *SyncState) RemovePlannedResourceInstanceObjects() { moduleAddr := ms.Addr for _, rs := range ms.Resources { - resAddr := rs.Addr + resAddr := rs.Addr.Resource for ik, is := range rs.Instances { instAddr := resAddr.Instance(ik) diff --git a/terraform/context_refresh_test.go b/terraform/context_refresh_test.go index 82765125c..099d0af42 100644 --- a/terraform/context_refresh_test.go +++ b/terraform/context_refresh_test.go @@ -1422,7 +1422,7 @@ func TestContext2Refresh_vars(t *testing.T) { } for _, r := range mod.Resources { - if r.Addr.Type == "" { + if r.Addr.Resource.Type == "" { t.Fatalf("no type: %#v", r) } } diff --git a/terraform/eval_count.go b/terraform/eval_count.go index f3b07ef0d..3da947f1f 100644 --- a/terraform/eval_count.go +++ b/terraform/eval_count.go @@ -111,7 +111,7 @@ func evaluateResourceCountExpressionKnown(expr hcl.Expression, ctx EvalContext) // Since the state is modified in-place, this function must take a writer lock // on the state. The caller must therefore not also be holding a state lock, // or this function will block forever awaiting the lock. -func fixResourceCountSetTransition(ctx EvalContext, addr addrs.AbsResource, countEnabled bool) { +func fixResourceCountSetTransition(ctx EvalContext, addr addrs.ConfigResource, countEnabled bool) { state := ctx.State() changed := state.MaybeFixUpResourceInstanceAddressForCount(addr, countEnabled) if changed { diff --git a/terraform/eval_count_boundary.go b/terraform/eval_count_boundary.go index 647c58d1e..855f14897 100644 --- a/terraform/eval_count_boundary.go +++ b/terraform/eval_count_boundary.go @@ -63,14 +63,13 @@ func (n *EvalCountFixZeroOneBoundaryGlobal) fixModule(ctx EvalContext, moduleAdd } for _, r := range ms.Resources { - addr := r.Addr.Absolute(moduleAddr) - rCfg := cfg.Module.ResourceByAddr(r.Addr) + rCfg := cfg.Module.ResourceByAddr(r.Addr.Resource) if rCfg == nil { - log.Printf("[WARN] Not fixing up EachModes for %s because it has no config", addr) + log.Printf("[WARN] Not fixing up EachModes for %s because it has no config", r.Addr) continue } hasCount := rCfg.Count != nil - fixResourceCountSetTransition(ctx, addr, hasCount) + fixResourceCountSetTransition(ctx, r.Addr.Config(), hasCount) } return nil diff --git a/terraform/node_data_refresh.go b/terraform/node_data_refresh.go index b16a73bd9..02d230155 100644 --- a/terraform/node_data_refresh.go +++ b/terraform/node_data_refresh.go @@ -19,7 +19,7 @@ var ( _ GraphNodeDynamicExpandable = (*NodeRefreshableDataResource)(nil) _ GraphNodeReferenceable = (*NodeRefreshableDataResource)(nil) _ GraphNodeReferencer = (*NodeRefreshableDataResource)(nil) - _ GraphNodeResource = (*NodeRefreshableDataResource)(nil) + _ GraphNodeConfigResource = (*NodeRefreshableDataResource)(nil) _ GraphNodeAttachResourceConfig = (*NodeRefreshableDataResource)(nil) _ GraphNodeAttachProviderMetaConfigs = (*NodeAbstractResource)(nil) ) diff --git a/terraform/node_resource_abstract.go b/terraform/node_resource_abstract.go index 0fc3ee0ea..77086bd1d 100644 --- a/terraform/node_resource_abstract.go +++ b/terraform/node_resource_abstract.go @@ -16,11 +16,11 @@ import ( // abstract resource to a concrete one of some type. type ConcreteResourceNodeFunc func(*NodeAbstractResource) dag.Vertex -// GraphNodeResource is implemented by any nodes that represent a resource. +// GraphNodeConfigResource is implemented by any nodes that represent a resource. // The type of operation cannot be assumed, only that this node represents // the given resource. -type GraphNodeResource interface { - ResourceAddr() addrs.AbsResource +type GraphNodeConfigResource interface { + ResourceAddr() addrs.ConfigResource } // ConcreteResourceInstanceNodeFunc is a callback type used to convert an @@ -69,7 +69,7 @@ var ( _ GraphNodeReferencer = (*NodeAbstractResource)(nil) _ GraphNodeProviderConsumer = (*NodeAbstractResource)(nil) _ GraphNodeProvisionerConsumer = (*NodeAbstractResource)(nil) - _ GraphNodeResource = (*NodeAbstractResource)(nil) + _ GraphNodeConfigResource = (*NodeAbstractResource)(nil) _ GraphNodeAttachResourceConfig = (*NodeAbstractResource)(nil) _ GraphNodeAttachResourceSchema = (*NodeAbstractResource)(nil) _ GraphNodeAttachProvisionerSchema = (*NodeAbstractResource)(nil) @@ -117,7 +117,7 @@ var ( _ GraphNodeReferencer = (*NodeAbstractResourceInstance)(nil) _ GraphNodeProviderConsumer = (*NodeAbstractResourceInstance)(nil) _ GraphNodeProvisionerConsumer = (*NodeAbstractResourceInstance)(nil) - _ GraphNodeResource = (*NodeAbstractResourceInstance)(nil) + _ GraphNodeConfigResource = (*NodeAbstractResourceInstance)(nil) _ GraphNodeResourceInstance = (*NodeAbstractResourceInstance)(nil) _ GraphNodeAttachResourceState = (*NodeAbstractResourceInstance)(nil) _ GraphNodeAttachResourceConfig = (*NodeAbstractResourceInstance)(nil) @@ -375,8 +375,8 @@ func (n *NodeAbstractResource) AttachProvisionerSchema(name string, schema *conf } // GraphNodeResource -func (n *NodeAbstractResource) ResourceAddr() addrs.AbsResource { - return n.addr() +func (n *NodeAbstractResource) ResourceAddr() addrs.ConfigResource { + return n.Addr } // GraphNodeResourceInstance @@ -384,11 +384,6 @@ func (n *NodeAbstractResourceInstance) ResourceInstanceAddr() addrs.AbsResourceI return n.NodeAbstractResource.addr().Instance(n.InstanceKey) } -// GraphNodeAddressable, TODO: remove, used by target, should unify -func (n *NodeAbstractResource) ResourceAddress() *ResourceAddress { - return NewLegacyResourceAddress(n.addr()) -} - // GraphNodeTargetable func (n *NodeAbstractResource) SetTargets(targets []addrs.Targetable) { n.Targets = targets diff --git a/terraform/node_resource_apply.go b/terraform/node_resource_apply.go index c21158a9f..2423ad04b 100644 --- a/terraform/node_resource_apply.go +++ b/terraform/node_resource_apply.go @@ -21,7 +21,7 @@ type NodeApplyableResource struct { } var ( - _ GraphNodeResource = (*NodeApplyableResource)(nil) + _ GraphNodeConfigResource = (*NodeApplyableResource)(nil) _ GraphNodeEvalable = (*NodeApplyableResource)(nil) _ GraphNodeProviderConsumer = (*NodeApplyableResource)(nil) _ GraphNodeAttachResourceConfig = (*NodeApplyableResource)(nil) diff --git a/terraform/node_resource_apply_instance.go b/terraform/node_resource_apply_instance.go index 84c1fd148..5d767dd20 100644 --- a/terraform/node_resource_apply_instance.go +++ b/terraform/node_resource_apply_instance.go @@ -28,7 +28,7 @@ type NodeApplyableResourceInstance struct { } var ( - _ GraphNodeResource = (*NodeApplyableResourceInstance)(nil) + _ GraphNodeConfigResource = (*NodeApplyableResourceInstance)(nil) _ GraphNodeResourceInstance = (*NodeApplyableResourceInstance)(nil) _ GraphNodeCreator = (*NodeApplyableResourceInstance)(nil) _ GraphNodeReferencer = (*NodeApplyableResourceInstance)(nil) @@ -99,8 +99,13 @@ func (n *NodeApplyableResourceInstance) References() []*addrs.Reference { } // GraphNodeAttachDependencies -func (n *NodeApplyableResourceInstance) AttachDependencies(deps []addrs.AbsResource) { - n.Dependencies = deps +func (n *NodeApplyableResourceInstance) AttachDependencies(deps []addrs.ConfigResource) { + var shimmed []addrs.AbsResource + for _, r := range deps { + shimmed = append(shimmed, r.Absolute(r.Module.UnkeyedInstanceShim())) + } + + n.Dependencies = shimmed } // GraphNodeEvalable diff --git a/terraform/node_resource_destroy.go b/terraform/node_resource_destroy.go index 54fba1dec..16c327fd1 100644 --- a/terraform/node_resource_destroy.go +++ b/terraform/node_resource_destroy.go @@ -26,7 +26,7 @@ type NodeDestroyResourceInstance struct { } var ( - _ GraphNodeResource = (*NodeDestroyResourceInstance)(nil) + _ GraphNodeConfigResource = (*NodeDestroyResourceInstance)(nil) _ GraphNodeResourceInstance = (*NodeDestroyResourceInstance)(nil) _ GraphNodeDestroyer = (*NodeDestroyResourceInstance)(nil) _ GraphNodeDestroyerCBD = (*NodeDestroyResourceInstance)(nil) @@ -292,10 +292,10 @@ type NodeDestroyResource struct { } var ( - _ GraphNodeResource = (*NodeDestroyResource)(nil) - _ GraphNodeReferenceable = (*NodeDestroyResource)(nil) - _ GraphNodeReferencer = (*NodeDestroyResource)(nil) - _ GraphNodeEvalable = (*NodeDestroyResource)(nil) + _ GraphNodeConfigResource = (*NodeDestroyResource)(nil) + _ GraphNodeReferenceable = (*NodeDestroyResource)(nil) + _ GraphNodeReferencer = (*NodeDestroyResource)(nil) + _ GraphNodeEvalable = (*NodeDestroyResource)(nil) // FIXME: this is here to document that this node is both // GraphNodeProviderConsumer by virtue of the embedded @@ -339,7 +339,7 @@ func (n *NodeDestroyResource) EvalTree() EvalNode { } // GraphNodeResource -func (n *NodeDestroyResource) ResourceAddr() addrs.AbsResource { +func (n *NodeDestroyResource) ResourceAddr() addrs.ConfigResource { return n.NodeAbstractResource.ResourceAddr() } diff --git a/terraform/node_resource_destroy_deposed.go b/terraform/node_resource_destroy_deposed.go index 7afab72bc..162655bf3 100644 --- a/terraform/node_resource_destroy_deposed.go +++ b/terraform/node_resource_destroy_deposed.go @@ -33,7 +33,7 @@ type NodePlanDeposedResourceInstanceObject struct { var ( _ GraphNodeDeposedResourceInstanceObject = (*NodePlanDeposedResourceInstanceObject)(nil) - _ GraphNodeResource = (*NodePlanDeposedResourceInstanceObject)(nil) + _ GraphNodeConfigResource = (*NodePlanDeposedResourceInstanceObject)(nil) _ GraphNodeResourceInstance = (*NodePlanDeposedResourceInstanceObject)(nil) _ GraphNodeReferenceable = (*NodePlanDeposedResourceInstanceObject)(nil) _ GraphNodeReferencer = (*NodePlanDeposedResourceInstanceObject)(nil) @@ -167,7 +167,7 @@ type NodeDestroyDeposedResourceInstanceObject struct { var ( _ GraphNodeDeposedResourceInstanceObject = (*NodeDestroyDeposedResourceInstanceObject)(nil) - _ GraphNodeResource = (*NodeDestroyDeposedResourceInstanceObject)(nil) + _ GraphNodeConfigResource = (*NodeDestroyDeposedResourceInstanceObject)(nil) _ GraphNodeResourceInstance = (*NodeDestroyDeposedResourceInstanceObject)(nil) _ GraphNodeDestroyer = (*NodeDestroyDeposedResourceInstanceObject)(nil) _ GraphNodeDestroyerCBD = (*NodeDestroyDeposedResourceInstanceObject)(nil) diff --git a/terraform/node_resource_plan.go b/terraform/node_resource_plan.go index 7d61d9ce0..0a339e6bb 100644 --- a/terraform/node_resource_plan.go +++ b/terraform/node_resource_plan.go @@ -23,7 +23,7 @@ var ( _ GraphNodeDynamicExpandable = (*NodePlannableResource)(nil) _ GraphNodeReferenceable = (*NodePlannableResource)(nil) _ GraphNodeReferencer = (*NodePlannableResource)(nil) - _ GraphNodeResource = (*NodePlannableResource)(nil) + _ GraphNodeConfigResource = (*NodePlannableResource)(nil) _ GraphNodeAttachResourceConfig = (*NodePlannableResource)(nil) ) diff --git a/terraform/node_resource_plan_destroy.go b/terraform/node_resource_plan_destroy.go index deb6b4f7b..d53c1441c 100644 --- a/terraform/node_resource_plan_destroy.go +++ b/terraform/node_resource_plan_destroy.go @@ -21,7 +21,7 @@ var ( _ GraphNodeReferenceable = (*NodePlanDestroyableResourceInstance)(nil) _ GraphNodeReferencer = (*NodePlanDestroyableResourceInstance)(nil) _ GraphNodeDestroyer = (*NodePlanDestroyableResourceInstance)(nil) - _ GraphNodeResource = (*NodePlanDestroyableResourceInstance)(nil) + _ GraphNodeConfigResource = (*NodePlanDestroyableResourceInstance)(nil) _ GraphNodeResourceInstance = (*NodePlanDestroyableResourceInstance)(nil) _ GraphNodeAttachResourceConfig = (*NodePlanDestroyableResourceInstance)(nil) _ GraphNodeAttachResourceState = (*NodePlanDestroyableResourceInstance)(nil) diff --git a/terraform/node_resource_plan_instance.go b/terraform/node_resource_plan_instance.go index 27465981a..38c115842 100644 --- a/terraform/node_resource_plan_instance.go +++ b/terraform/node_resource_plan_instance.go @@ -23,7 +23,7 @@ var ( _ GraphNodeModuleInstance = (*NodePlannableResourceInstance)(nil) _ GraphNodeReferenceable = (*NodePlannableResourceInstance)(nil) _ GraphNodeReferencer = (*NodePlannableResourceInstance)(nil) - _ GraphNodeResource = (*NodePlannableResourceInstance)(nil) + _ GraphNodeConfigResource = (*NodePlannableResourceInstance)(nil) _ GraphNodeResourceInstance = (*NodePlannableResourceInstance)(nil) _ GraphNodeAttachResourceConfig = (*NodePlannableResourceInstance)(nil) _ GraphNodeAttachResourceState = (*NodePlannableResourceInstance)(nil) diff --git a/terraform/node_resource_plan_orphan.go b/terraform/node_resource_plan_orphan.go index 61f8e621f..20ad53c35 100644 --- a/terraform/node_resource_plan_orphan.go +++ b/terraform/node_resource_plan_orphan.go @@ -16,7 +16,7 @@ var ( _ GraphNodeModuleInstance = (*NodePlannableResourceInstanceOrphan)(nil) _ GraphNodeReferenceable = (*NodePlannableResourceInstanceOrphan)(nil) _ GraphNodeReferencer = (*NodePlannableResourceInstanceOrphan)(nil) - _ GraphNodeResource = (*NodePlannableResourceInstanceOrphan)(nil) + _ GraphNodeConfigResource = (*NodePlannableResourceInstanceOrphan)(nil) _ GraphNodeResourceInstance = (*NodePlannableResourceInstanceOrphan)(nil) _ GraphNodeAttachResourceConfig = (*NodePlannableResourceInstanceOrphan)(nil) _ GraphNodeAttachResourceState = (*NodePlannableResourceInstanceOrphan)(nil) diff --git a/terraform/node_resource_refresh.go b/terraform/node_resource_refresh.go index ee3f084be..2284d1e43 100644 --- a/terraform/node_resource_refresh.go +++ b/terraform/node_resource_refresh.go @@ -28,14 +28,19 @@ var ( _ GraphNodeDynamicExpandable = (*NodeRefreshableManagedResource)(nil) _ GraphNodeReferenceable = (*NodeRefreshableManagedResource)(nil) _ GraphNodeReferencer = (*NodeRefreshableManagedResource)(nil) - _ GraphNodeResource = (*NodeRefreshableManagedResource)(nil) + _ GraphNodeConfigResource = (*NodeRefreshableManagedResource)(nil) _ GraphNodeAttachResourceConfig = (*NodeRefreshableManagedResource)(nil) _ GraphNodeAttachDependencies = (*NodeRefreshableManagedResource)(nil) ) // GraphNodeAttachDependencies -func (n *NodeRefreshableManagedResource) AttachDependencies(deps []addrs.AbsResource) { - n.Dependencies = deps +func (n *NodeRefreshableManagedResource) AttachDependencies(deps []addrs.ConfigResource) { + var shimmed []addrs.AbsResource + for _, r := range deps { + shimmed = append(shimmed, r.Absolute(r.Module.UnkeyedInstanceShim())) + } + + n.Dependencies = shimmed } // GraphNodeDynamicExpandable @@ -144,7 +149,7 @@ var ( _ GraphNodeReferenceable = (*NodeRefreshableManagedResourceInstance)(nil) _ GraphNodeReferencer = (*NodeRefreshableManagedResourceInstance)(nil) _ GraphNodeDestroyer = (*NodeRefreshableManagedResourceInstance)(nil) - _ GraphNodeResource = (*NodeRefreshableManagedResourceInstance)(nil) + _ GraphNodeConfigResource = (*NodeRefreshableManagedResourceInstance)(nil) _ GraphNodeResourceInstance = (*NodeRefreshableManagedResourceInstance)(nil) _ GraphNodeAttachResourceConfig = (*NodeRefreshableManagedResourceInstance)(nil) _ GraphNodeAttachResourceState = (*NodeRefreshableManagedResourceInstance)(nil) diff --git a/terraform/node_resource_validate.go b/terraform/node_resource_validate.go index f8374f3fb..83a67ed0c 100644 --- a/terraform/node_resource_validate.go +++ b/terraform/node_resource_validate.go @@ -18,7 +18,7 @@ var ( _ GraphNodeEvalable = (*NodeValidatableResource)(nil) _ GraphNodeReferenceable = (*NodeValidatableResource)(nil) _ GraphNodeReferencer = (*NodeValidatableResource)(nil) - _ GraphNodeResource = (*NodeValidatableResource)(nil) + _ GraphNodeConfigResource = (*NodeValidatableResource)(nil) _ GraphNodeAttachResourceConfig = (*NodeValidatableResource)(nil) _ GraphNodeAttachProviderMetaConfigs = (*NodeValidatableResource)(nil) ) diff --git a/terraform/resource_test.go b/terraform/resource_test.go index 5ad2de415..835163c4a 100644 --- a/terraform/resource_test.go +++ b/terraform/resource_test.go @@ -3,7 +3,6 @@ package terraform import ( "fmt" "reflect" - "strconv" "testing" "github.com/hashicorp/terraform/configs/configschema" @@ -13,63 +12,6 @@ import ( "github.com/mitchellh/reflectwalk" ) -func TestInstanceInfoResourceAddress(t *testing.T) { - tests := []struct { - Input *InstanceInfo - Want string - }{ - { - &InstanceInfo{ - Id: "test_resource.baz", - }, - "test_resource.baz", - }, - { - &InstanceInfo{ - Id: "test_resource.baz", - ModulePath: rootModulePath, - }, - "test_resource.baz", - }, - { - &InstanceInfo{ - Id: "test_resource.baz", - ModulePath: []string{"root", "foo"}, - }, - "module.foo.test_resource.baz", - }, - { - &InstanceInfo{ - Id: "test_resource.baz", - ModulePath: []string{"root", "foo", "bar"}, - }, - "module.foo.module.bar.test_resource.baz", - }, - { - &InstanceInfo{ - Id: "test_resource.baz (tainted)", - }, - "test_resource.baz.tainted", - }, - { - &InstanceInfo{ - Id: "test_resource.baz (deposed #0)", - }, - "test_resource.baz.deposed", - }, - } - - for i, test := range tests { - t.Run(strconv.Itoa(i), func(t *testing.T) { - gotAddr := test.Input.ResourceAddress() - got := gotAddr.String() - if got != test.Want { - t.Fatalf("wrong result\ngot: %s\nwant: %s", got, test.Want) - } - }) - } -} - func TestResourceConfigGet(t *testing.T) { fooStringSchema := &configschema.Block{ Attributes: map[string]*configschema.Attribute{ diff --git a/terraform/transform_attach_config_provider_meta.go b/terraform/transform_attach_config_provider_meta.go index 9947d120c..4eab86d7e 100644 --- a/terraform/transform_attach_config_provider_meta.go +++ b/terraform/transform_attach_config_provider_meta.go @@ -8,7 +8,7 @@ import ( // GraphNodeAttachProviderMetaConfigs is an interface that must be implemented // by nodes that want provider meta configurations attached. type GraphNodeAttachProviderMetaConfigs interface { - GraphNodeResource + GraphNodeConfigResource // Sets the configuration AttachProviderMetaConfigs(map[addrs.Provider]*configs.ProviderMeta) diff --git a/terraform/transform_attach_config_resource.go b/terraform/transform_attach_config_resource.go index a0f981bae..37afbde2e 100644 --- a/terraform/transform_attach_config_resource.go +++ b/terraform/transform_attach_config_resource.go @@ -10,7 +10,7 @@ import ( // GraphNodeAttachResourceConfig is an interface that must be implemented by nodes // that want resource configurations attached. type GraphNodeAttachResourceConfig interface { - GraphNodeResource + GraphNodeConfigResource // Sets the configuration AttachResourceConfig(*configs.Resource) @@ -40,7 +40,7 @@ func (t *AttachResourceConfigTransformer) Transform(g *Graph) error { addr := arn.ResourceAddr() // Get the configuration. - config := t.Config.DescendentForInstance(addr.Module) + config := t.Config.Descendent(addr.Module) if config == nil { log.Printf("[TRACE] AttachResourceConfigTransformer: %q (%T) has no configuration available", dag.VertexName(v), v) continue diff --git a/terraform/transform_attach_schema.go b/terraform/transform_attach_schema.go index 3165b0df1..0e1096392 100644 --- a/terraform/transform_attach_schema.go +++ b/terraform/transform_attach_schema.go @@ -13,7 +13,7 @@ import ( // GraphNodeAttachResourceSchema is an interface implemented by node types // that need a resource schema attached. type GraphNodeAttachResourceSchema interface { - GraphNodeResource + GraphNodeConfigResource GraphNodeProviderConsumer AttachResourceSchema(schema *configschema.Block, version uint64) diff --git a/terraform/transform_diff.go b/terraform/transform_diff.go index 637309fad..bed71a0e3 100644 --- a/terraform/transform_diff.go +++ b/terraform/transform_diff.go @@ -36,9 +36,9 @@ func (t *DiffTransformer) Transform(g *Graph) error { // get evaluated before any of the corresponding instances by creating // dependency edges, so we'll do some prep work here to ensure we'll only // create connections to nodes that existed before we started here. - resourceNodes := map[string][]GraphNodeResource{} + resourceNodes := map[string][]GraphNodeConfigResource{} for _, node := range g.Vertices() { - rn, ok := node.(GraphNodeResource) + rn, ok := node.(GraphNodeConfigResource) if !ok { continue } diff --git a/terraform/transform_orphan_count.go b/terraform/transform_orphan_count.go index 59c15c198..ed3dc8f15 100644 --- a/terraform/transform_orphan_count.go +++ b/terraform/transform_orphan_count.go @@ -18,44 +18,39 @@ import ( type OrphanResourceCountTransformer struct { Concrete ConcreteResourceInstanceNodeFunc - Addr addrs.AbsResource // Addr of the resource to look for orphans + Addr addrs.ConfigResource // Addr of the resource to look for orphans InstanceAddrs []addrs.AbsResourceInstance // Addresses that currently exist in config State *states.State // Full global state } func (t *OrphanResourceCountTransformer) Transform(g *Graph) error { - // FIXME: This is currently assuming that all of the instances of - // this resource belong to a single module instance, which is true - // at the time of writing this because Terraform Core doesn't support - // repetition of module calls yet, but this will need to be corrected - // in order to support count and for_each on module calls, where - // our t.InstanceAddrs may contain resource instances from many different - // module instances. - rs := t.State.Resource(t.Addr) - if rs == nil { + resources := t.State.Resources(t.Addr) + if len(resources) == 0 { return nil // Resource doesn't exist in state, so nothing to do! } - // This is an O(n*m) analysis, which we accept for now because the - // number of instances of a single resource ought to always be small in any - // reasonable Terraform configuration. -Have: - for key := range rs.Instances { - thisAddr := t.Addr.Instance(key) - for _, wantAddr := range t.InstanceAddrs { - if wantAddr.Equal(thisAddr) { - continue Have + for _, rs := range resources { + // This is an O(n*m) analysis, which we accept for now because the + // number of instances of a single resource ought to always be small in any + // reasonable Terraform configuration. + Have: + for key := range rs.Instances { + thisAddr := rs.Addr.Instance(key) + for _, wantAddr := range t.InstanceAddrs { + if wantAddr.Equal(thisAddr) { + continue Have + } } - } - // If thisAddr is not in t.InstanceAddrs then we've found an "orphan" + // If thisAddr is not in t.InstanceAddrs then we've found an "orphan" - abstract := NewNodeAbstractResourceInstance(thisAddr) - var node dag.Vertex = abstract - if f := t.Concrete; f != nil { - node = f(abstract) + abstract := NewNodeAbstractResourceInstance(thisAddr) + var node dag.Vertex = abstract + if f := t.Concrete; f != nil { + node = f(abstract) + } + log.Printf("[TRACE] OrphanResourceCountTransformer: adding %s as %T", thisAddr, node) + g.Add(node) } - log.Printf("[TRACE] OrphanResourceCountTransformer: adding %s as %T", thisAddr, node) - g.Add(node) } return nil diff --git a/terraform/transform_orphan_resource.go b/terraform/transform_orphan_resource.go index 50df1781e..9872a704d 100644 --- a/terraform/transform_orphan_resource.go +++ b/terraform/transform_orphan_resource.go @@ -74,13 +74,13 @@ func (t *OrphanResourceInstanceTransformer) transform(g *Graph, ms *states.Modul // pseudo-arguments here. They are handled by OrphanResourceCountTransformer. for _, rs := range ms.Resources { if m != nil { - if r := m.ResourceByAddr(rs.Addr); r != nil { + if r := m.ResourceByAddr(rs.Addr.Resource); r != nil { continue } } for key := range rs.Instances { - addr := rs.Addr.Instance(key).Absolute(moduleAddr) + addr := rs.Addr.Instance(key) abstract := NewNodeAbstractResourceInstance(addr) var node dag.Vertex = abstract if f := t.Concrete; f != nil { @@ -137,7 +137,7 @@ func (t *OrphanResourceTransformer) Transform(g *Graph) error { case GraphNodeResourceInstance: k := tv.ResourceInstanceAddr().ContainingResource().String() deps[k] = append(deps[k], v) - case GraphNodeResource: + case GraphNodeConfigResource: k := tv.ResourceAddr().String() deps[k] = append(deps[k], v) case GraphNodeDestroyer: @@ -153,13 +153,13 @@ func (t *OrphanResourceTransformer) Transform(g *Graph) error { for _, rs := range ms.Resources { if mc != nil { - if r := mc.Module.ResourceByAddr(rs.Addr); r != nil { + if r := mc.Module.ResourceByAddr(rs.Addr.Resource); r != nil { // It's in the config, so nothing to do for this one. continue } } - addr := rs.Addr.Absolute(moduleAddr) + addr := rs.Addr abstract := NewNodeAbstractResource(addr) var node dag.Vertex = abstract if f := t.Concrete; f != nil { diff --git a/terraform/transform_reference.go b/terraform/transform_reference.go index 5dff1a0ba..14353d43b 100644 --- a/terraform/transform_reference.go +++ b/terraform/transform_reference.go @@ -41,8 +41,8 @@ type GraphNodeReferencer interface { } type GraphNodeAttachDependencies interface { - GraphNodeResource - AttachDependencies([]addrs.AbsResource) + GraphNodeConfigResource + AttachDependencies([]addrs.ConfigResource) } // GraphNodeReferenceOutside is an interface that can optionally be implemented. @@ -116,6 +116,8 @@ type AttachDependenciesTransformer struct { } func (t AttachDependenciesTransformer) Transform(g *Graph) error { + // FIXME: this is only working with ResourceConfigAddr for now + for _, v := range g.Vertices() { attacher, ok := v.(GraphNodeAttachDependencies) if !ok { @@ -135,15 +137,15 @@ func (t AttachDependenciesTransformer) Transform(g *Graph) error { // dedupe addrs when there's multiple instances involved, or // multiple paths in the un-reduced graph - depMap := map[string]addrs.AbsResource{} + depMap := map[string]addrs.ConfigResource{} for _, d := range ans { - var addr addrs.AbsResource + var addr addrs.ConfigResource switch d := d.(type) { case GraphNodeResourceInstance: instAddr := d.ResourceInstanceAddr() - addr = instAddr.Resource.Resource.Absolute(instAddr.Module) - case GraphNodeResource: + addr = instAddr.ContainingResource().Config() + case GraphNodeConfigResource: addr = d.ResourceAddr() default: continue @@ -160,7 +162,7 @@ func (t AttachDependenciesTransformer) Transform(g *Graph) error { depMap[addr.String()] = addr } - deps := make([]addrs.AbsResource, 0, len(depMap)) + deps := make([]addrs.ConfigResource, 0, len(depMap)) for _, d := range depMap { deps = append(deps, d) } diff --git a/terraform/transform_resource_count.go b/terraform/transform_resource_count.go index 439cd9255..70a843ab5 100644 --- a/terraform/transform_resource_count.go +++ b/terraform/transform_resource_count.go @@ -16,7 +16,7 @@ type ResourceCountTransformer struct { Concrete ConcreteResourceInstanceNodeFunc Schema *configschema.Block - Addr addrs.AbsResource + Addr addrs.ConfigResource InstanceAddrs []addrs.AbsResourceInstance } diff --git a/terraform/transform_state.go b/terraform/transform_state.go index 0b52347df..a82f18591 100644 --- a/terraform/transform_state.go +++ b/terraform/transform_state.go @@ -43,10 +43,8 @@ func (t *StateTransformer) Transform(g *Graph) error { } for _, ms := range t.State.Modules { - moduleAddr := ms.Addr - for _, rs := range ms.Resources { - resourceAddr := rs.Addr.Absolute(moduleAddr) + resourceAddr := rs.Addr for key, is := range rs.Instances { addr := resourceAddr.Instance(key) diff --git a/terraform/transform_targets.go b/terraform/transform_targets.go index 80cff5364..a5d4ba934 100644 --- a/terraform/transform_targets.go +++ b/terraform/transform_targets.go @@ -58,7 +58,7 @@ func (t *TargetsTransformer) Transform(g *Graph) error { for _, v := range g.Vertices() { removable := false - if _, ok := v.(GraphNodeResource); ok { + if _, ok := v.(GraphNodeConfigResource); ok { removable = true } @@ -225,16 +225,12 @@ func (t *TargetsTransformer) nodeIsTarget(v dag.Vertex, targets []addrs.Targetab switch r := v.(type) { case GraphNodeResourceInstance: vertexAddr = r.ResourceInstanceAddr() - case GraphNodeResource: + case GraphNodeConfigResource: vertexAddr = r.ResourceAddr() default: // Only resource and resource instance nodes can be targeted. return false } - _, ok := v.(GraphNodeResource) - if !ok { - return false - } for _, targetAddr := range targets { if t.IgnoreIndices {