diff --git a/pkg/dashboard/helpers.go b/pkg/dashboard/helpers.go
index cc63317d5..fa37adbda 100644
--- a/pkg/dashboard/helpers.go
+++ b/pkg/dashboard/helpers.go
@@ -18,12 +18,12 @@ 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 getWarningWidth(counts validator.CountSummary, fullWidth int) uint {
+ return uint(float64(counts.Successes+counts.Warnings) / float64(counts.Successes+counts.Warnings+counts.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 getSuccessWidth(counts validator.CountSummary, fullWidth int) uint {
+ return uint(float64(counts.Successes) / float64(counts.Successes+counts.Warnings+counts.Errors) * float64(fullWidth))
}
func getGrade(rs validator.ResultSummary) string {
@@ -58,8 +58,8 @@ func getGrade(rs validator.ResultSummary) string {
}
func getScore(rs validator.ResultSummary) uint {
- total := (rs.Successes * 2) + rs.Warnings + (rs.Errors * 2)
- return uint((float64(rs.Successes*2) / float64(total)) * 100)
+ total := (rs.Totals.Successes * 2) + rs.Totals.Warnings + (rs.Totals.Errors * 2)
+ return uint((float64(rs.Totals.Successes*2) / float64(total)) * 100)
}
func getWeatherIcon(rs validator.ResultSummary) string {
diff --git a/pkg/dashboard/templates/dashboard.gohtml b/pkg/dashboard/templates/dashboard.gohtml
index 8be85ccdd..0afd67b81 100644
--- a/pkg/dashboard/templates/dashboard.gohtml
+++ b/pkg/dashboard/templates/dashboard.gohtml
@@ -47,9 +47,9 @@
- - {{ .AuditData.ClusterSummary.Results.Successes }} checks passed
- - {{ .AuditData.ClusterSummary.Results.Warnings }} checks had warnings
- - {{ .AuditData.ClusterSummary.Results.Errors }} checks had errors
+ - {{ .AuditData.ClusterSummary.Results.Totals.Successes }} checks passed
+ - {{ .AuditData.ClusterSummary.Results.Totals.Warnings }} checks had warnings
+ - {{ .AuditData.ClusterSummary.Results.Totals.Errors }} checks had errors
@@ -80,7 +80,32 @@
+
+
+ Health summary
+
+
+ {{ range $category, $summary := .AuditData.ClusterSummary.Results.ByCategory }}
+ -
+ {{ $category }}
+ {{ $summary.Errors }} errors, {{ $summary.Warnings }} warnings
+
+
+ {{ end }}
+
+
+ |
+
+
{{ range $namespace, $results := .AuditData.NamespacedResults }}
@@ -116,8 +141,8 @@
diff --git a/pkg/validator/container.go b/pkg/validator/container.go
index da81e6619..dff92354d 100644
--- a/pkg/validator/container.go
+++ b/pkg/validator/container.go
@@ -31,12 +31,10 @@ type ContainerValidation struct {
}
// ValidateContainer validates that each pod conforms to the Fairwinds config, returns a ResourceResult.
-func ValidateContainer(cnConf *conf.Configuration, container *corev1.Container) ResourceResult {
+func ValidateContainer(cnConf *conf.Configuration, container *corev1.Container) ContainerResult {
cv := ContainerValidation{
- Container: container,
- ResourceValidation: &ResourceValidation{
- Summary: &ResultSummary{},
- },
+ Container: container,
+ ResourceValidation: &ResourceValidation{},
}
cv.validateResources(&cnConf.Resources)
@@ -48,16 +46,10 @@ func ValidateContainer(cnConf *conf.Configuration, container *corev1.Container)
cRes := ContainerResult{
Name: container.Name,
Messages: cv.messages(),
+ Summary: cv.summary(),
}
- rr := ResourceResult{
- Name: container.Name,
- Type: "Container",
- Summary: cv.Summary,
- ContainerResults: []ContainerResult{cRes},
- }
-
- return rr
+ return cRes
}
func (cv *ContainerValidation) validateResources(resConf *conf.Resources) {
diff --git a/pkg/validator/container_test.go b/pkg/validator/container_test.go
index 55ea4be21..05c376514 100644
--- a/pkg/validator/container_test.go
+++ b/pkg/validator/container_test.go
@@ -69,10 +69,8 @@ func TestValidateResourcesEmptyConfig(t *testing.T) {
}
cv := ContainerValidation{
- Container: &container,
- ResourceValidation: &ResourceValidation{
- Summary: &ResultSummary{},
- },
+ Container: &container,
+ ResourceValidation: &ResourceValidation{},
}
expected := conf.Resources{}
@@ -195,10 +193,8 @@ func TestValidateResourcesFullyValid(t *testing.T) {
func testValidateResources(t *testing.T, container *corev1.Container, resourceConf *string, expectedErrors *[]*ResultMessage, expectedWarnings *[]*ResultMessage) {
cv := ContainerValidation{
- Container: container,
- ResourceValidation: &ResourceValidation{
- Summary: &ResultSummary{},
- },
+ Container: container,
+ ResourceValidation: &ResourceValidation{},
}
parsedConf, err := conf.Parse([]byte(*resourceConf))
@@ -227,10 +223,8 @@ func TestValidateHealthChecks(t *testing.T) {
probe := corev1.Probe{}
cv1 := ContainerValidation{
- Container: &corev1.Container{Name: ""},
- ResourceValidation: &ResourceValidation{
- Summary: &ResultSummary{},
- },
+ Container: &corev1.Container{Name: ""},
+ ResourceValidation: &ResourceValidation{},
}
cv2 := ContainerValidation{
Container: &corev1.Container{
@@ -238,9 +232,7 @@ func TestValidateHealthChecks(t *testing.T) {
LivenessProbe: &probe,
ReadinessProbe: &probe,
},
- ResourceValidation: &ResourceValidation{
- Summary: &ResultSummary{},
- },
+ ResourceValidation: &ResourceValidation{},
}
l := &ResultMessage{Type: "warning", Message: "Liveness probe should be configured", Category: "Health Checks"}
@@ -286,31 +278,23 @@ func TestValidateImage(t *testing.T) {
i3 := conf.Images{TagNotSpecified: conf.SeverityError}
cv1 := ContainerValidation{
- Container: &corev1.Container{Name: ""},
- ResourceValidation: &ResourceValidation{
- Summary: &ResultSummary{},
- },
+ Container: &corev1.Container{Name: ""},
+ ResourceValidation: &ResourceValidation{},
}
cv2 := ContainerValidation{
- Container: &corev1.Container{Name: "", Image: "test:tag"},
- ResourceValidation: &ResourceValidation{
- Summary: &ResultSummary{},
- },
+ Container: &corev1.Container{Name: "", Image: "test:tag"},
+ ResourceValidation: &ResourceValidation{},
}
cv3 := ContainerValidation{
- Container: &corev1.Container{Name: "", Image: "test:latest"},
- ResourceValidation: &ResourceValidation{
- Summary: &ResultSummary{},
- },
+ Container: &corev1.Container{Name: "", Image: "test:latest"},
+ ResourceValidation: &ResourceValidation{},
}
cv4 := ContainerValidation{
- Container: &corev1.Container{Name: "", Image: "test"},
- ResourceValidation: &ResourceValidation{
- Summary: &ResultSummary{},
- },
+ Container: &corev1.Container{Name: "", Image: "test"},
+ ResourceValidation: &ResourceValidation{},
}
f := &ResultMessage{Message: "Image tag should be specified", Type: "error", Category: "Images"}
@@ -351,10 +335,8 @@ func TestValidateNetworking(t *testing.T) {
}
emptyCV := ContainerValidation{
- Container: &corev1.Container{Name: ""},
- ResourceValidation: &ResourceValidation{
- Summary: &ResultSummary{},
- },
+ Container: &corev1.Container{Name: ""},
+ ResourceValidation: &ResourceValidation{},
}
badCV := ContainerValidation{
@@ -364,9 +346,7 @@ func TestValidateNetworking(t *testing.T) {
HostPort: 443,
}},
},
- ResourceValidation: &ResourceValidation{
- Summary: &ResultSummary{},
- },
+ ResourceValidation: &ResourceValidation{},
}
goodCV := ContainerValidation{
@@ -375,9 +355,7 @@ func TestValidateNetworking(t *testing.T) {
ContainerPort: 3000,
}},
},
- ResourceValidation: &ResourceValidation{
- Summary: &ResultSummary{},
- },
+ ResourceValidation: &ResourceValidation{},
}
var testCases = []struct {
@@ -497,10 +475,8 @@ func TestValidateSecurity(t *testing.T) {
}
emptyCV := ContainerValidation{
- Container: &corev1.Container{Name: ""},
- ResourceValidation: &ResourceValidation{
- Summary: &ResultSummary{},
- },
+ Container: &corev1.Container{Name: ""},
+ ResourceValidation: &ResourceValidation{},
}
badCV := ContainerValidation{
@@ -513,9 +489,7 @@ func TestValidateSecurity(t *testing.T) {
Add: []corev1.Capability{"AUDIT_CONTROL", "SYS_ADMIN", "NET_ADMIN"},
},
}},
- ResourceValidation: &ResourceValidation{
- Summary: &ResultSummary{},
- },
+ ResourceValidation: &ResourceValidation{},
}
goodCV := ContainerValidation{
@@ -528,9 +502,7 @@ func TestValidateSecurity(t *testing.T) {
Drop: []corev1.Capability{"NET_BIND_SERVICE", "FOWNER"},
},
}},
- ResourceValidation: &ResourceValidation{
- Summary: &ResultSummary{},
- },
+ ResourceValidation: &ResourceValidation{},
}
strongCV := ContainerValidation{
@@ -543,9 +515,7 @@ func TestValidateSecurity(t *testing.T) {
Drop: []corev1.Capability{"ALL"},
},
}},
- ResourceValidation: &ResourceValidation{
- Summary: &ResultSummary{},
- },
+ ResourceValidation: &ResourceValidation{},
}
var testCases = []struct {
diff --git a/pkg/validator/deploy.go b/pkg/validator/deploy.go
index 14729f76e..0fc28bd1a 100644
--- a/pkg/validator/deploy.go
+++ b/pkg/validator/deploy.go
@@ -63,10 +63,7 @@ func addResult(resResult ResourceResult, nsResults NamespacedResults, nsName str
}
nsResult.Results = append(nsResult.Results, resResult)
+ nsResult.Summary.appendResults(*resResult.Summary)
- // Aggregate all resource results summary counts to get a namespace wide count.
- nsResult.Summary.Successes += resResult.Summary.Successes
- nsResult.Summary.Warnings += resResult.Summary.Warnings
- nsResult.Summary.Errors += resResult.Summary.Errors
return nsResults
}
diff --git a/pkg/validator/fullaudit.go b/pkg/validator/fullaudit.go
index 4aa082e6b..853698371 100644
--- a/pkg/validator/fullaudit.go
+++ b/pkg/validator/fullaudit.go
@@ -40,14 +40,12 @@ func RunAudit(config conf.Configuration, kubeAPI *kube.API) (AuditData, error) {
return AuditData{}, err
}
- var clusterSuccesses, clusterErrors, clusterWarnings uint
+ clusterResults := ResultSummary{}
// Aggregate all summary counts to get a clusterwide count.
for _, nsRes := range nsResults {
for _, rr := range nsRes.Results {
- clusterErrors += rr.Summary.Errors
- clusterWarnings += rr.Summary.Warnings
- clusterSuccesses += rr.Summary.Successes
+ clusterResults.appendResults(*rr.Summary)
}
}
@@ -81,11 +79,7 @@ func RunAudit(config conf.Configuration, kubeAPI *kube.API) (AuditData, error) {
Nodes: len(nodes.Items),
Pods: numPods,
Namespaces: len(namespaces.Items),
- Results: ResultSummary{
- Errors: clusterErrors,
- Warnings: clusterWarnings,
- Successes: clusterSuccesses,
- },
+ Results: clusterResults,
},
NamespacedResults: nsResults,
}
diff --git a/pkg/validator/fullaudit_test.go b/pkg/validator/fullaudit_test.go
index 223e76cd2..d3a2d301e 100644
--- a/pkg/validator/fullaudit_test.go
+++ b/pkg/validator/fullaudit_test.go
@@ -20,17 +20,30 @@ func TestGetTemplateData(t *testing.T) {
}
sum := ResultSummary{
- Successes: uint(4),
+ Totals: CountSummary{
+ Successes: uint(4),
+ Warnings: uint(1),
+ Errors: uint(1),
+ },
+ ByCategory: CategorySummary{},
+ }
+ sum.ByCategory["Health Checks"] = &CountSummary{
+ Successes: uint(0),
Warnings: uint(1),
Errors: uint(1),
}
+ sum.ByCategory["Resources"] = &CountSummary{
+ Successes: uint(4),
+ Warnings: uint(0),
+ Errors: uint(0),
+ }
actualAudit, err := RunAudit(c, k8s)
assert.Equal(t, err, nil, "error should be nil")
- assert.EqualValues(t, actualAudit.ClusterSummary.Results, sum)
- assert.Equal(t, len(actualAudit.NamespacedResults["test"].Results), 1, "should be equal")
- assert.Equal(t, len(actualAudit.NamespacedResults["test"].Results[0].PodResults), 1, "should be equal")
- assert.Equal(t, len(actualAudit.NamespacedResults["test"].Results[0].PodResults[0].ContainerResults), 1, "should be equal")
- assert.Equal(t, len(actualAudit.NamespacedResults["test"].Results[0].PodResults[0].ContainerResults[0].Messages), 6, "should be equal")
+ assert.EqualValues(t, sum, actualAudit.ClusterSummary.Results)
+ assert.Equal(t, 1, len(actualAudit.NamespacedResults["test"].Results), "should be equal")
+ assert.Equal(t, 1, len(actualAudit.NamespacedResults["test"].Results[0].PodResults), "should be equal")
+ assert.Equal(t, 1, len(actualAudit.NamespacedResults["test"].Results[0].PodResults[0].ContainerResults), "should be equal")
+ assert.Equal(t, 6, len(actualAudit.NamespacedResults["test"].Results[0].PodResults[0].ContainerResults[0].Messages), "should be equal")
}
diff --git a/pkg/validator/pod.go b/pkg/validator/pod.go
index 1f8ae56f5..708e243ff 100644
--- a/pkg/validator/pod.go
+++ b/pkg/validator/pod.go
@@ -32,10 +32,8 @@ type PodValidation struct {
// ValidatePod validates that each pod conforms to the Fairwinds config, returns a ResourceResult.
func ValidatePod(podConf conf.Configuration, pod *corev1.PodSpec) ResourceResult {
pv := PodValidation{
- Pod: pod,
- ResourceValidation: &ResourceValidation{
- Summary: &ResultSummary{},
- },
+ Pod: pod,
+ ResourceValidation: &ResourceValidation{},
}
pv.validateSecurity(&podConf.Security)
@@ -51,23 +49,20 @@ func ValidatePod(podConf conf.Configuration, pod *corev1.PodSpec) ResourceResult
rr := ResourceResult{
Type: "Pod",
- Summary: pv.Summary,
+ Summary: pv.summary(),
PodResults: []PodResult{pRes},
}
+ for _, cRes := range pRes.ContainerResults {
+ rr.Summary.appendResults(*cRes.Summary)
+ }
return rr
}
func (pv *PodValidation) validateContainers(containers []corev1.Container, pRes *PodResult, podConf *conf.Configuration) {
for _, container := range containers {
- ctrRR := ValidateContainer(podConf, &container)
- pv.Summary.Successes += ctrRR.Summary.Successes
- pv.Summary.Warnings += ctrRR.Summary.Warnings
- pv.Summary.Errors += ctrRR.Summary.Errors
- pRes.ContainerResults = append(
- pRes.ContainerResults,
- ctrRR.ContainerResults[0],
- )
+ cRes := ValidateContainer(podConf, &container)
+ pRes.ContainerResults = append(pRes.ContainerResults, cRes)
}
}
diff --git a/pkg/validator/pod_test.go b/pkg/validator/pod_test.go
index 2c853d270..878ebeb42 100644
--- a/pkg/validator/pod_test.go
+++ b/pkg/validator/pod_test.go
@@ -39,7 +39,25 @@ func TestValidatePod(t *testing.T) {
pod := test.MockPod()
expectedSum := ResultSummary{
- Successes: uint(8),
+ Totals: CountSummary{
+ Successes: uint(8),
+ Warnings: uint(0),
+ Errors: uint(0),
+ },
+ ByCategory: make(map[string]*CountSummary),
+ }
+ expectedSum.ByCategory["Networking"] = &CountSummary{
+ Successes: uint(2),
+ Warnings: uint(0),
+ Errors: uint(0),
+ }
+ expectedSum.ByCategory["Resources"] = &CountSummary{
+ Successes: uint(4),
+ Warnings: uint(0),
+ Errors: uint(0),
+ }
+ expectedSum.ByCategory["Security"] = &CountSummary{
+ Successes: uint(2),
Warnings: uint(0),
Errors: uint(0),
}
diff --git a/pkg/validator/resource.go b/pkg/validator/resource.go
index 130088707..9db8d0ed3 100644
--- a/pkg/validator/resource.go
+++ b/pkg/validator/resource.go
@@ -22,7 +22,6 @@ import (
// ResourceValidation contains methods shared by PodValidation and ContainerValidation
type ResourceValidation struct {
- Summary *ResultSummary
Errors []*ResultMessage
Warnings []*ResultMessage
Successes []*ResultMessage
@@ -36,6 +35,43 @@ func (rv *ResourceValidation) messages() []*ResultMessage {
return messages
}
+func (rv *ResourceValidation) summary() *ResultSummary {
+ counts := CountSummary{
+ Errors: uint(len(rv.Errors)),
+ Warnings: uint(len(rv.Warnings)),
+ Successes: uint(len(rv.Successes)),
+ }
+ byCategory := CategorySummary{}
+ for _, msg := range rv.messages() {
+ if _, ok := byCategory[msg.Category]; !ok {
+ byCategory[msg.Category] = &CountSummary{}
+ }
+ if msg.Type == MessageTypeError {
+ byCategory[msg.Category].Errors++
+ } else if msg.Type == MessageTypeWarning {
+ byCategory[msg.Category].Warnings++
+ } else if msg.Type == MessageTypeSuccess {
+ byCategory[msg.Category].Successes++
+ }
+ }
+ return &ResultSummary{
+ Totals: counts,
+ ByCategory: byCategory,
+ }
+}
+
+func (rv *ResourceValidation) addMessage(message ResultMessage) {
+ if message.Type == MessageTypeError {
+ rv.Errors = append(rv.Errors, &message)
+ } else if message.Type == MessageTypeWarning {
+ rv.Warnings = append(rv.Warnings, &message)
+ } else if message.Type == MessageTypeSuccess {
+ rv.Successes = append(rv.Successes, &message)
+ } else {
+ panic("Bad message type")
+ }
+}
+
func (rv *ResourceValidation) addFailure(message string, severity conf.Severity, category string) {
if severity == conf.SeverityError {
rv.addError(message, category)
@@ -48,7 +84,6 @@ func (rv *ResourceValidation) addFailure(message string, severity conf.Severity,
}
func (rv *ResourceValidation) addError(message string, category string) {
- rv.Summary.Errors++
rv.Errors = append(rv.Errors, &ResultMessage{
Message: message,
Type: MessageTypeError,
@@ -57,7 +92,6 @@ func (rv *ResourceValidation) addError(message string, category string) {
}
func (rv *ResourceValidation) addWarning(message string, category string) {
- rv.Summary.Warnings++
rv.Warnings = append(rv.Warnings, &ResultMessage{
Message: message,
Type: MessageTypeWarning,
@@ -66,7 +100,6 @@ func (rv *ResourceValidation) addWarning(message string, category string) {
}
func (rv *ResourceValidation) addSuccess(message string, category string) {
- rv.Summary.Successes++
rv.Successes = append(rv.Successes, &ResultMessage{
Message: message,
Type: MessageTypeSuccess,
diff --git a/pkg/validator/types.go b/pkg/validator/types.go
index 482f2cd64..ef9e10b37 100644
--- a/pkg/validator/types.go
+++ b/pkg/validator/types.go
@@ -46,22 +46,52 @@ type ResourceResult struct {
PodResults []PodResult
}
-// ResultSummary provides a high level overview of success, warnings, and errors.
-type ResultSummary struct {
+// CountSummary provides a high level overview of success, warnings, and errors.
+type CountSummary struct {
Successes uint
Warnings uint
Errors uint
}
+func (cs *CountSummary) appendCounts(toAppend CountSummary) {
+ cs.Errors += toAppend.Errors
+ cs.Warnings += toAppend.Warnings
+ cs.Successes += toAppend.Successes
+}
+
+// CategorySummary provides a map from category name to a CountSummary
+type CategorySummary map[string]*CountSummary
+
+// ResultSummary provides a high level overview of success, warnings, and errors.
+type ResultSummary struct {
+ Totals CountSummary
+ ByCategory CategorySummary
+}
+
+func (rs *ResultSummary) appendResults(toAppend ResultSummary) {
+ rs.Totals.appendCounts(toAppend.Totals)
+ for category, summary := range toAppend.ByCategory {
+ if rs.ByCategory == nil {
+ rs.ByCategory = CategorySummary{}
+ }
+ if _, exists := rs.ByCategory[category]; !exists {
+ rs.ByCategory[category] = &CountSummary{}
+ }
+ rs.ByCategory[category].appendCounts(*summary)
+ }
+}
+
// ContainerResult provides a list of validation messages for each container.
type ContainerResult struct {
Name string
Messages []*ResultMessage
+ Summary *ResultSummary
}
// PodResult provides a list of validation messages for each pod.
type PodResult struct {
Name string
+ Summary *ResultSummary
Messages []*ResultMessage
ContainerResults []ContainerResult
}
@@ -72,8 +102,3 @@ type ResultMessage struct {
Type MessageType
Category string
}
-
-// Score represents a percentage of validations that were successful.
-func (rs *ResultSummary) Score() uint {
- return uint(float64(rs.Successes) / float64(rs.Successes+rs.Warnings+rs.Errors) * 100)
-}
diff --git a/pkg/webhook/validator.go b/pkg/webhook/validator.go
index d342e2136..1073d5b6d 100644
--- a/pkg/webhook/validator.go
+++ b/pkg/webhook/validator.go
@@ -103,7 +103,7 @@ func (v *Validator) Handle(ctx context.Context, req types.Request) types.Respons
return admission.ErrorResponse(http.StatusBadRequest, err)
}
- if results.Summary.Errors > 0 {
+ if results.Summary.Totals.Errors > 0 {
// TODO: Decide what message we want to return here.
allowed, reason = false, "failed validation checks, view details on dashbaord."
}
diff --git a/public/css/main.css b/public/css/main.css
index 227394721..35040937c 100644
--- a/public/css/main.css
+++ b/public/css/main.css
@@ -99,6 +99,10 @@ body {
margin-top: 10px;
}
+.cluster .expandable-table ul.message-list {
+ margin: 10px 26px;
+}
+
#clusterScoreChart {
width: 550px;
position: relative;
@@ -223,35 +227,40 @@ ul.message-list li i {
color: #a11f4c;
}
-.namespace td.status-bar {
+.namespace .status-bar {
vertical-align: top;
padding-top: 18px;
}
+.namespace .status-bar .status {
+ float: right;
+ animation: fadeIn 2s;
+}
+.cluster .status {
+ width: 280px;
+}
.namespace .status {
- float: right;
width: 200px;
}
-.namespace .status div {
+.status div {
height: 15px;
border-radius: 10px;
}
-.namespace .status .passing {
+.status .passing {
background-color: #8BD2DC;
float: left;
}
-.namespace .status .warning {
+.status .warning {
background-color: #f26c21;
float: left;
}
-.namespace .status .failing {
+.status .failing {
background-color: #a11f4c;
- width: 200px;
- animation: fadeIn 2s;
+ width: 100%;
}
@keyframes fadeIn {
diff --git a/public/js/charts.js b/public/js/charts.js
index c51e4b81f..aa88f8ae8 100644
--- a/public/js/charts.js
+++ b/public/js/charts.js
@@ -5,9 +5,9 @@ $(function () {
labels: ["Passing", "Warning", "Error"],
datasets: [{
data: [
- fairwindsAuditData.ClusterSummary.Results.Successes,
- fairwindsAuditData.ClusterSummary.Results.Warnings,
- fairwindsAuditData.ClusterSummary.Results.Errors,
+ fairwindsAuditData.ClusterSummary.Results.Totals.Successes,
+ fairwindsAuditData.ClusterSummary.Results.Totals.Warnings,
+ fairwindsAuditData.ClusterSummary.Results.Totals.Errors,
],
backgroundColor: ['#8BD2DC', '#f26c21', '#a11f4c'],
}]
|