diff --git a/render/container.go b/render/container.go index 347d56745..5a20984ea 100644 --- a/render/container.go +++ b/render/container.go @@ -32,10 +32,7 @@ var ContainerRenderer = Memoise(MakeFilter( return !ok || state != report.StateDeleted }, MakeReduce( - MakeMap( - MapProcess2Container, - ProcessRenderer, - ), + process2Container{}, ConnectionJoin(MapContainer2IP, report.Container), ), )) @@ -219,39 +216,36 @@ func MapContainer2IP(m report.Node) []string { return result } -// MapProcess2Container maps process Nodes to container -// Nodes. +// process2Container maps process Nodes to container Nodes. // -// Pseudo nodes are passed straight through. -// -// If this function is given a node without a docker_container_id, it -// will produce an "Uncontained" pseudo node. -// -// Otherwise, this function will produce a node with the correct ID +// This function will produce nodes with the correct ID // format for a container, but without any Major or Minor labels. // It does not have enough info to do that, and the resulting graph // must be merged with a container graph to get that info. -func MapProcess2Container(n report.Node) report.Node { - // Propagate pseudo nodes - if n.Topology == Pseudo { - return n - } - // Otherwise, if the process is not in a container, group it into - // a per-host "Uncontained" node. - var ( - id string - node report.Node - ) - if containerID, ok := n.Latest.Lookup(report.DockerContainerID); ok { - id = report.MakeContainerNodeID(containerID) - node = NewDerivedNode(id, n).WithTopology(report.Container) - } else { - hostID, _, _ := report.ParseProcessNodeID(n.ID) - id = MakePseudoNodeID(UncontainedID, hostID) - node = NewDerivedPseudoNode(id, n) +type process2Container struct{} + +func (m process2Container) Render(ctx context.Context, rpt report.Report) Nodes { + processes := ProcessRenderer.Render(ctx, rpt) + ret := newJoinResults(nil) + for _, n := range processes.Nodes { + if n.Topology == Pseudo { + ret.passThrough(n) + continue + } + + // If the process is not in a container, group it into + // a per-host "Uncontained" node. + if containerID, ok := n.Latest.Lookup(report.DockerContainerID); ok { + id := report.MakeContainerNodeID(containerID) + ret.addChildAndChildren(n, id, report.Container) + } else { + hostID, _, _ := report.ParseProcessNodeID(n.ID) + id := MakePseudoNodeID(UncontainedID, hostID) + ret.addChildAndChildren(n, id, Pseudo) + } } - return node + return ret.result(processes) } // containerImageRenderer produces a graph where each node is a container image diff --git a/render/container_test.go b/render/container_test.go index 5bb3d1171..eeedc1b2c 100644 --- a/render/container_test.go +++ b/render/container_test.go @@ -2,7 +2,6 @@ package render_test import ( "context" - "fmt" "testing" "github.com/weaveworks/common/test" @@ -25,32 +24,6 @@ var ( }) ) -func TestMapProcess2Container(t *testing.T) { - for _, input := range []testcase{ - {"empty", report.MakeNode("empty"), true}, - {"basic process", report.MakeNodeWith("basic", map[string]string{report.PID: "201", report.DockerContainerID: "a1b2c3"}), true}, - {"uncontained", report.MakeNodeWith("uncontained", map[string]string{report.PID: "201", report.HostNodeID: report.MakeHostNodeID("foo")}), true}, - } { - testMap(t, render.MapProcess2Container, input) - } -} - -type testcase struct { - name string - n report.Node - ok bool -} - -func testMap(t *testing.T, f render.MapFunc, input testcase) { - if have := f(input.n); input.ok != (have.ID != "") { - name := input.name - if name == "" { - name = fmt.Sprintf("%v", input.n) - } - t.Errorf("%s: want %v, have %v", name, input.ok, have) - } -} - func TestContainerRenderer(t *testing.T) { have := utils.Prune(render.ContainerWithImageNameRenderer.Render(context.Background(), fixture.Report).Nodes) want := utils.Prune(expected.RenderedContainers)