Repository: zegl/kube-score
Pull request #32 (2018-10-10 20:17:15)

probes: namespace support in pod probe targeted by service detection


Patch:
diff --git a/score/container.go b/score/container.go
index 373a0d1..05244e4 100644
--- a/score/container.go
+++ b/score/container.go
@@ -120,9 +120,11 @@ func scoreContainerProbes(allServices []corev1.Service) func(corev1.PodTemplateS
 		isTargetedByService := false
 
 		for _, service := range allServices {
-			for selectorKey, selectorVal := range service.Spec.Selector {
-				if podLabelVal, ok := podTemplate.Labels[selectorKey]; ok && podLabelVal == selectorVal {
-					isTargetedByService = true
+			if podTemplate.Namespace == service.Namespace {
+				for selectorKey, selectorVal := range service.Spec.Selector {
+					if podLabelVal, ok := podTemplate.Labels[selectorKey]; ok && podLabelVal == selectorVal {
+						isTargetedByService = true
+					}
 				}
 			}
 		}
diff --git a/score/score.go b/score/score.go
index 161046f..0cebd97 100644
--- a/score/score.go
+++ b/score/score.go
@@ -195,7 +195,7 @@ func Score(config Configuration) (*scorecard.Scorecard, error) {
 		scoreContainerSecurityContext,
 	}
 
-	serviceTests := []func(corev1.ServiceSpec) scorecard.TestScore{
+	serviceTests := []func(corev1.Service) scorecard.TestScore{
 		scoreServiceTargetsPod(pods, podspecers),
 	}
 
@@ -230,7 +230,7 @@ func Score(config Configuration) (*scorecard.Scorecard, error) {
 
 	for _, service := range services {
 		for _, serviceTest := range serviceTests {
-			score := serviceTest(service.Spec)
+			score := serviceTest(service)
 			score.AddMeta(service.TypeMeta, service.ObjectMeta)
 			scoreCard.Add(score)
 		}
diff --git a/score/service.go b/score/service.go
index 7ca2e11..f07b02f 100644
--- a/score/service.go
+++ b/score/service.go
@@ -5,30 +5,36 @@ import corev1 "k8s.io/api/core/v1"
 
 // scoreServiceTargetsPod checks if a Service targets a pod and issues a critical warning if no matching pod
 // could be found
-func scoreServiceTargetsPod(pods []corev1.Pod, podspecers []PodSpecer) func(spec corev1.ServiceSpec) scorecard.TestScore {
-	var allPodsWithLabels []map[string]string
+func scoreServiceTargetsPod(pods []corev1.Pod, podspecers []PodSpecer) func(corev1.Service) scorecard.TestScore {
+	podsInNamespace := make(map[string][]map[string]string)
 
 	for _, pod := range pods {
-		allPodsWithLabels = append(allPodsWithLabels, pod.Labels)
+		if _, ok := podsInNamespace[pod.Namespace]; !ok {
+			podsInNamespace[pod.Namespace] = []map[string]string{}
+		}
+		podsInNamespace[pod.Namespace] = append(podsInNamespace[pod.Namespace], pod.Labels)
 	}
 
 	for _, podSpec := range podspecers {
-		allPodsWithLabels = append(allPodsWithLabels, podSpec.GetPodTemplateSpec().Labels)
+		if _, ok := podsInNamespace[podSpec.GetObjectMeta().Namespace]; !ok {
+			podsInNamespace[podSpec.GetObjectMeta().Namespace] = []map[string]string{}
+		}
+		podsInNamespace[podSpec.GetObjectMeta().Namespace] = append(podsInNamespace[podSpec.GetObjectMeta().Namespace], podSpec.GetPodTemplateSpec().Labels)
 	}
 
-	return func(spec corev1.ServiceSpec) (score scorecard.TestScore) {
+	return func(service corev1.Service) (score scorecard.TestScore) {
 		score.Name = "Service Targets Pod"
 
 		hasMatch := false
 
-		for _, podLables := range allPodsWithLabels {
+		for _, podLables := range podsInNamespace[service.Namespace] {
 			matchCount := 0
-			for selectorKey, selectorVal := range spec.Selector {
+			for selectorKey, selectorVal := range service.Spec.Selector {
 				if labelVal, ok := podLables[selectorKey]; ok && labelVal == selectorVal {
 					matchCount++
 				}
 			}
-			if matchCount == len(spec.Selector) {
+			if matchCount == len(service.Spec.Selector) {
 				hasMatch = true
 			}
 		}


Test patch:
diff --git a/score/score_test.go b/score/score_test.go
index 9bd9f30..8a1be50 100644
--- a/score/score_test.go
+++ b/score/score_test.go
@@ -134,6 +134,20 @@ func TestProbesTargetedByService(t *testing.T) {
 	testExpectedScore(t, "pod-probes-targeted-by-service.yaml", "Pod Probes", 0)
 }
 
+func TestProbesTargetedByServiceSameNamespace(t *testing.T) {
+	comments := testGetComments(t, "pod-probes-targeted-by-service-same-namespace.yaml", "Pod Probes")
+	assert.Len(t, comments, 1)
+	assert.Equal(t, "Container is missing a readinessProbe", comments[0].Summary)
+
+	testExpectedScore(t, "pod-probes-targeted-by-service-same-namespace.yaml", "Pod Probes", 0)
+}
+
+func TestProbesTargetedByServiceDifferentNamespace(t *testing.T) {
+	comments := testGetComments(t, "pod-probes-targeted-by-service-different-namespace.yaml", "Pod Probes")
+	assert.Len(t, comments, 0)
+	testExpectedScore(t, "pod-probes-targeted-by-service-different-namespace.yaml", "Pod Probes", 10)
+}
+
 func TestProbesTargetedByServiceNotTargeted(t *testing.T) {
 	testExpectedScore(t, "pod-probes-not-targeted-by-service.yaml", "Pod Probes", 10)
 }
diff --git a/score/service_test.go b/score/service_test.go
index 113ea50..53fd1ac 100644
--- a/score/service_test.go
+++ b/score/service_test.go
@@ -24,4 +24,20 @@ func TestServiceTargetsPodRawMultiLabel(t *testing.T) {
 
 func TestServiceNotTargetsPodRawMultiLabel(t *testing.T) {
 	testExpectedScore(t, "service-not-target-pod-multi-label.yaml", "Service Targets Pod", 0)
-}
\ No newline at end of file
+}
+
+func TestServiceTargetsPodRawSameNamespace(t *testing.T) {
+	testExpectedScore(t, "service-target-pod-same-namespace.yaml", "Service Targets Pod", 10)
+}
+
+func TestServiceTargetsPodRawDifferentNamespace(t *testing.T) {
+	testExpectedScore(t, "service-target-pod-different-namespace.yaml", "Service Targets Pod", 0)
+}
+
+func TestServiceTargetsPodDeploymentSameNamespace(t *testing.T) {
+	testExpectedScore(t, "service-target-deployment-same-namespace.yaml", "Service Targets Pod", 10)
+}
+
+func TestServiceTargetsPodDeploymentDifferentNamespace(t *testing.T) {
+	testExpectedScore(t, "service-target-deployment-different-namespace.yaml", "Service Targets Pod", 0)
+}
diff --git a/score/testdata/pod-probes-targeted-by-service-different-namespace.yaml b/score/testdata/pod-probes-targeted-by-service-different-namespace.yaml
new file mode 100644
index 0000000..6f7469a
--- /dev/null
+++ b/score/testdata/pod-probes-targeted-by-service-different-namespace.yaml
@@ -0,0 +1,28 @@
+apiVersion: v1
+kind: Pod
+metadata:
+  name: pod-test-1
+  namespace: foospace
+  labels:
+    app: my-app
+spec:
+  containers:
+  - name: foobar
+    image: foo/bar:latest
+    livenessProbe:
+      httpGet:
+        path: /ready
+        port: 8080
+---
+kind: Service
+apiVersion: v1
+metadata:
+  name: my-service
+  namespace: not-foospace
+spec:
+  selector:
+    app: my-app
+  ports:
+  - protocol: TCP
+    port: 80
+    targetPort: 8080
diff --git a/score/testdata/pod-probes-targeted-by-service-same-namespace.yaml b/score/testdata/pod-probes-targeted-by-service-same-namespace.yaml
new file mode 100644
index 0000000..e673348
--- /dev/null
+++ b/score/testdata/pod-probes-targeted-by-service-same-namespace.yaml
@@ -0,0 +1,28 @@
+apiVersion: v1
+kind: Pod
+metadata:
+  name: pod-test-1
+  namespace: foospace
+  labels:
+    app: my-app
+spec:
+  containers:
+  - name: foobar
+    image: foo/bar:latest
+    livenessProbe:
+      httpGet:
+        path: /ready
+        port: 8080
+---
+kind: Service
+apiVersion: v1
+metadata:
+  name: my-service
+  namespace: foospace
+spec:
+  selector:
+    app: my-app
+  ports:
+  - protocol: TCP
+    port: 80
+    targetPort: 8080
diff --git a/score/testdata/service-target-deployment-different-namespace.yaml b/score/testdata/service-target-deployment-different-namespace.yaml
new file mode 100644
index 0000000..23a1134
--- /dev/null
+++ b/score/testdata/service-target-deployment-different-namespace.yaml
@@ -0,0 +1,27 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: deployment-test-1
+  namespace: foospace
+spec:
+  template:
+    metadata:
+      labels:
+        app: my-app
+    spec:
+      containers:
+      - name: foobar
+        image: foo/bar:123
+---
+kind: Service
+apiVersion: v1
+metadata:
+  name: my-service
+  namespace: not-foospace
+spec:
+  selector:
+    app: my-app
+  ports:
+  - protocol: TCP
+    port: 80
+    targetPort: 8080
diff --git a/score/testdata/service-target-deployment-same-namespace.yaml b/score/testdata/service-target-deployment-same-namespace.yaml
new file mode 100644
index 0000000..6b29e02
--- /dev/null
+++ b/score/testdata/service-target-deployment-same-namespace.yaml
@@ -0,0 +1,27 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: deployment-test-1
+  namespace: foospace
+spec:
+  template:
+    metadata:
+      labels:
+        app: my-app
+    spec:
+      containers:
+      - name: foobar
+        image: foo/bar:123
+---
+kind: Service
+apiVersion: v1
+metadata:
+  name: my-service
+  namespace: foospace
+spec:
+  selector:
+    app: my-app
+  ports:
+  - protocol: TCP
+    port: 80
+    targetPort: 8080
diff --git a/score/testdata/service-target-pod-different-namespace.yaml b/score/testdata/service-target-pod-different-namespace.yaml
new file mode 100644
index 0000000..2d781e8
--- /dev/null
+++ b/score/testdata/service-target-pod-different-namespace.yaml
@@ -0,0 +1,24 @@
+apiVersion: v1
+kind: Pod
+metadata:
+  name: pod-test-1
+  namespace: foospace
+  labels:
+    app: my-app
+spec:
+  containers:
+  - name: foobar
+    image: foo/bar:latest
+---
+kind: Service
+apiVersion: v1
+metadata:
+  name: my-service
+  namespace: not-foospace
+spec:
+  selector:
+    app: my-app
+  ports:
+  - protocol: TCP
+    port: 80
+    targetPort: 8080
diff --git a/score/testdata/service-target-pod-same-namespace.yaml b/score/testdata/service-target-pod-same-namespace.yaml
new file mode 100644
index 0000000..2094d86
--- /dev/null
+++ b/score/testdata/service-target-pod-same-namespace.yaml
@@ -0,0 +1,24 @@
+apiVersion: v1
+kind: Pod
+metadata:
+  name: pod-test-1
+  namespace: foospace
+  labels:
+    app: my-app
+spec:
+  containers:
+  - name: foobar
+    image: foo/bar:latest
+---
+kind: Service
+apiVersion: v1
+metadata:
+  name: my-service
+  namespace: foospace
+spec:
+  selector:
+    app: my-app
+  ports:
+  - protocol: TCP
+    port: 80
+    targetPort: 8080