diff --git a/internal/dao/generic.go b/internal/dao/generic.go index e450065c..ed214779 100644 --- a/internal/dao/generic.go +++ b/internal/dao/generic.go @@ -8,7 +8,6 @@ import ( "github.com/derailed/popeye/internal" "github.com/derailed/popeye/internal/client" - "github.com/rs/zerolog/log" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" @@ -22,14 +21,8 @@ type Generic struct { // List returns a collection of resources. func (g *Generic) List(ctx context.Context) ([]runtime.Object, error) { - labelSel, ok := ctx.Value(internal.KeyLabels).(string) - if !ok { - log.Debug().Msgf("No label selector found in context. Listing all resources") - } - ns, ok := ctx.Value(internal.KeyNamespace).(string) - if !ok { - panic("BOOM no ns in context") - } + labelSel, _ := ctx.Value(internal.KeyLabels).(string) + ns, _ := ctx.Value(internal.KeyNamespace).(string) if client.IsAllNamespace(ns) { ns = client.AllNamespaces } diff --git a/internal/db/db.go b/internal/db/db.go index 067451bf..76e012c4 100644 --- a/internal/db/db.go +++ b/internal/db/db.go @@ -382,17 +382,14 @@ func matchSel(labels map[string]string, e metav1.LabelSelectorRequirement) bool // MatchLabels check if pod labels match a selector. func MatchLabels(labels, sel map[string]string) bool { - if len(sel) == 0 { - return false - } - + var count int for k, v := range sel { - if v1, ok := labels[k]; !ok || v1 != v { - return false + if v1, ok := labels[k]; ok && v == v1 { + count++ } } - return true + return count > 0 } func (db *DB) Exists(kind types.GVR, fqn string) bool { diff --git a/internal/db/loader.go b/internal/db/loader.go index 5a25e50e..76875cf2 100644 --- a/internal/db/loader.go +++ b/internal/db/loader.go @@ -5,6 +5,7 @@ package db import ( "context" + "encoding/json" "fmt" "strings" "sync" @@ -58,7 +59,6 @@ func LoadResource[T metav1.ObjectMetaAccessor](ctx context.Context, l *Loader, g if l.isLoaded(gvr) || gvr == types.BlankGVR { return nil } - oo, err := loadResource(ctx, gvr) if err != nil { return err @@ -83,11 +83,25 @@ func Cast[T any](o runtime.Object) (T, error) { func Save[T metav1.ObjectMetaAccessor](ctx context.Context, dba *DB, gvr types.GVR, oo []runtime.Object) error { txn := dba.Txn(true) defer txn.Commit() - for _, o := range oo { - u, err := Cast[T](o) - if err != nil { - return err + var ( + u T + err error + ) + // !!BOZO!! Dud. Can't hydrate cnp/ccnp from unstructured?? + if gvr.R() == "ciliumnetworkpolicies" || gvr.R() == "ciliumclusterwidenetworkpolicies" { + bb, err := json.Marshal(o.(*unstructured.Unstructured)) + if err != nil { + return err + } + if err = json.Unmarshal(bb, &u); err != nil { + return err + } + } else { + u, err = Cast[T](o) + if err != nil { + return err + } } if err := txn.Insert(gvr.String(), u); err != nil { return err @@ -156,6 +170,7 @@ func (l *Loader) fetchPodsMetrics(c types.Connection) (*mv1beta1.PodMetricsList, } ctx, cancel := context.WithTimeout(context.Background(), client.CallTimeout) defer cancel() + return vc.MetricsV1beta1().PodMetricses(c.ActiveNamespace()).List(ctx, metav1.ListOptions{}) } @@ -167,6 +182,7 @@ func (l *Loader) fetchNodesMetrics(c types.Connection) (*mv1beta1.NodeMetricsLis ctx, cancel := context.WithTimeout(context.Background(), client.CallTimeout) defer cancel() + return vc.MetricsV1beta1().NodeMetricses().List(ctx, metav1.ListOptions{}) } diff --git a/internal/lint/cluster.go b/internal/lint/cluster.go index 087a6d05..794f6a1d 100644 --- a/internal/lint/cluster.go +++ b/internal/lint/cluster.go @@ -49,7 +49,7 @@ func (c *Cluster) checkVersion(ctx context.Context) error { return err } - ctx = internal.WithSpec(ctx, specFor("Version", nil)) + ctx = internal.WithSpec(ctx, SpecFor("Version", nil)) if rev.Major != tolerableMajor || rev.Minor < tolerableMinor { c.AddCode(ctx, 405) } else { diff --git a/internal/lint/cm.go b/internal/lint/cm.go index 84c5bc94..8e01675f 100644 --- a/internal/lint/cm.go +++ b/internal/lint/cm.go @@ -51,7 +51,7 @@ func (s *ConfigMap) checkStale(ctx context.Context, refs *sync.Map) error { cm := o.(*v1.ConfigMap) fqn := client.FQN(cm.Namespace, cm.Name) s.InitOutcome(fqn) - ctx = internal.WithSpec(ctx, specFor(fqn, cm)) + ctx = internal.WithSpec(ctx, SpecFor(fqn, cm)) if s.system.skip(fqn) { continue } diff --git a/internal/lint/cm_test.go b/internal/lint/cm_test.go index 606226af..986e86f8 100644 --- a/internal/lint/cm_test.go +++ b/internal/lint/cm_test.go @@ -45,45 +45,3 @@ func TestConfigMapLint(t *testing.T) { assert.Equal(t, `[POP-400] Used? Unable to locate resource reference`, ii[0].Message) assert.Equal(t, rules.InfoLevel, ii[0].Level) } - -// ---------------------------------------------------------------------------- -// Helpers... - -// type mockConfigMap struct{} - -// func newMockConfigMap() mockConfigMap { -// return mockConfigMap{} -// } - -// func (c mockConfigMap) PodRefs(refs *sync.Map) { -// refs.Store("cm:default/cm1", internal.StringSet{ -// "k1": internal.Blank, -// "k2": internal.Blank, -// }) -// refs.Store("cm:default/cm2", internal.AllKeys) -// refs.Store("cm:default/cm4", internal.StringSet{ -// "k1": internal.Blank, -// }) -// } - -// func (c mockConfigMap) ListConfigMaps() map[string]*v1.ConfigMap { -// return map[string]*v1.ConfigMap{ -// "default/cm1": makeMockConfigMap("cm1"), -// "default/cm2": makeMockConfigMap("cm2"), -// "default/cm3": makeMockConfigMap("cm3"), -// "default/cm4": makeMockConfigMap("cm4"), -// } -// } - -// func makeMockConfigMap(n string) *v1.ConfigMap { -// return &v1.ConfigMap{ -// ObjectMeta: metav1.ObjectMeta{ -// Name: n, -// Namespace: "default", -// }, -// Data: map[string]string{ -// "k1": "", -// "k2": "", -// }, -// } -// } diff --git a/internal/lint/container_test.go b/internal/lint/container_test.go index 6e78fff5..8c80a212 100644 --- a/internal/lint/container_test.go +++ b/internal/lint/container_test.go @@ -75,7 +75,7 @@ func TestContainerCheckUtilization(t *testing.T) { } ctx := test.MakeContext("containers", "container") - ctx = internal.WithSpec(ctx, specFor("default/p1", nil)) + ctx = internal.WithSpec(ctx, SpecFor("default/p1", nil)) for k := range uu { u := uu[k] t.Run(k, func(t *testing.T) { @@ -117,7 +117,7 @@ func TestContainerCheckResources(t *testing.T) { l := NewContainer("default/p1", newRangeCollector(t)) t.Run(k, func(t *testing.T) { - ctx = internal.WithSpec(ctx, specFor("default/p1", nil)) + ctx = internal.WithSpec(ctx, SpecFor("default/p1", nil)) ctx = internal.WithGroup(ctx, types.NewGVR("containers"), co.Name) l.checkResources(ctx, co) @@ -184,7 +184,7 @@ func TestContainerCheckImageTags(t *testing.T) { } ctx := test.MakeContext("containers", "container") - ctx = internal.WithSpec(ctx, specFor("default/p1", nil)) + ctx = internal.WithSpec(ctx, SpecFor("default/p1", nil)) ctx = internal.WithGroup(ctx, types.NewGVR("containers"), "c1") for k := range uu { u := uu[k] @@ -217,7 +217,7 @@ func TestContainerCheckImageRegistry(t *testing.T) { } ctx := test.MakeContext("containers", "container") - ctx = internal.WithSpec(ctx, specFor("default/p1", nil)) + ctx = internal.WithSpec(ctx, SpecFor("default/p1", nil)) ctx = internal.WithGroup(ctx, types.NewGVR("containers"), "c1") for k := range uu { u := uu[k] @@ -248,7 +248,7 @@ func TestContainerCheckNamedPorts(t *testing.T) { } ctx := test.MakeContext("containers", "container") - ctx = internal.WithSpec(ctx, specFor("p1", nil)) + ctx = internal.WithSpec(ctx, SpecFor("p1", nil)) ctx = internal.WithGroup(ctx, types.NewGVR("v1/pods"), "p1") for k := range uu { u := uu[k] diff --git a/internal/lint/cr.go b/internal/lint/cr.go index f801892e..76fafdd1 100644 --- a/internal/lint/cr.go +++ b/internal/lint/cr.go @@ -72,7 +72,7 @@ func (s *ClusterRole) checkStale(ctx context.Context, refs *sync.Map) { cr := o.(*rbacv1.ClusterRole) fqn := client.FQN(cr.Namespace, cr.Name) s.InitOutcome(fqn) - ctx = internal.WithSpec(ctx, specFor(fqn, cr)) + ctx = internal.WithSpec(ctx, SpecFor(fqn, cr)) if s.system.skip(fqn) { continue } diff --git a/internal/lint/crb.go b/internal/lint/crb.go index 6b4e837d..f8dcf254 100644 --- a/internal/lint/crb.go +++ b/internal/lint/crb.go @@ -46,7 +46,7 @@ func (c *ClusterRoleBinding) checkInUse(ctx context.Context) { fqn := client.FQN(crb.Namespace, crb.Name) c.InitOutcome(fqn) - ctx = internal.WithSpec(ctx, specFor(fqn, crb)) + ctx = internal.WithSpec(ctx, SpecFor(fqn, crb)) switch crb.RoleRef.Kind { case "ClusterRole": diff --git a/internal/lint/cronjob.go b/internal/lint/cronjob.go index a0c102fc..dd2d0c45 100644 --- a/internal/lint/cronjob.go +++ b/internal/lint/cronjob.go @@ -41,7 +41,7 @@ func (s *CronJob) Lint(ctx context.Context) error { cj := o.(*batchv1.CronJob) fqn := client.FQN(cj.Namespace, cj.Name) s.InitOutcome(fqn) - ctx = internal.WithSpec(ctx, specFor(fqn, cj)) + ctx = internal.WithSpec(ctx, SpecFor(fqn, cj)) s.checkCronJob(ctx, fqn, cj) s.checkContainers(ctx, fqn, cj.Spec.JobTemplate.Spec.Template.Spec) s.checkUtilization(ctx, over, fqn) diff --git a/internal/lint/dp.go b/internal/lint/dp.go index 7c021496..c35d02c1 100644 --- a/internal/lint/dp.go +++ b/internal/lint/dp.go @@ -39,7 +39,7 @@ func (s *Deployment) Lint(ctx context.Context) error { dp := o.(*appsv1.Deployment) fqn := client.FQN(dp.Namespace, dp.Name) s.InitOutcome(fqn) - ctx = internal.WithSpec(ctx, specFor(fqn, dp)) + ctx = internal.WithSpec(ctx, SpecFor(fqn, dp)) s.checkDeployment(ctx, dp) s.checkContainers(ctx, fqn, dp.Spec.Template.Spec) s.checkUtilization(ctx, over, dp) diff --git a/internal/lint/ds.go b/internal/lint/ds.go index 7f5491ae..523d9904 100644 --- a/internal/lint/ds.go +++ b/internal/lint/ds.go @@ -38,7 +38,7 @@ func (s *DaemonSet) Lint(ctx context.Context) error { ds := o.(*appsv1.DaemonSet) fqn := client.FQN(ds.Namespace, ds.Name) s.InitOutcome(fqn) - ctx = internal.WithSpec(ctx, specFor(fqn, ds)) + ctx = internal.WithSpec(ctx, SpecFor(fqn, ds)) s.checkDaemonSet(ctx, ds) s.checkContainers(ctx, fqn, ds.Spec.Template.Spec) diff --git a/internal/lint/gw.go b/internal/lint/gw.go index e4d1218b..89302b2f 100644 --- a/internal/lint/gw.go +++ b/internal/lint/gw.go @@ -40,7 +40,7 @@ func (s *Gateway) Lint(ctx context.Context) error { gw := o.(*gwv1.Gateway) fqn := client.FQN(gw.Namespace, gw.Name) s.InitOutcome(fqn) - ctx = internal.WithSpec(ctx, specFor(fqn, gw)) + ctx = internal.WithSpec(ctx, SpecFor(fqn, gw)) s.checkRefs(ctx, gw) } diff --git a/internal/lint/gwc.go b/internal/lint/gwc.go index 1476b151..fe0f2b02 100644 --- a/internal/lint/gwc.go +++ b/internal/lint/gwc.go @@ -39,7 +39,7 @@ func (s *GatewayClass) Lint(ctx context.Context) error { gwc := o.(*gwv1.GatewayClass) fqn := client.FQN(gwc.Namespace, gwc.Name) s.InitOutcome(fqn) - ctx = internal.WithSpec(ctx, specFor(fqn, gwc)) + ctx = internal.WithSpec(ctx, SpecFor(fqn, gwc)) s.checkRefs(ctx, gwc.Name) } diff --git a/internal/lint/gwr.go b/internal/lint/gwr.go index f241d891..9c33c205 100644 --- a/internal/lint/gwr.go +++ b/internal/lint/gwr.go @@ -41,7 +41,7 @@ func (s *HTTPRoute) Lint(ctx context.Context) error { gwr := o.(*gwv1.HTTPRoute) fqn := client.FQN(gwr.Namespace, gwr.Name) s.InitOutcome(fqn) - ctx = internal.WithSpec(ctx, specFor(fqn, gwr)) + ctx = internal.WithSpec(ctx, SpecFor(fqn, gwr)) s.checkRoute(ctx, fqn, gwr) } diff --git a/internal/lint/helper.go b/internal/lint/helper.go index 7e6239f9..bd74f488 100644 --- a/internal/lint/helper.go +++ b/internal/lint/helper.go @@ -28,7 +28,8 @@ const ( type qos = int -func specFor(fqn string, o metav1.ObjectMetaAccessor) rules.Spec { +// SpecFor construct a new run spec for a given resource. +func SpecFor(fqn string, o metav1.ObjectMetaAccessor) rules.Spec { spec := rules.Spec{ FQN: fqn, } @@ -197,3 +198,101 @@ func portAsStr(p v1.ServicePort) string { } return string(p.Protocol) + "::" + strconv.Itoa(int(p.Port)) } + +const ( + nodeUnreachablePodReason = "NodeLost" + completed = "Completed" + running = "Running" + terminating = "Terminating" +) + +func Phase(po *v1.Pod) string { + status := string(po.Status.Phase) + if po.Status.Reason != "" { + if po.DeletionTimestamp != nil && po.Status.Reason == nodeUnreachablePodReason { + return "Unknown" + } + status = po.Status.Reason + } + + status, ok := initContainerPhase(po, status) + if ok { + return status + } + + status, ok = containerPhase(po.Status, status) + if ok && status == completed { + status = running + } + if po.DeletionTimestamp == nil { + return status + } + + return terminating +} + +func containerPhase(st v1.PodStatus, status string) (string, bool) { + var running bool + for i := len(st.ContainerStatuses) - 1; i >= 0; i-- { + cs := st.ContainerStatuses[i] + switch { + case cs.State.Waiting != nil && cs.State.Waiting.Reason != "": + status = cs.State.Waiting.Reason + case cs.State.Terminated != nil && cs.State.Terminated.Reason != "": + status = cs.State.Terminated.Reason + case cs.State.Terminated != nil: + if cs.State.Terminated.Signal != 0 { + status = "Signal:" + strconv.Itoa(int(cs.State.Terminated.Signal)) + } else { + status = "ExitCode:" + strconv.Itoa(int(cs.State.Terminated.ExitCode)) + } + case cs.Ready && cs.State.Running != nil: + running = true + } + } + + return status, running +} + +func initContainerPhase(po *v1.Pod, status string) (string, bool) { + count := len(po.Spec.InitContainers) + rs := make(map[string]bool, count) + for _, c := range po.Spec.InitContainers { + rs[c.Name] = restartableInitCO(c.RestartPolicy) + } + for i, cs := range po.Status.InitContainerStatuses { + if s := checkInitContainerStatus(cs, i, count, rs[cs.Name]); s != "" { + return s, true + } + } + + return status, false +} + +func restartableInitCO(p *v1.ContainerRestartPolicy) bool { + return p != nil && *p == v1.ContainerRestartPolicyAlways +} + +func checkInitContainerStatus(cs v1.ContainerStatus, count, initCount int, restartable bool) string { + switch { + case cs.State.Terminated != nil: + if cs.State.Terminated.ExitCode == 0 { + return "" + } + if cs.State.Terminated.Reason != "" { + return "Init:" + cs.State.Terminated.Reason + } + if cs.State.Terminated.Signal != 0 { + return "Init:Signal:" + strconv.Itoa(int(cs.State.Terminated.Signal)) + } + return "Init:ExitCode:" + strconv.Itoa(int(cs.State.Terminated.ExitCode)) + case restartable && cs.Started != nil && *cs.Started: + if cs.Ready { + return "" + } + case cs.State.Waiting != nil && cs.State.Waiting.Reason != "" && cs.State.Waiting.Reason != "PodInitializing": + return "Init:" + cs.State.Waiting.Reason + } + + return "Init:" + strconv.Itoa(count) + "/" + strconv.Itoa(initCount) +} diff --git a/internal/lint/hpa.go b/internal/lint/hpa.go index b7f96364..528b008d 100644 --- a/internal/lint/hpa.go +++ b/internal/lint/hpa.go @@ -49,7 +49,7 @@ func (h *HorizontalPodAutoscaler) Lint(ctx context.Context) error { hpa := o.(*autoscalingv1.HorizontalPodAutoscaler) fqn := client.FQN(hpa.Namespace, hpa.Name) h.InitOutcome(fqn) - ctx = internal.WithSpec(ctx, specFor(fqn, hpa)) + ctx = internal.WithSpec(ctx, SpecFor(fqn, hpa)) var rcpu, rmem resource.Quantity ns, _ := namespaced(fqn) switch hpa.Spec.ScaleTargetRef.Kind { @@ -121,7 +121,7 @@ func (h *HorizontalPodAutoscaler) checkResources(ctx context.Context, max, curre func (h *HorizontalPodAutoscaler) checkUtilization(ctx context.Context, tcpu, tmem resource.Quantity, res v1.ResourceList) { acpu, amem := *res.Cpu(), *res.Memory() - ctx = internal.WithSpec(ctx, specFor("HPA", nil)) + ctx = internal.WithSpec(ctx, SpecFor("HPA", nil)) if toMC(tcpu) > toMC(acpu) { cpu := tcpu.DeepCopy() cpu.Sub(acpu) diff --git a/internal/lint/ing.go b/internal/lint/ing.go index 4e18fdb9..426097aa 100644 --- a/internal/lint/ing.go +++ b/internal/lint/ing.go @@ -42,7 +42,7 @@ func (s *Ingress) Lint(ctx context.Context) error { ing := o.(*netv1.Ingress) fqn := client.FQN(ing.Namespace, ing.Name) s.InitOutcome(fqn) - ctx = internal.WithSpec(ctx, specFor(fqn, ing)) + ctx = internal.WithSpec(ctx, SpecFor(fqn, ing)) for _, ing := range ing.Status.LoadBalancer.Ingress { for _, p := range ing.Ports { diff --git a/internal/lint/job.go b/internal/lint/job.go index d028ee13..f693ed67 100644 --- a/internal/lint/job.go +++ b/internal/lint/job.go @@ -39,7 +39,7 @@ func (s *Job) Lint(ctx context.Context) error { j := o.(*batchv1.Job) fqn := client.FQN(j.Namespace, j.Name) s.InitOutcome(fqn) - ctx = internal.WithSpec(ctx, specFor(fqn, j)) + ctx = internal.WithSpec(ctx, SpecFor(fqn, j)) s.checkJob(ctx, fqn, j) s.checkContainers(ctx, fqn, j.Spec.Template.Spec) s.checkUtilization(ctx, over, fqn) diff --git a/internal/lint/node.go b/internal/lint/node.go index c1d38020..9b21b875 100644 --- a/internal/lint/node.go +++ b/internal/lint/node.go @@ -48,7 +48,7 @@ func (n *Node) Lint(ctx context.Context) error { no := o.(*v1.Node) fqn := no.Name n.InitOutcome(fqn) - ctx = internal.WithSpec(ctx, specFor(fqn, no)) + ctx = internal.WithSpec(ctx, SpecFor(fqn, no)) n.checkConditions(ctx, no) if err := n.checkTaints(ctx, no.Spec.Taints, tt); err != nil { diff --git a/internal/lint/np.go b/internal/lint/np.go index 4526abb0..7abbb6a2 100644 --- a/internal/lint/np.go +++ b/internal/lint/np.go @@ -52,7 +52,7 @@ func (s *NetworkPolicy) Lint(ctx context.Context) error { np := o.(*netv1.NetworkPolicy) fqn := client.FQN(np.Namespace, np.Name) s.InitOutcome(fqn) - ctx = internal.WithSpec(ctx, specFor(fqn, np)) + ctx = internal.WithSpec(ctx, SpecFor(fqn, np)) s.checkSelector(ctx, fqn, np.Spec.PodSelector) s.checkIngresses(ctx, fqn, np.Spec.Ingress) diff --git a/internal/lint/ns.go b/internal/lint/ns.go index fd5aedb6..af5e5ebc 100644 --- a/internal/lint/ns.go +++ b/internal/lint/ns.go @@ -55,7 +55,7 @@ func (s *Namespace) Lint(ctx context.Context) error { continue } s.InitOutcome(fqn) - ctx = internal.WithSpec(ctx, specFor(fqn, ns)) + ctx = internal.WithSpec(ctx, SpecFor(fqn, ns)) if s.checkActive(ctx, ns.Status.Phase) { if _, ok := used[fqn]; !ok { diff --git a/internal/lint/pdb.go b/internal/lint/pdb.go index a8774c37..4bdb0b7f 100644 --- a/internal/lint/pdb.go +++ b/internal/lint/pdb.go @@ -36,7 +36,7 @@ func (p *PodDisruptionBudget) Lint(ctx context.Context) error { pdb := o.(*polv1.PodDisruptionBudget) fqn := client.FQN(pdb.Namespace, pdb.Name) p.InitOutcome(fqn) - ctx = internal.WithSpec(ctx, specFor(fqn, pdb)) + ctx = internal.WithSpec(ctx, SpecFor(fqn, pdb)) p.checkInUse(ctx, pdb) } diff --git a/internal/lint/pod.go b/internal/lint/pod.go index 0bd2ad32..22cdbc9e 100644 --- a/internal/lint/pod.go +++ b/internal/lint/pod.go @@ -59,7 +59,7 @@ func (s *Pod) Lint(ctx context.Context) error { s.InitOutcome(fqn) defer s.CloseOutcome(ctx, fqn, nil) - ctx = internal.WithSpec(ctx, specFor(fqn, po)) + ctx = internal.WithSpec(ctx, SpecFor(fqn, po)) s.checkStatus(ctx, po) s.checkContainerStatus(ctx, fqn, po) s.checkContainers(ctx, fqn, po) diff --git a/internal/lint/pod_test.go b/internal/lint/pod_test.go index 2d70a2e8..3c0d0d0f 100644 --- a/internal/lint/pod_test.go +++ b/internal/lint/pod_test.go @@ -91,7 +91,7 @@ func TestPodCheckSecure(t *testing.T) { } ctx := test.MakeContext("v1/pods", "po") - ctx = internal.WithSpec(ctx, specFor("default/p1", nil)) + ctx = internal.WithSpec(ctx, SpecFor("default/p1", nil)) ctx = context.WithValue(ctx, internal.KeyConfig, test.MakeConfig(t)) dba, err := test.NewTestDB() assert.NoError(t, err) diff --git a/internal/lint/pv.go b/internal/lint/pv.go index e55d642f..b35aafae 100644 --- a/internal/lint/pv.go +++ b/internal/lint/pv.go @@ -37,7 +37,7 @@ func (s *PersistentVolume) Lint(ctx context.Context) error { pv := o.(*v1.PersistentVolume) fqn := client.FQN(pv.Namespace, pv.Name) s.InitOutcome(fqn) - ctx = internal.WithSpec(ctx, specFor(fqn, pv)) + ctx = internal.WithSpec(ctx, SpecFor(fqn, pv)) s.checkBound(ctx, pv.Status.Phase) } diff --git a/internal/lint/pvc.go b/internal/lint/pvc.go index 3b37c790..5087955f 100644 --- a/internal/lint/pvc.go +++ b/internal/lint/pvc.go @@ -51,7 +51,7 @@ func (s *PersistentVolumeClaim) Lint(ctx context.Context) error { pvc := o.(*v1.PersistentVolumeClaim) fqn := client.FQN(pvc.Namespace, pvc.Name) s.InitOutcome(fqn) - ctx = internal.WithSpec(ctx, specFor(fqn, pvc)) + ctx = internal.WithSpec(ctx, SpecFor(fqn, pvc)) s.checkBound(ctx, pvc.Status.Phase) if _, ok := refs[fqn]; !ok { diff --git a/internal/lint/rb.go b/internal/lint/rb.go index ed09f40f..28492a34 100644 --- a/internal/lint/rb.go +++ b/internal/lint/rb.go @@ -45,7 +45,7 @@ func (r *RoleBinding) checkInUse(ctx context.Context) { rb := o.(*rbacv1.RoleBinding) fqn := client.FQN(rb.Namespace, rb.Name) r.InitOutcome(fqn) - ctx = internal.WithSpec(ctx, specFor(fqn, rb)) + ctx = internal.WithSpec(ctx, SpecFor(fqn, rb)) switch rb.RoleRef.Kind { case "ClusterRole": diff --git a/internal/lint/ro.go b/internal/lint/ro.go index ec604497..d41f07c3 100644 --- a/internal/lint/ro.go +++ b/internal/lint/ro.go @@ -34,12 +34,15 @@ func NewRole(c *issues.Collector, db *db.DB) *Role { // Lint cleanse the resource. func (s *Role) Lint(ctx context.Context) error { - var roRefs sync.Map + var refs sync.Map + crb := cache.NewClusterRoleBinding(s.db) - crb.ClusterRoleRefs(&roRefs) + crb.ClusterRoleRefs(&refs) + rb := cache.NewRoleBinding(s.db) - rb.RoleRefs(&roRefs) - s.checkInUse(ctx, &roRefs) + rb.RoleRefs(&refs) + + s.checkInUse(ctx, &refs) return nil } @@ -51,10 +54,9 @@ func (s *Role) checkInUse(ctx context.Context, refs *sync.Map) { ro := o.(*rbacv1.Role) fqn := client.FQN(ro.Namespace, ro.Name) s.InitOutcome(fqn) - ctx = internal.WithSpec(ctx, specFor(fqn, ro)) + ctx = internal.WithSpec(ctx, SpecFor(fqn, ro)) - _, ok := refs.Load(cache.ResFqn(cache.RoleKey, fqn)) - if !ok { + if _, ok := refs.Load(cache.ResFqn(cache.RoleKey, fqn)); !ok { s.AddCode(ctx, 400) } } diff --git a/internal/lint/rs.go b/internal/lint/rs.go index 5dbfebc3..2e9763bd 100644 --- a/internal/lint/rs.go +++ b/internal/lint/rs.go @@ -36,7 +36,7 @@ func (s *ReplicaSet) Lint(ctx context.Context) error { rs := o.(*appsv1.ReplicaSet) fqn := client.FQN(rs.Namespace, rs.Name) s.InitOutcome(fqn) - ctx = internal.WithSpec(ctx, specFor(fqn, rs)) + ctx = internal.WithSpec(ctx, SpecFor(fqn, rs)) s.checkHealth(ctx, rs) } diff --git a/internal/lint/sa.go b/internal/lint/sa.go index d44440e0..bad67425 100644 --- a/internal/lint/sa.go +++ b/internal/lint/sa.go @@ -52,7 +52,7 @@ func (s *ServiceAccount) Lint(ctx context.Context) error { sa := o.(*v1.ServiceAccount) fqn := client.FQN(sa.Namespace, sa.Name) s.InitOutcome(fqn) - ctx = internal.WithSpec(ctx, specFor(fqn, sa)) + ctx = internal.WithSpec(ctx, SpecFor(fqn, sa)) s.checkMounts(ctx, sa.AutomountServiceAccountToken) s.checkSecretRefs(ctx, fqn, sa.Secrets) diff --git a/internal/lint/sec.go b/internal/lint/sec.go index 24f86103..6c11aa48 100644 --- a/internal/lint/sec.go +++ b/internal/lint/sec.go @@ -61,7 +61,7 @@ func (s *Secret) checkStale(ctx context.Context, refs *sync.Map) { sec := o.(*v1.Secret) fqn := client.FQN(sec.Namespace, sec.Name) s.InitOutcome(fqn) - ctx = internal.WithSpec(ctx, specFor(fqn, sec)) + ctx = internal.WithSpec(ctx, SpecFor(fqn, sec)) if s.system.skip(fqn) { continue diff --git a/internal/lint/sts.go b/internal/lint/sts.go index 0dcfb413..6d94ea5d 100644 --- a/internal/lint/sts.go +++ b/internal/lint/sts.go @@ -48,7 +48,7 @@ func (s *StatefulSet) Lint(ctx context.Context) error { sts := o.(*appsv1.StatefulSet) fqn := client.FQN(sts.Namespace, sts.Name) s.InitOutcome(fqn) - ctx = internal.WithSpec(ctx, specFor(fqn, sts)) + ctx = internal.WithSpec(ctx, SpecFor(fqn, sts)) s.checkStatefulSet(ctx, sts) s.checkContainers(ctx, fqn, sts) diff --git a/internal/lint/svc.go b/internal/lint/svc.go index 5d81825a..0a401dc7 100644 --- a/internal/lint/svc.go +++ b/internal/lint/svc.go @@ -38,7 +38,7 @@ func (s *Service) Lint(ctx context.Context) error { svc := o.(*v1.Service) fqn := client.FQN(svc.Namespace, svc.Name) s.InitOutcome(fqn) - ctx = internal.WithSpec(ctx, specFor(fqn, svc)) + ctx = internal.WithSpec(ctx, SpecFor(fqn, svc)) if len(svc.Spec.Selector) > 0 { s.checkPorts(ctx, svc.Namespace, svc.Spec.Selector, svc.Spec.Ports) diff --git a/internal/lint/svc_test.go b/internal/lint/svc_test.go index ebbef2be..5381698c 100644 --- a/internal/lint/svc_test.go +++ b/internal/lint/svc_test.go @@ -105,7 +105,7 @@ func Test_svcCheckEndpoints(t *testing.T) { s := NewService(test.MakeCollector(t), dba) if u.fqn != "" { - ctx = internal.WithSpec(ctx, specFor(u.fqn, nil)) + ctx = internal.WithSpec(ctx, SpecFor(u.fqn, nil)) } s.checkEndpoints(ctx, u.fqn, u.kind) diff --git a/internal/scrub/cache.go b/internal/scrub/cache.go index 98aafebd..66b60146 100644 --- a/internal/scrub/cache.go +++ b/internal/scrub/cache.go @@ -10,7 +10,6 @@ import ( "github.com/derailed/popeye/internal/cache" "github.com/derailed/popeye/internal/dag" "github.com/derailed/popeye/internal/db" - "github.com/derailed/popeye/internal/issues" "github.com/derailed/popeye/pkg/config" "github.com/derailed/popeye/types" ) @@ -48,10 +47,9 @@ func (c *Cache) cluster(ctx context.Context) (*cache.Cluster, error) { return c.cl, nil } -type scrubFn func(context.Context, *Cache, *issues.Codes) Linter - -func Scrubers() map[internal.R]scrubFn { - return map[internal.R]scrubFn{ +// Scrubers return a collection of linter scrubbers. +func Scrubers() map[internal.R]ScrubFn { + return map[internal.R]ScrubFn{ internal.CL: NewCluster, internal.CM: NewConfigMap, internal.NS: NewNamespace, diff --git a/internal/test/helpers.go b/internal/test/helpers.go index b31904f4..89a34383 100644 --- a/internal/test/helpers.go +++ b/internal/test/helpers.go @@ -10,6 +10,7 @@ import ( "testing" "github.com/derailed/popeye/internal" + "github.com/derailed/popeye/internal/cilium" "github.com/derailed/popeye/internal/db" "github.com/derailed/popeye/internal/db/schema" "github.com/derailed/popeye/internal/issues" @@ -27,6 +28,7 @@ import ( func NewTestDB() (*db.DB, error) { initLinters() + initCiliumLinters() d, err := memdb.NewMemDB(schema.Init()) if err != nil { return nil, err @@ -35,6 +37,13 @@ func NewTestDB() (*db.DB, error) { return db.NewDB(d), nil } +func initCiliumLinters() { + internal.Glossary[cilium.CID] = types.NewGVR("cilium.io/v2/ciliumidentities") + internal.Glossary[cilium.CEP] = types.NewGVR("cilium.io/v2/ciliumendpoints") + internal.Glossary[cilium.CNP] = types.NewGVR("cilium.io/v2/ciliumnetworkpolicies") + internal.Glossary[cilium.CCNP] = types.NewGVR("cilium.io/v2/ciliumclusterwidenetworkpolicies") +} + func initLinters() { internal.Glossary = internal.Linters{ internal.CM: types.NewGVR("v1/configmaps"),