Compare commits

...
2 Commits
Author SHA1 Message Date
Robert Brennan 7ce71f1632 bump to version 0.5.2 (#224) 2019-11-13 15:27:24 -05:00
Robert Brennan 98b47e0aeb Fix resource success messages (#223)
* add success messages when resources are set

* add tests
2019-11-13 14:07:32 -05:00
7 changed files with 111 additions and 28 deletions
+3
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -41,7 +41,7 @@ import (
const (
// Version represents the current release version of Polaris
Version = "0.5.1"
Version = "0.5.2"
)
func main() {
+1 -1
View File
@@ -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
+8 -2
View File
@@ -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
}
+12 -4
View File
@@ -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)
}
}
+85 -19
View File
@@ -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 {