mirror of
https://github.com/komodorio/helm-dashboard.git
synced 2026-03-24 11:48:04 +00:00
feat(health): add health status for ExternalSecret, Job, HPA, and Namespace (#662)
Add condition-based health status calculation for additional resource kinds: - ExternalSecret: checks "Ready" condition - Job: checks "Complete" and "Failed" conditions - HorizontalPodAutoscaler: checks "AbleToScale" and "ScalingActive" conditions - Namespace: handles "Terminating" phase as Progressing Closes #418 Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -86,7 +86,7 @@ func EnhanceStatus(res *v12.Carp, err error) *v12.CarpStatus {
|
|||||||
c.Reason = "Exists" //since there is no condition to check here, we can set reason as exists.
|
c.Reason = "Exists" //since there is no condition to check here, we can set reason as exists.
|
||||||
} else if s.Phase == "" && len(s.Conditions) > 0 {
|
} else if s.Phase == "" && len(s.Conditions) > 0 {
|
||||||
applyCustomConditions(&s, &c)
|
applyCustomConditions(&s, &c)
|
||||||
} else if s.Phase == "Pending" {
|
} else if s.Phase == "Pending" || s.Phase == "Terminating" {
|
||||||
c.Status = Progressing
|
c.Status = Progressing
|
||||||
c.Reason = string(s.Phase)
|
c.Reason = string(s.Phase)
|
||||||
} else if s.Phase == "" {
|
} else if s.Phase == "" {
|
||||||
@@ -137,6 +137,34 @@ func applyCustomConditions(s *v12.CarpStatus, c *v12.CarpCondition) {
|
|||||||
}
|
}
|
||||||
c.Reason = cond.Reason
|
c.Reason = cond.Reason
|
||||||
c.Message = cond.Message
|
c.Message = cond.Message
|
||||||
|
} else if cond.Type == "Ready" && c.Status == Unknown { // condition for ExternalSecret
|
||||||
|
if cond.Status == "False" {
|
||||||
|
c.Status = Unhealthy
|
||||||
|
} else {
|
||||||
|
c.Status = Healthy
|
||||||
|
}
|
||||||
|
c.Reason = cond.Reason
|
||||||
|
c.Message = cond.Message
|
||||||
|
} else if cond.Type == "Complete" && c.Status == Unknown { // condition for Job
|
||||||
|
if cond.Status == "True" {
|
||||||
|
c.Status = Healthy
|
||||||
|
c.Reason = cond.Reason
|
||||||
|
c.Message = cond.Message
|
||||||
|
}
|
||||||
|
} else if cond.Type == "Failed" && c.Status == Unknown { // condition for Job
|
||||||
|
if cond.Status == "True" {
|
||||||
|
c.Status = Unhealthy
|
||||||
|
c.Reason = cond.Reason
|
||||||
|
c.Message = cond.Message
|
||||||
|
}
|
||||||
|
} else if (cond.Type == "AbleToScale" || cond.Type == "ScalingActive") && c.Status == Unknown { // condition for HorizontalPodAutoscaler
|
||||||
|
if cond.Status == "False" {
|
||||||
|
c.Status = Unhealthy
|
||||||
|
} else {
|
||||||
|
c.Status = Healthy
|
||||||
|
}
|
||||||
|
c.Reason = cond.Reason
|
||||||
|
c.Message = cond.Message
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
156
pkg/dashboard/handlers/kubeHandlers_test.go
Normal file
156
pkg/dashboard/handlers/kubeHandlers_test.go
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
v1 "k8s.io/apimachinery/pkg/apis/testapigroup/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestEnhanceStatus_ExternalSecret_Ready(t *testing.T) {
|
||||||
|
res := &v1.Carp{
|
||||||
|
Status: v1.CarpStatus{
|
||||||
|
Conditions: []v1.CarpCondition{
|
||||||
|
{Type: "Ready", Status: "True", Reason: "SecretSynced", Message: "Secret was synced"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
s := EnhanceStatus(res, nil)
|
||||||
|
hdCond := findHDHealth(s)
|
||||||
|
if hdCond == nil {
|
||||||
|
t.Fatal("expected hdHealth condition")
|
||||||
|
}
|
||||||
|
if hdCond.Status != Healthy {
|
||||||
|
t.Errorf("expected Healthy, got %s", hdCond.Status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEnhanceStatus_ExternalSecret_NotReady(t *testing.T) {
|
||||||
|
res := &v1.Carp{
|
||||||
|
Status: v1.CarpStatus{
|
||||||
|
Conditions: []v1.CarpCondition{
|
||||||
|
{Type: "Ready", Status: "False", Reason: "SecretSyncError", Message: "could not sync secret"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
s := EnhanceStatus(res, nil)
|
||||||
|
hdCond := findHDHealth(s)
|
||||||
|
if hdCond == nil {
|
||||||
|
t.Fatal("expected hdHealth condition")
|
||||||
|
}
|
||||||
|
if hdCond.Status != Unhealthy {
|
||||||
|
t.Errorf("expected Unhealthy, got %s", hdCond.Status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEnhanceStatus_Job_Complete(t *testing.T) {
|
||||||
|
res := &v1.Carp{
|
||||||
|
Status: v1.CarpStatus{
|
||||||
|
Conditions: []v1.CarpCondition{
|
||||||
|
{Type: "Complete", Status: "True", Reason: "JobComplete", Message: "Job completed"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
s := EnhanceStatus(res, nil)
|
||||||
|
hdCond := findHDHealth(s)
|
||||||
|
if hdCond == nil {
|
||||||
|
t.Fatal("expected hdHealth condition")
|
||||||
|
}
|
||||||
|
if hdCond.Status != Healthy {
|
||||||
|
t.Errorf("expected Healthy, got %s", hdCond.Status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEnhanceStatus_Job_Failed(t *testing.T) {
|
||||||
|
res := &v1.Carp{
|
||||||
|
Status: v1.CarpStatus{
|
||||||
|
Conditions: []v1.CarpCondition{
|
||||||
|
{Type: "Failed", Status: "True", Reason: "BackoffLimitExceeded", Message: "Job has reached the specified backoff limit"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
s := EnhanceStatus(res, nil)
|
||||||
|
hdCond := findHDHealth(s)
|
||||||
|
if hdCond == nil {
|
||||||
|
t.Fatal("expected hdHealth condition")
|
||||||
|
}
|
||||||
|
if hdCond.Status != Unhealthy {
|
||||||
|
t.Errorf("expected Unhealthy, got %s", hdCond.Status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEnhanceStatus_HPA_AbleToScale(t *testing.T) {
|
||||||
|
res := &v1.Carp{
|
||||||
|
Status: v1.CarpStatus{
|
||||||
|
Conditions: []v1.CarpCondition{
|
||||||
|
{Type: "AbleToScale", Status: "True", Reason: "ReadyForNewScale", Message: "recommended size matches current size"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
s := EnhanceStatus(res, nil)
|
||||||
|
hdCond := findHDHealth(s)
|
||||||
|
if hdCond == nil {
|
||||||
|
t.Fatal("expected hdHealth condition")
|
||||||
|
}
|
||||||
|
if hdCond.Status != Healthy {
|
||||||
|
t.Errorf("expected Healthy, got %s", hdCond.Status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEnhanceStatus_HPA_UnableToScale(t *testing.T) {
|
||||||
|
res := &v1.Carp{
|
||||||
|
Status: v1.CarpStatus{
|
||||||
|
Conditions: []v1.CarpCondition{
|
||||||
|
{Type: "AbleToScale", Status: "False", Reason: "FailedGetScale", Message: "the HPA controller was unable to get the target's current scale"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
s := EnhanceStatus(res, nil)
|
||||||
|
hdCond := findHDHealth(s)
|
||||||
|
if hdCond == nil {
|
||||||
|
t.Fatal("expected hdHealth condition")
|
||||||
|
}
|
||||||
|
if hdCond.Status != Unhealthy {
|
||||||
|
t.Errorf("expected Unhealthy, got %s", hdCond.Status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEnhanceStatus_Namespace_Active(t *testing.T) {
|
||||||
|
res := &v1.Carp{
|
||||||
|
Status: v1.CarpStatus{
|
||||||
|
Phase: "Active",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
s := EnhanceStatus(res, nil)
|
||||||
|
hdCond := findHDHealth(s)
|
||||||
|
if hdCond == nil {
|
||||||
|
t.Fatal("expected hdHealth condition")
|
||||||
|
}
|
||||||
|
if hdCond.Status != Healthy {
|
||||||
|
t.Errorf("expected Healthy, got %s", hdCond.Status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEnhanceStatus_Namespace_Terminating(t *testing.T) {
|
||||||
|
res := &v1.Carp{
|
||||||
|
Status: v1.CarpStatus{
|
||||||
|
Phase: "Terminating",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
s := EnhanceStatus(res, nil)
|
||||||
|
hdCond := findHDHealth(s)
|
||||||
|
if hdCond == nil {
|
||||||
|
t.Fatal("expected hdHealth condition")
|
||||||
|
}
|
||||||
|
if hdCond.Status != Progressing {
|
||||||
|
t.Errorf("expected Progressing, got %s", hdCond.Status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func findHDHealth(s *v1.CarpStatus) *v1.CarpCondition {
|
||||||
|
for i, c := range s.Conditions {
|
||||||
|
if c.Type == "hdHealth" {
|
||||||
|
return &s.Conditions[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user