Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions pkg/app/pipedv1/plugin/kubernetes/provider/health_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package provider

import (
"fmt"
"strings"

appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
Expand Down Expand Up @@ -43,6 +44,18 @@ func (m Manifest) calculateHealthStatus() (sdk.ResourceHealthStatus, string) {
return sdk.ResourceHealthStateUnknown, ""
}
return replicaSetHealthStatus(obj)
case m.IsDaemonSet():
obj := &appsv1.DaemonSet{}
if err := m.ConvertToStructuredObject(obj); err != nil {
return sdk.ResourceHealthStateUnknown, ""
}
return daemonSetHealthStatus(obj)
case m.IsPod():
obj := &corev1.Pod{}
if err := m.ConvertToStructuredObject(obj); err != nil {
return sdk.ResourceHealthStateUnknown, ""
}
return podHealthStatus(obj)
default:
// TODO: Implement health status calculation for other resource types.
return sdk.ResourceHealthStateUnknown, fmt.Sprintf("Unimplemented or unknown resource: %s", m.body.GroupVersionKind())
Expand Down Expand Up @@ -143,3 +156,49 @@ func replicaSetHealthStatus(obj *appsv1.ReplicaSet) (sdk.ResourceHealthStatus, s

return sdk.ResourceHealthStateHealthy, ""
}

func daemonSetHealthStatus(obj *appsv1.DaemonSet) (sdk.ResourceHealthStatus, string) {
if obj.Status.ObservedGeneration == 0 || obj.Generation > obj.Status.ObservedGeneration {
return sdk.ResourceHealthStateUnhealthy, "Waiting for rollout to finish because observed daemon set generation less than desired generation"
}

if obj.Status.UpdatedNumberScheduled < obj.Status.DesiredNumberScheduled {
return sdk.ResourceHealthStateUnhealthy, fmt.Sprintf("Waiting for daemon set %q rollout to finish because %d out of %d new pods have been updated", obj.GetName(), obj.Status.UpdatedNumberScheduled, obj.Status.DesiredNumberScheduled)
}
if obj.Status.NumberAvailable < obj.Status.DesiredNumberScheduled {
return sdk.ResourceHealthStateUnhealthy, fmt.Sprintf("Waiting for daemon set %q rollout to finish because %d of %d updated pods are available", obj.GetName(), obj.Status.NumberAvailable, obj.Status.DesiredNumberScheduled)
}

if obj.Status.NumberMisscheduled > 0 {
return sdk.ResourceHealthStateUnhealthy, fmt.Sprintf("%d nodes that are running the daemon pod, but are not supposed to run the daemon pod", obj.Status.NumberMisscheduled)
}
if obj.Status.NumberUnavailable > 0 {
return sdk.ResourceHealthStateUnhealthy, fmt.Sprintf("%d nodes that should be running the daemon pod and have none of the daemon pod running and available", obj.Status.NumberUnavailable)
}

return sdk.ResourceHealthStateHealthy, ""
}

func podHealthStatus(obj *corev1.Pod) (sdk.ResourceHealthStatus, string) {
if obj.Spec.RestartPolicy == corev1.RestartPolicyAlways {
var messages []string
for _, s := range obj.Status.ContainerStatuses {
waiting := s.State.Waiting
if waiting == nil {
continue
}
if strings.HasPrefix(waiting.Reason, "Err") || strings.HasSuffix(waiting.Reason, "Error") || strings.HasSuffix(waiting.Reason, "BackOff") {
messages = append(messages, waiting.Message)
}
}
if len(messages) > 0 {
return sdk.ResourceHealthStateUnhealthy, strings.Join(messages, ", ")
}
}

if obj.Status.Phase == corev1.PodRunning || obj.Status.Phase == corev1.PodSucceeded {
return sdk.ResourceHealthStateHealthy, obj.Status.Message
}

return sdk.ResourceHealthStateUnhealthy, obj.Status.Message
}
Loading