Add ModuleOutputs method to states
In order to efficiently build the module objects for evaluation, we need to collect the outputs from a set of module instances. The ModuleOutputs method will return a copy of the state outputs, while not requiring the unnecessary copying of each entire module.
This commit is contained in:
parent
e9eb8e04cc
commit
2c4c027a97
|
@ -82,6 +82,35 @@ func (s *State) ModuleInstances(addr addrs.Module) []*Module {
|
||||||
return ms
|
return ms
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ModuleOutputs returns all outputs for the given module call under the
|
||||||
|
// parentAddr instance.
|
||||||
|
func (s *State) ModuleOutputs(parentAddr addrs.ModuleInstance, module addrs.ModuleCall) []*OutputValue {
|
||||||
|
var os []*OutputValue
|
||||||
|
for _, m := range s.Modules {
|
||||||
|
// can't get outputs from the root module
|
||||||
|
if m.Addr.IsRoot() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
parent, call := m.Addr.Call()
|
||||||
|
// make sure this is a descendent in the correct path
|
||||||
|
if !parentAddr.Equal(parent) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// and check if this is the correct child
|
||||||
|
if call.Name != module.Name {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, o := range m.OutputValues {
|
||||||
|
os = append(os, o)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return os
|
||||||
|
}
|
||||||
|
|
||||||
// RemoveModule removes the module with the given address from the state,
|
// 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
|
// unless it is the root module. The root module cannot be deleted, and so
|
||||||
// this method will panic if that is attempted.
|
// this method will panic if that is attempted.
|
||||||
|
|
|
@ -43,6 +43,10 @@ func TestState(t *testing.T) {
|
||||||
|
|
||||||
childModule := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
|
childModule := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
|
||||||
childModule.SetOutputValue("pizza", cty.StringVal("hawaiian"), false)
|
childModule.SetOutputValue("pizza", cty.StringVal("hawaiian"), false)
|
||||||
|
multiModA := state.EnsureModule(addrs.RootModuleInstance.Child("multi", addrs.StringKey("a")))
|
||||||
|
multiModA.SetOutputValue("pizza", cty.StringVal("cheese"), false)
|
||||||
|
multiModB := state.EnsureModule(addrs.RootModuleInstance.Child("multi", addrs.StringKey("b")))
|
||||||
|
multiModB.SetOutputValue("pizza", cty.StringVal("sausage"), false)
|
||||||
|
|
||||||
want := &State{
|
want := &State{
|
||||||
Modules: map[string]*Module{
|
Modules: map[string]*Module{
|
||||||
|
@ -114,6 +118,40 @@ func TestState(t *testing.T) {
|
||||||
},
|
},
|
||||||
Resources: map[string]*Resource{},
|
Resources: map[string]*Resource{},
|
||||||
},
|
},
|
||||||
|
`module.multi["a"]`: {
|
||||||
|
Addr: addrs.RootModuleInstance.Child("multi", addrs.StringKey("a")),
|
||||||
|
LocalValues: map[string]cty.Value{},
|
||||||
|
OutputValues: map[string]*OutputValue{
|
||||||
|
"pizza": {
|
||||||
|
Addr: addrs.AbsOutputValue{
|
||||||
|
Module: addrs.RootModuleInstance.Child("multi", addrs.StringKey("a")),
|
||||||
|
OutputValue: addrs.OutputValue{
|
||||||
|
Name: "pizza",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Value: cty.StringVal("cheese"),
|
||||||
|
Sensitive: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Resources: map[string]*Resource{},
|
||||||
|
},
|
||||||
|
`module.multi["b"]`: {
|
||||||
|
Addr: addrs.RootModuleInstance.Child("multi", addrs.StringKey("b")),
|
||||||
|
LocalValues: map[string]cty.Value{},
|
||||||
|
OutputValues: map[string]*OutputValue{
|
||||||
|
"pizza": {
|
||||||
|
Addr: addrs.AbsOutputValue{
|
||||||
|
Module: addrs.RootModuleInstance.Child("multi", addrs.StringKey("b")),
|
||||||
|
OutputValue: addrs.OutputValue{
|
||||||
|
Name: "pizza",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Value: cty.StringVal("sausage"),
|
||||||
|
Sensitive: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Resources: map[string]*Resource{},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,6 +171,25 @@ func TestState(t *testing.T) {
|
||||||
for _, problem := range deep.Equal(state, want) {
|
for _, problem := range deep.Equal(state, want) {
|
||||||
t.Error(problem)
|
t.Error(problem)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expectedOutputs := map[string]string{
|
||||||
|
`module.multi["a"].output.pizza`: "cheese",
|
||||||
|
`module.multi["b"].output.pizza`: "sausage",
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, o := range state.ModuleOutputs(addrs.RootModuleInstance, addrs.ModuleCall{Name: "multi"}) {
|
||||||
|
addr := o.Addr.String()
|
||||||
|
expected := expectedOutputs[addr]
|
||||||
|
delete(expectedOutputs, addr)
|
||||||
|
|
||||||
|
if expected != o.Value.AsString() {
|
||||||
|
t.Fatalf("expected %q:%q, got %q", addr, expected, o.Value.AsString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for addr, o := range expectedOutputs {
|
||||||
|
t.Fatalf("missing output %q:%q", addr, o)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStateDeepCopy(t *testing.T) {
|
func TestStateDeepCopy(t *testing.T) {
|
||||||
|
|
|
@ -48,6 +48,18 @@ func (s *SyncState) Module(addr addrs.ModuleInstance) *Module {
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ModuleOutputs returns the set of OutputValues that matches the given path.
|
||||||
|
func (s *SyncState) ModuleOutputs(parentAddr addrs.ModuleInstance, module addrs.ModuleCall) []*OutputValue {
|
||||||
|
s.lock.RLock()
|
||||||
|
defer s.lock.RUnlock()
|
||||||
|
var os []*OutputValue
|
||||||
|
|
||||||
|
for _, o := range s.state.ModuleOutputs(parentAddr, module) {
|
||||||
|
os = append(os, o.DeepCopy())
|
||||||
|
}
|
||||||
|
return os
|
||||||
|
}
|
||||||
|
|
||||||
// RemoveModule removes the entire state for the given module, taking with
|
// RemoveModule removes the entire state for the given module, taking with
|
||||||
// it any resources associated with the module. This should generally be
|
// it any resources associated with the module. This should generally be
|
||||||
// called only for modules whose resources have all been destroyed, but
|
// called only for modules whose resources have all been destroyed, but
|
||||||
|
|
Loading…
Reference in New Issue