Repository: zegl/kube-score
Pull request #141 (2019-06-18 17:30:26)

score: don't execute tests that are ignored


Patch:
diff --git a/cmd/kube-score/main.go b/cmd/kube-score/main.go
index 4cc63c3..f388acf 100644
--- a/cmd/kube-score/main.go
+++ b/cmd/kube-score/main.go
@@ -134,11 +134,17 @@ Use "-" as filename to read from STDIN.`)
 		allFilePointers = append(allFilePointers, fp)
 	}
 
+	ignoredTests := make(map[string]struct{})
+	for _, testID := range *ignoreTests {
+		ignoredTests[testID] = struct{}{}
+	}
+
 	cnf := config.Configuration{
 		AllFiles:                              allFilePointers,
 		VerboseOutput:                         *verboseOutput,
 		IgnoreContainerCpuLimitRequirement:    *ignoreContainerCpuLimit,
 		IgnoreContainerMemoryLimitRequirement: *ignoreContainerMemoryLimit,
+		IgnoredTests:                          ignoredTests,
 	}
 
 	parsedFiles, err := parser.ParseFiles(cnf)
@@ -151,15 +157,10 @@ Use "-" as filename to read from STDIN.`)
 		return err
 	}
 
-	ignoredTests := make(map[string]struct{})
-	for _, testID := range *ignoreTests {
-		ignoredTests[testID] = struct{}{}
-	}
-
 	var exitCode int
