fix dashboard after output change

This commit is contained in:
Robert Brennan
2020-01-03 20:11:15 +00:00
parent 51cd3523fc
commit e129ba6971
8 changed files with 231 additions and 121 deletions

View File

@@ -257,11 +257,11 @@ ul.message-list li i.message-icon {
color: #8BD2DC;
}
.result-messages .warning i.message-icon {
.result-messages .failure.warning i.message-icon {
color: #f26c21;
}
.result-messages .error i.message-icon {
.result-messages .failure.error i.message-icon {
color: #a11f4c;
}

View File

@@ -5,9 +5,9 @@ $(function () {
labels: ["Passing", "Warning", "Error"],
datasets: [{
data: [
polarisAuditData.ClusterSummary.Results.Totals.Successes,
polarisAuditData.ClusterSummary.Results.Totals.Warnings,
polarisAuditData.ClusterSummary.Results.Totals.Errors,
polarisSummary.Successes,
polarisSummary.Warnings,
polarisSummary.Errors,
],
backgroundColor: ['#8BD2DC', '#f26c21', '#a11f4c'],
}]

View File

@@ -96,6 +96,7 @@ func GetBaseTemplate(name string) (*template.Template, error) {
"getWeatherText": getWeatherText,
"getGrade": getGrade,
"getIcon": getIcon,
"getResultClass": getResultClass,
"getCategoryLink": getCategoryLink,
"getCategoryInfo": getCategoryInfo,
})
@@ -229,7 +230,7 @@ func GetRouter(c config.Configuration, auditPath string, port int, basePath stri
// MainHandler gets template data and renders the dashboard with it.
func MainHandler(w http.ResponseWriter, r *http.Request, c config.Configuration, auditData validator.AuditData, basePath string) {
jsonData, err := json.Marshal(auditData)
jsonData, err := json.Marshal(auditData.GetSummary())
if err != nil {
http.Error(w, "Error serializing audit data", 500)

View File

@@ -76,6 +76,16 @@ func getWeatherIcon(counts validator.CountSummary) string {
}
}
func getResultClass(result validator.ResultMessage) string {
cls := string(result.Severity)
if result.Success {
cls += " success"
} else {
cls += " failure"
}
return cls
}
func getWeatherText(counts validator.CountSummary) string {
score := counts.GetScore()
if score >= 90 {

View File

@@ -9,10 +9,10 @@
<div class="cluster-overview">
<div class="cluster-score">
<div class="score-details">
<div class="weather"><i class="fas {{ getWeatherIcon .AuditData.ClusterSummary.Results.Totals }}"></i></div>
<div class="sailing">{{ getWeatherText .AuditData.ClusterSummary.Results.Totals }}</div>
<div class="scores"><span>Grade: </span><strong>{{ getGrade .AuditData.ClusterSummary.Results.Totals }}</strong></div>
<div class="scores"><span>Score: </span><strong>{{ .AuditData.ClusterSummary.Results.Totals.GetScore }}%</strong></div>
<div class="weather"><i class="fas {{ getWeatherIcon .AuditData.GetSummary }}"></i></div>
<div class="sailing">{{ getWeatherText .AuditData.GetSummary }}</div>
<div class="scores"><span>Grade: </span><strong>{{ getGrade .AuditData.GetSummary }}</strong></div>
<div class="scores"><span>Score: </span><strong>{{ .AuditData.GetSummary.GetScore }}%</strong></div>
</div>
</div>
<div class="graph">
@@ -20,9 +20,9 @@
</div>
<div class="result-messages">
<ul class="message-list">
<li class="success"><i class="message-icon fas fa-check"></i> {{ .AuditData.ClusterSummary.Results.Totals.Successes }} checks passed</li>
<li class="warning"><i class="message-icon fas fa-exclamation"></i> {{ .AuditData.ClusterSummary.Results.Totals.Warnings }} checks had warnings</li>
<li class="error"><i class="message-icon fas fa-times"></i> {{ .AuditData.ClusterSummary.Results.Totals.Errors }} checks had errors</li>
<li class="success"><i class="message-icon fas fa-check"></i> {{ .AuditData.GetSummary.Successes }} checks passed</li>
<li class="failure warning"><i class="message-icon fas fa-exclamation"></i> {{ .AuditData.GetSummary.Warnings }} checks had warnings</li>
<li class="failure error"><i class="message-icon fas fa-times"></i> {{ .AuditData.GetSummary.Errors }} checks had errors</li>
</ul>
</div>
</div>
@@ -33,19 +33,19 @@
<p class="kubernetes-overview">
<span class="kubernetes-stat">
<span>Kubernetes Version:</span>
<strong>{{.AuditData.ClusterSummary.Version}}</strong>
<strong>{{.AuditData.ClusterInfo.Version}}</strong>
</span>
<span class="kubernetes-stat">
<span>Nodes:</span>
<strong>{{.AuditData.ClusterSummary.Nodes}}</strong>
<strong>{{.AuditData.ClusterInfo.Nodes}}</strong>
</span>
<span class="kubernetes-stat">
<span>Pods:</span>
<strong>{{.AuditData.ClusterSummary.Pods}}</strong>
<strong>{{.AuditData.ClusterInfo.Pods}}</strong>
</span>
<span class="kubernetes-stat">
<span>Namespaces:</span>
<strong>{{.AuditData.ClusterSummary.Namespaces}}</strong>
<strong>{{.AuditData.ClusterInfo.Namespaces}}</strong>
</span>
</p>
</div>
@@ -54,7 +54,7 @@
<div class="card category">
<h3>Results by Category</h3>
<div class="expandable-table">
{{ range $category, $summary := .AuditData.ClusterSummary.Results.ByCategory }}
{{ range $category, $summary := .AuditData.GetSummaryByCategory }}
<div class="resource-info">
<div class="status-bar">
<div class="status">
@@ -74,30 +74,30 @@
</div>
</div>
{{ range $namespace, $nsResult := .AuditData.NamespacedResults }}
{{ range $namespace, $ctrlResults := .AuditData.GetResultsByNamespace }}
<div class="card namespace">
<h3>Namespace: <strong>{{ $namespace }}</strong></h3>
<div class="expandable-table">
{{ range getAllControllerResults $nsResult }}
{{ range $ctrlResults }}
<div class="resource-info">
<div class="status-bar">
<div class="status">
<div class="failing">
<div class="warning" style="width: {{ getWarningWidth .PodResult.Summary.Totals 200 }}px;">
<div class="passing" style="width: {{ getSuccessWidth .PodResult.Summary.Totals 200 }}px;"></div>
<div class="warning" style="width: {{ getWarningWidth .PodResult.GetSummary 200 }}px;">
<div class="passing" style="width: {{ getSuccessWidth .PodResult.GetSummary 200 }}px;"></div>
</div>
</div>
</div>
</div>
<div class="name"><span class="caret-expander"></span>
<span class="controller-type">{{ .Type }}:</span>
<span class="controller-type">{{ .Kind }}:</span>
<strong>{{ .Name }}</strong></div>
<div class="result-messages expandable-content">
<h4>Pod Spec:</h4>
<ul class="message-list">
{{ range $message := .PodResult.Messages}}
<li class="{{ .Type }}">
{{ range $message := .PodResult.Results.GetSortedMessages }}
<li class="{{ getResultClass . }}">
<i class="message-icon {{ getIcon $message }}"></i>
<span class="message">{{ .Message }}</span>
<a class="more-info" href="details/{{ getCategoryLink .Category }}">
@@ -107,12 +107,12 @@
{{ end }}
</ul>
</div>
{{ range .PodResult.ContainerResults}}
{{ range .PodResult.ContainerResults }}
<div class="result-messages expandable-content">
<h4>Container: {{ .Name }}</h4>
<ul class="message-list">
{{ range $message := .Messages}}
<li class="{{ .Type }}">
{{ range $message := .Results.GetSortedMessages }}
<li class="{{ getResultClass . }}">
<i class="message-icon {{ getIcon $message }}"></i>
<span class="message">{{ .Message }}</span>
<a class="more-info" href="details/{{ getCategoryLink .Category }}">
@@ -124,10 +124,10 @@
</div>
{{ end }} {{/* end range .PodResult.ContainerResults */}}
</div>
{{ end }} {{/* end range .DeploymentResults */}}
{{ end }} {{/* end range .Results.GetSortedMessages */}}
</div>
</div>
{{ end }} {{/* end range .AuditData.NamespacedResults */}}
{{ end }} {{/* end range .AuditData.GetResultsByNamespace */}}
<script src="static/js/charts.js">
</script>
{{end}}

View File

@@ -3,7 +3,7 @@
<head>
<script>
window.polarisAuditData = {{ .JSON }};
window.polarisSummary = {{ .JSON }};
</script>
{{ template "head" . }}
</head>

View File

@@ -81,93 +81,3 @@ type ContainerResult struct {
Name string
Results ResultSet
}
// CountSummary provides a high level overview of success, warnings, and errors.
type CountSummary struct {
Successes uint
Warnings uint
Errors uint
}
// GetScore returns an overall score in [0, 100] for the CountSummary
func (cs CountSummary) GetScore() uint {
total := (cs.Successes * 2) + cs.Warnings + (cs.Errors * 2)
return uint((float64(cs.Successes*2) / float64(total)) * 100)
}
func (cs *CountSummary) AddSummary(other CountSummary) {
cs.Successes += other.Successes
cs.Warnings += other.Warnings
cs.Errors += other.Errors
}
// CategorySummary provides a map from category name to a CountSummary
type CategorySummary map[string]*CountSummary
func (rs ResultSet) GetSummary() CountSummary {
cs := CountSummary{}
for _, result := range rs {
if result.Success == false {
if result.Severity == config.SeverityWarning {
cs.Warnings += 1
} else {
cs.Errors += 1
}
} else {
cs.Successes += 1
}
}
return cs
}
func (p PodResult) GetSummary() CountSummary {
summary := p.Results.GetSummary()
for _, containerResult := range p.ContainerResults {
summary.AddSummary(containerResult.Results.GetSummary())
}
return summary
}
func (c ControllerResult) GetSummary() CountSummary {
summary := c.Results.GetSummary()
summary.AddSummary(c.PodResult.GetSummary())
return summary
}
func (a AuditData) GetSummary() CountSummary {
summary := CountSummary{}
for _, ctrlResult := range a.Results {
summary.AddSummary(ctrlResult.GetSummary())
}
return summary
}
func (rs ResultSet) GetSuccesses() []ResultMessage {
successes := []ResultMessage{}
for _, msg := range rs {
if msg.Success {
successes = append(successes, msg)
}
}
return successes
}
func (rs ResultSet) GetWarnings() []ResultMessage {
warnings := []ResultMessage{}
for _, msg := range rs {
if msg.Success == false && msg.Severity == config.SeverityWarning {
warnings = append(warnings, msg)
}
}
return warnings
}
func (rs ResultSet) GetErrors() []ResultMessage {
errors := []ResultMessage{}
for _, msg := range rs {
if msg.Success == false && msg.Severity == config.SeverityError {
errors = append(errors, msg)
}
}
return errors
}

189
pkg/validator/summary.go Normal file
View File

@@ -0,0 +1,189 @@
package validator
import (
"github.com/fairwindsops/polaris/pkg/config"
)
// CountSummary provides a high level overview of success, warnings, and errors.
type CountSummary struct {
Successes uint
Warnings uint
Errors uint
}
// CountSummaryByCategory is a map from category to CountSummary
type CountSummaryByCategory map[string]CountSummary
// GetScore returns an overall score in [0, 100] for the CountSummary
func (cs CountSummary) GetScore() uint {
total := (cs.Successes * 2) + cs.Warnings + (cs.Errors * 2)
return uint((float64(cs.Successes*2) / float64(total)) * 100)
}
// AddSummary adds two CountSummaries together
func (cs *CountSummary) AddSummary(other CountSummary) {
cs.Successes += other.Successes
cs.Warnings += other.Warnings
cs.Errors += other.Errors
}
// AddSummary adds two CountSummaryByCategories together
func (csc CountSummaryByCategory) AddSummary(other CountSummaryByCategory) {
categories := []string{}
for cat, _ := range csc {
categories = append(categories, cat)
}
for cat, _ := range other {
categories = append(categories, cat)
}
for _, cat := range categories {
cur := csc[cat]
cur.AddSummary(other[cat])
csc[cat] = cur
}
}
// GetSummary summarizes a ResultSet
func (rs ResultSet) GetSummary() CountSummary {
cs := CountSummary{}
for _, result := range rs {
if result.Success == false {
if result.Severity == config.SeverityWarning {
cs.Warnings += 1
} else {
cs.Errors += 1
}
} else {
cs.Successes += 1
}
}
return cs
}
// GetSummaryByCategory summarizes a ResultSet
func (rs ResultSet) GetSummaryByCategory() CountSummaryByCategory {
summaries := CountSummaryByCategory{}
for _, result := range rs {
cs, ok := summaries[result.Category]
if !ok {
cs = CountSummary{}
}
if result.Success == false {
if result.Severity == config.SeverityWarning {
cs.Warnings += 1
} else {
cs.Errors += 1
}
} else {
cs.Successes += 1
}
summaries[result.Category] = cs
}
return summaries
}
// GetSummary summarizes a PodResult
func (p PodResult) GetSummary() CountSummary {
summary := p.Results.GetSummary()
for _, containerResult := range p.ContainerResults {
summary.AddSummary(containerResult.Results.GetSummary())
}
return summary
}
// GetSummaryByCategory summarizes a PodResult
func (p PodResult) GetSummaryByCategory() CountSummaryByCategory {
summaries := p.Results.GetSummaryByCategory()
for _, containerResult := range p.ContainerResults {
summaries.AddSummary(containerResult.Results.GetSummaryByCategory())
}
return summaries
}
// GetSummary summarizes a ControllerResult
func (c ControllerResult) GetSummary() CountSummary {
summary := c.Results.GetSummary()
summary.AddSummary(c.PodResult.GetSummary())
return summary
}
// GetSummaryByCategory summarizes a ControllerResult
func (c ControllerResult) GetSummaryByCategory() CountSummaryByCategory {
summary := c.Results.GetSummaryByCategory()
summary.AddSummary(c.PodResult.GetSummaryByCategory())
return summary
}
// GetSummary summarizes AuditData
func (a AuditData) GetSummary() CountSummary {
summary := CountSummary{}
for _, ctrlResult := range a.Results {
summary.AddSummary(ctrlResult.GetSummary())
}
return summary
}
// GetSummaryByCategory summarizes AuditData
func (a AuditData) GetSummaryByCategory() CountSummaryByCategory {
summaries := CountSummaryByCategory{}
for _, ctrlResult := range a.Results {
summaries.AddSummary(ctrlResult.GetSummaryByCategory())
}
return summaries
}
// GetResultsByNamespace organizes results by namespace
func (a AuditData) GetResultsByNamespace() map[string][]*ControllerResult {
allResults := map[string][]*ControllerResult{}
for idx, ctrlResult := range a.Results {
nsResults, ok := allResults[ctrlResult.Namespace]
if !ok {
nsResults = []*ControllerResult{}
}
nsResults = append(nsResults, &a.Results[idx])
allResults[ctrlResult.Namespace] = nsResults
}
return allResults
}
// GetSuccesses returns the success messages in a result set
func (rs ResultSet) GetSuccesses() []ResultMessage {
successes := []ResultMessage{}
for _, msg := range rs {
if msg.Success {
successes = append(successes, msg)
}
}
return successes
}
// GetWarnings returns the warning messages in a result set
func (rs ResultSet) GetWarnings() []ResultMessage {
warnings := []ResultMessage{}
for _, msg := range rs {
if msg.Success == false && msg.Severity == config.SeverityWarning {
warnings = append(warnings, msg)
}
}
return warnings
}
// GetErrors returns the error messages in a result set
func (rs ResultSet) GetErrors() []ResultMessage {
errors := []ResultMessage{}
for _, msg := range rs {
if msg.Success == false && msg.Severity == config.SeverityError {
errors = append(errors, msg)
}
}
return errors
}
// GetSortedMessages returns messages sorted as errors, then warnings, then successes
func (rs ResultSet) GetSortedMessages() []ResultMessage {
messages := []ResultMessage{}
messages = append(messages, rs.GetErrors()...)
messages = append(messages, rs.GetWarnings()...)
messages = append(messages, rs.GetSuccesses()...)
return messages
}