Make node status live.
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user