Remove replica sets

Use a special kind of selector renderer to elide replica sets from pod nodes
and directly reference deployment parents instead.
Do the inverse (replace replica sets with pods) during the mapping from pod to deployment.

Note we can no longer use renderParents since we're using a non-standard Selector
This commit is contained in:
Mike Lang
2017-06-27 17:28:34 -07:00
parent 5317b224ec
commit ef2b6f6c55
6 changed files with 64 additions and 60 deletions

View File

@@ -28,7 +28,6 @@ const (
containersByHostnameID = "containers-by-hostname"
containersByImageID = "containers-by-image"
podsID = "pods"
replicaSetsID = "replica-sets"
kubeControllersID = "kube-controllers"
servicesID = "services"
hostsID = "hosts"
@@ -97,7 +96,7 @@ func updateSwarmFilters(rpt report.Report, topologies []APITopologyDesc) []APITo
func updateKubeFilters(rpt report.Report, topologies []APITopologyDesc) []APITopologyDesc {
namespaces := map[string]struct{}{}
for _, t := range []report.Topology{rpt.Pod, rpt.Service, rpt.Deployment, rpt.ReplicaSet} {
for _, t := range []report.Topology{rpt.Pod, rpt.Service, rpt.Deployment} {
for _, n := range t.Nodes {
if state, ok := n.Latest.Lookup(kubernetes.State); ok && state == kubernetes.StateDeleted {
continue
@@ -119,7 +118,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 == replicaSetsID || t.id == kubeControllersID {
if t.id == containersID || t.id == podsID || t.id == servicesID || t.id == kubeControllersID {
topologies[i] = mergeTopologyFilters(t, []APITopologyOptionGroup{
namespaceFilters(ns, "All Namespaces"),
})
@@ -254,14 +253,6 @@ func MakeRegistry() *Registry {
Options: []APITopologyOptionGroup{unmanagedFilter},
HideIfEmpty: true,
},
APITopologyDesc{
id: replicaSetsID,
parent: podsID,
renderer: render.FilterUnconnectedPseudo(render.ReplicaSetRenderer),
Name: "replica sets",
Options: []APITopologyOptionGroup{unmanagedFilter},
HideIfEmpty: true,
},
APITopologyDesc{
id: kubeControllersID,
parent: podsID,

View File

@@ -131,16 +131,6 @@ var nodeSummaryGroupSpecs = []struct {
topologyID string
NodeSummaryGroup
}{
{
topologyID: report.ReplicaSet,
NodeSummaryGroup: NodeSummaryGroup{
Label: "Replica Sets",
Columns: []Column{
{ID: report.Pod, Label: "# Pods", Datatype: "number"},
{ID: kubernetes.ObservedGeneration, Label: "Observed Gen.", Datatype: "number"},
},
},
},
{
topologyID: report.Pod,
NodeSummaryGroup: NodeSummaryGroup{

View File

@@ -23,7 +23,6 @@ var (
getLabelForTopology = map[string]func(report.Node) string{
report.Container: getRenderableContainerName,
report.Pod: kubernetesParentLabel,
report.ReplicaSet: kubernetesParentLabel,
report.Deployment: kubernetesParentLabel,
report.DaemonSet: kubernetesParentLabel,
report.Service: kubernetesParentLabel,

View File

@@ -68,7 +68,6 @@ var renderers = map[string]func(NodeSummary, report.Node) (NodeSummary, bool){
report.Service: podGroupNodeSummary,
report.Deployment: podGroupNodeSummary,
report.DaemonSet: podGroupNodeSummary,
report.ReplicaSet: podGroupNodeSummary,
report.ECSTask: ecsTaskNodeSummary,
report.ECSService: ecsServiceNodeSummary,
report.SwarmService: swarmServiceNodeSummary,
@@ -89,7 +88,6 @@ var primaryAPITopology = map[string]string{
report.Container: "containers",
report.ContainerImage: "containers-by-image",
report.Pod: "pods",
report.ReplicaSet: "replica-sets",
report.Deployment: "kube-controllers",
report.DaemonSet: "kube-controllers",
report.Service: "services",

View File

@@ -18,7 +18,7 @@ const (
var UnmanagedIDPrefix = MakePseudoNodeID(UnmanagedID)
func renderKubernetesTopologies(rpt report.Report) bool {
return len(rpt.Pod.Nodes)+len(rpt.Service.Nodes)+len(rpt.Deployment.Nodes)+len(rpt.ReplicaSet.Nodes)+len(rpt.DaemonSet.Nodes) >= 1
return len(rpt.Pod.Nodes)+len(rpt.Service.Nodes)+len(rpt.Deployment.Nodes)+len(rpt.DaemonSet.Nodes) >= 1
}
func isPauseContainer(n report.Node) bool {
@@ -44,16 +44,20 @@ var PodRenderer = ConditionalRenderer(renderKubernetesTopologies,
return (!ok || state != kubernetes.StateDeleted)
},
MakeReduce(
renderParents(
report.Container, []string{report.Pod}, NoParentsPseudo, UnmanagedID, nil,
MakeFilter(
ComposeFilterFuncs(
IsRunning,
Complement(isPauseContainer),
MakeMap(
PropagateSingleMetrics(report.Container),
MakeMap(
Map2Parent([]string{report.Pod}, NoParentsPseudo, UnmanagedID, nil),
MakeFilter(
ComposeFilterFuncs(
IsRunning,
Complement(isPauseContainer),
),
ContainerWithImageNameRenderer,
),
ContainerWithImageNameRenderer,
),
),
selectPodsWithDeployments{},
ConnectionJoin(SelectPod, MapPod2IP),
),
),
@@ -68,33 +72,15 @@ var PodServiceRenderer = ConditionalRenderer(renderKubernetesTopologies,
),
)
// 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,
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,
),
),
renderParents(
report.Pod, []string{report.Deployment, report.DaemonSet},
NoParentsPseudo, UnmanagedID, makePodsChildren,
PodRenderer,
),
)
@@ -120,12 +106,53 @@ func renderParents(childTopology string, parentTopologies []string, noParentsAct
)...)
}
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)
// Renderer to return modified Pod nodes to elide replica sets and point directly
// to deployments where applicable.
type selectPodsWithDeployments struct{}
func (s selectPodsWithDeployments) Render(rpt report.Report, dct Decorator) report.Nodes {
result := report.Nodes{}
// For each pod, we check for any replica sets, and merge any deployments they point to
// into a replacement Parents value.
for podID, pod := range rpt.Pod.Nodes {
if replicaSetIDs, ok := pod.Parents.Lookup(report.ReplicaSet); ok {
newParents := pod.Parents.Delete(report.ReplicaSet)
for _, replicaSetID := range replicaSetIDs {
if replicaSet, ok := rpt.ReplicaSet.Nodes[replicaSetID]; ok {
if deploymentIDs, ok := replicaSet.Parents.Lookup(report.Deployment); ok {
newParents = newParents.Add(report.Deployment, deploymentIDs)
}
}
}
pod = pod.WithParents(newParents)
}
result[podID] = pod
}
return parent
return result
}
func (s selectPodsWithDeployments) Stats(rpt report.Report, _ Decorator) Stats {
return Stats{}
}
// When mapping from pods to deployments, complete the two-way relation by making the
// mapped-from pod a child of the mapped-to deployment, and remove any replica set children.
// This is needed because pods were originally mapped to deployments via an intermediate replica set
// which we need to remove.
func makePodsChildren(parent, original report.Node) report.Node {
children := parent.Children
// Gather all the replica sets...
replicaSetIDs := []string{}
children.ForEach(func(n report.Node) {
if n.Topology == report.ReplicaSet {
replicaSetIDs = append(replicaSetIDs, n.ID)
}
})
// ...and delete them.
children = children.Delete(replicaSetIDs...)
// Then add in the mapped-from pod.
children = children.Add(original)
return parent.WithChildren(children)
}
// MapPod2IP maps pod nodes to their IP address. This allows pods to

View File

@@ -31,7 +31,6 @@ var (
SelectService = TopologySelector(report.Service)
SelectDeployment = TopologySelector(report.Deployment)
SelectDaemonSet = TopologySelector(report.DaemonSet)
SelectReplicaSet = TopologySelector(report.ReplicaSet)
SelectECSTask = TopologySelector(report.ECSTask)
SelectECSService = TopologySelector(report.ECSService)
SelectSwarmService = TopologySelector(report.SwarmService)