spb/maclustr-console
Public
TypeScript 96.1%
CSS 3.1%
JavaScript 0.8%
1import { executeSSH } from "./ssh";2import { CLUSTER_NODES, NAS_DEVICES, type NASConfig } from "./cluster";34export interface NASMetrics {5 id: string;6 name: string;7 model: string;8 host: string;9 share: string;10 webUrl: string;11 online: boolean;12 totalBytes: number;13 usedBytes: number;14 availBytes: number;15 usedPercent: number;16 mountedNodes: number;17 totalNodes: number;18}1920/**21 * Reads each NAS's storage from its SMB share mounted on the cluster nodes (~/<mountSubdir>).22 * Reuses the existing SSH-key access to the nodes (no NAS credentials) and is immune to the23 * NAS SSH auto-blocking. One parallel `df` pass per NAS yields storage + mounted-node count.24 */25export async function collectNASMetrics(): Promise<NASMetrics[]> {26 return Promise.all(NAS_DEVICES.map((dev) => collectOne(dev)));27}2829async function collectOne(dev: NASConfig): Promise<NASMetrics> {30 const totalNodes = CLUSTER_NODES.length;31 const result: NASMetrics = {32 id: dev.id, name: dev.name, model: dev.model, host: dev.host,33 share: dev.share, webUrl: dev.webUrl,34 online: false, totalBytes: 0, usedBytes: 0, availBytes: 0,35 usedPercent: 0, mountedNodes: 0, totalNodes,36 };3738 const cmd = `df -k "$HOME/${dev.mountSubdir}" 2>/dev/null | tail -1`;39 const raws = await Promise.allSettled(40 CLUSTER_NODES.map((n) => executeSSH(n.hostname, cmd, 7000))41 );4243 let mounted = 0;44 for (const r of raws) {45 if (r.status !== "fulfilled") continue;46 const f = r.value.trim().split(/\s+/);47 if (f.length >= 4 && f[0].startsWith("//")) {48 mounted++;49 if (!result.online) {50 const blocks = parseInt(f[1], 10) || 0;51 const used = parseInt(f[2], 10) || 0;52 const avail = parseInt(f[3], 10) || 0;53 result.online = true;54 result.totalBytes = blocks * 1024;55 result.usedBytes = used * 1024;56 result.availBytes = avail * 1024;57 result.usedPercent = blocks > 0 ? (used / blocks) * 100 : 0;58 }59 }60 }61 result.mountedNodes = mounted;62 return result;63}64