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

Add categories to dashboard #65

Merged
merged 1 commit into from
Apr 24, 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
12 changes: 6 additions & 6 deletions pkg/dashboard/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ import (
"github.com/reactiveops/fairwinds/pkg/validator"
)

func getWarningWidth(rs validator.ResultSummary, fullWidth int) uint {
return uint(float64(rs.Successes+rs.Warnings) / float64(rs.Successes+rs.Warnings+rs.Errors) * float64(fullWidth))
func getWarningWidth(counts validator.CountSummary, fullWidth int) uint {
return uint(float64(counts.Successes+counts.Warnings) / float64(counts.Successes+counts.Warnings+counts.Errors) * float64(fullWidth))
}

func getSuccessWidth(rs validator.ResultSummary, fullWidth int) uint {
return uint(float64(rs.Successes) / float64(rs.Successes+rs.Warnings+rs.Errors) * float64(fullWidth))
func getSuccessWidth(counts validator.CountSummary, fullWidth int) uint {
return uint(float64(counts.Successes) / float64(counts.Successes+counts.Warnings+counts.Errors) * float64(fullWidth))
}

func getGrade(rs validator.ResultSummary) string {
Expand Down Expand Up @@ -58,8 +58,8 @@ func getGrade(rs validator.ResultSummary) string {
}

func getScore(rs validator.ResultSummary) uint {
total := (rs.Successes * 2) + rs.Warnings + (rs.Errors * 2)
return uint((float64(rs.Successes*2) / float64(total)) * 100)
total := (rs.Totals.Successes * 2) + rs.Totals.Warnings + (rs.Totals.Errors * 2)
return uint((float64(rs.Totals.Successes*2) / float64(total)) * 100)
}

func getWeatherIcon(rs validator.ResultSummary) string {
Expand Down
35 changes: 30 additions & 5 deletions pkg/dashboard/templates/dashboard.gohtml
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@
</div>
<div class="result-messages">
<ul class="message-list">
<li class="success"><i class="fas fa-check"></i> {{ .AuditData.ClusterSummary.Results.Successes }} checks passed</li>
<li class="warning"><i class="fas fa-exclamation"></i> {{ .AuditData.ClusterSummary.Results.Warnings }} checks had warnings</li>
<li class="error"><i class="fas fa-times"></i> {{ .AuditData.ClusterSummary.Results.Errors }} checks had errors</li>
<li class="success"><i class="fas fa-check"></i> {{ .AuditData.ClusterSummary.Results.Totals.Successes }} checks passed</li>
<li class="warning"><i class="fas fa-exclamation"></i> {{ .AuditData.ClusterSummary.Results.Totals.Warnings }} checks had warnings</li>
<li class="error"><i class="fas fa-times"></i> {{ .AuditData.ClusterSummary.Results.Totals.Errors }} checks had errors</li>
</ul>
</div>
<canvas id="clusterScoreChart"></canvas>
Expand Down Expand Up @@ -80,7 +80,32 @@
</div>
</td>
</tr>
<tr>
<td class="resource-info">
<div class="name"><span class="caret-expander"></span>Health summary</div>
<div class="expandable-content">
<ul class="message-list">
{{ range $category, $summary := .AuditData.ClusterSummary.Results.ByCategory }}
<li>
<span class="detail-label">{{ $category }}</span>
<span class="detail-value">{{ $summary.Errors }} errors, {{ $summary.Warnings }} warnings</span>
<div class="status-bar">
<div class="status">
<div class="failing">
<div class="warning" style="width: {{ getWarningWidth $summary 280 }}px;">
<div class="passing" style="width: {{ getSuccessWidth $summary 280 }}px;"></div>
</div>
</div>
</div>
</div>
</li>
{{ end }}
</ul>
</div>
</td>
</tr>
</table>

</div>

{{ range $namespace, $results := .AuditData.NamespacedResults }}
Expand Down Expand Up @@ -116,8 +141,8 @@
<td class="status-bar">
<div class="status">
<div class="failing">
<div class="warning" style="width: {{ getWarningWidth .Summary 200 }}px;">
<div class="passing" style="width: {{ getSuccessWidth .Summary 200 }}px;"></div>
<div class="warning" style="width: {{ getWarningWidth .Summary.Totals 200 }}px;">
<div class="passing" style="width: {{ getSuccessWidth .Summary.Totals 200 }}px;"></div>
</div>
</div>
</div>
Expand Down
18 changes: 5 additions & 13 deletions pkg/validator/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,10 @@ type ContainerValidation struct {
}

// ValidateContainer validates that each pod conforms to the Fairwinds config, returns a ResourceResult.
func ValidateContainer(cnConf *conf.Configuration, container *corev1.Container) ResourceResult {
func ValidateContainer(cnConf *conf.Configuration, container *corev1.Container) ContainerResult {
cv := ContainerValidation{
Container: container,
ResourceValidation: &ResourceValidation{
Summary: &ResultSummary{},
},
Container: container,
ResourceValidation: &ResourceValidation{},
}

cv.validateResources(&cnConf.Resources)
Expand All @@ -48,16 +46,10 @@ func ValidateContainer(cnConf *conf.Configuration, container *corev1.Container)
cRes := ContainerResult{
Name: container.Name,
Messages: cv.messages(),
Summary: cv.summary(),
}

rr := ResourceResult{
Name: container.Name,
Type: "Container",
Summary: cv.Summary,
ContainerResults: []ContainerResult{cRes},
}

return rr
return cRes
}

func (cv *ContainerValidation) validateResources(resConf *conf.Resources) {
Expand Down
78 changes: 24 additions & 54 deletions pkg/validator/container_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,8 @@ func TestValidateResourcesEmptyConfig(t *testing.T) {
}

cv := ContainerValidation{
Container: &container,
ResourceValidation: &ResourceValidation{
Summary: &ResultSummary{},
},
Container: &container,
ResourceValidation: &ResourceValidation{},
}

expected := conf.Resources{}
Expand Down Expand Up @@ -195,10 +193,8 @@ func TestValidateResourcesFullyValid(t *testing.T) {

func testValidateResources(t *testing.T, container *corev1.Container, resourceConf *string, expectedErrors *[]*ResultMessage, expectedWarnings *[]*ResultMessage) {
cv := ContainerValidation{
Container: container,
ResourceValidation: &ResourceValidation{
Summary: &ResultSummary{},
},
Container: container,
ResourceValidation: &ResourceValidation{},
}

parsedConf, err := conf.Parse([]byte(*resourceConf))
Expand Down Expand Up @@ -227,20 +223,16 @@ func TestValidateHealthChecks(t *testing.T) {

probe := corev1.Probe{}
cv1 := ContainerValidation{
Container: &corev1.Container{Name: ""},
ResourceValidation: &ResourceValidation{
Summary: &ResultSummary{},
},
Container: &corev1.Container{Name: ""},
ResourceValidation: &ResourceValidation{},
}
cv2 := ContainerValidation{
Container: &corev1.Container{
Name: "",
LivenessProbe: &probe,
ReadinessProbe: &probe,
},
ResourceValidation: &ResourceValidation{
Summary: &ResultSummary{},
},
ResourceValidation: &ResourceValidation{},
}

l := &ResultMessage{Type: "warning", Message: "Liveness probe should be configured", Category: "Health Checks"}
Expand Down Expand Up @@ -286,31 +278,23 @@ func TestValidateImage(t *testing.T) {
i3 := conf.Images{TagNotSpecified: conf.SeverityError}

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

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

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

cv4 := ContainerValidation{
Container: &corev1.Container{Name: "", Image: "test"},
ResourceValidation: &ResourceValidation{
Summary: &ResultSummary{},
},
Container: &corev1.Container{Name: "", Image: "test"},
ResourceValidation: &ResourceValidation{},
}

f := &ResultMessage{Message: "Image tag should be specified", Type: "error", Category: "Images"}
Expand Down Expand Up @@ -351,10 +335,8 @@ func TestValidateNetworking(t *testing.T) {
}

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

badCV := ContainerValidation{
Expand All @@ -364,9 +346,7 @@ func TestValidateNetworking(t *testing.T) {
HostPort: 443,
}},
},
ResourceValidation: &ResourceValidation{
Summary: &ResultSummary{},
},
ResourceValidation: &ResourceValidation{},
}

goodCV := ContainerValidation{
Expand All @@ -375,9 +355,7 @@ func TestValidateNetworking(t *testing.T) {
ContainerPort: 3000,
}},
},
ResourceValidation: &ResourceValidation{
Summary: &ResultSummary{},
},
ResourceValidation: &ResourceValidation{},
}

var testCases = []struct {
Expand Down Expand Up @@ -497,10 +475,8 @@ func TestValidateSecurity(t *testing.T) {
}

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

badCV := ContainerValidation{
Expand All @@ -513,9 +489,7 @@ func TestValidateSecurity(t *testing.T) {
Add: []corev1.Capability{"AUDIT_CONTROL", "SYS_ADMIN", "NET_ADMIN"},
},
}},
ResourceValidation: &ResourceValidation{
Summary: &ResultSummary{},
},
ResourceValidation: &ResourceValidation{},
}

goodCV := ContainerValidation{
Expand All @@ -528,9 +502,7 @@ func TestValidateSecurity(t *testing.T) {
Drop: []corev1.Capability{"NET_BIND_SERVICE", "FOWNER"},
},
}},
ResourceValidation: &ResourceValidation{
Summary: &ResultSummary{},
},
ResourceValidation: &ResourceValidation{},
}

strongCV := ContainerValidation{
Expand All @@ -543,9 +515,7 @@ func TestValidateSecurity(t *testing.T) {
Drop: []corev1.Capability{"ALL"},
},
}},
ResourceValidation: &ResourceValidation{
Summary: &ResultSummary{},
},
ResourceValidation: &ResourceValidation{},
}

var testCases = []struct {
Expand Down
5 changes: 1 addition & 4 deletions pkg/validator/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,7 @@ func addResult(resResult ResourceResult, nsResults NamespacedResults, nsName str
}

nsResult.Results = append(nsResult.Results, resResult)
nsResult.Summary.appendResults(*resResult.Summary)

// Aggregate all resource results summary counts to get a namespace wide count.
nsResult.Summary.Successes += resResult.Summary.Successes
nsResult.Summary.Warnings += resResult.Summary.Warnings
nsResult.Summary.Errors += resResult.Summary.Errors
return nsResults
}
12 changes: 3 additions & 9 deletions pkg/validator/fullaudit.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,12 @@ func RunAudit(config conf.Configuration, kubeAPI *kube.API) (AuditData, error) {
return AuditData{}, err
}

var clusterSuccesses, clusterErrors, clusterWarnings uint
clusterResults := ResultSummary{}

// Aggregate all summary counts to get a clusterwide count.
for _, nsRes := range nsResults {
for _, rr := range nsRes.Results {
clusterErrors += rr.Summary.Errors
clusterWarnings += rr.Summary.Warnings
clusterSuccesses += rr.Summary.Successes
clusterResults.appendResults(*rr.Summary)
}
}

Expand Down Expand Up @@ -81,11 +79,7 @@ func RunAudit(config conf.Configuration, kubeAPI *kube.API) (AuditData, error) {
Nodes: len(nodes.Items),
Pods: numPods,
Namespaces: len(namespaces.Items),
Results: ResultSummary{
Errors: clusterErrors,
Warnings: clusterWarnings,
Successes: clusterSuccesses,
},
Results: clusterResults,
},
NamespacedResults: nsResults,
}
Expand Down
25 changes: 19 additions & 6 deletions pkg/validator/fullaudit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,30 @@ func TestGetTemplateData(t *testing.T) {
}

