Merge pull request #239 from FairwindsOps/bb/exclude-check

Exclude individual checks from a controller
This commit is contained in:
baderbuddy
2020-01-29 12:53:04 -05:00
committed by GitHub
6 changed files with 78 additions and 4 deletions

View File

@@ -1,4 +1,5 @@
# x.x.x (next release)
* Added the ability to exempt a particular controller from a particular check.
# 0.6.0
* Fixed webhook support in Kubernetes 1.16

View File

@@ -7,7 +7,7 @@ Issues, whether bugs, tasks, or feature requests are essential for keeping Polar
This project adheres to a [code of conduct](CODE_OF_CONDUCT.md). Please review this document before contributing to this project.
## Sign the CLA
Before you can contribute, you will need to sign the [Contributor License Agreement](https://cla-assistant.io/fairwinds/polaris).
Before you can contribute, you will need to sign the [Contributor License Agreement](https://cla-assistant.io/fairwindsops/polaris).
## Project Structure

View File

@@ -62,7 +62,7 @@ There are additional examples in the [checks folder](/checks).
### Exemptions
Exemptions can be added two ways: by annotating a controller, or editing the Polaris config.
To exempt a controller via annotations, use the annotation `polaris.fairwinds.com/exempt=true`, e.g.
To exempt a controller from all checks via annotations, use the annotation `polaris.fairwinds.com/exempt=true`, e.g.
```
kubectl annotate deployment my-deployment polaris.fairwinds.com/exempt=true
```
@@ -76,6 +76,11 @@ exemptions:
- hostNetworkSet
```
To exempt a controller from a particular check via annotations, use an annotation in the form of `polaris.fairwinds.com/<check>-exempt=true`, e.g.
```
kubectl annotate deployment my-deployment polaris.fairwinds.com/cpuRequestsMissing-exempt=true
```
# Installing
There are several ways to install and use Polaris. Below outline ways to install using `kubectl`, `helm` and `local binary`.

View File

@@ -63,10 +63,14 @@ func getEmptyController(name string) controllers.Interface {
}
func testValidate(t *testing.T, container *corev1.Container, resourceConf *string, controllerName string, expectedErrors []ResultMessage, expectedWarnings []ResultMessage, expectedSuccesses []ResultMessage) {
testValidateWithController(t, container, resourceConf, getEmptyController(controllerName), expectedErrors, expectedWarnings, expectedSuccesses)
}
func testValidateWithController(t *testing.T, container *corev1.Container, resourceConf *string, controller controllers.Interface, expectedErrors []ResultMessage, expectedWarnings []ResultMessage, expectedSuccesses []ResultMessage) {
parsedConf, err := conf.Parse([]byte(*resourceConf))
assert.NoError(t, err, "Expected no error when parsing config")
results, err := applyContainerSchemaChecks(&parsedConf, getEmptyController(controllerName), container, false)
results, err := applyContainerSchemaChecks(&parsedConf, controller, container, false)
if err != nil {
panic(err)
}
@@ -1146,3 +1150,52 @@ func TestValidateResourcesExemption(t *testing.T) {
testValidate(t, &container, &disallowExemptionsConf, "foo", expectedErrors, expectedWarnings, expectedSuccesses)
}
func TestValidateResourcesEmptyContainerCPURequestsExempt(t *testing.T) {
container := corev1.Container{
Name: "Empty",
}
expectedWarnings := []ResultMessage{
{
ID: "memoryRequestsMissing",
Success: false,
Severity: "warning",
Message: "Memory requests should be set",
Category: "Resources",
},
}
expectedErrors := []ResultMessage{
{
ID: "cpuLimitsMissing",
Success: false,
Severity: "error",
Message: "CPU limits should be set",
Category: "Resources",
},
{
ID: "memoryLimitsMissing",
Success: false,
Severity: "error",
Message: "Memory limits should be set",
Category: "Resources",
},
}
expectedSuccesses := []ResultMessage{}
controller := controllers.NewDeploymentController(appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
Annotations: map[string]string {
"polaris.fairwinds.com/cpuRequestsMissing-exempt": "true", // Exempt this controller from cpuRequestsMissing
"polaris.fairwinds.com/memoryRequestsMissing-exempt": "truthy", // Don't actually exempt this controller from memoryRequestsMissing
} ,
},
Spec: appsv1.DeploymentSpec{
Template: corev1.PodTemplateSpec{},
},
})
testValidateWithController(t, &container, &resourceConfMinimal, controller, expectedErrors, expectedWarnings, expectedSuccesses)
}

View File

@@ -5,6 +5,7 @@ import (
"fmt"
"io"
"sort"
"strings"
packr "github.com/gobuffalo/packr/v2"
corev1 "k8s.io/api/core/v1"
@@ -105,10 +106,19 @@ func makeResult(conf *config.Configuration, check *config.SchemaCheck, passes bo
return result
}
func getExemptKey(checkID string) string {
return fmt.Sprintf("polaris.fairwinds.com/%s-exempt", checkID)
}
func applyPodSchemaChecks(conf *config.Configuration, controller controllers.Interface) (ResultSet, error) {
results := ResultSet{}
checkIDs := getSortedKeys(conf.Checks)
objectAnnotations := controller.GetObjectMeta().Annotations
for _, checkID := range checkIDs {
exemptValue := objectAnnotations[getExemptKey(checkID)]
if strings.ToLower(exemptValue) == "true" {
continue
}
check, err := resolveCheck(conf, checkID, controller, config.TargetPod, false)
if err != nil {
return nil, err
@@ -130,7 +140,12 @@ func applyPodSchemaChecks(conf *config.Configuration, controller controllers.Int
func applyContainerSchemaChecks(conf *config.Configuration, controller controllers.Interface, container *corev1.Container, isInit bool) (ResultSet, error) {
results := ResultSet{}
checkIDs := getSortedKeys(conf.Checks)
objectAnnotations := controller.GetObjectMeta().Annotations
for _, checkID := range checkIDs {
exemptValue := objectAnnotations[getExemptKey(checkID)]
if strings.ToLower(exemptValue) == "true" {
continue
}
check, err := resolveCheck(conf, checkID, controller, config.TargetContainer, isInit)
if err != nil {
return nil, err

View File

@@ -259,4 +259,4 @@ func TestValidateCustomCheckExemptions(t *testing.T) {
},
}
testValidate(t, &container, &customCheckExemptions, "notexempt", expectedErrors, expectedWarnings, expectedSuccesses)
}
}