Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding image pull policy validation #69

Merged
merged 1 commit into from
May 1, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ resources:
memoryLimitsMissing: error
images:
tagNotSpecified: error
pullPolicyNotAlways: ignore
healthChecks:
readinessProbeMissing: warning
livenessProbeMissing: warning
Expand Down
6 changes: 6 additions & 0 deletions pkg/dashboard/assets/css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ body {
}

.header .header-right {
padding: 15px;
float: right;
}

Expand Down Expand Up @@ -54,6 +55,11 @@ body {
border-radius: 5px;
}

.card.cluster {
margin-top: 15px;
}


.card.namespace {
padding: 10px 20px;
}
Expand Down
Binary file added pkg/dashboard/assets/images/polaris-logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 2 additions & 4 deletions pkg/dashboard/templates/dashboard.gohtml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
<body>
<div class="header">
<div class="header-content">
<img class="logo" src="/static/images/logo.png" alt="Fairwinds" />
<img class="logo" src="/static/images/polaris-logo.png" alt="Polaris" />
<div class="header-right">
<a href="https://reactiveops.com?source=fairwinds" target="_blank">
<span class="oss-text">Open Source Project By</span>
Expand Down Expand Up @@ -112,10 +112,9 @@
<div class="card namespace">
<h3>Namespace: <strong>{{ $namespace }}</strong></h3>
<table class="expandable-table" cellspacing="0">
{{ range $results.Results }}
<tr>
<td class="resource-info">
<div class="name"><span class="caret-expander"></span>{{ .Type }}: <strong>{{ .Name }}</strong></div>
<div class="name"><span class="caret-expander"></span>Deployment: <strong>{{ .Name }}</strong></div>

{{ range .PodResults}}
<div class="result-messages expandable-content">
Expand Down Expand Up @@ -148,7 +147,6 @@
</div>
</td>
</tr>
{{ end }} {{/* end range .Results */}}
</table>
</div>
{{ end }} {{/* end range .AuditData.NamespacedResults */}}
Expand Down
8 changes: 8 additions & 0 deletions pkg/validator/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,14 @@ func (cv *ContainerValidation) validateHealthChecks(conf *conf.HealthChecks) {

func (cv *ContainerValidation) validateImage(imageConf *conf.Images) {
category := messages.CategoryImages
if imageConf.PullPolicyNotAlways.IsActionable() {
if cv.Container.ImagePullPolicy != corev1.PullAlways {
cv.addFailure(messages.ImagePullPolicyFailure, imageConf.PullPolicyNotAlways, category)
} else {
cv.addSuccess(messages.ImagePullPolicySuccess, category)
}
}

if imageConf.TagNotSpecified.IsActionable() {
img := strings.Split(cv.Container.Image, ":")
if len(img) == 1 || img[1] == "latest" {
Expand Down
100 changes: 74 additions & 26 deletions pkg/validator/container_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -271,52 +271,100 @@ func TestValidateHealthChecks(t *testing.T) {
}

func TestValidateImage(t *testing.T) {
emptyConf := conf.Images{}
standardConf := conf.Images{
TagNotSpecified: conf.SeverityError,
PullPolicyNotAlways: conf.SeverityIgnore,
}
strongConf := conf.Images{
TagNotSpecified: conf.SeverityError,
PullPolicyNotAlways: conf.SeverityError,
}

// Test setup.
i1 := conf.Images{}
i2 := conf.Images{TagNotSpecified: conf.SeverityIgnore}
i3 := conf.Images{TagNotSpecified: conf.SeverityError}

cv1 := ContainerValidation{
Container: &corev1.Container{Name: ""},
emptyCV := ContainerValidation{
Container: &corev1.Container{},
ResourceValidation: &ResourceValidation{},
}

cv2 := ContainerValidation{
Container: &corev1.Container{Name: "", Image: "test:tag"},
badCV := ContainerValidation{
Container: &corev1.Container{Image: "test"},
ResourceValidation: &ResourceValidation{},
}

cv3 := ContainerValidation{
Container: &corev1.Container{Name: "", Image: "test:latest"},
lessBadCV := ContainerValidation{
Container: &corev1.Container{Image: "test:latest", ImagePullPolicy: ""},
ResourceValidation: &ResourceValidation{},
}

cv4 := ContainerValidation{
Container: &corev1.Container{Name: "", Image: "test"},
goodCV := ContainerValidation{
Container: &corev1.Container{Image: "test:0.1.0", ImagePullPolicy: "Always"},
ResourceValidation: &ResourceValidation{},
}

f := &ResultMessage{Message: "Image tag should be specified", Type: "error", Category: "Images"}
f1 := []*ResultMessage{}
f2 := []*ResultMessage{f}

var testCases = []struct {
name string
image conf.Images
cv ContainerValidation
expected []*ResultMessage
}{
{name: "image not configured", image: i1, cv: cv1, expected: f1},
{name: "image not required", image: i2, cv: cv1, expected: f1},
{name: "image tag required and configured", image: i3, cv: cv2, expected: f1},
{name: "image tag required, but not configured", image: i3, cv: cv1, expected: f2},
{name: "image tag required, but is latest", image: i3, cv: cv3, expected: f2},
{name: "image tag required, but is empty", image: i3, cv: cv4, expected: f2},
{
name: "emptyConf + emptyCV",
image: emptyConf,
cv: emptyCV,
expected: []*ResultMessage{},
},
{
name: "standardConf + emptyCV",
image: standardConf,
cv: emptyCV,
expected: []*ResultMessage{{
Message: "Image tag should be specified",
Type: "error",
Category: "Images",
}},
},
{
name: "standardConf + badCV",
image: standardConf,
cv: badCV,
expected: []*ResultMessage{{
Message: "Image tag should be specified",
Type: "error",
Category: "Images",
}},
},
{
name: "standardConf + lessBadCV",
image: standardConf,
cv: lessBadCV,
expected: []*ResultMessage{{
Message: "Image tag should be specified",
Type: "error",
Category: "Images",
}},
},
{
name: "strongConf + badCV",
image: strongConf,
cv: badCV,
expected: []*ResultMessage{{
Message: "Image pull policy should be \"Always\"",
Type: "error",
Category: "Images",
}, {
Message: "Image tag should be specified",
Type: "error",
Category: "Images",
}},
},
{
name: "strongConf + goodCV",
image: strongConf,
cv: goodCV,
expected: []*ResultMessage{},
},
}

for _, tt := range testCases {
t.Run(tt.name, func(t *testing.T) {
tt.cv = resetCV(tt.cv)
tt.cv.validateImage(&tt.image)
assert.Len(t, tt.cv.Errors, len(tt.expected))
assert.ElementsMatch(t, tt.cv.Errors, tt.expected)
Expand Down
4 changes: 4 additions & 0 deletions pkg/validator/messages/messages.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ const (
ImageTagFailure = "Image tag should be specified"
// ImageTagSuccess message
ImageTagSuccess = "Image tag is specified"
// ImagePullPolicyFailure message
ImagePullPolicyFailure = "Image pull policy should be \"Always\""
// ImagePullPolicySuccess message
ImagePullPolicySuccess = "Image pull policy is \"Always\""
// HostPortFailure message
HostPortFailure = "Host port should not be configured"
// HostPortSuccess message
Expand Down