mirror of
https://github.com/FairwindsOps/polaris.git
synced 2026-05-14 21:27:11 +00:00
Merge pull request #14 from reactiveops/rs/dashboard
Adding initial rough POC for dashboard UI
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -14,3 +14,4 @@ fairwinds
|
||||
|
||||
Tiltfile
|
||||
main
|
||||
.DS_Store
|
||||
|
||||
15
config.yml
Normal file
15
config.yml
Normal file
@@ -0,0 +1,15 @@
|
||||
resources:
|
||||
requests:
|
||||
cpu:
|
||||
min: 100m
|
||||
max: 1
|
||||
memory:
|
||||
min: 100M
|
||||
max: 3G
|
||||
limits:
|
||||
cpu:
|
||||
min: 150m
|
||||
max: 2
|
||||
memory:
|
||||
min: 150M
|
||||
max: 4G
|
||||
19
main.go
19
main.go
@@ -21,6 +21,7 @@ import (
|
||||
"os"
|
||||
|
||||
conf "github.com/reactiveops/fairwinds/pkg/config"
|
||||
"github.com/reactiveops/fairwinds/pkg/dashboard"
|
||||
"github.com/reactiveops/fairwinds/pkg/validator"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
@@ -49,7 +50,8 @@ func main() {
|
||||
|
||||
c, err := conf.ParseFile("config.yml")
|
||||
if err != nil {
|
||||
return
|
||||
glog.Println("Error parsing config.yml:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if *webhook {
|
||||
@@ -62,9 +64,18 @@ func main() {
|
||||
}
|
||||
|
||||
func startDashboardServer(c conf.Configuration) {
|
||||
http.HandleFunc("/validate", func(w http.ResponseWriter, r *http.Request) { validator.DeployHandler(w, r, c) })
|
||||
http.HandleFunc("/ping", validator.PingHandler)
|
||||
glog.Println("Starting Fairwinds dashboard webserver on port 8080.")
|
||||
http.HandleFunc("/results.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
dashboard.RenderJSON(w, r, c)
|
||||
})
|
||||
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("public/"))))
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path != "/" {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
dashboard.Render(w, r, c)
|
||||
})
|
||||
glog.Println("Starting Fairwinds dashboard server on port 8080.")
|
||||
glog.Fatal(http.ListenAndServe(":8080", nil))
|
||||
}
|
||||
|
||||
|
||||
80
pkg/dashboard/dashboard.go
Normal file
80
pkg/dashboard/dashboard.go
Normal file
@@ -0,0 +1,80 @@
|
||||
package dashboard
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"html/template"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
conf "github.com/reactiveops/fairwinds/pkg/config"
|
||||
"github.com/reactiveops/fairwinds/pkg/kube"
|
||||
"github.com/reactiveops/fairwinds/pkg/validator"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
type DashboardData struct {
|
||||
ClusterSummary *validator.ResultSummary
|
||||
NamespacedResults []validator.NamespacedResult
|
||||
}
|
||||
|
||||
var tmpl = template.Must(template.ParseFiles("pkg/dashboard/templates/charts.gohtml"))
|
||||
|
||||
func Render(w http.ResponseWriter, r *http.Request, c conf.Configuration) {
|
||||
dashboardData := getDashboardData()
|
||||
tmpl.Execute(w, dashboardData)
|
||||
}
|
||||
|
||||
func RenderJSON(w http.ResponseWriter, r *http.Request, c conf.Configuration) {
|
||||
results := []validator.Results{}
|
||||
pods, err := kube.CoreV1API.Pods("").List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
http.Error(w, "Error Fetching Pods", 500)
|
||||
return
|
||||
}
|
||||
log.Println("pods count:", len(pods.Items))
|
||||
for _, pod := range pods.Items {
|
||||
result := validator.ValidatePods(c, &pod.Spec, validator.Results{})
|
||||
results = append(results, result)
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(results)
|
||||
}
|
||||
|
||||
func getDashboardData() DashboardData {
|
||||
return DashboardData{
|
||||
ClusterSummary: &validator.ResultSummary{
|
||||
Successes: 46,
|
||||
Warnings: 8,
|
||||
Failures: 5,
|
||||
},
|
||||
NamespacedResults: []validator.NamespacedResult{{
|
||||
Namespace: "kube-system",
|
||||
Results: []validator.ResourceResult{{
|
||||
Name: "tiller",
|
||||
Type: "Deployment",
|
||||
Summary: &validator.ResultSummary{
|
||||
Successes: 7,
|
||||
Warnings: 3,
|
||||
Failures: 2,
|
||||
},
|
||||
Messages: []validator.ResultMessage{{
|
||||
Message: "Image Tag Specified",
|
||||
Type: "success",
|
||||
}, {
|
||||
Message: "Liveness Probe Specified",
|
||||
Type: "success",
|
||||
}, {
|
||||
Message: "Readiness Probe Specified",
|
||||
Type: "success",
|
||||
}, {
|
||||
Message: "Container Running As Root",
|
||||
Type: "warning",
|
||||
}, {
|
||||
Message: "Resource requests are not set",
|
||||
Type: "failure",
|
||||
}},
|
||||
}},
|
||||
}},
|
||||
}
|
||||
}
|
||||
177
pkg/dashboard/templates/charts.gohtml
Normal file
177
pkg/dashboard/templates/charts.gohtml
Normal file
@@ -0,0 +1,177 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||
<title>Fairwinds</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet">
|
||||
<link rel="stylesheet" href="/static/css/normalize.css">
|
||||
<link rel="stylesheet" href="/static/css/charts.css">
|
||||
|
||||
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.min.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="header">
|
||||
<h1>Fairwinds</h1>
|
||||
</div>
|
||||
|
||||
<div class="dashboard-content">
|
||||
<div class="charts">
|
||||
<div class="cluster-score chart-section">
|
||||
<h3>Overall Score:</h3>
|
||||
<div style="width:510px; height: 400px; left: -100px; position: relative;">
|
||||
<canvas id="clusterScoreChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<div class="namespace-score chart-section">
|
||||
<h3>Scores By Namespace:</h3>
|
||||
<canvas id="namespaceScoreChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{ range .NamespacedResults }}
|
||||
<div class="namespace">
|
||||
<h3>Namespace: <strong>{{ .Namespace }}</strong></h3>
|
||||
|
||||
<table class="namespace-content" cellspacing="0">
|
||||
{{ range .Results }}
|
||||
<tr>
|
||||
<td>
|
||||
<div class="name"><span class="caret-expander expanded"></span>{{ .Type }}: <strong>{{ .Name }}</strong></div>
|
||||
<ul class="extra">
|
||||
{{ range .Messages}}
|
||||
<li class="{{ .Type }}"><span>&#{{ .HTMLSpecialCharCode }};</span> {{ .Message }}</li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
</td>
|
||||
<td class="status-bar">
|
||||
<div class="status">
|
||||
<div class="failing">
|
||||
<div class="warning" style="width: {{ .Summary.WarningWidth 200 }}px;">
|
||||
<div class="passing" style="width: {{ .Summary.SuccessWidth 200 }}px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
</table>
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
|
||||
<script>
|
||||
window.onload = function renderCharts() {
|
||||
Chart.pluginService.register({
|
||||
beforeDraw: function (chart) {
|
||||
if (chart.config.options.elements.center) {
|
||||
//Get ctx from string
|
||||
var ctx = chart.chart.ctx;
|
||||
|
||||
//Get options from the center object in options
|
||||
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);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var namespaceChart = new Chart("namespaceScoreChart", {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: ["kube-system", "development", "staging", "infra", "default"],
|
||||
datasets: [{
|
||||
label: 'Passing',
|
||||
data: [118, 78, 65, 56, 43],
|
||||
backgroundColor: '#006469',
|
||||
},{
|
||||
label: 'Warning',
|
||||
data: [85, 54, 28, 23, 21],
|
||||
backgroundColor: '#AE7500',
|
||||
},{
|
||||
label: 'Failing',
|
||||
data: [38, 24, 18, 15, 12],
|
||||
backgroundColor: '#AE0400',
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
scales: {
|
||||
xAxes: [{
|
||||
stacked: true,
|
||||
}],
|
||||
yAxes: [{
|
||||
stacked: true,
|
||||
ticks: {
|
||||
beginAtZero: true
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var clusterChart = new Chart("clusterScoreChart", {
|
||||
type: 'doughnut',
|
||||
data: {
|
||||
labels: ["Passing", "Warning", "Failing"],
|
||||
datasets: [{
|
||||
data: [{{ .ClusterSummary.Successes }}, {{ .ClusterSummary.Warnings }}, {{ .ClusterSummary.Failures }}],
|
||||
backgroundColor: ['#006469','#AE7500','#AE0400'],
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
// responsive: false,
|
||||
cutoutPercentage: 75,
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
elements: {
|
||||
center: {
|
||||
text: '{{ .ClusterSummary.Score }}%',
|
||||
color: '#333', //Default black
|
||||
fontStyle: 'Helvetica', //Default Arial
|
||||
sidePadding: 30 //Default 20 (as a percentage)
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
78
pkg/dashboard/templates/dashboard.gohtml
Normal file
78
pkg/dashboard/templates/dashboard.gohtml
Normal file
@@ -0,0 +1,78 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||
<title>Fairwinds</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet">
|
||||
<link rel="stylesheet" href="/static/css/normalize.css">
|
||||
<link rel="stylesheet" href="/static/css/main.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="header">
|
||||
<h1>Fairwinds</h1>
|
||||
</div>
|
||||
|
||||
<div class="cluster-score">
|
||||
<p>Overall Score:</p>
|
||||
<h2>{{ .ClusterSummary.Score }}%</h2>
|
||||
<div class="status">
|
||||
<div class="failing">
|
||||
<div class="warning" style="width: {{ .ClusterSummary.WarningWidth 400 }}px;">
|
||||
<div class="passing" style="width: {{ .ClusterSummary.SuccessWidth 400 }}px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary">
|
||||
<div class="item">
|
||||
<span class="label">Successes:</span>
|
||||
<strong class="value">{{ .ClusterSummary.Successes }}</strong>
|
||||
</div>
|
||||
<div class="item">
|
||||
<span class="label">Warnings:</span>
|
||||
<strong class="value">{{ .ClusterSummary.Warnings }}</strong>
|
||||
</div>
|
||||
<div class="item">
|
||||
<span class="label">Failures:</span>
|
||||
<strong class="value">{{ .ClusterSummary.Failures }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{ range .NamespacedResults }}
|
||||
<div class="namespace-header">
|
||||
<h3>Namespace: <strong>{{ .Namespace }}</strong></h3>
|
||||
</div>
|
||||
|
||||
<table class="namespace-content">
|
||||
{{ range .Results }}
|
||||
<tr>
|
||||
<td>
|
||||
<div class="name"><span class="caret-expander expanded"></span>{{ .Type }}: <strong>{{ .Name }}</strong></div>
|
||||
<ul class="extra">
|
||||
{{ range .Messages}}
|
||||
<li class="{{ .Type }}"><span>&#{{ .HTMLSpecialCharCode }};</span> {{ .Message }}</li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
</td>
|
||||
<td class="status-bar">
|
||||
<div class="status">
|
||||
<div class="failing">
|
||||
<div class="warning" style="width: {{ .Summary.WarningWidth 200 }}px;">
|
||||
<div class="passing" style="width: {{ .Summary.SuccessWidth 200 }}px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
</table>
|
||||
{{ end }}
|
||||
</body>
|
||||
|
||||
</html>
|
||||
64
pkg/validator/types.go
Normal file
64
pkg/validator/types.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package validator
|
||||
|
||||
// namespaceResults: [{
|
||||
// name: "kube-system",
|
||||
// resourceResults: [{
|
||||
// name: "example-deployment",
|
||||
// type: "DaemonSet",
|
||||
// summary: {
|
||||
// successes: 28,
|
||||
// warnings: 12,
|
||||
// failures: 18,
|
||||
// },
|
||||
// messages: [{
|
||||
// message: "Resource requests are not set",
|
||||
// type: "failure",
|
||||
// }]
|
||||
// }]
|
||||
// }]
|
||||
|
||||
type NamespacedResult struct {
|
||||
Namespace string
|
||||
Results []ResourceResult
|
||||
}
|
||||
|
||||
type ResourceResult struct {
|
||||
Name string
|
||||
Type string
|
||||
Summary *ResultSummary
|
||||
Messages []ResultMessage
|
||||
}
|
||||
|
||||
type ResultSummary struct {
|
||||
Successes uint
|
||||
Warnings uint
|
||||
Failures uint
|
||||
}
|
||||
|
||||
type ResultMessage struct {
|
||||
Message string
|
||||
Type string
|
||||
}
|
||||
|
||||
func (rs *ResultSummary) Score() uint {
|
||||
return uint(float64(rs.Successes) / float64(rs.Successes+rs.Warnings+rs.Failures) * 100)
|
||||
}
|
||||
|
||||
func (rs *ResultSummary) WarningWidth(fullWidth uint) uint {
|
||||
return uint(float64(rs.Successes+rs.Warnings) / float64(rs.Successes+rs.Warnings+rs.Failures) * float64(fullWidth))
|
||||
}
|
||||
|
||||
func (rs *ResultSummary) SuccessWidth(fullWidth uint) uint {
|
||||
return uint(float64(rs.Successes) / float64(rs.Successes+rs.Warnings+rs.Failures) * float64(fullWidth))
|
||||
}
|
||||
|
||||
func (rm *ResultMessage) HTMLSpecialCharCode() string {
|
||||
switch rm.Type {
|
||||
case "success":
|
||||
return "9745"
|
||||
case "warning":
|
||||
return "9888"
|
||||
default:
|
||||
return "9746"
|
||||
}
|
||||
}
|
||||
192
public/charts.html
Normal file
192
public/charts.html
Normal file
@@ -0,0 +1,192 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||
<title>Fairwinds</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet">
|
||||
<link rel="stylesheet" href="css/normalize.css">
|
||||
<link rel="stylesheet" href="css/charts.css">
|
||||
|
||||
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.min.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="header">
|
||||
<h1>Fairwinds</h1>
|
||||
</div>
|
||||
|
||||
<div class="dashboard-content">
|
||||
<div class="charts">
|
||||
<div class="cluster-score chart-section">
|
||||
<h3>Overall Score:</h3>
|
||||
<div style="width:510px; height: 400px; left: -100px; position: relative;">
|
||||
<canvas id="clusterScoreChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<div class="namespace-score chart-section">
|
||||
<h3>Scores By Namespace:</h3>
|
||||
<canvas id="namespaceScoreChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="namespace">
|
||||
<h3>Namespace: <strong>kube-system</strong></h3>
|
||||
|
||||
<table class="namespace-content" cellspacing="0">
|
||||
<tr>
|
||||
<td>
|
||||
<div class="name"><span class="caret-expander"></span>DaemonSet: <strong>datadog-agent</strong></div>
|
||||
</td>
|
||||
<td class="status-bar">
|
||||
<div class="status">
|
||||
<div class="failing">
|
||||
<div class="warning" style="width: 124px;">
|
||||
<div class="passing" style="width: 82px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="name"><span class="caret-expander expanded"></span>Deployment: <strong>tiller-deployment</strong></div>
|
||||
<ul class="extra">
|
||||
<li class="success"><span>☑</span> Image Tag Specified</li>
|
||||
<li class="success"><span>☑</span> Resource Limits</li>
|
||||
<li class="success"><span>☑</span> Resource Requests</li>
|
||||
<li class="warning"><span>⚠</span> Run As Non Root User</li>
|
||||
<li class="failure"><span>☒</span> Liveness Probe</li>
|
||||
<li class="failure"><span>☒</span> Readiness Probe</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td class="status-bar">
|
||||
<div class="status">
|
||||
<div class="failing">
|
||||
<div class="warning" style="width: 150px;">
|
||||
<div class="passing" style="width: 106px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
window.onload = function renderCharts() {
|
||||
Chart.pluginService.register({
|
||||
beforeDraw: function (chart) {
|
||||
if (chart.config.options.elements.center) {
|
||||
//Get ctx from string
|
||||
var ctx = chart.chart.ctx;
|
||||
|
||||
//Get options from the center object in options
|
||||
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);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
var namespaceChart = new Chart("namespaceScoreChart", {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: ["kube-system", "development", "staging", "infra", "default"],
|
||||
datasets: [{
|
||||
label: 'Passing',
|
||||
data: [118, 78, 65, 56, 43],
|
||||
backgroundColor: '#006469',
|
||||
},{
|
||||
label: 'Warning',
|
||||
data: [85, 54, 28, 23, 21],
|
||||
backgroundColor: '#AE7500',
|
||||
},{
|
||||
label: 'Failing',
|
||||
data: [38, 24, 18, 15, 12],
|
||||
backgroundColor: '#AE0400',
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
scales: {
|
||||
xAxes: [{
|
||||
stacked: true,
|
||||
}],
|
||||
yAxes: [{
|
||||
stacked: true,
|
||||
ticks: {
|
||||
beginAtZero: true
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var clusterChart = new Chart("clusterScoreChart", {
|
||||
type: 'doughnut',
|
||||
data: {
|
||||
labels: ["Passing", "Warning", "Failing"],
|
||||
datasets: [{
|
||||
data: [118, 34, 28],
|
||||
backgroundColor: ['#006469','#AE7500','#AE0400'],
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
// responsive: false,
|
||||
cutoutPercentage: 75,
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
elements: {
|
||||
center: {
|
||||
text: '64%',
|
||||
color: '#333', //Default black
|
||||
fontStyle: 'Helvetica', //Default Arial
|
||||
sidePadding: 30 //Default 20 (as a percentage)
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
193
public/css/charts.css
Normal file
193
public/css/charts.css
Normal file
@@ -0,0 +1,193 @@
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif;
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
.header {
|
||||
background-color: #fff;
|
||||
color: #006369;
|
||||
padding: 20px 30px;
|
||||
box-shadow: 0 2px 5px rgba(0,0,0,0.3);
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-family: 'Lobster', sans-serif;
|
||||
font-size: 60px;
|
||||
font-weight: normal;
|
||||
margin: 0 auto;
|
||||
width: 900px;
|
||||
}
|
||||
|
||||
.dashboard-content {
|
||||
width: 960px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.charts {
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
.chart-section {
|
||||
float: left;
|
||||
margin: 20px;
|
||||
padding: 30px;
|
||||
width: 300px;
|
||||
height: 320px;
|
||||
color: #333;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 2px 5px rgba(0,0,0,0.3);
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.chart-section.namespace-score {
|
||||
margin-left: 0px;
|
||||
width: 480px;
|
||||
}
|
||||
|
||||
.chart-section h3 {
|
||||
margin: 0 0 15px;
|
||||
padding: 0 0 15px;
|
||||
font-weight: 300;
|
||||
font-size: 30px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
#clusterScoreChart {
|
||||
width: 260px;
|
||||
height: 260px;
|
||||
}
|
||||
|
||||
#namespaceScoreChart {
|
||||
width: 520px;
|
||||
height: 260px;
|
||||
}
|
||||
|
||||
.namespace {
|
||||
margin: 20px;
|
||||
padding: 10px 20px;
|
||||
color: #333;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 2px 5px rgba(0,0,0,0.3);
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.namespace h3 {
|
||||
margin: 0;
|
||||
font-weight: 300;
|
||||
font-size: 30px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.namespace h3 strong {
|
||||
margin: 0;
|
||||
font-weight: bold;
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
.cluster-score .status {
|
||||
width: 400px;
|
||||
height: 30px;
|
||||
margin: 30px auto;
|
||||
}
|
||||
|
||||
.namespace-content {
|
||||
width: 100%;
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.namespace-content tr {
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.namespace-content td {
|
||||
padding: 15px 20px;
|
||||
margin: 0;
|
||||
font-size: 18px;
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
|
||||
.namespace-content .caret-expander {
|
||||
display: inline-block;
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
margin-right: 10px;
|
||||
background-image: url('../images/caret-right.svg');
|
||||
background-size: 15px auto;
|
||||
background-repeat: no-repeat;
|
||||
background-position: 2px center;
|
||||
}
|
||||
|
||||
.namespace-content .caret-expander.expanded {
|
||||
background-image: url('../images/caret-bottom.svg');
|
||||
background-position: center center;
|
||||
}
|
||||
|
||||
.namespace-content .extra {
|
||||
list-style-type: none;
|
||||
font-size: 14px;
|
||||
line-height: 19px;
|
||||
margin: 10px 30px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.namespace-content .extra span {
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
width: 20px;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.namespace-content .extra .success {
|
||||
color: #006469;
|
||||
}
|
||||
|
||||
.namespace-content .extra .warning {
|
||||
color: #AE7500;
|
||||
}
|
||||
|
||||
.namespace-content .extra .warning span {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.namespace-content .extra .failure {
|
||||
color: #AE0400;
|
||||
}
|
||||
|
||||
.namespace-content td.status-bar {
|
||||
vertical-align: top;
|
||||
padding-top: 18px;
|
||||
}
|
||||
|
||||
.namespace-content .status {
|
||||
float: right;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.namespace-content .status div {
|
||||
height: 15px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.namespace-content .status .passing {
|
||||
background-color: #006469;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.namespace-content .status .warning {
|
||||
background-color: #AE7500;
|
||||
float: left;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
0% {opacity: 0;}
|
||||
100% {opacity: 1;}
|
||||
}
|
||||
|
||||
.namespace-content .status .failing {
|
||||
background-color: #AE0400;
|
||||
width: 200px;
|
||||
animation: fadeIn 2s;
|
||||
}
|
||||
|
||||
198
public/css/main.css
Normal file
198
public/css/main.css
Normal file
@@ -0,0 +1,198 @@
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: 'Helvetica', 'Arial', sans-serif;
|
||||
}
|
||||
|
||||
.header {
|
||||
background-color: #006369;
|
||||
color: #fff;
|
||||
padding: 50px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-family: 'Lobster', sans-serif;
|
||||
font-size: 100px;
|
||||
font-weight: normal;
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.cluster-score {
|
||||
margin: 0;
|
||||
padding: 30px;
|
||||
color: #003339;
|
||||
background-color: #eaf3f9;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.cluster-score h2 {
|
||||
margin: 0;
|
||||
font-size: 80px;
|
||||
}
|
||||
|
||||
.cluster-score .status {
|
||||
width: 400px;
|
||||
height: 30px;
|
||||
margin: 30px auto;
|
||||
}
|
||||
|
||||
.cluster-score .status div {
|
||||
height: 30px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.cluster-score .status .passing {
|
||||
background-color: #4ab977;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.cluster-score .status .warning {
|
||||
background-color: #bdbd63;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.cluster-score .status .failing {
|
||||
background-color: #c37575;
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
.cluster-score p {
|
||||
margin: 10px 0;
|
||||
font-weight: 300;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.cluster-score .summary {
|
||||
margin: 30px auto;
|
||||
font-weight: 300;
|
||||
font-size: 24px;
|
||||
width: 300px;
|
||||
text-align: left;
|
||||
line-height: 40px;
|
||||
}
|
||||
|
||||
.cluster-score .summary .value {
|
||||
float: right;
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.namespace-header {
|
||||
background-color: #006369;
|
||||
color: #fff;
|
||||
font-size: 50px;
|
||||
font-weight: normal;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.namespace-header h3 {
|
||||
margin: 0;
|
||||
font-weight: 300;
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
.namespace-header h3 strong {
|
||||
margin: 0;
|
||||
font-weight: bold;
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
.cluster-score .status {
|
||||
width: 400px;
|
||||
height: 30px;
|
||||
margin: 30px auto;
|
||||
}
|
||||
|
||||
.namespace-content {
|
||||
width: 100%;
|
||||
background-color: #eaf3f9;
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.namespace-content tr {
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.namespace-content td {
|
||||
padding: 15px 20px;
|
||||
margin: 0;
|
||||
font-size: 18px;
|
||||
border-bottom: 1px solid #aac3c9;
|
||||
}
|
||||
|
||||
.namespace-content .caret-expander {
|
||||
display: inline-block;
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
margin-right: 10px;
|
||||
background-image: url('../images/caret-right.svg');
|
||||
background-size: 15px auto;
|
||||
background-repeat: no-repeat;
|
||||
background-position: 2px center;
|
||||
}
|
||||
|
||||
.namespace-content .caret-expander.expanded {
|
||||
background-image: url('../images/caret-bottom.svg');
|
||||
background-position: center center;
|
||||
}
|
||||
|
||||
.namespace-content .extra {
|
||||
list-style-type: none;
|
||||
font-size: 14px;
|
||||
line-height: 19px;
|
||||
margin: 10px 30px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.namespace-content .extra span {
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.namespace-content .extra .success {
|
||||
color: #2a9957;
|
||||
}
|
||||
|
||||
.namespace-content .extra .warning {
|
||||
color: #adad43;
|
||||
}
|
||||
|
||||
.namespace-content .extra .warning span {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.namespace-content .extra .failure {
|
||||
color: #a35555;
|
||||
}
|
||||
|
||||
.namespace-content td.status-bar {
|
||||
vertical-align: top;
|
||||
padding-top: 18px;
|
||||
}
|
||||
|
||||
.namespace-content .status {
|
||||
float: right;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.namespace-content .status div {
|
||||
height: 15px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.namespace-content .status .passing {
|
||||
background-color: #4ab977;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.namespace-content .status .warning {
|
||||
background-color: #bdbd63;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.namespace-content .status .failing {
|
||||
background-color: #c37575;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
349
public/css/normalize.css
vendored
Normal file
349
public/css/normalize.css
vendored
Normal file
@@ -0,0 +1,349 @@
|
||||
/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
|
||||
|
||||
/* Document
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* 1. Correct the line height in all browsers.
|
||||
* 2. Prevent adjustments of font size after orientation changes in iOS.
|
||||
*/
|
||||
|
||||
html {
|
||||
line-height: 1.15; /* 1 */
|
||||
-webkit-text-size-adjust: 100%; /* 2 */
|
||||
}
|
||||
|
||||
/* Sections
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Remove the margin in all browsers.
|
||||
*/
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the `main` element consistently in IE.
|
||||
*/
|
||||
|
||||
main {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct the font size and margin on `h1` elements within `section` and
|
||||
* `article` contexts in Chrome, Firefox, and Safari.
|
||||
*/
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
margin: 0.67em 0;
|
||||
}
|
||||
|
||||
/* Grouping content
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* 1. Add the correct box sizing in Firefox.
|
||||
* 2. Show the overflow in Edge and IE.
|
||||
*/
|
||||
|
||||
hr {
|
||||
box-sizing: content-box; /* 1 */
|
||||
height: 0; /* 1 */
|
||||
overflow: visible; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the inheritance and scaling of font size in all browsers.
|
||||
* 2. Correct the odd `em` font sizing in all browsers.
|
||||
*/
|
||||
|
||||
pre {
|
||||
font-family: monospace, monospace; /* 1 */
|
||||
font-size: 1em; /* 2 */
|
||||
}
|
||||
|
||||
/* Text-level semantics
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Remove the gray background on active links in IE 10.
|
||||
*/
|
||||
|
||||
a {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Remove the bottom border in Chrome 57-
|
||||
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
|
||||
*/
|
||||
|
||||
abbr[title] {
|
||||
border-bottom: none; /* 1 */
|
||||
text-decoration: underline; /* 2 */
|
||||
text-decoration: underline dotted; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct font weight in Chrome, Edge, and Safari.
|
||||
*/
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the inheritance and scaling of font size in all browsers.
|
||||
* 2. Correct the odd `em` font sizing in all browsers.
|
||||
*/
|
||||
|
||||
code,
|
||||
kbd,
|
||||
samp {
|
||||
font-family: monospace, monospace; /* 1 */
|
||||
font-size: 1em; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct font size in all browsers.
|
||||
*/
|
||||
|
||||
small {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent `sub` and `sup` elements from affecting the line height in
|
||||
* all browsers.
|
||||
*/
|
||||
|
||||
sub,
|
||||
sup {
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
position: relative;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
/* Embedded content
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Remove the border on images inside links in IE 10.
|
||||
*/
|
||||
|
||||
img {
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
/* Forms
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* 1. Change the font styles in all browsers.
|
||||
* 2. Remove the margin in Firefox and Safari.
|
||||
*/
|
||||
|
||||
button,
|
||||
input,
|
||||
optgroup,
|
||||
select,
|
||||
textarea {
|
||||
font-family: inherit; /* 1 */
|
||||
font-size: 100%; /* 1 */
|
||||
line-height: 1.15; /* 1 */
|
||||
margin: 0; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the overflow in IE.
|
||||
* 1. Show the overflow in Edge.
|
||||
*/
|
||||
|
||||
button,
|
||||
input { /* 1 */
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the inheritance of text transform in Edge, Firefox, and IE.
|
||||
* 1. Remove the inheritance of text transform in Firefox.
|
||||
*/
|
||||
|
||||
button,
|
||||
select { /* 1 */
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct the inability to style clickable types in iOS and Safari.
|
||||
*/
|
||||
|
||||
button,
|
||||
[type="button"],
|
||||
[type="reset"],
|
||||
[type="submit"] {
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the inner border and padding in Firefox.
|
||||
*/
|
||||
|
||||
button::-moz-focus-inner,
|
||||
[type="button"]::-moz-focus-inner,
|
||||
[type="reset"]::-moz-focus-inner,
|
||||
[type="submit"]::-moz-focus-inner {
|
||||
border-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the focus styles unset by the previous rule.
|
||||
*/
|
||||
|
||||
button:-moz-focusring,
|
||||
[type="button"]:-moz-focusring,
|
||||
[type="reset"]:-moz-focusring,
|
||||
[type="submit"]:-moz-focusring {
|
||||
outline: 1px dotted ButtonText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct the padding in Firefox.
|
||||
*/
|
||||
|
||||
fieldset {
|
||||
padding: 0.35em 0.75em 0.625em;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the text wrapping in Edge and IE.
|
||||
* 2. Correct the color inheritance from `fieldset` elements in IE.
|
||||
* 3. Remove the padding so developers are not caught out when they zero out
|
||||
* `fieldset` elements in all browsers.
|
||||
*/
|
||||
|
||||
legend {
|
||||
box-sizing: border-box; /* 1 */
|
||||
color: inherit; /* 2 */
|
||||
display: table; /* 1 */
|
||||
max-width: 100%; /* 1 */
|
||||
padding: 0; /* 3 */
|
||||
white-space: normal; /* 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct vertical alignment in Chrome, Firefox, and Opera.
|
||||
*/
|
||||
|
||||
progress {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the default vertical scrollbar in IE 10+.
|
||||
*/
|
||||
|
||||
textarea {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Add the correct box sizing in IE 10.
|
||||
* 2. Remove the padding in IE 10.
|
||||
*/
|
||||
|
||||
[type="checkbox"],
|
||||
[type="radio"] {
|
||||
box-sizing: border-box; /* 1 */
|
||||
padding: 0; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct the cursor style of increment and decrement buttons in Chrome.
|
||||
*/
|
||||
|
||||
[type="number"]::-webkit-inner-spin-button,
|
||||
[type="number"]::-webkit-outer-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the odd appearance in Chrome and Safari.
|
||||
* 2. Correct the outline style in Safari.
|
||||
*/
|
||||
|
||||
[type="search"] {
|
||||
-webkit-appearance: textfield; /* 1 */
|
||||
outline-offset: -2px; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the inner padding in Chrome and Safari on macOS.
|
||||
*/
|
||||
|
||||
[type="search"]::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the inability to style clickable types in iOS and Safari.
|
||||
* 2. Change font properties to `inherit` in Safari.
|
||||
*/
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
-webkit-appearance: button; /* 1 */
|
||||
font: inherit; /* 2 */
|
||||
}
|
||||
|
||||
/* Interactive
|
||||
========================================================================== */
|
||||
|
||||
/*
|
||||
* Add the correct display in Edge, IE 10+, and Firefox.
|
||||
*/
|
||||
|
||||
details {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the correct display in all browsers.
|
||||
*/
|
||||
|
||||
summary {
|
||||
display: list-item;
|
||||
}
|
||||
|
||||
/* Misc
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Add the correct display in IE 10+.
|
||||
*/
|
||||
|
||||
template {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct display in IE 10.
|
||||
*/
|
||||
|
||||
[hidden] {
|
||||
display: none;
|
||||
}
|
||||
3
public/images/caret-bottom.svg
Executable file
3
public/images/caret-bottom.svg
Executable file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="8" height="8" viewBox="0 0 8 8">
|
||||
<path d="M0 0l4 4 4-4h-8z" transform="translate(0 2)" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 145 B |
3
public/images/caret-right.svg
Executable file
3
public/images/caret-right.svg
Executable file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="8" height="8" viewBox="0 0 8 8">
|
||||
<path d="M0 0v8l4-4-4-4z" transform="translate(2)" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 142 B |
3
public/images/circle-check.svg
Executable file
3
public/images/circle-check.svg
Executable file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="8" height="8" viewBox="0 0 8 8">
|
||||
<path d="M4 0c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm2 1.78l.72.72-3.22 3.22-1.72-1.72.72-.72 1 1 2.5-2.5z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 213 B |
3
public/images/circle-x.svg
Executable file
3
public/images/circle-x.svg
Executable file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="8" height="8" viewBox="0 0 8 8">
|
||||
<path d="M4 0c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm-1.5 1.78l1.5 1.5 1.5-1.5.72.72-1.5 1.5 1.5 1.5-.72.72-1.5-1.5-1.5 1.5-.72-.72 1.5-1.5-1.5-1.5.72-.72z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 262 B |
3
public/images/warning.svg
Executable file
3
public/images/warning.svg
Executable file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="8" height="8" viewBox="0 0 8 8">
|
||||
<path d="M3.09 0c-.06 0-.1.04-.13.09l-2.94 6.81c-.02.05-.03.13-.03.19v.81c0 .05.04.09.09.09h6.81c.05 0 .09-.04.09-.09v-.81c0-.05-.01-.14-.03-.19l-2.94-6.81c-.02-.05-.07-.09-.13-.09h-.81zm-.09 3h1v2h-1v-2zm0 3h1v1h-1v-1z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 312 B |
92
public/index.html
Normal file
92
public/index.html
Normal file
@@ -0,0 +1,92 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||
<title>Fairwinds</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet">
|
||||
<link rel="stylesheet" href="css/normalize.css">
|
||||
<link rel="stylesheet" href="css/main.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="header">
|
||||
<h1>Fairwinds</h1>
|
||||
</div>
|
||||
|
||||
<div class="cluster-score">
|
||||
<p>Overall Score:</p>
|
||||
<h2>64%</h2>
|
||||
<div class="status">
|
||||
<div class="failing">
|
||||
<div class="warning" style="width: 300px;">
|
||||
<div class="passing" style="width: 216px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary">
|
||||
<div class="item">
|
||||
<span class="label">Successes:</span>
|
||||
<strong class="value">118</strong>
|
||||
</div>
|
||||
<div class="item">
|
||||
<span class="label">Warnings:</span>
|
||||
<strong class="value">34</strong>
|
||||
</div>
|
||||
<div class="item">
|
||||
<span class="label">Failures:</span>
|
||||
<strong class="value">28</strong>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="namespace-header">
|
||||
<h3>Namespace: <strong>kube-system</strong></h3>
|
||||
</div>
|
||||
|
||||
<table class="namespace-content" cellspacing="0">
|
||||
<tr>
|
||||
<td>
|
||||
<div class="name"><span class="caret-expander"></span>DaemonSet: <strong>datadog-agent</strong></div>
|
||||
</td>
|
||||
<td class="status-bar">
|
||||
<div class="status">
|
||||
<div class="failing">
|
||||
<div class="warning" style="width: 124px;">
|
||||
<div class="passing" style="width: 82px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="name"><span class="caret-expander expanded"></span>Deployment: <strong>tiller-deployment</strong></div>
|
||||
<ul class="extra">
|
||||
<li class="pass"><span>☑</span> Image Tag Specified</li>
|
||||
<li class="pass"><span>☑</span> Resource Limits</li>
|
||||
<li class="pass"><span>☑</span> Resource Requests</li>
|
||||
<li class="warn"><span>⚠</span> Run As Non Root User</li>
|
||||
<li class="fail"><span>☒</span> Liveness Probe</li>
|
||||
<li class="fail"><span>☒</span> Readiness Probe</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td class="status-bar">
|
||||
<div class="status">
|
||||
<div class="failing">
|
||||
<div class="warning" style="width: 150px;">
|
||||
<div class="passing" style="width: 106px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Reference in New Issue
Block a user