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 { useInstanceContext } from '../hooks/useInstanceContext';
import { useNodes, useDiscoveryStatus } from '../hooks/useNodes'; import { useNodes, useDiscoveryStatus } from '../hooks/useNodes';
import { useCluster } from '../hooks/useCluster'; import { useCluster } from '../hooks/useCluster';
import { useClusterStatus } from '../services/api/hooks/useCluster';
import { BootstrapModal } from './cluster/BootstrapModal'; import { BootstrapModal } from './cluster/BootstrapModal';
import { NodeStatusBadge } from './nodes/NodeStatusBadge'; import { NodeStatusBadge } from './nodes/NodeStatusBadge';
import { NodeFormDrawer } from './nodes/NodeFormDrawer'; import { NodeFormDrawer } from './nodes/NodeFormDrawer';
@@ -49,6 +50,8 @@ export function ClusterNodesComponent() {
status: clusterStatus status: clusterStatus
} = useCluster(currentInstance); } = useCluster(currentInstance);
const { data: clusterStatusData } = useClusterStatus(currentInstance || '');
const [discoverSubnet, setDiscoverSubnet] = useState(''); const [discoverSubnet, setDiscoverSubnet] = useState('');
const [addNodeIp, setAddNodeIp] = useState(''); const [addNodeIp, setAddNodeIp] = useState('');
const [discoverError, setDiscoverError] = useState<string | null>(null); const [discoverError, setDiscoverError] = useState<string | null>(null);
@@ -241,6 +244,9 @@ export function ClusterNodesComponent() {
// Derive status from backend state flags for each node // Derive status from backend state flags for each node
const assignedNodes = nodes.map(node => { const assignedNodes = nodes.map(node => {
// Get runtime status from cluster status
const runtimeStatus = clusterStatusData?.node_statuses?.[node.hostname];
let status = 'pending'; let status = 'pending';
if (node.maintenance) { if (node.maintenance) {
status = 'provisioning'; status = 'provisioning';
@@ -249,7 +255,14 @@ export function ClusterNodesComponent() {
} else if (node.applied) { } else if (node.applied) {
status = 'ready'; 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 // Check if cluster needs bootstrap

View File

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

View File

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

View File

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