diff --git a/pkg/dashboard/assets/css/dashboard.css b/pkg/dashboard/assets/css/dashboard.css index e915e831..6c930e8c 100644 --- a/pkg/dashboard/assets/css/dashboard.css +++ b/pkg/dashboard/assets/css/dashboard.css @@ -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; } diff --git a/pkg/dashboard/assets/js/charts.js b/pkg/dashboard/assets/js/charts.js index f7cba310..b91fa5c7 100644 --- a/pkg/dashboard/assets/js/charts.js +++ b/pkg/dashboard/assets/js/charts.js @@ -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'], }] diff --git a/pkg/dashboard/dashboard.go b/pkg/dashboard/dashboard.go index dc2a0bb0..95fa5d69 100644 --- a/pkg/dashboard/dashboard.go +++ b/pkg/dashboard/dashboard.go @@ -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) diff --git a/pkg/dashboard/helpers.go b/pkg/dashboard/helpers.go index efe1ef39..1a041f55 100644 --- a/pkg/dashboard/helpers.go +++ b/pkg/dashboard/helpers.go @@ -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 { diff --git a/pkg/dashboard/templates/dashboard.gohtml b/pkg/dashboard/templates/dashboard.gohtml index df87c3a2..56ca6a09 100644 --- a/pkg/dashboard/templates/dashboard.gohtml +++ b/pkg/dashboard/templates/dashboard.gohtml @@ -9,10 +9,10 @@
-
-
{{ getWeatherText .AuditData.ClusterSummary.Results.Totals }}
-
Grade: {{ getGrade .AuditData.ClusterSummary.Results.Totals }}
-
Score: {{ .AuditData.ClusterSummary.Results.Totals.GetScore }}%
+
+
{{ getWeatherText .AuditData.GetSummary }}
+
Grade: {{ getGrade .AuditData.GetSummary }}
+
Score: {{ .AuditData.GetSummary.GetScore }}%
@@ -20,9 +20,9 @@
@@ -33,19 +33,19 @@

Kubernetes Version: - {{.AuditData.ClusterSummary.Version}} + {{.AuditData.ClusterInfo.Version}} Nodes: - {{.AuditData.ClusterSummary.Nodes}} + {{.AuditData.ClusterInfo.Nodes}} Pods: - {{.AuditData.ClusterSummary.Pods}} + {{.AuditData.ClusterInfo.Pods}} Namespaces: - {{.AuditData.ClusterSummary.Namespaces}} + {{.AuditData.ClusterInfo.Namespaces}}

@@ -54,7 +54,7 @@

Results by Category

- {{ range $category, $summary := .AuditData.ClusterSummary.Results.ByCategory }} + {{ range $category, $summary := .AuditData.GetSummaryByCategory }}
@@ -74,30 +74,30 @@
- {{ range $namespace, $nsResult := .AuditData.NamespacedResults }} + {{ range $namespace, $ctrlResults := .AuditData.GetResultsByNamespace }}

Namespace: {{ $namespace }}

- {{ end }} {{/* end range .AuditData.NamespacedResults */}} + {{ end }} {{/* end range .AuditData.GetResultsByNamespace */}} {{end}} diff --git a/pkg/dashboard/templates/main.gohtml b/pkg/dashboard/templates/main.gohtml index 92b722bc..7c999931 100644 --- a/pkg/dashboard/templates/main.gohtml +++ b/pkg/dashboard/templates/main.gohtml @@ -3,7 +3,7 @@ {{ template "head" . }} diff --git a/pkg/validator/output.go b/pkg/validator/output.go index b35f03d9..49fc7626 100644 --- a/pkg/validator/output.go +++ b/pkg/validator/output.go @@ -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 -} diff --git a/pkg/validator/summary.go b/pkg/validator/summary.go new file mode 100644 index 00000000..e605c682 --- /dev/null +++ b/pkg/validator/summary.go @@ -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 +}