Files
polaris/pkg/validator/schema_test.go

264 lines
6.5 KiB
Go

package validator
import (
"testing"
conf "github.com/fairwindsops/polaris/pkg/config"
"github.com/stretchr/testify/assert"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
)
var customCheckExemptions = `
checks:
foo: danger
customChecks:
foo:
successMessage: success!
failureMessage: fail!
target: Container
category: Security
schema:
properties:
image:
pattern: ^quay.io
exemptions:
- controllerNames:
- exempt
rules:
- foo
`
var resourceConfRanges = `
checks:
memoryRequestsRange: danger
memoryLimitsRange: warning
customChecks:
memoryLimitsRange:
containers:
exclude:
- initContainer
successMessage: Memory limits are within the required range
failureMessage: Memory limits should be within the required range
category: Efficiency
target: Container
schema:
'$schema': http://json-schema.org/draft-07/schema
type: object
required:
- resources
properties:
resources:
type: object
required:
- limits
properties:
limits:
type: object
required:
- memory
properties:
memory:
type: string
resourceMinimum: 200M
resourceMaximum: 6G
memoryRequestsRange:
successMessage: Memory requests are within the required range
failureMessage: Memory requests should be within the required range
category: Efficiency
target: Container
containers:
exclude:
- initContainer
schema:
'$schema': http://json-schema.org/draft-07/schema
type: object
required:
- resources
properties:
resources:
type: object
required:
- requests
properties:
requests:
required:
- memory
properties:
memory:
type: string
resourceMinimum: 200M
resourceMaximum: 3G
`
func TestValidateResourcesPartiallyValid(t *testing.T) {
cpuRequest, err := resource.ParseQuantity("100m")
assert.NoError(t, err, "Error parsing quantity")
cpuLimit, err := resource.ParseQuantity("200m")
assert.NoError(t, err, "Error parsing quantity")
container := corev1.Container{
Name: "Empty",
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
"cpu": cpuRequest,
},
Limits: corev1.ResourceList{
"cpu": cpuLimit,
},
},
}
expectedWarnings := []ResultMessage{
{
ID: "memoryLimitsRange",
Success: false,
Severity: "warning",
Message: "Memory limits should be within the required range",
Category: "Efficiency",
},
}
expectedDangers := []ResultMessage{
{
ID: "memoryRequestsRange",
Success: false,
Severity: "danger",
Message: "Memory requests should be within the required range",
Category: "Efficiency",
},
}
expectedSuccesses := []ResultMessage{}
testValidate(t, &container, &resourceConfRanges, "foo", expectedDangers, expectedWarnings, expectedSuccesses)
}
func TestValidateResourcesInit(t *testing.T) {
emptyContainer := &corev1.Container{}
controller := getEmptyWorkload(t, "")
parsedConf, err := conf.Parse([]byte(resourceConfRanges))
assert.NoError(t, err, "Expected no error when parsing config")
var results ResultSet
results, err = applyContainerSchemaChecks(&parsedConf, controller, emptyContainer, false)
if err != nil {
panic(err)
}
assert.Equal(t, uint(1), results.GetSummary().Dangers)
assert.Equal(t, uint(1), results.GetSummary().Warnings)
results, err = applyContainerSchemaChecks(&parsedConf, controller, emptyContainer, true)
if err != nil {
panic(err)
}
assert.Equal(t, uint(0), results.GetSummary().Dangers)
assert.Equal(t, uint(0), results.GetSummary().Warnings)
}
func TestValidateResourcesFullyValid(t *testing.T) {
cpuRequest, err := resource.ParseQuantity("300m")
assert.NoError(t, err, "Error parsing quantity")
cpuLimit, err := resource.ParseQuantity("400m")
assert.NoError(t, err, "Error parsing quantity")
memoryRequest, err := resource.ParseQuantity("400Mi")
assert.NoError(t, err, "Error parsing quantity")
memoryLimit, err := resource.ParseQuantity("500Mi")
assert.NoError(t, err, "Error parsing quantity")
container := corev1.Container{
Name: "Empty",
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
"cpu": cpuRequest,
"memory": memoryRequest,
},
Limits: corev1.ResourceList{
"cpu": cpuLimit,
"memory": memoryLimit,
},
},
}
expectedSuccesses := []ResultMessage{
{
ID: "memoryRequestsRange",
Success: true,
Severity: "danger",
Message: "Memory requests are within the required range",
Category: "Efficiency",
},
{
ID: "memoryLimitsRange",
Success: true,
Severity: "warning",
Message: "Memory limits are within the required range",
Category: "Efficiency",
},
}
testValidate(t, &container, &resourceConfRanges, "foo", []ResultMessage{}, []ResultMessage{}, expectedSuccesses)
expectedSuccesses = []ResultMessage{
{
ID: "cpuRequestsMissing",
Success: true,
Severity: "warning",
Message: "CPU requests are set",
Category: "Efficiency",
},
{
ID: "memoryRequestsMissing",
Success: true,
Severity: "warning",
Message: "Memory requests are set",
Category: "Efficiency",
},
{
ID: "cpuLimitsMissing",
Success: true,
Severity: "danger",
Message: "CPU limits are set",
Category: "Efficiency",
},
{
ID: "memoryLimitsMissing",
Success: true,
Severity: "danger",
Message: "Memory limits are set",
Category: "Efficiency",
},
}
testValidate(t, &container, &resourceConfMinimal, "foo", []ResultMessage{}, []ResultMessage{}, expectedSuccesses)
}
func TestValidateCustomCheckExemptions(t *testing.T) {
container := corev1.Container{
Name: "example",
Image: "hub.docker.com/foo",
}
expectedWarnings := []ResultMessage{}
expectedDangers := []ResultMessage{}
expectedSuccesses := []ResultMessage{}
testValidate(t, &container, &customCheckExemptions, "exempt", expectedDangers, expectedWarnings, expectedSuccesses)
expectedDangers = []ResultMessage{
{
ID: "foo",
Success: false,
Severity: "danger",
Message: "fail!",
Category: "Security",
},
}
testValidate(t, &container, &customCheckExemptions, "notexempt", expectedDangers, expectedWarnings, expectedSuccesses)
}