diff --git a/pkg/dashboard/dashboard.go b/pkg/dashboard/dashboard.go index 482b4c60..b722fd20 100644 --- a/pkg/dashboard/dashboard.go +++ b/pkg/dashboard/dashboard.go @@ -1,3 +1,17 @@ +// Copyright 2019 ReactiveOps +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package dashboard import ( @@ -44,22 +58,13 @@ func MainHandler(w http.ResponseWriter, r *http.Request, c conf.Configuration, k JSON: template.JS(jsonData), } tmpl, err := template.New(TemplateName).Funcs(template.FuncMap{ - "getWarningWidth": func(rs validator.ResultSummary, fullWidth int) uint { - return uint(float64(rs.Successes+rs.Warnings) / float64(rs.Successes+rs.Warnings+rs.Errors) * float64(fullWidth)) - }, - "getSuccessWidth": func(rs validator.ResultSummary, fullWidth int) uint { - return uint(float64(rs.Successes) / float64(rs.Successes+rs.Warnings+rs.Errors) * float64(fullWidth)) - }, - "getIcon": func(rm validator.ResultMessage) string { - switch rm.Type { - case "success": - return "fas fa-check" - case "warning": - return "fas fa-exclamation" - default: - return "fas fa-times" - } - }, + "getWarningWidth": getWarningWidth, + "getSuccessWidth": getSuccessWidth, + "getWeatherIcon": getWeatherIcon, + "getWeatherText": getWeatherText, + "getGrade": getGrade, + "getScore": getScore, + "getIcon": getIcon, }).ParseFiles(TemplateFile) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) diff --git a/pkg/dashboard/helpers.go b/pkg/dashboard/helpers.go new file mode 100644 index 00000000..cc63317d --- /dev/null +++ b/pkg/dashboard/helpers.go @@ -0,0 +1,104 @@ +// Copyright 2019 ReactiveOps +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package dashboard + +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 getSuccessWidth(rs validator.ResultSummary, fullWidth int) uint { + return uint(float64(rs.Successes) / float64(rs.Successes+rs.Warnings+rs.Errors) * float64(fullWidth)) +} + +func getGrade(rs validator.ResultSummary) string { + score := getScore(rs) + if score >= 97 { + return "A+" + } else if score >= 93 { + return "A" + } else if score >= 90 { + return "A-" + } else if score >= 87 { + return "B+" + } else if score >= 83 { + return "B" + } else if score >= 80 { + return "B-" + } else if score >= 77 { + return "C+" + } else if score >= 73 { + return "C" + } else if score >= 70 { + return "C-" + } else if score >= 67 { + return "D+" + } else if score >= 63 { + return "D" + } else if score >= 60 { + return "D-" + } else { + return "F" + } +} + +func getScore(rs validator.ResultSummary) uint { + total := (rs.Successes * 2) + rs.Warnings + (rs.Errors * 2) + return uint((float64(rs.Successes*2) / float64(total)) * 100) +} + +func getWeatherIcon(rs validator.ResultSummary) string { + score := getScore(rs) + if score >= 90 { + return "fa-sun" + } else if score >= 80 { + return "fa-cloud-sun" + } else if score >= 70 { + return "fa-cloud" + } else if score >= 60 { + return "fa-cloud-rain" + } else { + return "fa-cloud-showers-heavy" + } +} + +func getWeatherText(rs validator.ResultSummary) string { + score := getScore(rs) + if score >= 90 { + return "Smooth sailing" + } else if score >= 80 { + return "Mostly smooth sailing" + } else if score >= 70 { + return "Smooth sailing within sight" + } else if score >= 60 { + return "A little stormy" + } else { + return "Storms ahead, be careful" + } +} + +func getIcon(rm validator.ResultMessage) string { + switch rm.Type { + case "success": + return "fas fa-check" + case "warning": + return "fas fa-exclamation" + default: + return "fas fa-times" + } +} diff --git a/pkg/dashboard/templates/dashboard.gohtml b/pkg/dashboard/templates/dashboard.gohtml index 2d2635b3..2d08ca1b 100644 --- a/pkg/dashboard/templates/dashboard.gohtml +++ b/pkg/dashboard/templates/dashboard.gohtml @@ -8,7 +8,7 @@ - + @@ -27,8 +27,8 @@
- - by + + Open Source Project By
@@ -36,16 +36,22 @@
-
-
-

Overall Score:

-
- +
+

Cluster Overview

+
+
+
+
{{ getWeatherText .AuditData.ClusterSummary }}
+
Grade: {{ getGrade .AuditData.ClusterSummary }} | Score: {{ getScore .AuditData.ClusterSummary }}%
-
-
-

Scores By Namespace:

- +
+
    +
  • {{ .AuditData.ClusterSummary.Successes }} checks passed
  • +
  • {{ .AuditData.ClusterSummary.Warnings }} checks had warnings
  • +
  • {{ .AuditData.ClusterSummary.Errors }} checks had errors
  • +
+
+
@@ -59,7 +65,7 @@
{{ .Type }}: {{ .Name }}
{{ range .PodResults}} -
+

Pod Spec:

    {{ range $message := .Messages}} @@ -68,7 +74,7 @@
{{ range .ContainerResults}} -
+

Container: {{ .Name }}

    {{ range $message := .Messages}} @@ -96,7 +102,7 @@
- - - -
-

- - -

