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
|
||||
}
|
||||
|
||||
// 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,
|
||||
// unless it is the root module. The root module cannot be deleted, and so
|
||||
// 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.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{
|
||||
Modules: map[string]*Module{
|
||||
|
@ -114,6 +118,40 @@ func TestState(t *testing.T) {
|
|||
},
|
||||
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) {
|
||||
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) {
|
||||
|
|
|
@ -48,6 +48,18 @@ func (s *SyncState) Module(addr addrs.ModuleInstance) *Module {
|
|||
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
|
||||
// it any resources associated with the module. This should generally be
|
||||
// called only for modules whose resources have all been destroyed, but
|
||||
|
|
Loading…
Reference in New Issue