normalized volume list, with usedBy counts * create POST {"name": "...", "driver": "local", "path": "/mnt/cache/..." (optional)} * remove POST {"name": "...", "force": false} */ declare(strict_types=1); require __DIR__ . '/../include/bootstrap.php'; $action = $_GET['action'] ?? ''; switch ($action) { case 'list': podman_json_response(volumes_list($client)); break; case 'create': $body = podman_read_json_body(); $name = (string) ($body['name'] ?? ''); if ($name === '') { podman_json_error('Missing name in request body', 400); } $path = trim((string) ($body['path'] ?? '')); if ($path !== '' && !str_starts_with($path, '/')) { podman_json_error("Host path ({$path}) must be an absolute path.", 400); } podman_json_response($client->createVolume($name, (string) ($body['driver'] ?? 'local'), $path !== '' ? $path : null)); break; case 'remove': $body = podman_read_json_body(); $name = (string) ($body['name'] ?? ''); if ($name === '') { podman_json_error('Missing name in request body', 400); } $client->removeVolume($name, (bool) ($body['force'] ?? false)); podman_json_response(['status' => 'removed']); break; default: podman_json_error("Unknown action '{$action}'", 400); } /** @return array> */ function volumes_list(PodmanClient $client): array { $raw = $client->listVolumes(); $usageCounts = []; foreach ($client->listContainers(true) as $c) { foreach (($c['Mounts'] ?? []) as $mount) { $volName = $mount['Name'] ?? null; if (is_string($volName) && $volName !== '') { $usageCounts[$volName] = ($usageCounts[$volName] ?? 0) + 1; } } } $out = []; foreach ($raw as $v) { $name = (string) ($v['Name'] ?? ''); $options = $v['Options'] ?? []; // A volume created with our "Host path" field carries // type=none,o=bind,device= (see PodmanClient::createVolume) // — surfaced separately from 'mountpoint' (podman's own internal // storage path, which stays populated even for bind-backed // volumes) so the UI can show users the host path they actually // asked for. $hostPath = (is_array($options) && ($options['o'] ?? '') === 'bind') ? (string) ($options['device'] ?? '') : null; $out[] = [ 'name' => $name, 'driver' => (string) ($v['Driver'] ?? 'local'), 'mountpoint' => (string) ($v['Mountpoint'] ?? ''), 'hostPath' => $hostPath, 'createdAt' => podman_parse_time($v['CreatedAt'] ?? null), 'usedBy' => $usageCounts[$name] ?? 0, ]; } usort($out, static fn($a, $b) => strcmp($a['name'], $b['name'])); return $out; }