diff --git a/pkg/schema/v1/pod.go b/pkg/schema/v1/pod.go index 3c1e6ea..b4c8aba 100644 --- a/pkg/schema/v1/pod.go +++ b/pkg/schema/v1/pod.go @@ -12,6 +12,11 @@ import ( "strings" ) +const Ok = "ok" +const Warning = "warning" +const Critical = "critical" +const Unknown = "unknown" + type PodFactory struct { clientset *kubernetes.Clientset } @@ -23,6 +28,7 @@ type Pod struct { NominatedNodeName string Ip string Phase string + IcingaState string CpuLimits int64 CpuRequests int64 MemoryLimits int64 @@ -99,6 +105,7 @@ func (p *Pod) Obtain(k8s kmetav1.Object) { p.NominatedNodeName = pod.Status.NominatedNodeName p.Ip = pod.Status.PodIP p.Phase = strcase.Snake(string(pod.Status.Phase)) + p.IcingaState = getPodMonitoringState(pod) p.Reason = pod.Status.Reason p.Message = pod.Status.Message p.Qos = strcase.Snake(string(pod.Status.QOSClass)) @@ -269,6 +276,66 @@ func (p *Pod) Obtain(k8s kmetav1.Object) { } } +func getPodMonitoringState(pod *kcorev1.Pod) string { + readyContainers := 0 + state := Unknown + + if pod.DeletionTimestamp != nil { + return Ok + } + + initializing := false + for _, container := range pod.Status.InitContainerStatuses { + switch { + case container.State.Terminated != nil && container.State.Terminated.ExitCode == 0: + continue + case container.State.Terminated != nil: + state = Critical + initializing = true + case container.State.Waiting != nil && len(container.State.Waiting.Reason) > 0 && container.State.Waiting.Reason != "PodInitializing": + state = Critical + initializing = true + default: + initializing = true + } + break + } + if !initializing { + for _, container := range pod.Status.ContainerStatuses { + if !container.Ready { + state = Critical + } + if container.State.Waiting != nil && container.State.Waiting.Reason != "" && container.RestartCount >= 3 { + state = Critical + } else if container.State.Terminated != nil && container.State.Terminated.Reason != "" && container.State.Terminated.ExitCode == 0 { + state = Ok + } else if container.State.Terminated != nil && container.State.Terminated.Reason == "" { + state = Critical + } else if container.Ready && container.State.Running != nil { + readyContainers++ + state = Ok + } + } + } + + for _, condition := range pod.Status.Conditions { + if pod.Status.Phase == kcorev1.PodRunning { + if condition.Type == kcorev1.PodReady && condition.Status == kcorev1.ConditionTrue { + state = Ok + } + if condition.Type == kcorev1.PodReady && condition.Status == kcorev1.ConditionFalse { + state = Critical + } + } + } + + if readyContainers == len(pod.Spec.Containers) { + state = Ok + } + + return state +} + func (p *Pod) Relations() []database.Relation { fk := database.WithForeignKey("pod_id") diff --git a/schema/mysql/schema.sql b/schema/mysql/schema.sql index 9f8c022..e419b41 100644 --- a/schema/mysql/schema.sql +++ b/schema/mysql/schema.sql @@ -72,6 +72,7 @@ CREATE TABLE pod ( memory_limits bigint unsigned NOT NULL, memory_requests bigint unsigned NOT NULL, phase enum('pending', 'running', 'succeeded', 'failed') COLLATE utf8mb4_unicode_ci NOT NULL, + icinga_state enum('ok', 'warning', 'critical', 'unknown') COLLATE utf8mb4_unicode_ci NOT NULL, reason varchar(255) NULL DEFAULT NULL, message varchar(255) NULL DEFAULT NULL, qos enum('guaranteed', 'burstable', 'best_effort') COLLATE utf8mb4_unicode_ci NOT NULL,