mirror of
https://github.com/FairwindsOps/polaris.git
synced 2026-02-14 18:09:54 +00:00
* Bump lins * Code refactoring * Fixign issues * Fixing issues * Fixing issues * Fixing issues * [WIP] * [WIP] * [WIP] * Trying to fix tests * Trying to fix tests * Fixing issues * Fixing issues * Fixing issues * Fixing issues * Fixing issues * Fixing issues * Revert go mod * Revert go mod * Revert go mod * Revert go mod * Fixing issues * Fixing issue * Code refactoring * Updating json schema version * Updating json schema version
279 lines
7.1 KiB
Go
279 lines
7.1 KiB
Go
// Copyright 2022 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 (
|
|
"context"
|
|
"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': https://json-schema.org/draft/2019-09/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': https://json-schema.org/draft/2019-09/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(context.Background(), &parsedConf, nil, 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(context.Background(), &parsedConf, nil, 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)
|
|
}
|