Skip to content

Commit

Permalink
skip health checks for jobs, cronjobs, and initContainers (#216)
Browse files Browse the repository at this point in the history
  • Loading branch information
Robert Brennan authored Nov 6, 2019
1 parent 152c876 commit 22ab851
Show file tree
Hide file tree
Showing 9 changed files with 192 additions and 80 deletions.
14 changes: 6 additions & 8 deletions pkg/validator/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ type ContainerValidation struct {
// relevant podSpec in order to check certain aspects of a containerSpec.
// Perhaps there is a more ideal solution instead of attaching a parent
// podSpec to every container Validation struct...
func ValidateContainer(container *corev1.Container, parentPodResult *PodResult, controllerName string, conf *config.Configuration, isInit bool) ContainerResult {
func ValidateContainer(container *corev1.Container, parentPodResult *PodResult, conf *config.Configuration, controllerName string, controllerType config.SupportedController, isInit bool) ContainerResult {
cv := ContainerValidation{
Container: container,
ResourceValidation: &ResourceValidation{},
Expand All @@ -58,7 +58,9 @@ func ValidateContainer(container *corev1.Container, parentPodResult *PodResult,
}

cv.validateResources(conf, controllerName)
cv.validateHealthChecks(conf, controllerName)
if !isInit && controllerType != config.Jobs && controllerType != config.CronJobs {
cv.validateHealthChecks(conf, controllerName)
}
cv.validateImage(conf, controllerName)
cv.validateNetworking(conf, controllerName)
cv.validateSecurity(conf, controllerName)
Expand Down Expand Up @@ -138,12 +140,8 @@ func (cv *ContainerValidation) validateResourceRange(id, resourceName string, ra
cv.addError(fmt.Sprintf(messages.ResourceAmountTooLowFailure, resourceName, errorBelow.String()), category, id)
} else if warnBelow != nil && warnBelow.MilliValue() > res.MilliValue() {
cv.addWarning(fmt.Sprintf(messages.ResourceAmountTooLowFailure, resourceName, warnBelow.String()), category, id)
} else {
if warnAbove != nil || warnBelow != nil || errorAbove != nil || errorBelow != nil {
cv.addSuccess(fmt.Sprintf(messages.ResourceAmountSuccess, resourceName), category, id)
} else {
cv.addSuccess(fmt.Sprintf(messages.ResourcePresentSuccess, resourceName), category, id)
}
} else if errorAbove != nil && warnAbove != nil && errorBelow != nil && warnBelow != nil {
cv.addSuccess(fmt.Sprintf(messages.ResourceAmountSuccess, resourceName), category, id)
}
}

Expand Down
4 changes: 2 additions & 2 deletions pkg/validator/container_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -285,10 +285,10 @@ func testValidateResources(t *testing.T, container *corev1.Container, resourceCo

cv.validateResources(&parsedConf, controllerName)
assert.Len(t, cv.Warnings, len(*expectedWarnings))
assert.ElementsMatch(t, cv.Warnings, *expectedWarnings)
assert.ElementsMatch(t, *expectedWarnings, cv.Warnings)

assert.Len(t, cv.Errors, len(*expectedErrors))
assert.ElementsMatch(t, cv.Errors, *expectedErrors)
assert.ElementsMatch(t, *expectedErrors, cv.Errors)
}

func TestValidateHealthChecks(t *testing.T) {
Expand Down
5 changes: 3 additions & 2 deletions pkg/validator/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,11 @@ import (

// ValidateController validates a single controller, returns a ControllerResult.
func ValidateController(conf conf.Configuration, controller controller.Interface) ControllerResult {
controllerType := controller.GetType()
pod := controller.GetPodSpec()
podResult := ValidatePod(conf, controller.GetName(), pod)
podResult := ValidatePod(conf, pod, controller.GetName(), controllerType)
return ControllerResult{
Type: controller.GetType().String(),
Type: controllerType.String(),
Name: controller.GetName(),
PodResult: podResult,
}
Expand Down
136 changes: 136 additions & 0 deletions pkg/validator/controller_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
// Copyright 2019 FairwindsOps Inc
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package validator

import (
"testing"

conf "github.com/fairwindsops/polaris/pkg/config"
controller "github.com/fairwindsops/polaris/pkg/validator/controllers"
corev1 "k8s.io/api/core/v1"

"github.com/fairwindsops/polaris/test"
"github.com/stretchr/testify/assert"
)

func TestValidateController(t *testing.T) {
c := conf.Configuration{
Security: conf.Security{
HostIPCSet: conf.SeverityError,
HostPIDSet: conf.SeverityError,
},
}
deployment := controller.NewDeploymentController(test.MockDeploy())
expectedSum := ResultSummary{
Totals: CountSummary{
Successes: uint(2),
Warnings: uint(0),
Errors: uint(0),
},
ByCategory: make(map[string]*CountSummary),
}
expectedSum.ByCategory["Security"] = &CountSummary{
Successes: uint(2),
Warnings: uint(0),
Errors: uint(0),
}

expectedMessages := []*ResultMessage{
{ID: "hostIPCSet", Message: "Host IPC is not configured", Type: "success", Category: "Security"},
{ID: "hostPIDSet", Message: "Host PID is not configured", Type: "success", Category: "Security"},
}

actualResult := ValidateController(c, deployment)

assert.Equal(t, "Deployments", actualResult.Type)
assert.Equal(t, 1, len(actualResult.PodResult.ContainerResults), "should be equal")
assert.EqualValues(t, &expectedSum, actualResult.PodResult.Summary)
assert.EqualValues(t, expectedMessages, actualResult.PodResult.Messages)
}

func TestSkipHealthChecks(t *testing.T) {
c := conf.Configuration{
HealthChecks: conf.HealthChecks{
ReadinessProbeMissing: conf.SeverityError,
LivenessProbeMissing: conf.SeverityWarning,
},
ControllersToScan: []conf.SupportedController{
conf.Deployments,
conf.StatefulSets,
conf.DaemonSets,
conf.Jobs,
conf.CronJobs,
conf.ReplicationControllers,
},
}
deploymentBase := test.MockDeploy()
deploymentBase.Spec.Template.Spec.InitContainers = []corev1.Container{test.MockContainer("test")}
deployment := controller.NewDeploymentController(deploymentBase)
expectedSum := ResultSummary{
Totals: CountSummary{
Successes: uint(0),
Warnings: uint(1),
Errors: uint(1),
},
ByCategory: make(map[string]*CountSummary),
}
expectedSum.ByCategory["Health Checks"] = &CountSummary{
Successes: uint(0),
Warnings: uint(1),
Errors: uint(1),
}
expectedMessages := []*ResultMessage{
{ID: "readinessProbeMissing", Message: "Readiness probe should be configured", Type: "error", Category: "Health Checks"},
{ID: "livenessProbeMissing", Message: "Liveness probe should be configured", Type: "warning", Category: "Health Checks"},
}
actualResult := ValidateController(c, deployment)
assert.Equal(t, "Deployments", actualResult.Type)
assert.Equal(t, 2, len(actualResult.PodResult.ContainerResults), "should be equal")
assert.EqualValues(t, &expectedSum, actualResult.PodResult.Summary)
assert.EqualValues(t, []*ResultMessage{}, actualResult.PodResult.ContainerResults[0].Messages)
assert.EqualValues(t, expectedMessages, actualResult.PodResult.ContainerResults[1].Messages)

job := controller.NewJobController(test.MockJob())
expectedSum = ResultSummary{
Totals: CountSummary{
Successes: uint(0),
Warnings: uint(0),
Errors: uint(0),
},
ByCategory: make(map[string]*CountSummary),
}
expectedMessages = []*ResultMessage{}
actualResult = ValidateController(c, job)
assert.Equal(t, "Jobs", actualResult.Type)
assert.Equal(t, 1, len(actualResult.PodResult.ContainerResults), "should be equal")
assert.EqualValues(t, &expectedSum, actualResult.PodResult.Summary)
assert.EqualValues(t, expectedMessages, actualResult.PodResult.ContainerResults[0].Messages)

cronjob := controller.NewCronJobController(test.MockCronJob())
expectedSum = ResultSummary{
Totals: CountSummary{
Successes: uint(0),
Warnings: uint(0),
Errors: uint(0),
},
ByCategory: make(map[string]*CountSummary),
}
expectedMessages = []*ResultMessage{}
actualResult = ValidateController(c, cronjob)
assert.Equal(t, "CronJobs", actualResult.Type)
assert.Equal(t, 1, len(actualResult.PodResult.ContainerResults), "should be equal")
assert.EqualValues(t, &expectedSum, actualResult.PodResult.Summary)
assert.EqualValues(t, expectedMessages, actualResult.PodResult.ContainerResults[0].Messages)
}
19 changes: 7 additions & 12 deletions pkg/validator/fullaudit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,21 +33,16 @@ func TestGetTemplateData(t *testing.T) {
// TODO: split out the logic for calculating summaries into another set of tests
sum := ResultSummary{
Totals: CountSummary{
Successes: uint(24),
Warnings: uint(6),
Errors: uint(6),
Successes: uint(0),
Warnings: uint(4),
Errors: uint(4),
},
ByCategory: CategorySummary{},
}
sum.ByCategory["Health Checks"] = &CountSummary{
Successes: uint(0),
Warnings: uint(6),
Errors: uint(6),
}
sum.ByCategory["Resources"] = &CountSummary{
Successes: uint(24),
Warnings: uint(0),
Errors: uint(0),
Warnings: uint(4),
Errors: uint(4),
}

actualAudit, err := RunAudit(c, resources)
Expand All @@ -60,10 +55,10 @@ func TestGetTemplateData(t *testing.T) {
assert.Equal(t, 1, len(actualAudit.NamespacedResults["test"].DeploymentResults), "should be equal")
assert.Equal(t, 1, len(actualAudit.NamespacedResults["test"].DeploymentResults), "should be equal")
assert.Equal(t, 1, len(actualAudit.NamespacedResults["test"].DeploymentResults[0].PodResult.ContainerResults), "should be equal")
assert.Equal(t, 6, len(actualAudit.NamespacedResults["test"].DeploymentResults[0].PodResult.ContainerResults[0].Messages), "should be equal")
assert.Equal(t, 2, len(actualAudit.NamespacedResults["test"].DeploymentResults[0].PodResult.ContainerResults[0].Messages), "should be equal")

assert.Equal(t, 1, len(actualAudit.NamespacedResults["test"].StatefulSetResults), "should be equal")
assert.Equal(t, 1, len(actualAudit.NamespacedResults["test"].StatefulSetResults), "should be equal")
assert.Equal(t, 1, len(actualAudit.NamespacedResults["test"].StatefulSetResults[0].PodResult.ContainerResults), "should be equal")
assert.Equal(t, 6, len(actualAudit.NamespacedResults["test"].StatefulSetResults[0].PodResult.ContainerResults[0].Messages), "should be equal")
assert.Equal(t, 2, len(actualAudit.NamespacedResults["test"].StatefulSetResults[0].PodResult.ContainerResults[0].Messages), "should be equal")
}
10 changes: 5 additions & 5 deletions pkg/validator/pod.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ type PodValidation struct {
}

// ValidatePod validates that each pod conforms to the Polaris config, returns a ResourceResult.
func ValidatePod(conf config.Configuration, controllerName string, pod *corev1.PodSpec) PodResult {
func ValidatePod(conf config.Configuration, pod *corev1.PodSpec, controllerName string, controllerType config.SupportedController) PodResult {
pv := PodValidation{
Pod: pod,
ResourceValidation: &ResourceValidation{},
Expand All @@ -43,8 +43,8 @@ func ValidatePod(conf config.Configuration, controllerName string, pod *corev1.P
podSpec: *pod,
}

pv.validateContainers(pod.InitContainers, &pRes, controllerName, &conf, true)
pv.validateContainers(pod.Containers, &pRes, controllerName, &conf, false)
pv.validateContainers(pod.InitContainers, &pRes, &conf, controllerName, controllerType, true)
pv.validateContainers(pod.Containers, &pRes, &conf, controllerName, controllerType, false)

for _, cRes := range pRes.ContainerResults {
pRes.Summary.appendResults(*cRes.Summary)
Expand All @@ -53,9 +53,9 @@ func ValidatePod(conf config.Configuration, controllerName string, pod *corev1.P
return pRes
}

func (pv *PodValidation) validateContainers(containers []corev1.Container, pRes *PodResult, controllerName string, conf *config.Configuration, isInit bool) {
func (pv *PodValidation) validateContainers(containers []corev1.Container, pRes *PodResult, conf *config.Configuration, controllerName string, controllerType config.SupportedController, isInit bool) {
for _, container := range containers {
cRes := ValidateContainer(&container, pRes, controllerName, conf, isInit)
cRes := ValidateContainer(&container, pRes, conf, controllerName, controllerType, isInit)
pRes.ContainerResults = append(pRes.ContainerResults, cRes)
}
}
Expand Down
Loading

0 comments on commit 22ab851

Please sign in to comment.