Repository: zegl/kube-score
Pull request #29 (2018-10-09 18:46:45)

score: add Service Targets Pod check


Patch:
diff --git a/score/score.go b/score/score.go
index b37262c..161046f 100644
--- a/score/score.go
+++ b/score/score.go
@@ -195,6 +195,10 @@ func Score(config Configuration) (*scorecard.Scorecard, error) {
 		scoreContainerSecurityContext,
 	}
 
+	serviceTests := []func(corev1.ServiceSpec) scorecard.TestScore{
+		scoreServiceTargetsPod(pods, podspecers),
+	}
+
 	scoreCard := scorecard.New()
 
 	for _, meta := range typeMetas {
@@ -224,5 +228,13 @@ func Score(config Configuration) (*scorecard.Scorecard, error) {
 		}
 	}
 
+	for _, service := range services {
+		for _, serviceTest := range serviceTests {
+			score := serviceTest(service.Spec)
+			score.AddMeta(service.TypeMeta, service.ObjectMeta)
+			scoreCard.Add(score)
+		}
+	}
+
 	return scoreCard, nil
 }
diff --git a/score/service.go b/score/service.go
new file mode 100644
index 0000000..7ca2e11
--- /dev/null
+++ b/score/service.go
@@ -0,0 +1,44 @@
+package score
+
+import "github.com/zegl/kube-score/scorecard"
+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
+
+	for _, pod := range pods {
+		allPodsWithLabels = append(allPodsWithLabels, pod.Labels)
+	}
+
+	for _, podSpec := range podspecers {
+		allPodsWithLabels = append(allPodsWithLabels, podSpec.GetPodTemplateSpec().Labels)
+	}
+
+	return func(spec corev1.ServiceSpec) (score scorecard.TestScore) {
+		score.Name = "Service Targets Pod"
+
+		hasMatch := false
+
+		for _, podLables := range allPodsWithLabels {
+			matchCount := 0
+			for selectorKey, selectorVal := range spec.Selector {
+				if labelVal, ok := podLables[selectorKey]; ok && labelVal == selectorVal {
+					matchCount++
+				}
+			}
+			if matchCount == len(spec.Selector) {
+				hasMatch = true
+			}
+		}
+
+		if hasMatch {
+			score.Grade = 10
+		} else {
+			score.AddComment("" , "The services selector does not match any pods", "")
+		}
+
+		return
+	}
+}