-	if scoreCard.AnyBelowOrEqualToGrade(scorecard.GradeCritical, ignoredTests) {
+	if scoreCard.AnyBelowOrEqualToGrade(scorecard.GradeCritical) {
 		exitCode = 1
-	} else if *exitOneOnWarning && scoreCard.AnyBelowOrEqualToGrade(scorecard.Grade(*warningThreshold), ignoredTests) {
+	} else if *exitOneOnWarning && scoreCard.AnyBelowOrEqualToGrade(scorecard.Grade(*warningThreshold)) {
 		exitCode = 1
 	} else {
 		exitCode = 0
@@ -168,15 +169,14 @@ Use "-" as filename to read from STDIN.`)
 	var r io.Reader
 
 	if *outputFormat == "json" {
-		// TODO: Don't print tests that should be ignored, this is best solved by not executing those tests.
 		d, _ := json.MarshalIndent(scoreCard, "", "    ")
 		w := bytes.NewBufferString("")
 		w.WriteString(string(d))
 		r = w
 	} else if *outputFormat == "human" {
-		r = outputHuman(scoreCard, *okThreshold, *warningThreshold, ignoredTests)
+		r = outputHuman(scoreCard, *okThreshold, *warningThreshold)
 	} else {
-		r = outputCi(scoreCard, *okThreshold, *warningThreshold, ignoredTests)
+		r = outputCi(scoreCard, *okThreshold, *warningThreshold)
 	}
 
 	output, _ := ioutil.ReadAll(r)
@@ -218,7 +218,7 @@ func statusString(grade scorecard.Grade, okThreshold, warningThreshold int) stri
 	}
 }
 
-func outputHuman(scoreCard *scorecard.Scorecard, okThreshold, warningThreshold int, ignoredTests map[string]struct{}) io.Reader {
+func outputHuman(scoreCard *scorecard.Scorecard, okThreshold, warningThreshold int) io.Reader {
 	// Print the items sorted by scorecard key
 	var keys []string
 	for k := range *scoreCard {
@@ -240,10 +240,6 @@ func outputHuman(scoreCard *scorecard.Scorecard, okThreshold, warningThreshold i
 		}
 
 		for _, card := range scoredObject.Checks {
-			if _, ok := ignoredTests[card.Check.ID]; ok {
-				continue
-			}
-
 			r := outputHumanStep(card, okThreshold, warningThreshold)
 			io.Copy(w, r)
 		}
@@ -291,7 +287,7 @@ func outputHumanStep(card scorecard.TestScore, okThreshold, warningThreshold int
 }
 
 // "Machine" / CI friendly output
-func outputCi(scoreCard *scorecard.Scorecard, okThreshold, warningThreshold int, ignoredTests map[string]struct{}) io.Reader {
+func outputCi(scoreCard *scorecard.Scorecard, okThreshold, warningThreshold int) io.Reader {
 	w := bytes.NewBufferString("")
 
 	// Print the items sorted by scorecard key
@@ -305,10 +301,6 @@ func outputCi(scoreCard *scorecard.Scorecard, okThreshold, warningThreshold int,
 		scoredObject := (*scoreCard)[key]
 
 		for _, card := range scoredObject.Checks {
-			if _, ok := ignoredTests[card.Check.ID]; ok {
-				continue
-			}
-
 			if len(card.Comments) == 0 {
 				fmt.Fprintf(w, "[%s] %s\n",
 					statusString(card.Grade, okThreshold, warningThreshold),
diff --git a/config/config.go b/config/config.go
index 359f662..6cf6010 100644
--- a/config/config.go
+++ b/config/config.go
@@ -7,4 +7,5 @@ type Configuration struct {
 	VerboseOutput                         bool
 	IgnoreContainerCpuLimitRequirement    bool
 	IgnoreContainerMemoryLimitRequirement bool
+	IgnoredTests                          map[string]struct{}
 }
diff --git a/score/checks/checks.go b/score/checks/checks.go
index b0ac465..650b67c 100644
--- a/score/checks/checks.go
+++ b/score/checks/checks.go
@@ -10,12 +10,15 @@ import (
 	networkingv1 "k8s.io/api/networking/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
+	"github.com/zegl/kube-score/config"
 	ks "github.com/zegl/kube-score/domain"
 	"github.com/zegl/kube-score/scorecard"
 )
 
-func New() *Checks {
+func New(cnf config.Configuration) *Checks {
 	return &Checks{
+		cnf: cnf,
+
 		all:             make([]ks.Check, 0),
 		metas:           make(map[string]MetaCheck),
 		pods:            make(map[string]PodCheck),
@@ -93,10 +96,22 @@ type Checks struct {
 	networkpolicies map[string]NetworkPolicyCheck
 	ingresses       map[string]IngressCheck
 	cronjobs        map[string]CronJobCheck
+
+	cnf config.Configuration
+}
+
+func (c Checks) isIgnored(id string) bool {
+	_, ok := c.cnf.IgnoredTests[id]
+	return ok
 }
 
 func (c *Checks) RegisterMetaCheck(name, comment string, fn func(meta ks.BothMeta) scorecard.TestScore) {
 	ch := NewCheck(name, "all", comment)
+
+	if c.isIgnored(ch.ID) {
+		return
+	}
+
 	c.all = append(c.all, ch)
 	c.metas[machineFriendlyName(name)] = MetaCheck{ch, fn}
 }
@@ -107,6 +122,11 @@ func (c *Checks) Metas() map[string]MetaCheck {
 
 func (c *Checks) RegisterPodCheck(name, comment string, fn func(corev1.PodTemplateSpec, metav1.TypeMeta) scorecard.TestScore) {
 	ch := NewCheck(name, "Pod", comment)
+
+	if c.isIgnored(ch.ID) {
+		return
+	}
+
 	c.all = append(c.all, ch)
 	c.pods[machineFriendlyName(name)] = PodCheck{ch, fn}
 }
@@ -117,6 +137,11 @@ func (c *Checks) Pods() map[string]PodCheck {
 
 func (c *Checks) RegisterCronJobCheck(name, comment string, fn func(batchv1beta1.CronJob) scorecard.TestScore) {
 	ch := NewCheck(name, "CronJob", comment)
+
+	if c.isIgnored(ch.ID) {
+		return
+	}
+
 	c.all = append(c.all, ch)
 	c.cronjobs[machineFriendlyName(name)] = CronJobCheck{ch, fn}
 }
@@ -127,6 +152,11 @@ func (c *Checks) CronJobs() map[string]CronJobCheck {
 
 func (c *Checks) RegisterStatefulSetCheck(name, comment string, fn func(appsv1.StatefulSet) (scorecard.TestScore, error)) {
 	ch := NewCheck(name, "StatefulSet", comment)
+
+	if c.isIgnored(ch.ID) {
+		return
+	}
+
 	c.all = append(c.all, ch)
 	c.statefulsets[machineFriendlyName(name)] = StatefulSetCheck{ch, fn}
 }
@@ -137,6 +167,11 @@ func (c *Checks) StatefulSets() map[string]StatefulSetCheck {
 
 func (c *Checks) RegisterDeploymentCheck(name, comment string, fn func(appsv1.Deployment) (scorecard.TestScore, error)) {
 	ch := NewCheck(name, "Deployment", comment)
+
+	if c.isIgnored(ch.ID) {
+		return
+	}
+
 	c.all = append(c.all, ch)
 	c.deployments[machineFriendlyName(name)] = DeploymentCheck{ch, fn}
 }
@@ -147,6 +182,11 @@ func (c *Checks) Deployments() map[string]DeploymentCheck {
 
 func (c *Checks) RegisterIngressCheck(name, comment string, fn func(extensionsv1beta1.Ingress) scorecard.TestScore) {
 	ch := NewCheck(name, "Ingress", comment)
+
+	if c.isIgnored(ch.ID) {
+		return
+	}
+
 	c.all = append(c.all, ch)
 	c.ingresses[machineFriendlyName(name)] = IngressCheck{ch, fn}
 }
@@ -157,6 +197,11 @@ func (c *Checks) Ingresses() map[string]IngressCheck {
 
 func (c *Checks) RegisterNetworkPolicyCheck(name, comment string, fn func(networkingv1.NetworkPolicy) scorecard.TestScore) {
 	ch := NewCheck(name, "NetworkPolicy", comment)
+
+	if c.isIgnored(ch.ID) {
+		return
+	}
+
 	c.all = append(c.all, ch)
 	c.networkpolicies[machineFriendlyName(name)] = NetworkPolicyCheck{ch, fn}
 }
@@ -167,6 +212,11 @@ func (c *Checks) NetworkPolicies() map[string]NetworkPolicyCheck {
 
 func (c *Checks) RegisterServiceCheck(name, comment string, fn func(corev1.Service) scorecard.TestScore) {
 	ch := NewCheck(name, "Service", comment)
+
+	if c.isIgnored(ch.ID) {
+		return
+	}
+
 	c.all = append(c.all, ch)
 	c.services[machineFriendlyName(name)] = ServiceCheck{ch, fn}
 }
diff --git a/score/score.go b/score/score.go
index b5d370c..9aaf27f 100644
--- a/score/score.go
+++ b/score/score.go
@@ -21,7 +21,7 @@ import (
 )
 
 func RegisterAllChecks(allObjects ks.AllTypes, cnf config.Configuration) *checks.Checks {
-	allChecks := checks.New()
+	allChecks := checks.New(cnf)
 
 	ingress.Register(allChecks, allObjects)
 	cronjob.Register(allChecks)
diff --git a/scorecard/scorecard.go b/scorecard/scorecard.go
index 9bbb79a..e43b4c7 100644
--- a/scorecard/scorecard.go
+++ b/scorecard/scorecard.go
@@ -1,9 +1,10 @@
 package scorecard
 
 import (
-	ks "github.com/zegl/kube-score/domain"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"strings"
+
+	ks "github.com/zegl/kube-score/domain"
 )
 
 const (
@@ -35,13 +36,9 @@ func (s Scorecard) NewObject(typeMeta metav1.TypeMeta, objectMeta metav1.ObjectM
 	return o
 }
 
-func (s Scorecard) AnyBelowOrEqualToGrade(threshold Grade, ignoredTests map[string]struct{}) bool {
+func (s Scorecard) AnyBelowOrEqualToGrade(threshold Grade) bool {
 	for _, o := range s {
 		for _, s := range o.Checks {
-			if _, ok := ignoredTests[s.Check.ID]; ok {
-				continue
-			}
-
 			if s.Grade <= threshold {
 				return true
 			}
@@ -92,9 +89,9 @@ func (so *ScoredObject) Add(ts TestScore, check ks.Check) {
 }
 
 type TestScore struct {
-	Check ks.Check
-	Grade        Grade
-	Comments     []TestScoreComment
+	Check    ks.Check
+	Grade    Grade
+	Comments []TestScoreComment
 }
 
 type Grade int


Test patch:
diff --git a/cmd/kube-score/output_test.go b/cmd/kube-score/output_test.go
index bb6c1ac..98482d4 100644
--- a/cmd/kube-score/output_test.go
+++ b/cmd/kube-score/output_test.go
@@ -63,10 +63,8 @@ func TestCiOutput(t *testing.T) {
 		},
 	}
 
-	ignoredTests := make(map[string]struct{})
-
 	// Defaults
-	r := outputCi(card, 10, 5, ignoredTests)
+	r := outputCi(card, 10, 5)
 	all, err := ioutil.ReadAll(r)
 	assert.Nil(t, err)
 	assert.Equal(t, `[WARNING] foo/foofoo v1/Testing: (a) summary
@@ -75,7 +73,7 @@ func TestCiOutput(t *testing.T) {
 `, string(all))
 
 	// OK at 9 or higher
-	r = outputCi(card, 9, 5, ignoredTests)
+	r = outputCi(card, 9, 5)
 	all, err = ioutil.ReadAll(r)
 	assert.Nil(t, err)
 	assert.Equal(t, `[OK] foo/foofoo v1/Testing: (a) summary
@@ -84,7 +82,7 @@ func TestCiOutput(t *testing.T) {
 `, string(all))
 
 	// OK at 8 or higher
-	r = outputCi(card, 8, 5, ignoredTests)
+	r = outputCi(card, 8, 5)
 	all, err = ioutil.ReadAll(r)
 	assert.Nil(t, err)
 	assert.Equal(t, `[OK] foo/foofoo v1/Testing: (a) summary
@@ -146,10 +144,8 @@ func TestHumanOutput(t *testing.T) {
 		},
 	}
 
-	ignoredTests := make(map[string]struct{})
-
 	// Defaults
-	r := outputHuman(card, 10, 5, ignoredTests)
+	r := outputHuman(card, 10, 5)
 	all, err := ioutil.ReadAll(r)
 	assert.Nil(t, err)
 	assert.Equal(t, `v1/Testing foo in foofoo
@@ -163,7 +159,7 @@ v1/Testing bar-no-namespace
 `, string(all))
 
 	// OK at 9 or higher
-	r = outputHuman(card, 9, 5, ignoredTests)
+	r = outputHuman(card, 9, 5)
 	all, err = ioutil.ReadAll(r)
 	assert.Nil(t, err)
 	assert.Equal(t, `v1/Testing foo in foofoo
@@ -177,7 +173,7 @@ v1/Testing bar-no-namespace
 `, string(all))
 
 	// OK at 8 or higher
-	r = outputHuman(card, 8, 5, ignoredTests)
+	r = outputHuman(card, 8, 5)
 	all, err = ioutil.ReadAll(r)
 	assert.Nil(t, err)
 	assert.Equal(t, `v1/Testing foo in foofoo
diff --git a/score/testdata/all-ok.yaml b/score/testdata/all-ok.yaml
new file mode 100644
index 0000000..b99ec32
--- /dev/null
+++ b/score/testdata/all-ok.yaml
@@ -0,0 +1,9 @@
+apiVersion: v1
+kind: Pod
+metadata:
+  name: pod-test-1
+spec:
+  containers:
+    - name: foobar
+      image: foo/bar:123
+      imagePullPolicy: Always