$bindIp, 'port' => $port, 'path' => $path, 'API_KEY' => API_KEY, 'remove_hosts' => $clientList, ]; $jsonPayload = json_encode($payload); if ($jsonPayload === false) { // Encoding failed – return a clear error. return [ 'status' => 'error', 'code' => 0, 'message' => 'Failed to encode request payload: ' . json_last_error_msg(), ]; } // Prepare the HTTP context for a POST request. $headers = [ "Content-Type: application/json", "Content-Length: " . strlen($jsonPayload), "User-Agent: PHP/" . PHP_VERSION, ]; $ctxOptions = [ 'http' => [ 'method' => 'POST', 'header' => implode("\r\n", $headers), 'content' => $jsonPayload, 'timeout' => 5, 'ignore_errors' => true, // Still receive body for 4xx/5xx ] ]; $ctx = stream_context_create($ctxOptions); $url = "http://172.25.1.18:5001/storage_client_delete"; $ctx = stream_context_create([ 'http' => [ 'timeout' => 5, 'header' => "User-Agent: PHP/" . PHP_VERSION . "\r\n" ] ]); $json = @file_get_contents($url, false, $ctx); if ($json === false) { return []; // caller will handle empty case } $data = json_decode($json, true); if (!is_array($data)) { return ['fail']; } return $data; } $removedHostsMsg = ''; if ($_SERVER['REQUEST_METHOD'] === 'POST') { $raw = file_get_contents('php://input'); $data = json_decode($raw, true); if (json_last_error() === JSON_ERROR_NONE && isset($data['API_KEY'], $data['remove_hosts']) && $data['API_KEY'] === API_KEY ) { /* ---- For demo purposes we just echo a message. In a real system you would perform the removal logic here. ---- */ $removedHostsMsg = '

Removed hosts: ' . h(implode(', ', $data['remove_hosts'])) . '

'; echo "Time to remove ".$data['remove_hosts']." ['bind' => '10.200.27.20', 'port' => '5000'], 'drive_health' => ['bind' => '172.25.1.18', 'port' => '5001'], // new API ]; /* ---------- Helper: fetch client details ---------- */ function fetchClientDetails(string $bindIp, string $port, string $path = '/client_details'): array { $url = "http://{$bindIp}:{$port}{$path}"; $ctx = stream_context_create([ 'http' => [ 'timeout' => 5, 'header' => "User-Agent: PHP/" . PHP_VERSION . "\r\n" ] ]); $json = @file_get_contents($url, false, $ctx); if ($json === false) { return []; // caller will handle empty case } $data = json_decode($json, true); if (!is_array($data)) { return ['fail']; } return $data; } /* ---------- Fetch client details ---------- */ $apiInfo = $apiConfig[$mode]; $clients = fetchClientDetails($apiInfo['bind'], $apiInfo['port']); /* ---------- Ensure each client has a short_id ---------- */ foreach ($clients as &$client) { if (!isset($client['short_id'])) { $client['short_id'] = substr($client['uuid'] ?? '', 0, 8); } } unset($client); /* ---------- Determine selected hosts (Drive Health only) ---------- */ $selectedHosts = $_GET['hosts'] ?? []; if ($mode === 'drive_health') { if (isset($_GET['action'])) { switch ($_GET['action']) { case 'all': $selectedHosts = array_column($clients, 'short_id'); break; case 'none': $selectedHosts = []; break; // 'apply' – nothing to do; $selectedHosts already contains the posted hosts } } } /* ---- Determine selected host ---- */ $selectedId = $_GET['host'] ?? ''; $selectedIdx = null; foreach ($clients as $idx => $client) { if (isset($client['short_id']) && $client['short_id'] === $selectedId) { $selectedIdx = $idx; break; } } if ($selectedIdx === null) { // Default to the first client (if any) $selectedIdx = 0; $selectedId = $clients[$selectedIdx]['short_id'] ?? ''; } $client = $clients[$selectedIdx] ?? null; $properties = $client['client_properties'][0] ?? []; $systemProperties = $properties['system_properties'] ?? []; $systemComponents = $properties['system_components'] ?? []; $selectedHost = $clients[$selectedIdx]['hostname'] ?? 'Unknown'; /* ---- ---- */ /* ---- Sidebar Renderer ---- */ function renderSidebar(string $mode){ global $clients, $client, $properties, $systemProperties, $systemComponents, $selectedHost, $selectedHosts, $selectedId, $selectedIdx, $removedHostsMsg; /* Show a removal‑success message if we just processed a POST */ if ($removedHostsMsg) { echo $removedHostsMsg; } $modes = [ 'cosmostat' => 'Cosmostat', 'drive_health' => 'Drive Health', ]; ?>

Could not retrieve data from the API for mode "' . h($mode) . '".

'); } if ($mode === 'drive_health') { // If nothing is selected, show a friendly message if (empty($selectedHosts)) { echo '

No hosts selected.

'; return; } echo '
'; foreach ($selectedHosts as $sid) { // Find the client that matches this short_id $c = null; foreach ($clients as $cl) { if ($cl['short_id'] === $sid) { $c = $cl; break; } } if ($c === null) continue; // safety $hostname = $c['name'] ?? 'Unknown'; echo '
'; echo '

Drive Health - ' . h($hostname) . '

'; echo '

IP: ' . h($c['ip']) . '
'; echo 'Timestamp: ' . date('F j, Y g:i a', (int) $c['timestamp']) . '

'; if (isset($c['drives']) && is_array($c['drives']) && count($c['drives']) > 0) { echo ''; echo ''; echo ''; foreach ($c['drives'] as $drive) { echo ''; echo ''; echo ''; echo ''; echo ''; echo ''; echo ''; echo ''; } echo '
Drive LetterModelCapacityPower On HoursHost WritesWear Level
' . h($drive['drive_letter'] ?? '') . '' . h($drive['model'] ?? '') . '' . h($drive['capacity'] ?? '') . '' . h($drive['power_on_hours'] ?? '') . '' . h($drive['host_writes'] ?? '') . '' . h($drive['wear_level'] ?? '') . '
'; } else { echo '

No drive data available for this host.

'; } echo '
'; } echo '
'; return; } ?>

Matt-Cloud Cosmostat Dashboard

This dashboard shows the local Matt-Cloud system stats.

Component Desriptor

To view the component descriptor, you may
curl -s https:///descriptor

This will return the entire JSON descriptor variable.
The agent then reports back to the Cosmostat Server with all the data found in the descriptor.
Full Source Code can be found at its Gitea page.

System Properties

Live System Metrics

Connecting...

Components

Shuttle Gali

Cosmostat - <?= h($selectedHost) ?>