Test patch:
diff --git a/score/service_test.go b/score/service_test.go
new file mode 100644
index 0000000..113ea50
--- /dev/null
+++ b/score/service_test.go
@@ -0,0 +1,27 @@
+package score
+
+import "testing"
+
+func TestServiceTargetsPodDeployment(t *testing.T) {
+	testExpectedScore(t, "service-target-deployment.yaml", "Service Targets Pod", 10)
+}
+
+func TestServiceNotTargetsPodDeployment(t *testing.T) {
+	testExpectedScore(t, "service-not-target-deployment.yaml", "Service Targets Pod", 0)
+}
+
+func TestServiceTargetsPodRaw(t *testing.T) {
+	testExpectedScore(t, "service-target-pod.yaml", "Service Targets Pod", 10)
+}
+
+func TestServiceNotTargetsPodRaw(t *testing.T) {
+	testExpectedScore(t, "service-not-target-pod.yaml", "Service Targets Pod", 0)
+}
+
+func TestServiceTargetsPodRawMultiLabel(t *testing.T) {
+	testExpectedScore(t, "service-target-pod-multi-label.yaml", "Service Targets Pod", 10)
+}
+
+func TestServiceNotTargetsPodRawMultiLabel(t *testing.T) {
+	testExpectedScore(t, "service-not-target-pod-multi-label.yaml", "Service Targets Pod", 0)
+}
\ No newline at end of file
diff --git a/score/testdata/service-not-target-deployment.yaml b/score/testdata/service-not-target-deployment.yaml
new file mode 100644
index 0000000..2fb5b86
--- /dev/null
+++ b/score/testdata/service-not-target-deployment.yaml
@@ -0,0 +1,25 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: deployment-test-1
+spec:
+  template:
+    metadata:
+      labels:
+        app: my-app
+    spec:
+      containers:
+      - name: foobar
+        image: foo/bar:123
+---
+kind: Service
+apiVersion: v1
+metadata:
+  name: my-service-no-match
+spec:
+  selector:
+    app: my-app-no-match
+  ports:
+  - protocol: TCP
+    port: 80
+    targetPort: 8080
diff --git a/score/testdata/service-not-target-pod-multi-label.yaml b/score/testdata/service-not-target-pod-multi-label.yaml
new file mode 100644
index 0000000..d86a516
--- /dev/null
+++ b/score/testdata/service-not-target-pod-multi-label.yaml
@@ -0,0 +1,24 @@
+apiVersion: v1
+kind: Pod
+metadata:
+  name: pod-test-1
+  labels:
+    app: my-app
+    foo: bar
+spec:
+  containers:
+  - name: foobar
+    image: foo/bar:latest
+---
+kind: Service
+apiVersion: v1
+metadata:
+  name: my-service
+spec:
+  selector:
+    app: my-app
+    foo: bar-not-matching
+  ports:
+  - protocol: TCP
+    port: 80
+    targetPort: 8080
diff --git a/score/testdata/service-not-target-pod.yaml b/score/testdata/service-not-target-pod.yaml
new file mode 100644
index 0000000..e1c0a81
--- /dev/null
+++ b/score/testdata/service-not-target-pod.yaml
@@ -0,0 +1,22 @@
+apiVersion: v1
+kind: Pod
+metadata:
+  name: pod-test-1
+  labels:
+    app: my-app
+spec:
+  containers:
+  - name: foobar
+    image: foo/bar:latest
+---
+kind: Service
+apiVersion: v1
+metadata:
+  name: my-service
+spec:
+  selector:
+    app: my-app-not-matching
+  ports:
+  - protocol: TCP
+    port: 80
+    targetPort: 8080
diff --git a/score/testdata/service-target-deployment.yaml b/score/testdata/service-target-deployment.yaml
new file mode 100644
index 0000000..c723980
--- /dev/null
+++ b/score/testdata/service-target-deployment.yaml
@@ -0,0 +1,25 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: deployment-test-1
+spec:
+  template:
+    metadata:
+      labels:
+        app: my-app
+    spec:
+      containers:
+      - name: foobar
+        image: foo/bar:123
+---
+kind: Service
+apiVersion: v1
+metadata:
+  name: my-service
+spec:
+  selector:
+    app: my-app
+  ports:
+  - protocol: TCP
+    port: 80
+    targetPort: 8080
diff --git a/score/testdata/service-target-pod-multi-label.yaml b/score/testdata/service-target-pod-multi-label.yaml
new file mode 100644
index 0000000..6fdfb4c
--- /dev/null
+++ b/score/testdata/service-target-pod-multi-label.yaml
@@ -0,0 +1,24 @@
+apiVersion: v1
+kind: Pod
+metadata:
+  name: pod-test-1
+  labels:
+    app: my-app
+    foo: bar
+spec:
+  containers:
+  - name: foobar
+    image: foo/bar:latest
+---
+kind: Service
+apiVersion: v1
+metadata:
+  name: my-service
+spec:
+  selector:
+    app: my-app
+    foo: bar
+  ports:
+  - protocol: TCP
+    port: 80
+    targetPort: 8080
diff --git a/score/testdata/service-target-pod.yaml b/score/testdata/service-target-pod.yaml
new file mode 100644
index 0000000..dde8f4b
--- /dev/null
+++ b/score/testdata/service-target-pod.yaml
@@ -0,0 +1,22 @@
+apiVersion: v1
+kind: Pod
+metadata:
+  name: pod-test-1
+  labels:
+    app: my-app
+spec:
+  containers:
+  - name: foobar
+    image: foo/bar:latest
+---
+kind: Service
+apiVersion: v1
+metadata:
+  name: my-service
+spec:
+  selector:
+    app: my-app
+  ports:
+  - protocol: TCP
+    port: 80
+    targetPort: 8080