mirror of
https://github.com/FairwindsOps/polaris.git
synced 2026-05-08 18:26:43 +00:00
fix dashboard after output change
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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'],
|
||||
}]
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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}}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
<head>
|
||||
<script>
|
||||
window.polarisAuditData = {{ .JSON }};
|
||||
window.polarisSummary = {{ .JSON }};
|
||||
</script>
|
||||
{{ template "head" . }}
|
||||
</head>
|
||||
|
||||
@@ -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
189
pkg/validator/summary.go
Normal 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
|
||||
}
|
||||
Reference in New Issue
Block a user