From c3bbbde631a00dc02868b3abe7652c9ce6285ff8 Mon Sep 17 00:00:00 2001 From: jessicagreben Date: Mon, 31 Dec 2018 11:21:46 -0800 Subject: [PATCH] add image and healthcheck config and checks --- deploy/all.yaml | 9 ++++----- pkg/config/config.go | 25 +++++++++++++++++++++++- pkg/config/config_test.go | 4 ++-- pkg/validator/container.go | 39 +++++++++++++++++++------------------- 4 files changed, 50 insertions(+), 27 deletions(-) diff --git a/deploy/all.yaml b/deploy/all.yaml index 248c881a..e7b2809c 100644 --- a/deploy/all.yaml +++ b/deploy/all.yaml @@ -81,16 +81,15 @@ data: whitelist: - '*.example.com' prevent_overlaps: true - health_checks: + healthchecks: readiness: require: true liveness: require: true images: - require_tag: true - repos: - whitelist: - - gcr.io + tagRequired: true + whitelistRepos: + - gcr.io namespaces: require_labels: true security_context: diff --git a/pkg/config/config.go b/pkg/config/config.go index 44629992..e6de771e 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -5,25 +5,32 @@ import ( "fmt" "io" "io/ioutil" + corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/util/yaml" ) +// ResourceMinMax sets a range for a min and max setting for a resource. type ResourceMinMax struct { Min *resource.Quantity Max *resource.Quantity } +// ResourceList does x. type ResourceList map[corev1.ResourceName]ResourceMinMax +// RequestsAndLimits contains config for resource requests and limits. type RequestsAndLimits struct { Requests ResourceList Limits ResourceList } +// Configuration contains all of the config for the validation checks. type Configuration struct { - Resources RequestsAndLimits + Resources RequestsAndLimits + Healthchecks Probes + Images Images } // ParseFile parses config from a file @@ -49,3 +56,19 @@ func Parse(rawBytes []byte) (Configuration, error) { } } } + +// Probes contains config for the readiness and liveness probes. +type Probes struct { + Readiness resourceRequire + Liveness resourceRequire +} + +type resourceRequire map[require]bool + +type require string + +// Images contains the config for images. +type Images struct { + TagRequired bool + WhitelistRepos []string +} diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index d35bf714..96e290e0 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -41,7 +41,7 @@ resources: max: 4G ` -var resourceConfJson1 = `{ +var resourceConfJSON1 = `{ "resources": { "requests": { "cpu": { @@ -89,7 +89,7 @@ func TestParseYaml(t *testing.T) { } func TestParseJson(t *testing.T) { - parsedConf, err := Parse([]byte(resourceConfJson1)) + parsedConf, err := Parse([]byte(resourceConfJSON1)) assert.NoError(t, err, "Expected no error when parsing config") requests := parsedConf.Resources.Requests diff --git a/pkg/validator/container.go b/pkg/validator/container.go index 305f4e35..259fafd9 100644 --- a/pkg/validator/container.go +++ b/pkg/validator/container.go @@ -15,6 +15,8 @@ package validator import ( + "strings" + conf "github.com/reactiveops/fairwinds/pkg/config" "github.com/reactiveops/fairwinds/pkg/types" corev1 "k8s.io/api/core/v1" @@ -33,8 +35,8 @@ func validateContainer(conf conf.Configuration, container corev1.Container) Cont } cv.validateResources(conf.Resources) - // cv.validateHealthChecks(conf.HealthChecks) - // cv.validateTags(conf.Image) + cv.validateHealthChecks(conf.Healthchecks) + cv.validateImage(conf.Images) return cv } @@ -65,24 +67,23 @@ func (cv *ContainerValidation) withinRange(resourceName string, expectedRange co } } -// func probes(conf conf.ResourceRequestsAndLimits, c corev1.Container, results types.ContainerResults) types.ContainerResults { -// if c.ReadinessProbe == nil { -// results.AddFailure("Readiness Probe", "placeholder", "placeholder") -// } +func (cv *ContainerValidation) validateHealthChecks(conf conf.Probes) { + if conf.Readiness["require"] && cv.Container.ReadinessProbe == nil { + cv.addFailure("readiness", "probe needs to be configured", "nil") + } + if conf.Liveness["require"] && cv.Container.LivenessProbe == nil { + cv.addFailure("liveness", "probe needs to be configured", "nil") + } +} -// if c.LivenessProbe == nil { -// results.AddFailure("Liveness Probe", "placeholder", "placeholder") -// } -// return results -// } - -// func tag(conf conf.ResourceRequestsAndLimits, c corev1.Container, results types.ContainerResults) types.ContainerResults { -// img := strings.Split(c.Image, ":") -// if len(img) == 1 || img[1] == "latest" { -// results.AddFailure("Image Tag", "not latest", "latest") -// } -// return results -// } +func (cv *ContainerValidation) validateImage(conf conf.Images) { + if conf.TagRequired { + img := strings.Split(cv.Container.Image, ":") + if len(img) == 1 || img[1] == "latest" { + cv.addFailure("Image Tag", "not latest", "latest") + } + } +} // func hostPort(conf conf.ResourceRequestsAndLimits, c corev1.Container, results types.ContainerResults) types.ContainerResults { // for _, port := range c.Ports {