Skip to content

Commit

Permalink
all: setup initial project and a first test for pods and deployments
Browse files Browse the repository at this point in the history
  • Loading branch information
zegl committed Sep 16, 2018
0 parents commit d99c77b
Show file tree
Hide file tree
Showing 8 changed files with 325 additions and 0 deletions.
28 changes: 28 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
module github.com/zegl/kube-score

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/gogo/protobuf v1.1.1 // indirect
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf // indirect
github.com/ikgo/gocode v0.0.0-20180912135031-6e257e1c6842 // indirect
github.com/json-iterator/go v1.1.5 // indirect
github.com/labstack/echo v3.2.1+incompatible // indirect
github.com/labstack/gommon v0.2.7 // indirect
github.com/mattn/go-colorable v0.0.9 // indirect
github.com/mattn/go-isatty v0.0.4 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/testify v1.2.2
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v0.0.0-20170224212429-dcecefd839c4 // indirect
golang.org/x/crypto v0.0.0-20180910181607-0e37d006457b // indirect
golang.org/x/net v0.0.0-20180911220305-26e67e76b6c3 // indirect
golang.org/x/text v0.3.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.2.0
k8s.io/api v0.0.0-20180913155108-f456898a08e4
k8s.io/apimachinery v0.0.0-20180912233634-99c5fa21f872
)
55 changes: 55 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf h1:+RRA9JqSOZFfKrOeqr2z77+8R2RKyh8PG66dcu1V0ck=
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
github.com/ikgo/gocode v0.0.0-20180912135031-6e257e1c6842 h1:xEjS0/c3SJtqJZgoxJsB89FKwaYfWEgowP09Uf635dY=
github.com/ikgo/gocode v0.0.0-20180912135031-6e257e1c6842/go.mod h1:/vQ5DCTq0XUco6jXwdF04kI1ek0jqRrI8YtYY1VJ+sY=
github.com/json-iterator/go v1.1.5 h1:gL2yXlmiIo4+t+y32d4WGwOjKGYcGOuyrg46vadswDE=
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/labstack/echo v3.2.1+incompatible h1:J2M7YArHx4gi8p/3fDw8tX19SXhBCoRpviyAZSN3I88=
github.com/labstack/echo v3.2.1+incompatible/go.mod h1:0INS7j/VjnFxD4E2wkz67b8cVwCLbBmJyDaka6Cmk1s=
github.com/labstack/gommon v0.2.7 h1:2qOPq/twXDrQ6ooBGrn3mrmVOC+biLlatwgIu8lbzRM=
github.com/labstack/gommon v0.2.7/go.mod h1:/tj9csK2iPSBvn+3NLM9e52usepMtrd5ilFYA+wQNJ4=
github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v0.0.0-20170224212429-dcecefd839c4 h1:gKMu1Bf6QINDnvyZuTaACm9ofY+PRh+5vFz4oxBZeF8=
github.com/valyala/fasttemplate v0.0.0-20170224212429-dcecefd839c4/go.mod h1:50wTf68f99/Zt14pr046Tgt3Lp2vLyFZKzbFXTOabXw=
golang.org/x/crypto v0.0.0-20180910181607-0e37d006457b h1:2b9XGzhjiYsYPnKXoEfL7klWZQIt8IfyRCz62gCqqlQ=
golang.org/x/crypto v0.0.0-20180910181607-0e37d006457b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/net v0.0.0-20180911220305-26e67e76b6c3 h1:czFLhve3vsQetD6JOJ8NZZvGQIXlnN3/yXxbT6/awxI=
golang.org/x/net v0.0.0-20180911220305-26e67e76b6c3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20180831211245-7ca132754999 h1:mf2VYfMpSMTlp0I/UXrX13w5LejDx34QeUUHH4TrUA8=
golang.org/x/tools v0.0.0-20180831211245-7ca132754999/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/yaml.v2 v2.0.0 h1:uUkhRGrsEyx/laRdeS6YIQKIys8pg+lRSRdVMTYjivs=
gopkg.in/yaml.v2 v2.0.0/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.0 h1:ucE2Go3MGv/WipgucyA7X3+4pRLSbl5sd8WaEs60obQ=
gopkg.in/yaml.v2 v2.2.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
k8s.io/api v0.0.0-20180913155108-f456898a08e4 h1:ULsewO4HnVexbLMSexmlht7KBZgsrSHaFCiekvs+1eg=
k8s.io/api v0.0.0-20180913155108-f456898a08e4/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA=
k8s.io/apimachinery v0.0.0-20180912233634-99c5fa21f872 h1:gCsLgEftNQkx/C6l4elbT4r/wrwU2M76IPhRQYuohWY=
k8s.io/apimachinery v0.0.0-20180912233634-99c5fa21f872/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0=
148 changes: 148 additions & 0 deletions score/score.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
package score

import (
"io"
"io/ioutil"
"log"

"gopkg.in/yaml.v2"

//"errors"
//"fmt"
// "github.com/labstack/echo"
// "k8s.io/api/admission/v1beta1"
appsv1 "k8s.io/api/apps/v1"
// batchv1 "k8s.io/api/batch/v1"
// batchv1beta1 "k8s.io/api/batch/v1beta1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer"
// "reflect"
)

var scheme = runtime.NewScheme()
var codecs = serializer.NewCodecFactory(scheme)

func init() {
addToScheme(scheme)
}

