Merge pull request #24807 from hashicorp/jbardin/remove-each-mode

Remove EachMode from state
This commit is contained in:
James Bardin 2020-05-03 10:54:07 -04:00 committed by GitHub
commit 9debd341bc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 43 additions and 215 deletions

View File

@ -259,6 +259,7 @@ func marshalResources(resources map[string]*states.Resource, module addrs.Module
current := resource{ current := resource{
Address: r.Addr.Instance(k).String(), Address: r.Addr.Instance(k).String(),
Index: k,
Type: resAddr.Type, Type: resAddr.Type,
Name: resAddr.Name, Name: resAddr.Name,
ProviderName: r.ProviderConfig.Provider.String(), ProviderName: r.ProviderConfig.Provider.String(),
@ -276,10 +277,6 @@ func marshalResources(resources map[string]*states.Resource, module addrs.Module
) )
} }
if r.EachMode != states.NoEach {
current.Index = k
}
schema, _ := schemas.ResourceTypeConfig( schema, _ := schemas.ResourceTypeConfig(
r.ProviderConfig.Provider, r.ProviderConfig.Provider,
resAddr.Mode, resAddr.Mode,

View File

@ -193,7 +193,6 @@ func TestMarshalResources(t *testing.T) {
Name: "bar", Name: "bar",
}, },
}, },
EachMode: states.NoEach,
Instances: map[addrs.InstanceKey]*states.ResourceInstance{ Instances: map[addrs.InstanceKey]*states.ResourceInstance{
addrs.NoKey: { addrs.NoKey: {
Current: &states.ResourceInstanceObjectSrc{ Current: &states.ResourceInstanceObjectSrc{
@ -237,7 +236,6 @@ func TestMarshalResources(t *testing.T) {
Name: "bar", Name: "bar",
}, },
}, },
EachMode: states.EachList,
Instances: map[addrs.InstanceKey]*states.ResourceInstance{ Instances: map[addrs.InstanceKey]*states.ResourceInstance{
addrs.IntKey(0): { addrs.IntKey(0): {
Current: &states.ResourceInstanceObjectSrc{ Current: &states.ResourceInstanceObjectSrc{
@ -281,7 +279,6 @@ func TestMarshalResources(t *testing.T) {
Name: "bar", Name: "bar",
}, },
}, },
EachMode: states.EachMap,
Instances: map[addrs.InstanceKey]*states.ResourceInstance{ Instances: map[addrs.InstanceKey]*states.ResourceInstance{
addrs.StringKey("rockhopper"): { addrs.StringKey("rockhopper"): {
Current: &states.ResourceInstanceObjectSrc{ Current: &states.ResourceInstanceObjectSrc{
@ -325,7 +322,6 @@ func TestMarshalResources(t *testing.T) {
Name: "bar", Name: "bar",
}, },
}, },
EachMode: states.NoEach,
Instances: map[addrs.InstanceKey]*states.ResourceInstance{ Instances: map[addrs.InstanceKey]*states.ResourceInstance{
addrs.NoKey: { addrs.NoKey: {
Deposed: map[states.DeposedKey]*states.ResourceInstanceObjectSrc{ Deposed: map[states.DeposedKey]*states.ResourceInstanceObjectSrc{
@ -371,7 +367,6 @@ func TestMarshalResources(t *testing.T) {
Name: "bar", Name: "bar",
}, },
}, },
EachMode: states.NoEach,
Instances: map[addrs.InstanceKey]*states.ResourceInstance{ Instances: map[addrs.InstanceKey]*states.ResourceInstance{
addrs.NoKey: { addrs.NoKey: {
Deposed: map[states.DeposedKey]*states.ResourceInstanceObjectSrc{ Deposed: map[states.DeposedKey]*states.ResourceInstanceObjectSrc{

View File

@ -279,10 +279,6 @@ func (c *StateMvCommand) Run(args []string) int {
ssFrom.ForgetResourceInstanceAll(addrFrom) ssFrom.ForgetResourceInstanceAll(addrFrom)
ssFrom.RemoveResourceIfEmpty(fromResourceAddr) ssFrom.RemoveResourceIfEmpty(fromResourceAddr)
// since this is moving an instance, we can infer the target
// mode from the address.
toEachMode := eachModeForInstanceKey(addrTo.Resource.Key)
rs := stateTo.Resource(addrTo.ContainingResource()) rs := stateTo.Resource(addrTo.ContainingResource())
if rs == nil { if rs == nil {
// If we're moving to an address without an index then that // If we're moving to an address without an index then that
@ -291,15 +287,13 @@ func (c *StateMvCommand) Run(args []string) int {
// address covers both). If there's an index in the // address covers both). If there's an index in the
// target then allow creating the new instance here. // target then allow creating the new instance here.
resourceAddr := addrTo.ContainingResource() resourceAddr := addrTo.ContainingResource()
stateTo.SyncWrapper().SetResourceMeta( stateTo.SyncWrapper().SetResourceProvider(
resourceAddr, resourceAddr,
toEachMode,
fromProviderAddr, // in this case, we bring the provider along as if we were moving the whole resource fromProviderAddr, // in this case, we bring the provider along as if we were moving the whole resource
) )
rs = stateTo.Resource(resourceAddr) rs = stateTo.Resource(resourceAddr)
} }
rs.EachMode = toEachMode
rs.Instances[addrTo.Resource.Key] = is rs.Instances[addrTo.Resource.Key] = is
} }
default: default:
@ -372,20 +366,6 @@ func (c *StateMvCommand) Run(args []string) int {
return 0 return 0
} }
func eachModeForInstanceKey(key addrs.InstanceKey) states.EachMode {
switch key.(type) {
case addrs.IntKey:
return states.EachList
case addrs.StringKey:
return states.EachMap
default:
if key == addrs.NoKey {
return states.NoEach
}
panic(fmt.Sprintf("don't know an each mode for instance key %#v", key))
}
}
// sourceObjectAddrs takes a single source object address and expands it to // sourceObjectAddrs takes a single source object address and expands it to
// potentially multiple objects that need to be handled within it. // potentially multiple objects that need to be handled within it.
// //
@ -415,11 +395,13 @@ func (c *StateMvCommand) sourceObjectAddrs(state *states.State, matched addrs.Ta
// terraform state mv aws_instance.foo aws_instance.bar[1] // terraform state mv aws_instance.foo aws_instance.bar[1]
// That wouldn't be allowed if aws_instance.foo had multiple instances // That wouldn't be allowed if aws_instance.foo had multiple instances
// since we can't move multiple instances into one. // since we can't move multiple instances into one.
if rs := state.Resource(addr); rs != nil && rs.EachMode == states.NoEach { if rs := state.Resource(addr); rs != nil {
if _, ok := rs.Instances[addrs.NoKey]; ok {
ret = append(ret, addr.Instance(addrs.NoKey)) ret = append(ret, addr.Instance(addrs.NoKey))
} else { } else {
ret = append(ret, addr) ret = append(ret, addr)
} }
}
default: default:
ret = append(ret, matched) ret = append(ret, matched)
} }

View File

@ -97,9 +97,10 @@ func TestStateMv(t *testing.T) {
if diags.HasErrors() { if diags.HasErrors() {
t.Fatal(diags.Err()) t.Fatal(diags.Err())
} }
i := s.Resource(addr) for key := range s.Resource(addr).Instances {
if i.EachMode != states.EachList { if _, ok := key.(addrs.IntKey); !ok {
t.Fatalf("expected each mode List, got %s", i.EachMode) t.Fatalf("expected each mode List, got key %q", key)
}
} }
// change from list to map // change from list to map
@ -118,9 +119,10 @@ func TestStateMv(t *testing.T) {
if diags.HasErrors() { if diags.HasErrors() {
t.Fatal(diags.Err()) t.Fatal(diags.Err())
} }
i = s.Resource(addr) for key := range s.Resource(addr).Instances {
if i.EachMode != states.EachMap { if _, ok := key.(addrs.StringKey); !ok {
t.Fatalf("expected each mode Map, got %s", i.EachMode) t.Fatalf("expected each mode map, found key %q", key)
}
} }
// change from from map back to single // change from from map back to single
@ -139,9 +141,10 @@ func TestStateMv(t *testing.T) {
if diags.HasErrors() { if diags.HasErrors() {
t.Fatal(diags.Err()) t.Fatal(diags.Err())
} }
i = s.Resource(addr) for key := range s.Resource(addr).Instances {
if i.EachMode != states.NoEach { if key != addrs.NoKey {
t.Fatalf("expected each mode NoEach, got %s", i.EachMode) t.Fatalf("expected no each mode, found key %q", key)
}
} }
} }
@ -179,13 +182,12 @@ func TestStateMv_resourceToInstance(t *testing.T) {
Module: addrs.RootModule, Module: addrs.RootModule,
}, },
) )
s.SetResourceMeta( s.SetResourceProvider(
addrs.Resource{ addrs.Resource{
Mode: addrs.ManagedResourceMode, Mode: addrs.ManagedResourceMode,
Type: "test_instance", Type: "test_instance",
Name: "bar", Name: "bar",
}.Absolute(addrs.RootModuleInstance), }.Absolute(addrs.RootModuleInstance),
states.EachList,
addrs.AbsProviderConfig{ addrs.AbsProviderConfig{
Provider: addrs.NewLegacyProvider("test"), Provider: addrs.NewLegacyProvider("test"),
Module: addrs.RootModule, Module: addrs.RootModule,

View File

@ -1,35 +0,0 @@
// Code generated by "stringer -type EachMode"; DO NOT EDIT.
package states
import "strconv"
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[NoEach-0]
_ = x[EachList-76]
_ = x[EachMap-77]
}
const (
_EachMode_name_0 = "NoEach"
_EachMode_name_1 = "EachListEachMap"
)
var (
_EachMode_index_1 = [...]uint8{0, 8, 15}
)
func (i EachMode) String() string {
switch {
case i == 0:
return _EachMode_name_0
case 76 <= i && i <= 77:
i -= 76
return _EachMode_name_1[_EachMode_index_1[i]:_EachMode_index_1[i+1]]
default:
return "EachMode(" + strconv.FormatInt(int64(i), 10) + ")"
}
}

View File

@ -51,10 +51,10 @@ func (ms *Module) ResourceInstance(addr addrs.ResourceInstance) *ResourceInstanc
return rs.Instance(addr.Key) return rs.Instance(addr.Key)
} }
// SetResourceMeta updates the resource-level metadata for the resource // SetResourceProvider updates the resource-level metadata for the resource
// with the given address, creating the resource state for it if it doesn't // with the given address, creating the resource state for it if it doesn't
// already exist. // already exist.
func (ms *Module) SetResourceMeta(addr addrs.Resource, eachMode EachMode, provider addrs.AbsProviderConfig) { func (ms *Module) SetResourceProvider(addr addrs.Resource, provider addrs.AbsProviderConfig) {
rs := ms.Resource(addr) rs := ms.Resource(addr)
if rs == nil { if rs == nil {
rs = &Resource{ rs = &Resource{
@ -64,7 +64,6 @@ func (ms *Module) SetResourceMeta(addr addrs.Resource, eachMode EachMode, provid
ms.Resources[addr.String()] = rs ms.Resources[addr.String()] = rs
} }
rs.EachMode = eachMode
rs.ProviderConfig = provider rs.ProviderConfig = provider
} }
@ -97,9 +96,7 @@ func (ms *Module) SetResourceInstanceCurrent(addr addrs.ResourceInstance, obj *R
if obj == nil && rs != nil { if obj == nil && rs != nil {
// does the resource have any other objects? // does the resource have any other objects?
// if not then delete the whole resource // if not then delete the whole resource
// When deleting the resource, ensure that its EachMode is NoEach, if len(rs.Instances) == 0 {
// as a resource with EachList or EachMap can have 0 instances and be valid
if rs.EachMode == NoEach && len(rs.Instances) == 0 {
delete(ms.Resources, addr.Resource.String()) delete(ms.Resources, addr.Resource.String())
return return
} }
@ -115,7 +112,7 @@ func (ms *Module) SetResourceInstanceCurrent(addr addrs.ResourceInstance, obj *R
// If we have no objects at all then we'll clean up. // If we have no objects at all then we'll clean up.
delete(rs.Instances, addr.Key) delete(rs.Instances, addr.Key)
// Delete the resource if it has no instances, but only if NoEach // Delete the resource if it has no instances, but only if NoEach
if rs.EachMode == NoEach && len(rs.Instances) == 0 { if len(rs.Instances) == 0 {
delete(ms.Resources, addr.Resource.String()) delete(ms.Resources, addr.Resource.String())
return return
} }
@ -125,7 +122,7 @@ func (ms *Module) SetResourceInstanceCurrent(addr addrs.ResourceInstance, obj *R
} }
if rs == nil && obj != nil { if rs == nil && obj != nil {
// We don't have have a resource so make one, which is a side effect of setResourceMeta // We don't have have a resource so make one, which is a side effect of setResourceMeta
ms.SetResourceMeta(addr.Resource, eachModeForInstanceKey(addr.Key), provider) ms.SetResourceProvider(addr.Resource, provider)
// now we have a resource! so update the rs value to point to it // now we have a resource! so update the rs value to point to it
rs = ms.Resource(addr.Resource) rs = ms.Resource(addr.Resource)
} }
@ -134,8 +131,8 @@ func (ms *Module) SetResourceInstanceCurrent(addr addrs.ResourceInstance, obj *R
if is == nil { if is == nil {
// if we don't have a resource, create one and add to the instances // if we don't have a resource, create one and add to the instances
is = rs.CreateInstance(addr.Key) is = rs.CreateInstance(addr.Key)
// update the resource meta because we have a new instance, so EachMode may have changed // update the resource meta because we have a new
ms.SetResourceMeta(addr.Resource, eachModeForInstanceKey(addr.Key), provider) ms.SetResourceProvider(addr.Resource, provider)
} }
// Update the resource's ProviderConfig, in case the provider has updated // Update the resource's ProviderConfig, in case the provider has updated
rs.ProviderConfig = provider rs.ProviderConfig = provider
@ -159,7 +156,7 @@ func (ms *Module) SetResourceInstanceCurrent(addr addrs.ResourceInstance, obj *R
// the instance is left with no objects after this operation then it will // the instance is left with no objects after this operation then it will
// be removed from its containing resource altogether. // be removed from its containing resource altogether.
func (ms *Module) SetResourceInstanceDeposed(addr addrs.ResourceInstance, key DeposedKey, obj *ResourceInstanceObjectSrc, provider addrs.AbsProviderConfig) { func (ms *Module) SetResourceInstanceDeposed(addr addrs.ResourceInstance, key DeposedKey, obj *ResourceInstanceObjectSrc, provider addrs.AbsProviderConfig) {
ms.SetResourceMeta(addr.Resource, eachModeForInstanceKey(addr.Key), provider) ms.SetResourceProvider(addr.Resource, provider)
rs := ms.Resource(addr.Resource) rs := ms.Resource(addr.Resource)
is := rs.EnsureInstance(addr.Key) is := rs.EnsureInstance(addr.Key)
@ -173,7 +170,7 @@ func (ms *Module) SetResourceInstanceDeposed(addr addrs.ResourceInstance, key De
// If we have no objects at all then we'll clean up. // If we have no objects at all then we'll clean up.
delete(rs.Instances, addr.Key) delete(rs.Instances, addr.Key)
} }
if rs.EachMode == NoEach && len(rs.Instances) == 0 { if len(rs.Instances) == 0 {
// Also clean up if we only expect to have one instance anyway // Also clean up if we only expect to have one instance anyway
// and there are none. We leave the resource behind if an each mode // and there are none. We leave the resource behind if an each mode
// is active because an empty list or map of instances is a valid state. // is active because an empty list or map of instances is a valid state.
@ -190,7 +187,7 @@ func (ms *Module) ForgetResourceInstanceAll(addr addrs.ResourceInstance) {
} }
delete(rs.Instances, addr.Key) delete(rs.Instances, addr.Key)
if rs.EachMode == NoEach && len(rs.Instances) == 0 { if len(rs.Instances) == 0 {
// Also clean up if we only expect to have one instance anyway // Also clean up if we only expect to have one instance anyway
// and there are none. We leave the resource behind if an each mode // and there are none. We leave the resource behind if an each mode
// is active because an empty list or map of instances is a valid state. // is active because an empty list or map of instances is a valid state.
@ -215,7 +212,7 @@ func (ms *Module) ForgetResourceInstanceDeposed(addr addrs.ResourceInstance, key
// If we have no objects at all then we'll clean up. // If we have no objects at all then we'll clean up.
delete(rs.Instances, addr.Key) delete(rs.Instances, addr.Key)
} }
if rs.EachMode == NoEach && len(rs.Instances) == 0 { if len(rs.Instances) == 0 {
// Also clean up if we only expect to have one instance anyway // Also clean up if we only expect to have one instance anyway
// and there are none. We leave the resource behind if an each mode // and there are none. We leave the resource behind if an each mode
// is active because an empty list or map of instances is a valid state. // is active because an empty list or map of instances is a valid state.

View File

@ -14,12 +14,6 @@ type Resource struct {
// belongs to. // belongs to.
Addr addrs.AbsResource 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
// type of value is returned when accessing this resource via expressions
// in the Terraform language.
EachMode EachMode
// Instances contains the potentially-multiple instances associated with // Instances contains the potentially-multiple instances associated with
// this resource. This map can contain a mixture of different key types, // this resource. This map can contain a mixture of different key types,
// but only the ones of InstanceKeyType are considered current. // but only the ones of InstanceKeyType are considered current.
@ -173,31 +167,6 @@ func (i *ResourceInstance) findUnusedDeposedKey() DeposedKey {
} }
} }
// EachMode specifies the multi-instance mode for a resource.
type EachMode rune
const (
NoEach EachMode = 0
EachList EachMode = 'L'
EachMap EachMode = 'M'
)
//go:generate go run golang.org/x/tools/cmd/stringer -type EachMode
func eachModeForInstanceKey(key addrs.InstanceKey) EachMode {
switch key.(type) {
case addrs.IntKey:
return EachList
case addrs.StringKey:
return EachMap
default:
if key == addrs.NoKey {
return NoEach
}
panic(fmt.Sprintf("don't know an each mode for instance key %#v", key))
}
}
// DeposedKey is a 8-character hex string used to uniquely identify deposed // DeposedKey is a 8-character hex string used to uniquely identify deposed
// instance objects in the state. // instance objects in the state.
type DeposedKey string type DeposedKey string

View File

@ -88,7 +88,6 @@ func (rs *Resource) DeepCopy() *Resource {
return &Resource{ return &Resource{
Addr: rs.Addr, Addr: rs.Addr,
EachMode: rs.EachMode,
Instances: instances, Instances: instances,
ProviderConfig: rs.ProviderConfig, // technically mutable, but immutable by convention ProviderConfig: rs.ProviderConfig, // technically mutable, but immutable by convention
} }

View File

@ -83,7 +83,6 @@ func TestState(t *testing.T) {
Name: "baz", Name: "baz",
}.Absolute(addrs.RootModuleInstance), }.Absolute(addrs.RootModuleInstance),
EachMode: EachList,
Instances: map[addrs.InstanceKey]*ResourceInstance{ Instances: map[addrs.InstanceKey]*ResourceInstance{
addrs.IntKey(0): { addrs.IntKey(0): {
Current: &ResourceInstanceObjectSrc{ Current: &ResourceInstanceObjectSrc{

View File

@ -95,27 +95,10 @@ func prepareStateV4(sV4 *stateV4) (*File, tfdiags.Diagnostics) {
} }
} }
var eachMode states.EachMode
switch rsV4.EachMode {
case "":
eachMode = states.NoEach
case "list":
eachMode = states.EachList
case "map":
eachMode = states.EachMap
default:
diags = diags.Append(tfdiags.Sourceless(
tfdiags.Error,
"Invalid resource metadata in state",
fmt.Sprintf("Resource %s has invalid \"each\" value %q in state.", rAddr.Absolute(moduleAddr), eachMode),
))
continue
}
ms := state.EnsureModule(moduleAddr) ms := state.EnsureModule(moduleAddr)
// Ensure the resource container object is present in the state. // Ensure the resource container object is present in the state.
ms.SetResourceMeta(rAddr, eachMode, providerAddr) ms.SetResourceProvider(rAddr, providerAddr)
for _, isV4 := range rsV4.Instances { for _, isV4 := range rsV4.Instances {
keyRaw := isV4.IndexKey keyRaw := isV4.IndexKey
@ -272,7 +255,7 @@ func prepareStateV4(sV4 *stateV4) (*File, tfdiags.Diagnostics) {
// on the incoming objects. That behavior is useful when we're making // on the incoming objects. That behavior is useful when we're making
// piecemeal updates to the state during an apply, but when we're // piecemeal updates to the state during an apply, but when we're
// reading the state file we want to reflect its contents exactly. // reading the state file we want to reflect its contents exactly.
ms.SetResourceMeta(rAddr, eachMode, providerAddr) ms.SetResourceProvider(rAddr, providerAddr)
} }
// The root module is special in that we persist its attributes and thus // The root module is special in that we persist its attributes and thus
@ -394,29 +377,11 @@ func writeStateV4(file *File, w io.Writer) tfdiags.Diagnostics {
continue continue
} }
var eachMode string
switch rs.EachMode {
case states.NoEach:
eachMode = ""
case states.EachList:
eachMode = "list"
case states.EachMap:
eachMode = "map"
default:
diags = diags.Append(tfdiags.Sourceless(
tfdiags.Error,
"Failed to serialize resource in state",
fmt.Sprintf("Resource %s has \"each\" mode %s, which cannot be serialized in state", resourceAddr.Absolute(moduleAddr), rs.EachMode),
))
continue
}
sV4.Resources = append(sV4.Resources, resourceStateV4{ sV4.Resources = append(sV4.Resources, resourceStateV4{
Module: moduleAddr.String(), Module: moduleAddr.String(),
Mode: mode, Mode: mode,
Type: resourceAddr.Type, Type: resourceAddr.Type,
Name: resourceAddr.Name, Name: resourceAddr.Name,
EachMode: eachMode,
ProviderConfig: rs.ProviderConfig.String(), ProviderConfig: rs.ProviderConfig.String(),
Instances: []instanceObjectStateV4{}, Instances: []instanceObjectStateV4{},
}) })

View File

@ -154,6 +154,6 @@ func TestFullInitialState() *states.State {
Provider: addrs.NewLegacyProvider(rAddr.ImpliedProvider()), Provider: addrs.NewLegacyProvider(rAddr.ImpliedProvider()),
Module: addrs.RootModule, Module: addrs.RootModule,
} }
childMod.SetResourceMeta(rAddr, states.EachList, providerAddr) childMod.SetResourceProvider(rAddr, providerAddr)
return state return state
} }

View File

@ -197,12 +197,12 @@ func (s *SyncState) ResourceInstanceObject(addr addrs.AbsResourceInstance, gen G
// SetResourceMeta updates the resource-level metadata for the resource at // SetResourceMeta updates the resource-level metadata for the resource at
// the given address, creating the containing module state and resource state // the given address, creating the containing module state and resource state
// as a side-effect if not already present. // as a side-effect if not already present.
func (s *SyncState) SetResourceMeta(addr addrs.AbsResource, eachMode EachMode, provider addrs.AbsProviderConfig) { func (s *SyncState) SetResourceProvider(addr addrs.AbsResource, provider addrs.AbsProviderConfig) {
s.lock.Lock() s.lock.Lock()
defer s.lock.Unlock() defer s.lock.Unlock()
ms := s.state.EnsureModule(addr.Module) ms := s.state.EnsureModule(addr.Module)
ms.SetResourceMeta(addr.Resource, eachMode, provider) ms.SetResourceProvider(addr.Resource, provider)
} }
// RemoveResource removes the entire state for the given resource, taking with // RemoveResource removes the entire state for the given resource, taking with

View File

@ -2637,7 +2637,7 @@ func TestContext2Apply_orphanResource(t *testing.T) {
Type: "test_thing", Type: "test_thing",
Name: "one", Name: "one",
}.Absolute(addrs.RootModuleInstance) }.Absolute(addrs.RootModuleInstance)
s.SetResourceMeta(oneAddr, states.EachList, providerAddr) s.SetResourceProvider(oneAddr, providerAddr)
s.SetResourceInstanceCurrent(oneAddr.Instance(addrs.IntKey(0)), &states.ResourceInstanceObjectSrc{ s.SetResourceInstanceCurrent(oneAddr.Instance(addrs.IntKey(0)), &states.ResourceInstanceObjectSrc{
Status: states.ObjectReady, Status: states.ObjectReady,
AttrsJSON: []byte(`{}`), AttrsJSON: []byte(`{}`),
@ -6111,9 +6111,7 @@ func TestContext2Apply_destroyWithModuleVariableAndCount(t *testing.T) {
//Test that things were destroyed //Test that things were destroyed
actual := strings.TrimSpace(state.String()) actual := strings.TrimSpace(state.String())
expected := strings.TrimSpace(` expected := strings.TrimSpace(`
<no state> <no state>`)
module.child:
<no state>`)
if actual != expected { if actual != expected {
t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual) t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual)
} }
@ -6269,9 +6267,7 @@ func TestContext2Apply_destroyWithModuleVariableAndCountNested(t *testing.T) {
//Test that things were destroyed //Test that things were destroyed
actual := strings.TrimSpace(state.String()) actual := strings.TrimSpace(state.String())
expected := strings.TrimSpace(` expected := strings.TrimSpace(`
<no state> <no state>`)
module.child.child2:
<no state>`)
if actual != expected { if actual != expected {
t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual) t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual)
} }

View File

@ -475,7 +475,7 @@ func (n *EvalWriteResourceState) Eval(ctx EvalContext) (interface{}, error) {
return nil, diags.Err() return nil, diags.Err()
} }
state.SetResourceMeta(n.Addr, states.EachList, n.ProviderAddr) state.SetResourceProvider(n.Addr, n.ProviderAddr)
expander.SetResourceCount(n.Addr.Module, n.Addr.Resource, count) expander.SetResourceCount(n.Addr.Module, n.Addr.Resource, count)
case n.Config.ForEach != nil: case n.Config.ForEach != nil:
@ -487,11 +487,11 @@ func (n *EvalWriteResourceState) Eval(ctx EvalContext) (interface{}, error) {
// This method takes care of all of the business logic of updating this // This method takes care of all of the business logic of updating this
// while ensuring that any existing instances are preserved, etc. // while ensuring that any existing instances are preserved, etc.
state.SetResourceMeta(n.Addr, states.EachMap, n.ProviderAddr) state.SetResourceProvider(n.Addr, n.ProviderAddr)
expander.SetResourceForEach(n.Addr.Module, n.Addr.Resource, forEach) expander.SetResourceForEach(n.Addr.Module, n.Addr.Resource, forEach)
default: default:
state.SetResourceMeta(n.Addr, states.NoEach, n.ProviderAddr) state.SetResourceProvider(n.Addr, n.ProviderAddr)
expander.SetResourceSingle(n.Addr.Module, n.Addr.Resource) expander.SetResourceSingle(n.Addr.Module, n.Addr.Resource)
} }

View File

@ -4,7 +4,6 @@ import (
"fmt" "fmt"
"os" "os"
"path/filepath" "path/filepath"
"strconv"
"sync" "sync"
"github.com/agext/levenshtein" "github.com/agext/levenshtein"
@ -803,43 +802,6 @@ func (d *evaluationStateData) getResourceSchema(addr addrs.Resource, providerAdd
return schema return schema
} }
// coerceInstanceKey attempts to convert the given key to the type expected
// for the given EachMode.
//
// If the key is already of the correct type or if it cannot be converted then
// it is returned verbatim. If conversion is required and possible, the
// converted value is returned. Callers should not try to determine if
// conversion was possible, should instead just check if the result is of
// the expected type.
func (d *evaluationStateData) coerceInstanceKey(key addrs.InstanceKey, mode states.EachMode) addrs.InstanceKey {
if key == addrs.NoKey {
// An absent key can't be converted
return key
}
switch mode {
case states.NoEach:
// No conversions possible at all
return key
case states.EachMap:
if intKey, isInt := key.(addrs.IntKey); isInt {
return addrs.StringKey(strconv.Itoa(int(intKey)))
}
return key
case states.EachList:
if strKey, isStr := key.(addrs.StringKey); isStr {
i, err := strconv.Atoi(string(strKey))
if err != nil {
return key
}
return addrs.IntKey(i)
}
return key
default:
return key
}
}
func (d *evaluationStateData) GetTerraformAttr(addr addrs.TerraformAttr, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) { func (d *evaluationStateData) GetTerraformAttr(addr addrs.TerraformAttr, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics var diags tfdiags.Diagnostics
switch addr.Name { switch addr.Name {