diff --git a/report/map_keys.go b/report/map_keys.go index 865a3143b8..aec4a26cfb 100644 --- a/report/map_keys.go +++ b/report/map_keys.go @@ -69,6 +69,7 @@ const ( KubernetesSuspended = "kubernetes_suspended" KubernetesLastScheduled = "kubernetes_last_scheduled" KubernetesActiveJobs = "kubernetes_active_jobs" + KubernetesStateDeleted = "deleted" // probe/awsecs ECSCluster = "ecs_cluster" ECSCreatedAt = "ecs_created_at" diff --git a/report/report.go b/report/report.go index 2ea3dd596e..2cac43de1d 100644 --- a/report/report.go +++ b/report/report.go @@ -371,7 +371,7 @@ func (r Report) Validate() error { // // This for now creates node's LatestControls from Controls. func (r Report) Upgrade() Report { - return r.upgradeLatestControls().upgradePodNodes() + return r.upgradeLatestControls().upgradePodNodes().upgradeNamespaces() } func (r Report) upgradeLatestControls() Report { @@ -439,6 +439,36 @@ func (r Report) upgradePodNodes() Report { return r } +func (r Report) upgradeNamespaces() Report { + if len(r.Namespace.Nodes) > 0 { + return r + } + + namespaces := map[string]struct{}{} + for _, t := range []Topology{r.Pod, r.Service, r.Deployment, r.DaemonSet, r.StatefulSet, r.CronJob} { + for _, n := range t.Nodes { + if state, ok := n.Latest.Lookup(KubernetesState); ok && state == KubernetesStateDeleted { + continue + } + if namespace, ok := n.Latest.Lookup(KubernetesNamespace); ok { + namespaces[namespace] = struct{}{} + } + } + } + + nodes := make(Nodes, len(namespaces)) + for ns := range namespaces { + // Namespace ID: + // Probes did not use to report namespace ids, but since creating a report node requires an id, + // the namespace name, which is unique, is passed to `MakeNamespaceNodeID` + namespaceID := MakeNamespaceNodeID(ns) + nodes[namespaceID] = MakeNodeWith(namespaceID, map[string]string{KubernetesName: ns}) + } + r.Namespace.Nodes = nodes + + return r +} + // BackwardCompatible returns a new backward-compatible report. // // This for now creates node's Controls from LatestControls. diff --git a/report/report_test.go b/report/report_test.go index f65576e79d..a87ca74d8e 100644 --- a/report/report_test.go +++ b/report/report_test.go @@ -99,8 +99,14 @@ func TestReportUpgrade(t *testing.T) { mtime.NowForce(time.Now()) defer mtime.NowReset() parentsWithDeployment := report.MakeSets().Add(report.Deployment, report.MakeStringSet("id")) - rsNode := report.MakeNode("bar").WithParents(parentsWithDeployment) - podNode := report.MakeNode("foo").WithControls("alive").WithParents(report.MakeSets().Add(report.ReplicaSet, report.MakeStringSet("bar"))) + rsNode := report.MakeNode("bar"). + WithParents(parentsWithDeployment) + namespaceName := "ns" + namespaceID := report.MakeNamespaceNodeID(namespaceName) + podNode := report.MakeNode("foo"). + WithLatests(map[string]string{report.KubernetesNamespace: namespaceName}). + WithControls("alive"). + WithParents(report.MakeSets().Add(report.ReplicaSet, report.MakeStringSet("bar"))) controls := map[string]report.NodeControlData{ "alive": { Dead: false, @@ -110,9 +116,12 @@ func TestReportUpgrade(t *testing.T) { rpt := report.MakeReport() rpt.ReplicaSet.AddNode(rsNode) rpt.Pod.AddNode(podNode) + namespaceNode := report.MakeNode(namespaceID). + WithLatests(map[string]string{report.KubernetesName: namespaceName}) expected := report.MakeReport() expected.ReplicaSet.AddNode(rsNode) expected.Pod.AddNode(expectedPodNode) + expected.Namespace.AddNode(namespaceNode) got := rpt.Upgrade() if !s_reflect.DeepEqual(expected, got) { t.Error(test.Diff(expected, got))