Make node status live.

This commit is contained in:
2025-11-08 23:16:42 +00:00
parent 854a6023cd
commit 960282d4ed
4 changed files with 36 additions and 9 deletions

View File

@@ -8,6 +8,7 @@ import { Cpu, HardDrive, Network, Monitor, CheckCircle, AlertCircle, BookOpen, E
import { useInstanceContext } from '../hooks/useInstanceContext';
import { useNodes, useDiscoveryStatus } from '../hooks/useNodes';
import { useCluster } from '../hooks/useCluster';
import { useClusterStatus } from '../services/api/hooks/useCluster';
import { BootstrapModal } from './cluster/BootstrapModal';
import { NodeStatusBadge } from './nodes/NodeStatusBadge';
import { NodeFormDrawer } from './nodes/NodeFormDrawer';
@@ -49,6 +50,8 @@ export function ClusterNodesComponent() {
status: clusterStatus
} = useCluster(currentInstance);
const { data: clusterStatusData } = useClusterStatus(currentInstance || '');
const [discoverSubnet, setDiscoverSubnet] = useState('');
const [addNodeIp, setAddNodeIp] = useState('');
const [discoverError, setDiscoverError] = useState<string | null>(null);
@@ -241,6 +244,9 @@ export function ClusterNodesComponent() {
// Derive status from backend state flags for each node
const assignedNodes = nodes.map(node => {
// Get runtime status from cluster status
const runtimeStatus = clusterStatusData?.node_statuses?.[node.hostname];
let status = 'pending';
if (node.maintenance) {
status = 'provisioning';
@@ -249,7 +255,14 @@ export function ClusterNodesComponent() {
} else if (node.applied) {
status = 'ready';
}
return { ...node, status };
return {
...node,
status,
isReachable: runtimeStatus?.ready,
inKubernetes: runtimeStatus?.ready, // Whether in cluster (from backend 'ready' field)
kubernetesReady: runtimeStatus?.kubernetes_ready, // Whether K8s Ready condition is true
};
});
// Check if cluster needs bootstrap

View File

@@ -4,6 +4,13 @@ export interface ClusterConfig {
version?: string;
}
export interface NodeStatus {
hostname: string;
ready: boolean;
kubernetes_ready: boolean;
role: string;
}
export interface ClusterStatus {
ready: boolean;
nodes: number;
@@ -11,6 +18,7 @@ export interface ClusterStatus {
workerNodes: number;
kubernetesVersion?: string;
talosVersion?: string;
node_statuses?: Record<string, NodeStatus>;
}
export interface HealthCheck {

View File

@@ -17,6 +17,7 @@ export interface Node {
// Optional runtime fields for enhanced status
isReachable?: boolean;
inKubernetes?: boolean;
kubernetesReady?: boolean;
lastHealthCheck?: string;
// Optional fields (not yet returned by API)
hardware?: HardwareInfo;

View File

@@ -35,24 +35,29 @@ export function deriveNodeStatus(node: Node): NodeStatus {
}
if (node.applied) {
// Check Kubernetes membership for healthy state
if (node.inKubernetes === true) {
// Check Kubernetes membership and readiness
if (node.inKubernetes === true && node.kubernetesReady === true) {
return NodeStatus.HEALTHY;
}
// Applied but not yet in Kubernetes (could be provisioning or ready)
if (node.isReachable === true) {
// In Kubernetes but not Ready
if (node.inKubernetes === true && node.kubernetesReady === false) {
return NodeStatus.DEGRADED;
}
// Applied and reachable but not yet in Kubernetes
if (node.isReachable === true && node.inKubernetes !== true) {
return NodeStatus.READY;
}
// Applied but status unknown
// Applied but status unknown (no cluster status data yet)
if (node.isReachable === undefined && node.inKubernetes === undefined) {
return NodeStatus.READY;
}
// Applied but having issues
if (node.inKubernetes === false) {
return NodeStatus.DEGRADED;
// Applied but not reachable at all
if (node.isReachable === false) {
return NodeStatus.UNREACHABLE;
}
}