mirror of
https://github.com/weaveworks/scope.git
synced 2026-07-18 04:49:55 +00:00
The nodes returned from Map2Parent are mostly empty, and need joining with their full topologies before being useful. But we want to filter out any nodes that weren't already in the graph. We make a new Renderer type to implement this. We also add the missing types to the type option group
241 lines
7.1 KiB
Go
241 lines
7.1 KiB
Go
package render
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/weaveworks/scope/probe/docker"
|
|
"github.com/weaveworks/scope/probe/kubernetes"
|
|
"github.com/weaveworks/scope/report"
|
|
)
|
|
|
|
// Constants are used in the tests.
|
|
const (
|
|
UnmanagedID = "unmanaged"
|
|
UnmanagedMajor = "Unmanaged"
|
|
)
|
|
|
|
func renderKubernetesTopologies(rpt report.Report) bool {
|
|
return len(rpt.Pod.Nodes)+len(rpt.Service.Nodes)+len(rpt.Deployment.Nodes)+len(rpt.ReplicaSet.Nodes) >= 1
|
|
}
|
|
|
|
func isPauseContainer(n report.Node) bool {
|
|
image, ok := n.Latest.Lookup(docker.ImageName)
|
|
return ok && kubernetes.IsPauseImageName(image)
|
|
}
|
|
|
|
type noParentsActionEnum int
|
|
|
|
// Constants for specifying noParentsAction in Map2Parent
|
|
const (
|
|
NoParentsPseudo noParentsActionEnum = iota
|
|
NoParentsDrop
|
|
NoParentsKeep
|
|
)
|
|
|
|
// PodRenderer is a Renderer which produces a renderable kubernetes
|
|
// graph by merging the container graph and the pods topology.
|
|
var PodRenderer = ConditionalRenderer(renderKubernetesTopologies,
|
|
MakeFilter(
|
|
func(n report.Node) bool {
|
|
state, ok := n.Latest.Lookup(kubernetes.State)
|
|
return (!ok || state != kubernetes.StateDeleted)
|
|
},
|
|
MakeMap(
|
|
PropagateSingleMetrics(report.Container),
|
|
MakeReduce(
|
|
MakeMap(
|
|
Map2Parent([]string{report.Pod}, NoParentsPseudo, UnmanagedID, nil),
|
|
MakeFilter(
|
|
ComposeFilterFuncs(
|
|
IsRunning,
|
|
Complement(isPauseContainer),
|
|
),
|
|
ContainerWithImageNameRenderer,
|
|
),
|
|
),
|
|
ShortLivedConnectionJoin(SelectPod, MapPod2IP),
|
|
SelectPod,
|
|
),
|
|
),
|
|
),
|
|
)
|
|
|
|
// PodServiceRenderer is a Renderer which produces a renderable kubernetes services
|
|
// graph by merging the pods graph and the services topology.
|
|
var PodServiceRenderer = ConditionalRenderer(renderKubernetesTopologies,
|
|
MakeMap(
|
|
PropagateSingleMetrics(report.Pod),
|
|
MakeReduce(
|
|
MakeMap(
|
|
Map2Parent([]string{report.Service}, NoParentsDrop, "", nil),
|
|
PodRenderer,
|
|
),
|
|
SelectService,
|
|
),
|
|
),
|
|
)
|
|
|
|
// DeploymentRenderer is a Renderer which produces a renderable kubernetes deployments
|
|
// graph by merging the pods graph and the deployments topology.
|
|
var DeploymentRenderer = ConditionalRenderer(renderKubernetesTopologies,
|
|
MakeMap(
|
|
PropagateSingleMetrics(report.ReplicaSet),
|
|
MakeReduce(
|
|
MakeMap(
|
|
Map2Parent([]string{report.Deployment}, NoParentsDrop, "", mapPodCounts),
|
|
ReplicaSetRenderer,
|
|
),
|
|
SelectDeployment,
|
|
),
|
|
),
|
|
)
|
|
|
|
// ReplicaSetRenderer is a Renderer which produces a renderable kubernetes replica sets
|
|
// graph by merging the pods graph and the replica sets topology.
|
|
var ReplicaSetRenderer = ConditionalRenderer(renderKubernetesTopologies,
|
|
MakeMap(
|
|
PropagateSingleMetrics(report.Pod),
|
|
MakeReduce(
|
|
MakeMap(
|
|
Map2Parent([]string{report.ReplicaSet}, NoParentsDrop, "", nil),
|
|
PodRenderer,
|
|
),
|
|
SelectReplicaSet,
|
|
),
|
|
),
|
|
)
|
|
|
|
// DaemonSetRenderer is a Renderer which produces a renderable kubernetes daemonsets
|
|
// graph by merging the pods graph and the daemonsets topology.
|
|
var DaemonSetRenderer = ConditionalRenderer(renderKubernetesTopologies,
|
|
MakeMap(
|
|
PropagateSingleMetrics(report.Pod),
|
|
MakeReduce(
|
|
MakeMap(
|
|
Map2Parent([]string{report.DaemonSet}, NoParentsDrop, "", nil),
|
|
PodRenderer,
|
|
),
|
|
SelectDaemonSet,
|
|
),
|
|
),
|
|
)
|
|
|
|
// KubeCombinedRenderer is a Renderer which combines the 'top abstraction' of all pods.
|
|
// We first map pods to all possible things they can map to, then we map again to
|
|
// deployments since some things (replica sets) can map to those (the rest are passed through
|
|
// unchanged).
|
|
// We can't simply combine the rendered graphs of the high level objects as they would never
|
|
// have connections to each other.
|
|
// We combine with all the full topologies using ReduceFirstOnly, which keeps the same
|
|
// set of nodes but merges in the full data from the other renderers.
|
|
var KubeCombinedRenderer = ConditionalRenderer(renderKubernetesTopologies,
|
|
MakeReduceFirstOnly(
|
|
MakeMap(
|
|
Map2Parent([]string{report.Deployment}, NoParentsKeep, "", nil),
|
|
MakeReduceFirstOnly(
|
|
MakeMap(
|
|
Map2Parent([]string{
|
|
report.ReplicaSet,
|
|
report.DaemonSet,
|
|
}, NoParentsKeep, "", nil),
|
|
PodRenderer,
|
|
),
|
|
SelectReplicaSet,
|
|
SelectDaemonSet,
|
|
),
|
|
),
|
|
SelectDeployment,
|
|
),
|
|
)
|
|
|
|
func mapPodCounts(parent, original report.Node) report.Node {
|
|
// When mapping ReplicaSets to Deployments, we want to propagate the Pods counter
|
|
if count, ok := original.Counters.Lookup(report.Pod); ok {
|
|
parent.Counters = parent.Counters.Add(report.Pod, count)
|
|
}
|
|
return parent
|
|
}
|
|
|
|
// MapPod2IP maps pod nodes to their IP address. This allows pods to
|
|
// be joined directly with the endpoint topology.
|
|
func MapPod2IP(m report.Node) []string {
|
|
// if this pod belongs to the host's networking namespace
|
|
// we cannot use its IP to attribute connections
|
|
// (they could come from any other process on the host or DNAT-ed IPs)
|
|
if _, ok := m.Latest.Lookup(kubernetes.IsInHostNetwork); ok {
|
|
return nil
|
|
}
|
|
|
|
ip, ok := m.Latest.Lookup(kubernetes.IP)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
return []string{report.MakeScopedEndpointNodeID("", ip, "")}
|
|
}
|
|
|
|
// Map2Parent returns a MapFunc which maps Nodes to some parent grouping.
|
|
func Map2Parent(
|
|
// The topology IDs to look for parents in
|
|
topologies []string,
|
|
// Choose what to do in the case of nodes with no parents. One of:
|
|
// NoParentsPseudo: Map them to a common pseudo node id with prefix noParentsPseudoID
|
|
// NoParentsDrop: Map them to no node.
|
|
// NoParentsKeep: Map them to themselves, preserving them in the new graph.
|
|
noParentsAction noParentsActionEnum,
|
|
// The ID prefix of the pseudo node to use for nodes without any parents in the group
|
|
// if noParentsAction == Pseudo, eg. UnmanagedID
|
|
noParentsPseudoID string,
|
|
// Optional (can be nil) function to modify any parent nodes,
|
|
// eg. to copy over details from the original node.
|
|
modifyMappedNode func(parent, original report.Node) report.Node,
|
|
) MapFunc {
|
|
return func(n report.Node, _ report.Networks) report.Nodes {
|
|
// Uncontained becomes Unmanaged/whatever if noParentsAction == Pseudo
|
|
if noParentsAction == NoParentsPseudo && strings.HasPrefix(n.ID, MakePseudoNodeID(UncontainedID)) {
|
|
id := MakePseudoNodeID(noParentsPseudoID, report.ExtractHostID(n))
|
|
node := NewDerivedPseudoNode(id, n)
|
|
return report.Nodes{id: node}
|
|
}
|
|
|
|
// Propagate all pseudo nodes
|
|
if n.Topology == Pseudo {
|
|
return report.Nodes{n.ID: n}
|
|
}
|
|
|
|
// For each topology, map to any parents we can find
|
|
result := report.Nodes{}
|
|
for _, topology := range topologies {
|
|
if groupIDs, ok := n.Parents.Lookup(topology); ok {
|
|
for _, id := range groupIDs {
|
|
node := NewDerivedNode(id, n).WithTopology(topology)
|
|
node.Counters = node.Counters.Add(n.Topology, 1)
|
|
if modifyMappedNode != nil {
|
|
node = modifyMappedNode(node, n)
|
|
}
|
|
result[id] = node
|
|
}
|
|
}
|
|
}
|
|
|
|
if len(result) == 0 {
|
|
switch noParentsAction {
|
|
case NoParentsPseudo:
|
|
// Map to pseudo node
|
|
id := MakePseudoNodeID(UnmanagedID, report.ExtractHostID(n))
|
|
node := NewDerivedPseudoNode(id, n)
|
|
result[id] = node
|
|
case NoParentsKeep:
|
|
// Pass n to output unmodified
|
|
result[n.ID] = n
|
|
case NoParentsDrop:
|
|
// Do nothing, we will return an empty result
|
|
default:
|
|
panic(fmt.Sprintf("Map2Parent got bad noParentsAction %v", noParentsAction))
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
}
|