mirror of
https://github.com/FairwindsOps/polaris.git
synced 2026-08-29 22:17:16 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7ce71f1632 | ||
|
|
98b47e0aeb |
@@ -1,5 +1,8 @@
|
||||
# x.x.x (next release)
|
||||
|
||||
# 0.5.2
|
||||
* Fixed missing success messages for resource requests/limits
|
||||
|
||||
# 0.5.1
|
||||
* Added a few more exemptions
|
||||
* Started checking exemptions based on controller name prefix
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
[![Version][version-image]][version-link] [![CircleCI][circleci-image]][circleci-link] [![Go Report Card][goreport-image]][goreport-link]
|
||||
</div>
|
||||
|
||||
[version-image]: https://img.shields.io/static/v1.svg?label=Version&message=0.5.1&color=239922
|
||||
[version-image]: https://img.shields.io/static/v1.svg?label=Version&message=0.5.2&color=239922
|
||||
[version-link]: https://github.com/FairwindsOps/polaris
|
||||
|
||||
[goreport-image]: https://goreportcard.com/badge/github.com/FairwindsOps/polaris
|
||||
|
||||
@@ -41,7 +41,7 @@ import (
|
||||
|
||||
const (
|
||||
// Version represents the current release version of Polaris
|
||||
Version = "0.5.1"
|
||||
Version = "0.5.2"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
@@ -125,8 +125,8 @@ type SecurityCapabilityLists struct {
|
||||
func ParseFile(path string) (Configuration, error) {
|
||||
var rawBytes []byte
|
||||
var err error
|
||||
configBox := packr.New("Config", "../../examples")
|
||||
if path == "" {
|
||||
configBox := packr.New("Config", "../../examples")
|
||||
rawBytes, err = configBox.Find("config.yaml")
|
||||
} else if strings.HasPrefix(path, "https://") || strings.HasPrefix(path, "http://") {
|
||||
//path is a url
|
||||
|
||||
@@ -9,10 +9,16 @@ import (
|
||||
func (conf *Configuration) IsActionable(subConf interface{}, ruleName, controllerName string) bool {
|
||||
ruleID := GetIDFromField(subConf, ruleName)
|
||||
subConfRef := reflect.ValueOf(subConf)
|
||||
severity, ok := reflect.Indirect(subConfRef).FieldByName(ruleName).Interface().(Severity)
|
||||
if ok && !severity.IsActionable() {
|
||||
fieldVal := reflect.Indirect(subConfRef).FieldByName(ruleName).Interface()
|
||||
if severity, ok := fieldVal.(Severity); ok && !severity.IsActionable() {
|
||||
return false
|
||||
}
|
||||
if ranges, ok := fieldVal.(ResourceRanges); ok {
|
||||
if ranges.Warning.Above == nil && ranges.Warning.Below == nil &&
|
||||
ranges.Error.Above == nil && ranges.Error.Below == nil {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if conf.DisallowExemptions {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -86,42 +86,50 @@ func (cv *ContainerValidation) validateResources(conf *config.Configuration, con
|
||||
|
||||
missingName := "CPURequestsMissing"
|
||||
rangeName := "CPURequestRanges"
|
||||
id := config.GetIDFromField(conf.Resources, missingName)
|
||||
if conf.IsActionable(conf.Resources, missingName, controllerName) && res.Requests.Cpu().MilliValue() == 0 {
|
||||
id := config.GetIDFromField(conf.Resources, missingName)
|
||||
cv.addFailure(messages.CPURequestsFailure, conf.Resources.CPURequestsMissing, category, id)
|
||||
} else if conf.IsActionable(conf.Resources, rangeName, controllerName) {
|
||||
id := config.GetIDFromField(conf.Resources, rangeName)
|
||||
cv.validateResourceRange(id, messages.CPURequestsLabel, &conf.Resources.CPURequestRanges, res.Requests.Cpu())
|
||||
} else if conf.IsActionable(conf.Resources, missingName, controllerName) {
|
||||
cv.addSuccess(fmt.Sprintf(messages.ResourcePresentSuccess, messages.CPURequestsLabel), category, id)
|
||||
}
|
||||
|
||||
missingName = "CPULimitsMissing"
|
||||
rangeName = "CPULimitRanges"
|
||||
id = config.GetIDFromField(conf.Resources, missingName)
|
||||
if conf.IsActionable(conf.Resources, missingName, controllerName) && res.Limits.Cpu().MilliValue() == 0 {
|
||||
id := config.GetIDFromField(conf.Resources, missingName)
|
||||
cv.addFailure(messages.CPULimitsFailure, conf.Resources.CPULimitsMissing, category, id)
|
||||
} else if conf.IsActionable(conf.Resources, rangeName, controllerName) {
|
||||
id := config.GetIDFromField(conf.Resources, rangeName)
|
||||
cv.validateResourceRange(id, messages.CPULimitsLabel, &conf.Resources.CPULimitRanges, res.Requests.Cpu())
|
||||
} else if conf.IsActionable(conf.Resources, missingName, controllerName) {
|
||||
cv.addSuccess(fmt.Sprintf(messages.ResourcePresentSuccess, messages.CPULimitsLabel), category, id)
|
||||
}
|
||||
|
||||
missingName = "MemoryRequestsMissing"
|
||||
rangeName = "MemoryRequestRanges"
|
||||
id = config.GetIDFromField(conf.Resources, missingName)
|
||||
if conf.IsActionable(conf.Resources, missingName, controllerName) && res.Requests.Memory().MilliValue() == 0 {
|
||||
id := config.GetIDFromField(conf.Resources, missingName)
|
||||
cv.addFailure(messages.MemoryRequestsFailure, conf.Resources.MemoryRequestsMissing, category, id)
|
||||
} else if conf.IsActionable(conf.Resources, rangeName, controllerName) {
|
||||
id := config.GetIDFromField(conf.Resources, rangeName)
|
||||
cv.validateResourceRange(id, messages.MemoryRequestsLabel, &conf.Resources.MemoryRequestRanges, res.Requests.Memory())
|
||||
} else if conf.IsActionable(conf.Resources, missingName, controllerName) {
|
||||
cv.addSuccess(fmt.Sprintf(messages.ResourcePresentSuccess, messages.MemoryRequestsLabel), category, id)
|
||||
}
|
||||
|
||||
missingName = "MemoryLimitsMissing"
|
||||
rangeName = "MemoryLimitRanges"
|
||||
id = config.GetIDFromField(conf.Resources, missingName)
|
||||
if conf.IsActionable(conf.Resources, missingName, controllerName) && res.Limits.Memory().MilliValue() == 0 {
|
||||
id := config.GetIDFromField(conf.Resources, missingName)
|
||||
cv.addFailure(messages.MemoryLimitsFailure, conf.Resources.MemoryLimitsMissing, category, id)
|
||||
} else if conf.IsActionable(conf.Resources, rangeName, controllerName) {
|
||||
id := config.GetIDFromField(conf.Resources, rangeName)
|
||||
cv.validateResourceRange(id, messages.MemoryLimitsLabel, &conf.Resources.MemoryLimitRanges, res.Limits.Memory())
|
||||
} else if conf.IsActionable(conf.Resources, missingName, controllerName) {
|
||||
cv.addSuccess(fmt.Sprintf(messages.ResourcePresentSuccess, messages.MemoryLimitsLabel), category, id)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -120,6 +120,27 @@ exemptions:
|
||||
- foo
|
||||
`
|
||||
|
||||
func testValidateResources(t *testing.T, container *corev1.Container, resourceConf *string, controllerName string, expectedErrors []*ResultMessage, expectedWarnings []*ResultMessage, expectedSuccesses []*ResultMessage) {
|
||||
cv := ContainerValidation{
|
||||
Container: container,
|
||||
ResourceValidation: &ResourceValidation{},
|
||||
}
|
||||
|
||||
parsedConf, err := conf.Parse([]byte(*resourceConf))
|
||||
assert.NoError(t, err, "Expected no error when parsing config")
|
||||
|
||||
cv.validateResources(&parsedConf, controllerName)
|
||||
|
||||
assert.Len(t, cv.Warnings, len(expectedWarnings))
|
||||
assert.ElementsMatch(t, expectedWarnings, cv.Warnings)
|
||||
|
||||
assert.Len(t, cv.Errors, len(expectedErrors))
|
||||
assert.ElementsMatch(t, expectedErrors, cv.Errors)
|
||||
|
||||
assert.Len(t, cv.Successes, len(expectedSuccesses))
|
||||
assert.ElementsMatch(t, expectedSuccesses, cv.Successes)
|
||||
}
|
||||
|
||||
func TestValidateResourcesEmptyConfig(t *testing.T) {
|
||||
container := corev1.Container{
|
||||
Name: "Empty",
|
||||
@@ -169,7 +190,9 @@ func TestValidateResourcesEmptyContainer(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
testValidateResources(t, &container, &resourceConf2, "foo", &expectedErrors, &expectedWarnings)
|
||||
expectedSuccesses := []*ResultMessage{}
|
||||
|
||||
testValidateResources(t, &container, &resourceConf2, "foo", expectedErrors, expectedWarnings, expectedSuccesses)
|
||||
}
|
||||
|
||||
func TestValidateResourcesPartiallyValid(t *testing.T) {
|
||||
@@ -221,7 +244,9 @@ func TestValidateResourcesPartiallyValid(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
testValidateResources(t, &container, &resourceConf1, "foo", &expectedErrors, &expectedWarnings)
|
||||
expectedSuccesses := []*ResultMessage{}
|
||||
|
||||
testValidateResources(t, &container, &resourceConf1, "foo", expectedErrors, expectedWarnings, expectedSuccesses)
|
||||
}
|
||||
|
||||
func TestValidateResourcesInit(t *testing.T) {
|
||||
@@ -272,24 +297,63 @@ func TestValidateResourcesFullyValid(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
testValidateResources(t, &container, &resourceConf1, "foo", &[]*ResultMessage{}, &[]*ResultMessage{})
|
||||
}
|
||||
|
||||
func testValidateResources(t *testing.T, container *corev1.Container, resourceConf *string, controllerName string, expectedErrors *[]*ResultMessage, expectedWarnings *[]*ResultMessage) {
|
||||
cv := ContainerValidation{
|
||||
Container: container,
|
||||
ResourceValidation: &ResourceValidation{},
|
||||
expectedSuccesses := []*ResultMessage{
|
||||
{
|
||||
ID: "cpuRequestRanges",
|
||||
Type: "success",
|
||||
Message: "CPU requests are within the expected range",
|
||||
Category: "Resources",
|
||||
},
|
||||
{
|
||||
ID: "memoryRequestRanges",
|
||||
Type: "success",
|
||||
Message: "Memory requests are within the expected range",
|
||||
Category: "Resources",
|
||||
},
|
||||
{
|
||||
ID: "cpuLimitRanges",
|
||||
Type: "success",
|
||||
Message: "CPU limits are within the expected range",
|
||||
Category: "Resources",
|
||||
},
|
||||
{
|
||||
ID: "memoryLimitRanges",
|
||||
Type: "success",
|
||||
Message: "Memory limits are within the expected range",
|
||||
Category: "Resources",
|
||||
},
|
||||
}
|
||||
|
||||
parsedConf, err := conf.Parse([]byte(*resourceConf))
|
||||
assert.NoError(t, err, "Expected no error when parsing config")
|
||||
testValidateResources(t, &container, &resourceConf1, "foo", []*ResultMessage{}, []*ResultMessage{}, expectedSuccesses)
|
||||
|
||||
cv.validateResources(&parsedConf, controllerName)
|
||||
assert.Len(t, cv.Warnings, len(*expectedWarnings))
|
||||
assert.ElementsMatch(t, *expectedWarnings, cv.Warnings)
|
||||
expectedSuccesses = []*ResultMessage{
|
||||
{
|
||||
ID: "cpuRequestsMissing",
|
||||
Type: "success",
|
||||
Message: "CPU requests are set",
|
||||
Category: "Resources",
|
||||
},
|
||||
{
|
||||
ID: "memoryRequestsMissing",
|
||||
Type: "success",
|
||||
Message: "Memory requests are set",
|
||||
Category: "Resources",
|
||||
},
|
||||
{
|
||||
ID: "cpuLimitsMissing",
|
||||
Type: "success",
|
||||
Message: "CPU limits are set",
|
||||
Category: "Resources",
|
||||
},
|
||||
{
|
||||
ID: "memoryLimitsMissing",
|
||||
Type: "success",
|
||||
Message: "Memory limits are set",
|
||||
Category: "Resources",
|
||||
},
|
||||
}
|
||||
|
||||
assert.Len(t, cv.Errors, len(*expectedErrors))
|
||||
assert.ElementsMatch(t, *expectedErrors, cv.Errors)
|
||||
testValidateResources(t, &container, &resourceConf2, "foo", []*ResultMessage{}, []*ResultMessage{}, expectedSuccesses)
|
||||
}
|
||||
|
||||
func TestValidateHealthChecks(t *testing.T) {
|
||||
@@ -1212,8 +1276,9 @@ func TestValidateResourcesExemption(t *testing.T) {
|
||||
|
||||
expectedWarnings := []*ResultMessage{}
|
||||
expectedErrors := []*ResultMessage{}
|
||||
expectedSuccesses := []*ResultMessage{}
|
||||
|
||||
testValidateResources(t, &container, &resourceConfExemptions, "foo", &expectedErrors, &expectedWarnings)
|
||||
testValidateResources(t, &container, &resourceConfExemptions, "foo", expectedErrors, expectedWarnings, expectedSuccesses)
|
||||
|
||||
expectedWarnings = []*ResultMessage{
|
||||
{
|
||||
@@ -1247,7 +1312,7 @@ func TestValidateResourcesExemption(t *testing.T) {
|
||||
|
||||
disallowExemptionsConf := resourceConfExemptions + "\ndisallowExemptions: true"
|
||||
|
||||
testValidateResources(t, &container, &disallowExemptionsConf, "foo", &expectedErrors, &expectedWarnings)
|
||||
testValidateResources(t, &container, &disallowExemptionsConf, "foo", expectedErrors, expectedWarnings, expectedSuccesses)
|
||||
}
|
||||
|
||||
func TestValidateResourceRangeExemption(t *testing.T) {
|
||||
@@ -1257,8 +1322,9 @@ func TestValidateResourceRangeExemption(t *testing.T) {
|
||||
|
||||
expectedWarnings := []*ResultMessage{}
|
||||
expectedErrors := []*ResultMessage{}
|
||||
expectedSuccesses := []*ResultMessage{}
|
||||
|
||||
testValidateResources(t, &container, &resourceConfRangeExemptions, "foo", &expectedErrors, &expectedWarnings)
|
||||
testValidateResources(t, &container, &resourceConfRangeExemptions, "foo", expectedErrors, expectedWarnings, expectedSuccesses)
|
||||
}
|
||||
|
||||
func resetCV(cv ContainerValidation) ContainerValidation {
|
||||
|
||||
Reference in New Issue
Block a user