121 lines
3.9 KiB
QML
121 lines
3.9 KiB
QML
pragma Singleton
|
|
|
|
import Quickshell
|
|
import Quickshell.Io
|
|
import QtQuick
|
|
|
|
Singleton {
|
|
id: root
|
|
|
|
property string status: "loading" // "loading" | "ok" | "degraded" | "error" | "stale"
|
|
property var pods: [] // Array of {app, ready, cpuM, memMi}
|
|
property int readyCount: 0
|
|
property int totalCount: 0
|
|
property var quota: null // quota object from metrics script
|
|
property int lastUpdatedSecs: 0 // seconds since last successful status fetch
|
|
|
|
Process {
|
|
id: statusProc
|
|
command: ["bash", Config.scriptsDir + "/k8s-status.sh", Config.kubeNamespace]
|
|
stdout: StdioCollector {
|
|
onStreamFinished: {
|
|
if (this.text.trim() === "") {
|
|
root.status = (root.status === "ok" || root.status === "degraded") ? "stale" : "error";
|
|
return;
|
|
}
|
|
try {
|
|
let data = JSON.parse(this.text);
|
|
// Preserve existing cpuM/memMi from last metrics fetch
|
|
let byApp = {};
|
|
for (let p of root.pods) byApp[p.app] = p;
|
|
root.pods = data.pods.map(p => ({
|
|
app: p.app,
|
|
ready: p.ready,
|
|
cpuM: byApp[p.app]?.cpuM ?? -1,
|
|
memMi: byApp[p.app]?.memMi ?? -1
|
|
}));
|
|
root.readyCount = data.readyCount;
|
|
root.totalCount = data.totalCount;
|
|
root.status = data.pods.every(p => p.ready) ? "ok" : "degraded";
|
|
root.lastUpdatedSecs = 0;
|
|
} catch(e) {
|
|
console.warn("Kubernetes: status parse error:", e);
|
|
root.status = (root.status === "ok" || root.status === "degraded") ? "stale" : "error";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Process {
|
|
id: metricsProc
|
|
command: ["bash", Config.scriptsDir + "/k8s-metrics.sh", Config.kubeNamespace]
|
|
stdout: StdioCollector {
|
|
onStreamFinished: {
|
|
if (this.text.trim() === "") return;
|
|
try {
|
|
let data = JSON.parse(this.text);
|
|
let byApp = {};
|
|
for (let m of data.podMetrics) byApp[m.app] = m;
|
|
root.pods = root.pods.map(p => ({
|
|
app: p.app,
|
|
ready: p.ready,
|
|
cpuM: byApp[p.app]?.cpuM ?? -1,
|
|
memMi: byApp[p.app]?.memMi ?? -1
|
|
}));
|
|
root.quota = data.quota;
|
|
} catch(e) {
|
|
console.warn("Kubernetes: metrics parse error:", e);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Ticker: increments lastUpdatedSecs every second (only once status is known)
|
|
Timer {
|
|
interval: 1000
|
|
running: root.status !== "loading"
|
|
repeat: true
|
|
onTriggered: root.lastUpdatedSecs++
|
|
}
|
|
|
|
// Status poller
|
|
Timer {
|
|
interval: Config.kubeStatusRefreshMs
|
|
running: true
|
|
repeat: true
|
|
onTriggered: statusProc.running = true
|
|
}
|
|
|
|
// Metrics poller
|
|
Timer {
|
|
interval: Config.kubeMetricsRefreshMs
|
|
running: true
|
|
repeat: true
|
|
onTriggered: metricsProc.running = true
|
|
}
|
|
|
|
// Stagger: fire metricsProc once at startup (500ms after status)
|
|
Timer {
|
|
id: metricsStagger
|
|
interval: 500
|
|
repeat: false
|
|
onTriggered: metricsProc.running = true
|
|
}
|
|
|
|
// Staleness check: flip to "stale" if no successful fetch for >60s
|
|
Timer {
|
|
interval: 10000
|
|
running: true
|
|
repeat: true
|
|
onTriggered: {
|
|
if (root.lastUpdatedSecs > 60 && (root.status === "ok" || root.status === "degraded"))
|
|
root.status = "stale";
|
|
}
|
|
}
|
|
|
|
Component.onCompleted: {
|
|
statusProc.running = true;
|
|
metricsStagger.running = true;
|
|
}
|
|
}
|