mirror of
https://github.com/weaveworks/scope.git
synced 2026-07-28 09:41:57 +00:00
Merge pull request #2552 from weaveworks/mike/k8s/combined-view
add k8s combined view
This commit is contained in:
@@ -29,8 +29,7 @@ const (
|
||||
containersByImageID = "containers-by-image"
|
||||
podsID = "pods"
|
||||
replicaSetsID = "replica-sets"
|
||||
deploymentsID = "deployments"
|
||||
daemonsetsID = "daemonsets"
|
||||
kubeControllersID = "kube-controllers"
|
||||
servicesID = "services"
|
||||
hostsID = "hosts"
|
||||
weaveID = "weave"
|
||||
@@ -120,7 +119,7 @@ func updateKubeFilters(rpt report.Report, topologies []APITopologyDesc) []APITop
|
||||
sort.Strings(ns)
|
||||
topologies = append([]APITopologyDesc{}, topologies...) // Make a copy so we can make changes safely
|
||||
for i, t := range topologies {
|
||||
if t.id == containersID || t.id == podsID || t.id == servicesID || t.id == deploymentsID || t.id == replicaSetsID || t.id == daemonsetsID {
|
||||
if t.id == containersID || t.id == podsID || t.id == servicesID || t.id == replicaSetsID || t.id == kubeControllersID {
|
||||
topologies[i] = mergeTopologyFilters(t, []APITopologyOptionGroup{
|
||||
namespaceFilters(ns, "All Namespaces"),
|
||||
})
|
||||
@@ -196,6 +195,17 @@ func MakeRegistry() *Registry {
|
||||
},
|
||||
}
|
||||
|
||||
k8sControllersTypeFilter := APITopologyOptionGroup{
|
||||
ID: "grouptype",
|
||||
Default: "",
|
||||
SelectType: "union",
|
||||
NoneLabel: "All Types",
|
||||
Options: []APITopologyOption{
|
||||
{Value: report.Deployment, Label: "Deployments", filter: render.IsTopology(report.Deployment), filterPseudo: false},
|
||||
{Value: report.DaemonSet, Label: "Daemonsets", filter: render.IsTopology(report.DaemonSet), filterPseudo: false},
|
||||
},
|
||||
}
|
||||
|
||||
// Topology option labels should tell the current state. The first item must
|
||||
// be the verb to get to that state
|
||||
registry.Add(
|
||||
@@ -253,19 +263,11 @@ func MakeRegistry() *Registry {
|
||||
HideIfEmpty: true,
|
||||
},
|
||||
APITopologyDesc{
|
||||
id: deploymentsID,
|
||||
id: kubeControllersID,
|
||||
parent: podsID,
|
||||
renderer: render.DeploymentRenderer,
|
||||
Name: "deployments",
|
||||
Options: []APITopologyOptionGroup{unmanagedFilter},
|
||||
HideIfEmpty: true,
|
||||
},
|
||||
APITopologyDesc{
|
||||
id: daemonsetsID,
|
||||
parent: podsID,
|
||||
renderer: render.DaemonSetRenderer,
|
||||
Name: "daemonsets",
|
||||
Options: []APITopologyOptionGroup{unmanagedFilter},
|
||||
renderer: render.KubeControllerRenderer,
|
||||
Name: "controllers",
|
||||
Options: []APITopologyOptionGroup{unmanagedFilter, k8sControllersTypeFilter},
|
||||
HideIfEmpty: true,
|
||||
},
|
||||
APITopologyDesc{
|
||||
|
||||
@@ -11,11 +11,14 @@ import {
|
||||
pathElement,
|
||||
circleElement,
|
||||
rectangleElement,
|
||||
cloudShapeProps,
|
||||
circleShapeProps,
|
||||
triangleShapeProps,
|
||||
squareShapeProps,
|
||||
pentagonShapeProps,
|
||||
hexagonShapeProps,
|
||||
heptagonShapeProps,
|
||||
octagonShapeProps,
|
||||
cloudShapeProps,
|
||||
} from '../utils/node-shape-utils';
|
||||
|
||||
|
||||
@@ -69,8 +72,11 @@ function NodeShape(shapeType, shapeElement, shapeProps, { id, highlighted, color
|
||||
);
|
||||
}
|
||||
|
||||
export const NodeShapeCloud = props => NodeShape('cloud', pathElement, cloudShapeProps, props);
|
||||
export const NodeShapeCircle = props => NodeShape('circle', circleElement, circleShapeProps, props);
|
||||
export const NodeShapeTriangle = props => NodeShape('triangle', pathElement, triangleShapeProps, props);
|
||||
export const NodeShapeSquare = props => NodeShape('square', rectangleElement, squareShapeProps, props);
|
||||
export const NodeShapePentagon = props => NodeShape('pentagon', pathElement, pentagonShapeProps, props);
|
||||
export const NodeShapeHexagon = props => NodeShape('hexagon', pathElement, hexagonShapeProps, props);
|
||||
export const NodeShapeHeptagon = props => NodeShape('heptagon', pathElement, heptagonShapeProps, props);
|
||||
export const NodeShapeSquare = props => NodeShape('square', rectangleElement, squareShapeProps, props);
|
||||
export const NodeShapeOctagon = props => NodeShape('octagon', pathElement, octagonShapeProps, props);
|
||||
export const NodeShapeCloud = props => NodeShape('cloud', pathElement, cloudShapeProps, props);
|
||||
|
||||
@@ -14,20 +14,26 @@ import { NODE_BASE_SIZE } from '../constants/styles';
|
||||
import NodeShapeStack from './node-shape-stack';
|
||||
import NodeNetworksOverlay from './node-networks-overlay';
|
||||
import {
|
||||
NodeShapeCloud,
|
||||
NodeShapeCircle,
|
||||
NodeShapeTriangle,
|
||||
NodeShapeSquare,
|
||||
NodeShapePentagon,
|
||||
NodeShapeHexagon,
|
||||
NodeShapeHeptagon,
|
||||
NodeShapeOctagon,
|
||||
NodeShapeCloud,
|
||||
} from './node-shapes';
|
||||
|
||||
|
||||
const labelWidth = 1.2 * NODE_BASE_SIZE;
|
||||
const nodeShapes = {
|
||||
circle: NodeShapeCircle,
|
||||
triangle: NodeShapeTriangle,
|
||||
square: NodeShapeSquare,
|
||||
pentagon: NodeShapePentagon,
|
||||
hexagon: NodeShapeHexagon,
|
||||
heptagon: NodeShapeHeptagon,
|
||||
square: NodeShapeSquare,
|
||||
octagon: NodeShapeOctagon,
|
||||
cloud: NodeShapeCloud,
|
||||
};
|
||||
|
||||
|
||||
@@ -20,8 +20,11 @@ function curvedUnitPolygonPath(n) {
|
||||
]));
|
||||
}
|
||||
|
||||
export const squareShapeProps = { width: 1.8, height: 1.8, rx: 0.4, ry: 0.4, x: -0.9, y: -0.9 };
|
||||
export const heptagonShapeProps = { d: curvedUnitPolygonPath(7) };
|
||||
export const hexagonShapeProps = { d: curvedUnitPolygonPath(6) };
|
||||
export const cloudShapeProps = { d: UNIT_CLOUD_PATH };
|
||||
export const circleShapeProps = { r: 1 };
|
||||
export const triangleShapeProps = { d: curvedUnitPolygonPath(3) };
|
||||
export const squareShapeProps = { width: 1.8, height: 1.8, rx: 0.4, ry: 0.4, x: -0.9, y: -0.9 };
|
||||
export const pentagonShapeProps = { d: curvedUnitPolygonPath(5) };
|
||||
export const hexagonShapeProps = { d: curvedUnitPolygonPath(6) };
|
||||
export const heptagonShapeProps = { d: curvedUnitPolygonPath(7) };
|
||||
export const octagonShapeProps = { d: curvedUnitPolygonPath(8) };
|
||||
export const cloudShapeProps = { d: UNIT_CLOUD_PATH };
|
||||
|
||||
@@ -12,8 +12,8 @@ import { shownNodesSelector, shownResourceTopologyIdsSelector } from '../selecto
|
||||
const TOPOLOGY_DISPLAY_PRIORITY = [
|
||||
'ecs-services',
|
||||
'ecs-tasks',
|
||||
'kube-controllers',
|
||||
'services',
|
||||
'deployments',
|
||||
'replica-sets',
|
||||
'pods',
|
||||
'containers',
|
||||
|
||||
@@ -48,5 +48,6 @@ func (d *daemonSet) GetNode() report.Node {
|
||||
DesiredReplicas: fmt.Sprint(d.Status.DesiredNumberScheduled),
|
||||
Replicas: fmt.Sprint(d.Status.CurrentNumberScheduled),
|
||||
MisscheduledReplicas: fmt.Sprint(d.Status.NumberMisscheduled),
|
||||
NodeType: "Daemon Set",
|
||||
})
|
||||
}
|
||||
|
||||
@@ -54,5 +54,6 @@ func (d *deployment) GetNode(probeID string) report.Node {
|
||||
UnavailableReplicas: fmt.Sprint(d.Status.UnavailableReplicas),
|
||||
Strategy: string(d.Spec.Strategy.Type),
|
||||
report.ControlProbeID: probeID,
|
||||
NodeType: "Deployment",
|
||||
}).WithLatestActiveControls(ScaleUp, ScaleDown)
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ const (
|
||||
ObservedGeneration = "kubernetes_observed_generation"
|
||||
Replicas = "kubernetes_replicas"
|
||||
DesiredReplicas = "kubernetes_desired_replicas"
|
||||
NodeType = "kubernetes_node_type"
|
||||
)
|
||||
|
||||
// Exposed for testing
|
||||
@@ -46,6 +47,7 @@ var (
|
||||
ServiceMetricTemplates = PodMetricTemplates
|
||||
|
||||
DeploymentMetadataTemplates = report.MetadataTemplates{
|
||||
NodeType: {ID: NodeType, Label: "Type", From: report.FromLatest, Priority: 1},
|
||||
Namespace: {ID: Namespace, Label: "Namespace", From: report.FromLatest, Priority: 2},
|
||||
Created: {ID: Created, Label: "Created", From: report.FromLatest, Datatype: "datetime", Priority: 3},
|
||||
ObservedGeneration: {ID: ObservedGeneration, Label: "Observed Gen.", From: report.FromLatest, Datatype: "number", Priority: 4},
|
||||
@@ -67,6 +69,7 @@ var (
|
||||
ReplicaSetMetricTemplates = PodMetricTemplates
|
||||
|
||||
DaemonSetMetadataTemplates = report.MetadataTemplates{
|
||||
NodeType: {ID: NodeType, Label: "Type", From: report.FromLatest, Priority: 1},
|
||||
Namespace: {ID: Namespace, Label: "Namespace", From: report.FromLatest, Priority: 2},
|
||||
Created: {ID: Created, Label: "Created", From: report.FromLatest, Datatype: "datetime", Priority: 3},
|
||||
DesiredReplicas: {ID: DesiredReplicas, Label: "Desired Replicas", From: report.FromLatest, Datatype: "number", Priority: 4},
|
||||
|
||||
@@ -90,8 +90,8 @@ var primaryAPITopology = map[string]string{
|
||||
report.ContainerImage: "containers-by-image",
|
||||
report.Pod: "pods",
|
||||
report.ReplicaSet: "replica-sets",
|
||||
report.Deployment: "deployments",
|
||||
report.DaemonSet: "daemonsets",
|
||||
report.Deployment: "kube-controllers",
|
||||
report.DaemonSet: "kube-controllers",
|
||||
report.Service: "services",
|
||||
report.ECSTask: "ecs-tasks",
|
||||
report.ECSService: "ecs-services",
|
||||
@@ -257,13 +257,23 @@ func podNodeSummary(base NodeSummary, n report.Node) (NodeSummary, bool) {
|
||||
return base, true
|
||||
}
|
||||
|
||||
var podGroupNodeTypeName = map[string]string{
|
||||
report.Deployment: "Deployment",
|
||||
report.DaemonSet: "Daemon Set",
|
||||
}
|
||||
|
||||
func podGroupNodeSummary(base NodeSummary, n report.Node) (NodeSummary, bool) {
|
||||
base = addKubernetesLabelAndRank(base, n)
|
||||
base.Stack = true
|
||||
|
||||
// NB: pods are the highest aggregation level for which we display
|
||||
// counts.
|
||||
base.LabelMinor = pluralize(n.Counters, report.Pod, "pod", "pods")
|
||||
count := pluralize(n.Counters, report.Pod, "pod", "pods")
|
||||
if typeName, ok := podGroupNodeTypeName[n.Topology]; ok {
|
||||
base.LabelMinor = fmt.Sprintf("%s of %s", typeName, count)
|
||||
} else {
|
||||
base.LabelMinor = count
|
||||
}
|
||||
|
||||
return base, true
|
||||
}
|
||||
|
||||
@@ -6,32 +6,20 @@ import (
|
||||
|
||||
// ECSTaskRenderer is a Renderer for Amazon ECS tasks.
|
||||
var ECSTaskRenderer = ConditionalRenderer(renderECSTopologies,
|
||||
MakeMap(
|
||||
PropagateSingleMetrics(report.Container),
|
||||
MakeReduce(
|
||||
MakeMap(
|
||||
Map2Parent(report.ECSTask, UnmanagedID, nil),
|
||||
MakeFilter(
|
||||
IsRunning,
|
||||
ContainerWithImageNameRenderer,
|
||||
),
|
||||
),
|
||||
SelectECSTask,
|
||||
renderParents(
|
||||
report.Container, []string{report.ECSTask}, NoParentsPseudo, UnmanagedID, nil,
|
||||
MakeFilter(
|
||||
IsRunning,
|
||||
ContainerWithImageNameRenderer,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
// ECSServiceRenderer is a Renderer for Amazon ECS services.
|
||||
var ECSServiceRenderer = ConditionalRenderer(renderECSTopologies,
|
||||
MakeMap(
|
||||
PropagateSingleMetrics(report.ECSTask),
|
||||
MakeReduce(
|
||||
MakeMap(
|
||||
Map2Parent(report.ECSService, "", nil),
|
||||
ECSTaskRenderer,
|
||||
),
|
||||
SelectECSService,
|
||||
),
|
||||
renderParents(
|
||||
report.ECSTask, []string{report.ECSService}, NoParentsDrop, "", nil,
|
||||
ECSTaskRenderer,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@@ -311,12 +311,6 @@ func IsNotPseudo(n report.Node) bool {
|
||||
return n.Topology != Pseudo || strings.HasSuffix(n.ID, TheInternetID) || strings.HasPrefix(n.ID, ServiceNodeIDPrefix)
|
||||
}
|
||||
|
||||
// IsPseudoTopology returns true if the node is in a pseudo topology,
|
||||
// mimicing the check performed by MakeFilter() instead of the more complex check in IsNotPseudo()
|
||||
func IsPseudoTopology(n report.Node) bool {
|
||||
return n.Topology == Pseudo
|
||||
}
|
||||
|
||||
// IsNamespace checks if the node is a pod/service in the specified namespace
|
||||
func IsNamespace(namespace string) FilterFunc {
|
||||
return func(n report.Node) bool {
|
||||
@@ -336,6 +330,17 @@ func IsNamespace(namespace string) FilterFunc {
|
||||
}
|
||||
}
|
||||
|
||||
// IsTopology checks if the node is from a particular report topology
|
||||
func IsTopology(topology string) FilterFunc {
|
||||
return func(n report.Node) bool {
|
||||
return n.Topology == topology
|
||||
}
|
||||
}
|
||||
|
||||
// IsPseudoTopology returns true if the node is in a pseudo topology,
|
||||
// mimicing the check performed by MakeFilter() instead of the more complex check in IsNotPseudo()
|
||||
var IsPseudoTopology = IsTopology(Pseudo)
|
||||
|
||||
var systemContainerNames = map[string]struct{}{
|
||||
"weavescope": {},
|
||||
"weavedns": {},
|
||||
|
||||
173
render/pod.go
173
render/pod.go
@@ -26,6 +26,15 @@ func isPauseContainer(n report.Node) bool {
|
||||
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,
|
||||
@@ -34,22 +43,18 @@ var PodRenderer = ConditionalRenderer(renderKubernetesTopologies,
|
||||
state, ok := n.Latest.Lookup(kubernetes.State)
|
||||
return (!ok || state != kubernetes.StateDeleted)
|
||||
},
|
||||
MakeMap(
|
||||
PropagateSingleMetrics(report.Container),
|
||||
MakeReduce(
|
||||
MakeMap(
|
||||
Map2Parent(report.Pod, UnmanagedID, nil),
|
||||
MakeFilter(
|
||||
ComposeFilterFuncs(
|
||||
IsRunning,
|
||||
Complement(isPauseContainer),
|
||||
),
|
||||
ContainerWithImageNameRenderer,
|
||||
MakeReduce(
|
||||
renderParents(
|
||||
report.Container, []string{report.Pod}, NoParentsPseudo, UnmanagedID, nil,
|
||||
MakeFilter(
|
||||
ComposeFilterFuncs(
|
||||
IsRunning,
|
||||
Complement(isPauseContainer),
|
||||
),
|
||||
ContainerWithImageNameRenderer,
|
||||
),
|
||||
ConnectionJoin(SelectPod, MapPod2IP),
|
||||
SelectPod,
|
||||
),
|
||||
ConnectionJoin(SelectPod, MapPod2IP),
|
||||
),
|
||||
),
|
||||
)
|
||||
@@ -57,62 +62,63 @@ var PodRenderer = ConditionalRenderer(renderKubernetesTopologies,
|
||||
// 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(report.Service, "", 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(report.Deployment, "", mapPodCounts),
|
||||
ReplicaSetRenderer,
|
||||
),
|
||||
SelectDeployment,
|
||||
),
|
||||
renderParents(
|
||||
report.Pod, []string{report.Service}, NoParentsDrop, "", nil,
|
||||
PodRenderer,
|
||||
),
|
||||
)
|
||||
|
||||
// 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(report.ReplicaSet, "", nil),
|
||||
renderParents(
|
||||
report.Pod, []string{report.ReplicaSet}, NoParentsDrop, "", nil,
|
||||
PodRenderer,
|
||||
),
|
||||
)
|
||||
|
||||
// KubeControllerRenderer is a Renderer which combines all the 'controller' topologies.
|
||||
// We first map pods to daemonsets and replica sets, then to deployments since replica sets
|
||||
// can map to those (the rest are passed through unchanged).
|
||||
// Pods with no controller are mapped to 'Unmanaged'
|
||||
// We can't simply combine the rendered graphs of the high level objects as they would never
|
||||
// have connections to each other.
|
||||
var KubeControllerRenderer = ConditionalRenderer(renderKubernetesTopologies,
|
||||
MakeFilter(
|
||||
// Filter out any remaining unmatched replica sets
|
||||
Complement(IsTopology(report.ReplicaSet)),
|
||||
renderParents(
|
||||
report.ReplicaSet, []string{report.Deployment}, NoParentsKeep, "", mapPodCounts,
|
||||
renderParents(
|
||||
report.Pod, []string{report.ReplicaSet, report.DaemonSet},
|
||||
NoParentsPseudo, UnmanagedID, 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(
|
||||
// renderParents produces a 'standard' renderer for mapping from some child topology to some parent topologies,
|
||||
// by taking a child renderer, mapping to parents, propagating single metrics, and joining with full parent topology.
|
||||
// Most options are as per Map2Parent.
|
||||
func renderParents(childTopology string, parentTopologies []string, noParentsAction noParentsActionEnum,
|
||||
noParentsPseudoID string, modifyMappedNode func(parent, original report.Node) report.Node,
|
||||
childRenderer Renderer) Renderer {
|
||||
selectors := make([]Renderer, len(parentTopologies))
|
||||
for i, topology := range parentTopologies {
|
||||
selectors[i] = TopologySelector(topology)
|
||||
}
|
||||
return MakeReduce(append(
|
||||
selectors,
|
||||
MakeMap(
|
||||
PropagateSingleMetrics(childTopology),
|
||||
MakeMap(
|
||||
Map2Parent(report.DaemonSet, "", nil),
|
||||
PodRenderer,
|
||||
Map2Parent(parentTopologies, noParentsAction, noParentsPseudoID, modifyMappedNode),
|
||||
childRenderer,
|
||||
),
|
||||
SelectDaemonSet,
|
||||
),
|
||||
),
|
||||
)
|
||||
)...)
|
||||
}
|
||||
|
||||
func mapPodCounts(parent, original report.Node) report.Node {
|
||||
// When mapping ReplicaSets to Deployments, we want to propagate the Pods counter
|
||||
@@ -141,18 +147,23 @@ func MapPod2IP(m report.Node) []string {
|
||||
|
||||
// Map2Parent returns a MapFunc which maps Nodes to some parent grouping.
|
||||
func Map2Parent(
|
||||
// The topology ID of the parents
|
||||
topology string,
|
||||
// Either the ID prefix of the pseudo node to use for nodes without
|
||||
// any parents in the group, eg. UnmanagedID, or "" to drop nodes without any parents.
|
||||
// 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 noParentsPseudoID is set
|
||||
if noParentsPseudoID != "" && strings.HasPrefix(n.ID, UncontainedIDPrefix) {
|
||||
// Uncontained becomes Unmanaged/whatever if noParentsAction == Pseudo
|
||||
if noParentsAction == NoParentsPseudo && strings.HasPrefix(n.ID, UncontainedIDPrefix) {
|
||||
id := MakePseudoNodeID(noParentsPseudoID, report.ExtractHostID(n))
|
||||
node := NewDerivedPseudoNode(id, n)
|
||||
return report.Nodes{id: node}
|
||||
@@ -163,28 +174,36 @@ func Map2Parent(
|
||||
return report.Nodes{n.ID: n}
|
||||
}
|
||||
|
||||
// If some some reason the node doesn't have any of these ids
|
||||
// (maybe slightly out of sync reports, or its not in this group),
|
||||
// either drop it or put it in Uncontained/Unmanaged/whatever if one was given
|
||||
groupIDs, ok := n.Parents.Lookup(topology)
|
||||
if !ok || len(groupIDs) == 0 {
|
||||
if noParentsPseudoID == "" {
|
||||
return report.Nodes{}
|
||||
// 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
|
||||
}
|
||||
}
|
||||
id := MakePseudoNodeID(UnmanagedID, report.ExtractHostID(n))
|
||||
node := NewDerivedPseudoNode(id, n)
|
||||
return report.Nodes{id: node}
|
||||
}
|
||||
|
||||
result := report.Nodes{}
|
||||
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)
|
||||
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
|
||||
}
|
||||
result[id] = node
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,17 +6,11 @@ import (
|
||||
|
||||
// SwarmServiceRenderer is a Renderer for Docker Swarm services
|
||||
var SwarmServiceRenderer = ConditionalRenderer(renderSwarmTopologies,
|
||||
MakeMap(
|
||||
PropagateSingleMetrics(report.Container),
|
||||
MakeReduce(
|
||||
MakeMap(
|
||||
Map2Parent(report.SwarmService, UnmanagedID, nil),
|
||||
MakeFilter(
|
||||
IsRunning,
|
||||
ContainerWithImageNameRenderer,
|
||||
),
|
||||
),
|
||||
SelectSwarmService,
|
||||
renderParents(
|
||||
report.Container, []string{report.SwarmService}, NoParentsPseudo, UnmanagedID, nil,
|
||||
MakeFilter(
|
||||
IsRunning,
|
||||
ContainerWithImageNameRenderer,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
@@ -29,9 +29,12 @@ const (
|
||||
|
||||
// Shapes used for different nodes
|
||||
Circle = "circle"
|
||||
Triangle = "triangle"
|
||||
Square = "square"
|
||||
Heptagon = "heptagon"
|
||||
Pentagon = "pentagon"
|
||||
Hexagon = "hexagon"
|
||||
Heptagon = "heptagon"
|
||||
Octagon = "octagon"
|
||||
Cloud = "cloud"
|
||||
|
||||
// Used when counting the number of containers
|
||||
@@ -163,15 +166,15 @@ func MakeReport() Report {
|
||||
WithLabel("service", "services"),
|
||||
|
||||
Deployment: MakeTopology().
|
||||
WithShape(Heptagon).
|
||||
WithShape(Octagon).
|
||||
WithLabel("deployment", "deployments"),
|
||||
|
||||
ReplicaSet: MakeTopology().
|
||||
WithShape(Heptagon).
|
||||
WithShape(Triangle).
|
||||
WithLabel("replica set", "replica sets"),
|
||||
|
||||
DaemonSet: MakeTopology().
|
||||
WithShape(Heptagon).
|
||||
WithShape(Pentagon).
|
||||
WithLabel("daemonset", "daemonsets"),
|
||||
|
||||
Overlay: MakeTopology().
|
||||
|
||||
Reference in New Issue
Block a user