sum := ResultSummary{
Successes: uint(4),
Totals: CountSummary{
Successes: uint(4),
Warnings: uint(1),
Errors: uint(1),
},
ByCategory: CategorySummary{},
}
sum.ByCategory["Health Checks"] = &CountSummary{
Successes: uint(0),
Warnings: uint(1),
Errors: uint(1),
}
sum.ByCategory["Resources"] = &CountSummary{
Successes: uint(4),
Warnings: uint(0),
Errors: uint(0),
}

actualAudit, err := RunAudit(c, k8s)
assert.Equal(t, err, nil, "error should be nil")

assert.EqualValues(t, actualAudit.ClusterSummary.Results, sum)
assert.Equal(t, len(actualAudit.NamespacedResults["test"].Results), 1, "should be equal")
assert.Equal(t, len(actualAudit.NamespacedResults["test"].Results[0].PodResults), 1, "should be equal")
assert.Equal(t, len(actualAudit.NamespacedResults["test"].Results[0].PodResults[0].ContainerResults), 1, "should be equal")
assert.Equal(t, len(actualAudit.NamespacedResults["test"].Results[0].PodResults[0].ContainerResults[0].Messages), 6, "should be equal")
assert.EqualValues(t, sum, actualAudit.ClusterSummary.Results)
assert.Equal(t, 1, len(actualAudit.NamespacedResults["test"].Results), "should be equal")
assert.Equal(t, 1, len(actualAudit.NamespacedResults["test"].Results[0].PodResults), "should be equal")
assert.Equal(t, 1, len(actualAudit.NamespacedResults["test"].Results[0].PodResults[0].ContainerResults), "should be equal")
assert.Equal(t, 6, len(actualAudit.NamespacedResults["test"].Results[0].PodResults[0].ContainerResults[0].Messages), "should be equal")
}
Loading