func addToScheme(scheme *runtime.Scheme) {
corev1.AddToScheme(scheme)
appsv1.AddToScheme(scheme)
// batchv1.AddToScheme(scheme)
// batchv1beta1.AddToScheme(scheme)
// v1beta1.AddToScheme(scheme)
}

type Scorecard struct {
Scores []TestScore
}

type TestScore struct {
Name string
Description string
Grade int
Comments []string
}

func Score(file io.Reader) (*Scorecard, error) {
allData, err := ioutil.ReadAll(file)
if err != nil {
return nil, err
}

type detectKind struct {
Kind string `yaml:"kind"`
}

var detect detectKind
err = yaml.Unmarshal(allData, &detect)
if err != nil {
return nil, err
}

var pods []corev1.Pod
var deployments []appsv1.Deployment

decode := func(data []byte, object runtime.Object) {
deserializer := codecs.UniversalDeserializer()
if _, _, err := deserializer.Decode(data, nil, object); err != nil {
panic(err)
}
}

switch detect.Kind {
case "Pod":
var pod corev1.Pod
decode(allData, &pod)
pods = append(pods, pod)

case "Deployment":
var deployment appsv1.Deployment
decode(allData, &deployment)
deployments = append(deployments, deployment)
}

podTests := []func(corev1.PodSpec) TestScore{
scoreContainerLimits,
}

scoreCard := Scorecard{}

for _, pod := range pods {
for _, podTest := range podTests {
scoreCard.Scores = append(scoreCard.Scores, podTest(pod.Spec))
}
}

for _, deployment := range deployments {
for _, podTest := range podTests {
scoreCard.Scores = append(scoreCard.Scores, podTest(deployment.Spec.Template.Spec))
}
}

return &scoreCard, nil
}

func scoreContainerLimits(pod corev1.PodSpec) (score TestScore) {
score.Name = "Container Resources"

allContainers := pod.InitContainers
allContainers = append(allContainers, pod.Containers...)

hasMissingLimit := false
hasMissingRequest := false

for _, container := range allContainers {
if container.Resources.Limits.Cpu().IsZero() {
score.Comments = append(score.Comments, "CPU limit is not set")
hasMissingLimit = true
}
if container.Resources.Limits.Memory().IsZero() {
score.Comments = append(score.Comments, "Memory limit is not set")
hasMissingLimit = true
}
if container.Resources.Requests.Cpu().IsZero() {
score.Comments = append(score.Comments, "CPU request is not set")
hasMissingRequest = true
}
if container.Resources.Requests.Memory().IsZero() {
score.Comments = append(score.Comments, "Memory request is not set")
hasMissingRequest = true
}
}

if len(allContainers) == 0 {
score.Grade = 0
score.Comments = append(score.Comments, "No containers defined")
} else if hasMissingLimit {
score.Grade = 0
} else if hasMissingRequest {
score.Grade = 5
} else {
score.Grade = 10
}

return
}
44 changes: 44 additions & 0 deletions score/score_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package score

import (
"github.com/stretchr/testify/assert"
"os"
"testing"
)

func testFile(name string) *os.File {
fp, err := os.Open("testdata/" + name)
if err != nil {
panic(err)
}
return fp
}

func testExpectedScore(t *testing.T, filename string, testcase string, expectedScore int) {
sc, err := Score(testFile(filename))
assert.NoError(t, err)
tested := false
for _, s := range sc.Scores {
if s.Name == testcase {
assert.Equal(t, expectedScore, s.Grade)
tested = true
}
}
assert.True(t, tested, "Was not tested")
}

func TestPodContainerNoResources(t *testing.T) {
testExpectedScore(t, "pod-test-resources-none.yaml", "Container Resources", 0)
}

func TestPodContainerResourceLimits(t *testing.T) {
testExpectedScore(t, "pod-test-resources-only-limits.yaml", "Container Resources", 5)
}

func TestPodContainerResourceLimitsAndRequests(t *testing.T) {
testExpectedScore(t, "pod-test-resources-limits-and-requests.yaml", "Container Resources", 10)
}

func TestDeploymentResources(t *testing.T) {
testExpectedScore(t, "deployment-test-resources.yaml", "Container Resources", 5)
}
15 changes: 15 additions & 0 deletions score/testdata/deployment-test-resources.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment-test-1
spec:
template:
spec:
containers:
- name: foobar
image: foo/bar:123
resources:
limits:
cpu: 200m
memory: 1Gi

15 changes: 15 additions & 0 deletions score/testdata/pod-test-resources-limits-and-requests.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
apiVersion: v1
kind: Pod
metadata:
name: pod-test-1
spec:
containers:
- name: foobar
image: foo/bar:123
resources:
limits:
cpu: 200m
memory: 1Gi
requests:
cpu: 200m
memory: 1Gi
8 changes: 8 additions & 0 deletions score/testdata/pod-test-resources-none.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
apiVersion: v1
kind: Pod
metadata:
name: pod-test-1
spec:
containers:
- name: foobar
image: foo/bar:123
12 changes: 12 additions & 0 deletions score/testdata/pod-test-resources-only-limits.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
apiVersion: v1
kind: Pod
metadata:
name: pod-test-1
spec:
containers:
- name: foobar
image: foo/bar:123
resources:
limits:
cpu: 200m
memory: 1Gi

0 comments on commit d99c77b

Please sign in to comment.