mirror of
https://github.com/weaveworks/scope.git
synced 2026-03-05 03:01:11 +00:00
Squash of: * We have to keep all the container hostnames until the end so we can count how many we've filtered * Adding tests for ContainerHostnameRenderer and PodServiceRenderer with filters * Because we filter on image name we need the image name before filtering * Alternative approach to passing decorators. * Refactor out some of the decorator capture * Don't memoise decorated calls to Render * Fixing filtered counts on containers topology Tricky, because we need the filters to be silent sometimes (when they're in the middle), but not when they're at the top, so we take the "top" filter's stats. However, this means we have to compose all user-specified filters into a single Filter layer, so we can get all stats. There are no more Silent filters, as all filters are silent (unless they are at the top). Additionally, I clarified some of the filters as their usage/terminology was inconsistent and confused. Now Filter(IsFoo, ...) *keeps* only nodes where IsFoo is true.
138 lines
4.2 KiB
Go
138 lines
4.2 KiB
Go
package render
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/weaveworks/scope/probe/kubernetes"
|
|
"github.com/weaveworks/scope/report"
|
|
)
|
|
|
|
// Constants are used in the tests.
|
|
const (
|
|
UnmanagedID = "unmanaged"
|
|
UnmanagedMajor = "Unmanaged"
|
|
)
|
|
|
|
// PodRenderer is a Renderer which produces a renderable kubernetes
|
|
// graph by merging the container graph and the pods topology.
|
|
var PodRenderer = FilterEmpty(report.Container,
|
|
MakeReduce(
|
|
MakeFilter(
|
|
func(n report.Node) bool {
|
|
// Drop unconnected pseudo nodes (could appear due to filtering)
|
|
_, isConnected := n.Latest.Lookup(IsConnected)
|
|
return n.Topology != Pseudo || isConnected
|
|
},
|
|
ColorConnected(MakeMap(
|
|
MapContainer2Pod,
|
|
ContainerWithImageNameRenderer,
|
|
)),
|
|
),
|
|
SelectPod,
|
|
),
|
|
)
|
|
|
|
// PodServiceRenderer is a Renderer which produces a renderable kubernetes services
|
|
// graph by merging the pods graph and the services topology.
|
|
var PodServiceRenderer = FilterEmpty(report.Pod,
|
|
MakeReduce(
|
|
MakeMap(
|
|
MapPod2Service,
|
|
PodRenderer,
|
|
),
|
|
SelectService,
|
|
),
|
|
)
|
|
|
|
// MapContainer2Pod maps container Nodes to pod
|
|
// Nodes.
|
|
//
|
|
// If this function is given a node without a kubernetes_pod_id
|
|
// (including other pseudo nodes), it will produce an "Unmanaged"
|
|
// pseudo node.
|
|
//
|
|
// Otherwise, this function will produce a node 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 MapContainer2Pod(n report.Node, _ report.Networks) report.Nodes {
|
|
// Uncontainerd becomes unmanaged in the pods view
|
|
if strings.HasPrefix(n.ID, MakePseudoNodeID(UncontainedID)) {
|
|
id := MakePseudoNodeID(UnmanagedID, 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}
|
|
}
|
|
|
|
// Otherwise, if some some reason the container doesn't have a pod_id (maybe
|
|
// slightly out of sync reports, or its not in a pod), just drop it
|
|
namespace, ok := n.Latest.Lookup(kubernetes.Namespace)
|
|
if !ok {
|
|
id := MakePseudoNodeID(UnmanagedID, report.ExtractHostID(n))
|
|
node := NewDerivedPseudoNode(id, n)
|
|
return report.Nodes{id: node}
|
|
}
|
|
podID, ok := n.Latest.Lookup(kubernetes.PodID)
|
|
if !ok {
|
|
id := MakePseudoNodeID(UnmanagedID, report.ExtractHostID(n))
|
|
node := NewDerivedPseudoNode(id, n)
|
|
return report.Nodes{id: node}
|
|
}
|
|
podName := strings.TrimPrefix(podID, namespace+"/")
|
|
id := report.MakePodNodeID(namespace, podName)
|
|
|
|
// Due to a bug in kubernetes, addon pods on the master node are not returned
|
|
// from the API. Adding the namespace and pod name is a workaround until
|
|
// https://github.com/kubernetes/kubernetes/issues/14738 is fixed.
|
|
return report.Nodes{
|
|
id: NewDerivedNode(id, n).
|
|
WithTopology(report.Pod).
|
|
WithLatests(map[string]string{
|
|
kubernetes.Namespace: namespace,
|
|
kubernetes.PodName: podName,
|
|
}),
|
|
}
|
|
}
|
|
|
|
// MapPod2Service maps pod Nodes to service Nodes.
|
|
//
|
|
// If this function is given a node without a kubernetes_pod_id
|
|
// (including other pseudo nodes), it will produce an "Uncontained"
|
|
// pseudo node.
|
|
//
|
|
// Otherwise, this function will produce a node 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 pod graph to get that info.
|
|
func MapPod2Service(pod report.Node, _ report.Networks) report.Nodes {
|
|
// Propagate all pseudo nodes
|
|
if pod.Topology == Pseudo {
|
|
return report.Nodes{pod.ID: pod}
|
|
}
|
|
|
|
// Otherwise, if some some reason the pod doesn't have a service_ids (maybe
|
|
// slightly out of sync reports, or its not in a service), just drop it
|
|
namespace, ok := pod.Latest.Lookup(kubernetes.Namespace)
|
|
if !ok {
|
|
return report.Nodes{}
|
|
}
|
|
ids, ok := pod.Latest.Lookup(kubernetes.ServiceIDs)
|
|
if !ok {
|
|
return report.Nodes{}
|
|
}
|
|
|
|
result := report.Nodes{}
|
|
for _, serviceID := range strings.Fields(ids) {
|
|
serviceName := strings.TrimPrefix(serviceID, namespace+"/")
|
|
id := report.MakeServiceNodeID(namespace, serviceName)
|
|
node := NewDerivedNode(id, pod).WithTopology(report.Service)
|
|
node.Counters = node.Counters.Add(pod.Topology, 1)
|
|
result[id] = node
|
|
}
|
|
return result
|
|
}
|