Skip to content

Commit

Permalink
visualize Pod and Node statuses on the graph
Browse files Browse the repository at this point in the history
  • Loading branch information
iximiuz committed Oct 9, 2023
1 parent 2efc072 commit ab890a3
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 28 deletions.
57 changes: 57 additions & 0 deletions ui/src/common/repr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,63 @@ function pretty<T extends RawKubeObject>(obj: KubeObject<T>): T {
};
}

export type PodPhase = "Unknown" | "Pending" | "NotReady" | "Ready" | "Succeeded" | "Failed";

export interface PodPhaseRepr {
phase: PodPhase;
title: string;
reason?: string;
message?: string;
}

export function reprPodPhase(pod: V1Pod): PodPhaseRepr {
// TODO: add the STATUS-like info from the kubectl get pod command.

if (!pod.status || !pod.status.phase) {
return {
phase: "Unknown",
title: "Unknown",
reason: "No Pod status field",
};
}

if (pod.status.phase !== "Running") {
return {
phase: pod.status.phase as PodPhase,
title: pod.status.phase,
};
}

if (pod.status.phase === "Running") {
if ((pod.status.conditions || []).find((c) => c.type === "Ready" && c.status === "True")) {
return {
phase: "Ready",
title: "Running (Ready)",
};
}

return {
phase: "NotReady",
title: "Running (Not Ready)",
};
}

return {
phase: "Unknown",
title: "Unknown",
reason: "Unknown Pod phase",
};
}

export const podPhaseClass = {
Pending: "status-waiting",
NotReady: "status-not-ready",
Ready: "status-ready",
Succeeded: "status-terminated-ok",
Failed: "status-terminated-ko",
Unknown: "status-unknown",
} as Record<PodPhase, string>;

export interface ContainerStatusRepr {
status: "waiting" | "starting" | "not-ready" | "ready" | "terminated-ok" | "terminated-ko" | "unknown";
title: string;
Expand Down
29 changes: 4 additions & 25 deletions ui/src/components/KubeObjectViewerPodInsightsTab.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script lang="ts" setup>
import { computed } from "vue";
import { reprTimeRelative } from "../common/repr";
import { podPhaseClass, reprTimeRelative, reprPodPhase } from "../common/repr";
import type { KubeObject, V1Pod } from "../common/types";
import KubeObjectViewerPodConditions from "./KubeObjectViewerPodConditions.vue";
Expand All @@ -14,22 +14,7 @@ const props = defineProps<{
},
}>();
const phase = computed(() => {
// TODO: add the STATUS-like into from the kubectl get pod command.
if (!props.object.raw.status || !props.object.raw.status.phase) {
return "Unknown";
}
if (props.object.raw.status.phase !== "Running") {
return props.object.raw.status.phase;
}
if (!(props.object.raw.status.conditions || []).find((c) => c.type === "Ready" && c.status === "True")) {
return "Running (Not Ready)";
}
return "Running (Ready)";
});
const phase = computed(() => reprPodPhase(props.object.raw));
</script>

<template>
Expand All @@ -45,15 +30,9 @@ const phase = computed(() => {
>
<span
class="border border-black h-[0.7rem] rounded-full w-[0.7rem]"
:class="{
'bg-status-waiting': phase === 'Pending',
'bg-status-not-ready': phase === 'Running (Not Ready)',
'bg-status-ready': phase === 'Running (Ready)',
'bg-status-terminated-ok': phase === 'Succeeded',
'bg-status-terminated-ko': phase === 'Failed',
}"
:class="['bg-' + podPhaseClass[phase.phase]]"
/>
{{ phase }}
{{ phase.title }}
</div>
<div>Started:</div>
<div :title="object.raw.status!.startTime + ''">
Expand Down
31 changes: 28 additions & 3 deletions ui/src/components/KubeObjectsGraph.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,13 @@ import { onMounted, ref, watchEffect } from "vue";

import { splitGVK } from "../common/kubeutil";
import { objectRelations } from "../common/relations";
import { reprContainerStatus, reprInitContainerStatus, reprSidecarContainerStatus } from "../common/repr";
import {
podPhaseClass,
reprContainerStatus,
reprInitContainerStatus,
reprPodPhase,
reprSidecarContainerStatus,
} from "../common/repr";
import { useAppStore } from "../stores";

const weights = {
Expand Down Expand Up @@ -322,10 +328,29 @@ onMounted(() => {

const label = [
"<div class=\"node-label\">",
`<p class="node-label-kind">${data.object.gvk.kind}</p>`,
`<p class="node-label-title">${data.object.name}</p>`,
`<span class="node-label-kind flex items-center justify-center">${data.object.gvk.kind}`,
];

if (data.object.gvk.toString() === "v1/Pod") {
const phase = reprPodPhase(data.object.raw);
label.push(`<div title="${phase.title}" class="border ml-2 border-black h-[0.7rem] rounded-full w-[0.7rem] bg-${podPhaseClass[phase.phase]}"></div>`);
} else if (data.object.gvk.toString() === "v1/Node") {
// TODO: Move this logic to reprNodeStatus.
const ready = data.object.raw.status
? data.object.raw.status.conditions.find((c) => c.type === "Ready")
: { status: "Unknown" };
const readyClass = ready.status === "True"
? "bg-status-ready"
: ready.status === "False"
? "bg-status-not-ready"
: "bg-status-unknown";

label.push(`<div title="Ready: ${ready.status}" class="border ml-2 border-black h-[0.7rem] rounded-full w-[0.7rem] ${readyClass}"></div>`);
}

label.push("</span>");
label.push(`<p class="node-label-title">${data.object.name}</p>`);

if (data.object.gvk.toString() === "v1/Pod") {
label.push(..._podLabel(data.object));
} else {
Expand Down
10 changes: 10 additions & 0 deletions ui/tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ module.exports = {
'./index.html',
'./src/**/*.{vue,js,ts,jsx,tsx}',
],
safelist: [
'bg-status-waiting',
'bg-status-starting',
'bg-status-not-ready',
'bg-status-ready',
'bg-status-terminated-ok',
'bg-status-terminated-ko',
'bg-status-unknown',
],
darkMode: 'media', // or 'media' or 'class'
theme: {
extend: {
Expand All @@ -16,6 +25,7 @@ module.exports = {
"status-ready": "rgb(34, 197, 94)",
"status-terminated-ok": "#a1dea1",
"status-terminated-ko": "#e36561",
"status-unknown": "#fff",
},
fontFamily: {
sans: ["Inter var", ...defaultTheme.fontFamily.sans],
Expand Down

0 comments on commit ab890a3

Please sign in to comment.