Only group processes not in containers AND doing network IO into uncontained nodes.

This commit is contained in:
Tom Wilkie
2015-08-24 12:52:57 +00:00
parent 142aa067ec
commit e7dc258119
7 changed files with 111 additions and 31 deletions

View File

@@ -59,6 +59,7 @@ var (
Adjacency: adjacency,
Origins: report.MakeIDList(
test.RandomClientNodeID,
test.GoogleEndpointNodeID,
),
}
}
@@ -124,14 +125,15 @@ var (
},
nonContainerProcessID: {
ID: nonContainerProcessID,
LabelMajor: "bash",
LabelMajor: test.NonContainerComm,
LabelMinor: fmt.Sprintf("%s (%s)", test.ServerHostID, test.NonContainerPID),
Rank: test.NonContainerComm,
Pseudo: false,
Adjacency: report.MakeIDList(),
Adjacency: report.MakeIDList(render.TheInternetID),
Origins: report.MakeIDList(
test.NonContainerProcessNodeID,
test.ServerHostNodeID,
test.NonContainerNodeID,
),
NodeMetadata: report.MakeNodeMetadata(),
EdgeMetadata: report.EdgeMetadata{},
@@ -180,16 +182,17 @@ var (
EgressByteCount: newu64(2100),
},
},
"bash": {
ID: "bash",
LabelMajor: "bash",
test.NonContainerComm: {
ID: test.NonContainerComm,
LabelMajor: test.NonContainerComm,
LabelMinor: "1 process",
Rank: "bash",
Rank: test.NonContainerComm,
Pseudo: false,
Adjacency: report.MakeIDList(),
Adjacency: report.MakeIDList(render.TheInternetID),
Origins: report.MakeIDList(
test.NonContainerProcessNodeID,
test.ServerHostNodeID,
test.NonContainerNodeID,
),
NodeMetadata: report.MakeNodeMetadata(),
EdgeMetadata: report.EdgeMetadata{},
@@ -246,10 +249,11 @@ var (
LabelMinor: test.ServerHostName,
Rank: "",
Pseudo: true,
Adjacency: report.MakeIDList(),
Adjacency: report.MakeIDList(render.TheInternetID),
Origins: report.MakeIDList(
test.NonContainerProcessNodeID,
test.ServerHostNodeID,
test.NonContainerNodeID,
),
NodeMetadata: report.MakeNodeMetadata(),
EdgeMetadata: report.EdgeMetadata{},
@@ -305,8 +309,9 @@ var (
LabelMinor: test.ServerHostName,
Rank: "",
Pseudo: true,
Adjacency: report.MakeIDList(),
Adjacency: report.MakeIDList(render.TheInternetID),
Origins: report.MakeIDList(
test.NonContainerNodeID,
test.NonContainerProcessNodeID,
test.ServerHostNodeID,
),

View File

@@ -269,27 +269,79 @@ func (m LeafMap) EdgeMetadata(rpt report.Report, srcRenderableID, dstRenderableI
return metadata
}
// FilterUnconnected is a Renderer which filters out unconnected nodes.
type FilterUnconnected struct {
// CustomRenderer allow for mapping functions that recived the entire topology
// in one call - useful for functions that need to consider the entire graph
type CustomRenderer struct {
RenderFunc func(RenderableNodes) RenderableNodes
Renderer
}
// Render produces a set of RenderableNodes given a Report
func (f FilterUnconnected) Render(rpt report.Report) RenderableNodes {
return OnlyConnected(f.Renderer.Render(rpt))
// Render implements Renderer
func (c CustomRenderer) Render(rpt report.Report) RenderableNodes {
return c.RenderFunc(c.Renderer.Render(rpt))
}
// IsConnected is the key added to NodeMetadata by ColorConnected
// to indicate a node has an edge pointing to it or from it
const IsConnected = "is_connected"
// OnlyConnected filters out unconnected RenderedNodes
func OnlyConnected(input RenderableNodes) RenderableNodes {
output := RenderableNodes{}
for id, node := range ColorConnected(input) {
if _, ok := node.NodeMetadata.Metadata[IsConnected]; ok {
output[id] = node
}
}
return output
}
// FilterUnconnected produces a renderer that filters unconnected nodes
// from the given renderer
func FilterUnconnected(r Renderer) Renderer {
return CustomRenderer{
RenderFunc: OnlyConnected,
Renderer: r,
}
}
// ColorConnected colors nodes with the IsConnected key if
// they have edges to or from them.
func ColorConnected(input RenderableNodes) RenderableNodes {
connected := map[string]struct{}{}
void := struct{}{}
for id, node := range input {
if len(node.Adjacency) == 0 {
continue
}
output[id] = node
connected[id] = void
for _, id := range node.Adjacency {
output[id] = input[id]
connected[id] = void
}
}
for id := range connected {
node := input[id]
node.NodeMetadata.Metadata[IsConnected] = "true"
input[id] = node
}
return input
}
// Filter removes nodes from a view based on a predicate.
type Filter struct {
Renderer
f func(RenderableNode) bool
}
// Render implements Renderer
func (f Filter) Render(rpt report.Report) RenderableNodes {
output := RenderableNodes{}
for id, node := range f.Renderer.Render(rpt) {
if f.f(node) {
output[id] = node
}
}
return output

View File

@@ -149,18 +149,17 @@ func TestMapEdge(t *testing.T) {
}
func TestFilterRender(t *testing.T) {
renderer := render.FilterUnconnected{
Renderer: mockRenderer{RenderableNodes: render.RenderableNodes{
"foo": {ID: "foo", Adjacency: report.MakeIDList("bar")},
"bar": {ID: "bar", Adjacency: report.MakeIDList("foo")},
"baz": {ID: "baz", Adjacency: report.MakeIDList()},
}},
}
renderer := render.FilterUnconnected(
mockRenderer{RenderableNodes: render.RenderableNodes{
"foo": {ID: "foo", Adjacency: report.MakeIDList("bar"), NodeMetadata: report.MakeNodeMetadata()},
"bar": {ID: "bar", Adjacency: report.MakeIDList("foo"), NodeMetadata: report.MakeNodeMetadata()},
"baz": {ID: "baz", Adjacency: report.MakeIDList(), NodeMetadata: report.MakeNodeMetadata()},
}})
want := render.RenderableNodes{
"foo": {ID: "foo", Adjacency: report.MakeIDList("bar")},
"bar": {ID: "bar", Adjacency: report.MakeIDList("foo")},
"foo": {ID: "foo", Adjacency: report.MakeIDList("bar"), NodeMetadata: report.MakeNodeMetadata()},
"bar": {ID: "bar", Adjacency: report.MakeIDList("foo"), NodeMetadata: report.MakeNodeMetadata()},
}
have := renderer.Render(report.MakeReport())
have := sterilize(renderer.Render(report.MakeReport()), true)
if !reflect.DeepEqual(want, have) {
t.Errorf("want %+v, have %+v", want, have)
}

View File

@@ -82,8 +82,22 @@ var ProcessNameRenderer = Map{
// graph by merging the process graph and the container topology.
var ContainerRenderer = MakeReduce(
Map{
MapFunc: MapProcess2Container,
Renderer: ProcessRenderer,
MapFunc: MapProcess2Container,
// We only want processes in container _or_ processes with network connections
// but we need to be careful to ensure we only include each edge once, by only
// including the ProcessRenderer once.
Renderer: Filter{
f: func(n RenderableNode) bool {
_, inContainer := n.NodeMetadata.Metadata[docker.ContainerID]
_, isConnected := n.NodeMetadata.Metadata[IsConnected]
return inContainer || isConnected
},
Renderer: CustomRenderer{
RenderFunc: ColorConnected,
Renderer: ProcessRenderer,
},
},
},
LeafMap{
Selector: report.SelectContainer,