-
- -
-
-
-

Overall Score:

-
- -
-
-
-

Scores By Namespace:

- -
-
- -
-

Namespace: kube-system

- - - - - - - - - - -
-
DaemonSet: datadog-agent
-
-
-
-
-
-
-
-
-
-
Deployment: tiller-deployment
-
    -
  • Image Tag Specified
  • -
  • Resource Limits
  • -
  • Resource Requests
  • -
  • Run As Non Root User
  • -
  • Liveness Probe
  • -
  • Readiness Probe
  • -
-
-
-
-
-
-
-
-
-
-
-
- - - - - \ No newline at end of file diff --git a/public/js/charts.js b/public/js/charts.js index b616174b..46244a05 100644 --- a/public/js/charts.js +++ b/public/js/charts.js @@ -1,57 +1,4 @@ -if (!Object.values) { - Object.values = function(obj) { - return Object.keys(obj).map(function(key) { - return obj[key]; - }) - } -} - $(function () { - var namespaceChart = new Chart("namespaceScoreChart", { - type: 'bar', - data: { - labels: Object.keys(fairwindsAuditData.NamespacedResults), - datasets: [{ - label: 'Passing', - data: Object.values(fairwindsAuditData.NamespacedResults) - .map(function(r) { return r.Summary.Successes}), - backgroundColor: '#8BD2DC', - },{ - label: 'Warning', - data: Object.values(fairwindsAuditData.NamespacedResults) - .map(function(r) { return r.Summary.Warnings}), - backgroundColor: '#f26c21', - },{ - label: 'Failing', - data: Object.values(fairwindsAuditData.NamespacedResults) - .map(function(r) { return r.Summary.Errors}), - backgroundColor: '#a11f4c', - }] - }, - options: { - legend: { - display: false, - }, - scales: { - xAxes: [{ - stacked: true, - }], - yAxes: [{ - stacked: true, - ticks: { - beginAtZero: true - } - }] - } - } - }); - - var score = fairwindsAuditData.ClusterSummary.Successes / ( - fairwindsAuditData.ClusterSummary.Successes + - fairwindsAuditData.ClusterSummary.Warnings + - fairwindsAuditData.ClusterSummary.Errors); - score = Math.round(score * 100); - var clusterChart = new Chart("clusterScoreChart", { type: 'doughnut', data: { @@ -62,24 +9,14 @@ $(function () { fairwindsAuditData.ClusterSummary.Warnings, fairwindsAuditData.ClusterSummary.Errors, ], - backgroundColor: ['#8BD2DC','#f26c21','#a11f4c'], + backgroundColor: ['#8BD2DC', '#f26c21', '#a11f4c'], }] }, options: { - // responsive: false, - cutoutPercentage: 75, + responsive: false, legend: { display: false, }, - elements: { - center: { - text: score + '%', - color: '#333', //Default black - fontStyle: 'Helvetica', //Default Arial - sidePadding: 30 //Default 20 (as a percentage) - } - } } }); -}); - +}); \ No newline at end of file diff --git a/public/js/main.js b/public/js/main.js index 2eaaafb0..8bf969f4 100644 --- a/public/js/main.js +++ b/public/js/main.js @@ -1,46 +1,14 @@ +if (!Object.values) { + Object.values = function (obj) { + return Object.keys(obj).map(function (key) { + return obj[key]; + }) + } +} + + $(function () { - // Chart.js plugin for rendering text inside of donut chart - // Credit: https://stackoverflow.com/a/43026361/8870697 - Chart.pluginService.register({ - beforeDraw: function (chart) { - if (chart.config.options.elements.center) { - var ctx = chart.chart.ctx; - var centerConfig = chart.config.options.elements.center; - var fontStyle = centerConfig.fontStyle || 'Arial'; - var txt = centerConfig.text; - var color = centerConfig.color || '#000'; - var sidePadding = centerConfig.sidePadding || 20; - var sidePaddingCalculated = (sidePadding/100) * (chart.innerRadius * 2) - // Start with a base font of 30px - ctx.font = "30px " + fontStyle; - - // Get the width of the string and also the width of the element minus 10 to give it 5px side padding - var stringWidth = ctx.measureText(txt).width; - var elementWidth = (chart.innerRadius * 2) - sidePaddingCalculated; - - // Find out how much the font can grow in width. - var widthRatio = elementWidth / stringWidth; - var newFontSize = Math.floor(30 * widthRatio); - var elementHeight = (chart.innerRadius * 2); - - // Pick a new font size so it will not be larger than the height of label. - var fontSizeToUse = Math.min(newFontSize, elementHeight); - - // Set font settings to draw it correctly. - ctx.textAlign = 'center'; - ctx.textBaseline = 'middle'; - var centerX = ((chart.chartArea.left + chart.chartArea.right) / 2); - var centerY = ((chart.chartArea.top + chart.chartArea.bottom) / 2); - ctx.font = "bold "+fontSizeToUse+"px " + fontStyle; - ctx.fillStyle = color; - - // Draw text in center - ctx.fillText(txt, centerX, centerY); - } - } - }); - - $('.namespace .resource-info .name').on('click', function(e) { + $('.namespace .resource-info .name').on('click', function (e) { console.log('clicked', arguments) console.log('parent', $(e.srcElement).parent('.resource-info')); $(e.srcElement).parents('.resource-info').toggleClass('expanded');