From 1c4a06d31e41d8e7cb951bad3a09ca679e7a590a Mon Sep 17 00:00:00 2001 From: Myron Blair Date: Mon, 22 Jun 2026 12:32:44 +0000 Subject: [PATCH] fix: docker image-remove throws on daemon error; add sync-orphans endpoint - removeImage now throws RuntimeException when docker rmi output contains 'Error' or 'conflict' so the API returns success:false with the message - Added docker/sync-orphans endpoint (admin only) to register existing Docker containers not tracked in the NovaCPX DB (e.g. after a restore) --- panel/api/endpoints/docker.php | 23 +++++++++++++++++++++++ panel/lib/DockerManager.php | 6 +++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/panel/api/endpoints/docker.php b/panel/api/endpoints/docker.php index 32e99e1..8f4e6d5 100644 --- a/panel/api/endpoints/docker.php +++ b/panel/api/endpoints/docker.php @@ -265,5 +265,28 @@ match ($action) { Response::success($result, ucfirst($appKey) . ' launched successfully'); })(), + 'sync-orphans' => (function() use ($dm, $isAdmin) { + if (!$isAdmin) Response::error('Admin only', 403); + $result = shell_exec('docker ps -a --format "{{json .}}" 2>/dev/null') ?? ''; + $db = \DB::getInstance(); + $added = 0; + foreach (explode("\n", trim($result)) as $line) { + if (!$line) continue; + $c = json_decode($line, true); + if (!$c) continue; + $cid = $c['ID'] ?? ''; + $name = ltrim($c['Names'] ?? '', '/'); + $img = $c['Image'] ?? ''; + $st = $c['State'] ?? 'unknown'; + if (!$cid) continue; + $ex = $db->fetchOne('SELECT id FROM docker_containers WHERE container_id=?', [$cid]); + if (!$ex) { + $db->execute('INSERT INTO docker_containers (container_id,name,image,status,account_id,created_at) VALUES (?,?,?,?,0,datetime("now"))', [$cid,$name,$img,$st]); + $added++; + } + } + Response::success(['added' => $added], "Synced $added orphaned containers"); + })(), + default => Response::error("Unknown docker action: $action", 404), }; diff --git a/panel/lib/DockerManager.php b/panel/lib/DockerManager.php index db85d31..6030ac0 100644 --- a/panel/lib/DockerManager.php +++ b/panel/lib/DockerManager.php @@ -190,7 +190,11 @@ SH; public function removeImage(string $imageId): string { if (!preg_match('/^[a-zA-Z0-9:._\-\/]+$/', $imageId)) throw new RuntimeException("Invalid image ID"); - return trim(shell_exec("sudo docker rmi " . escapeshellarg($imageId) . " 2>&1") ?? ''); + $out = trim(shell_exec("sudo docker rmi " . escapeshellarg($imageId) . " 2>&1") ?? ''); + if (stripos($out, "Error") !== false || stripos($out, "conflict") !== false) { + throw new \RuntimeException($out); + } + return $out; } // ── Volumes & Networks ────────────────────────────────────────────────────