Show manual Watchtower run status
All checks were successful
Build & Push Docker Image to Gitea Registry / build-and-push (push) Successful in 12s
All checks were successful
Build & Push Docker Image to Gitea Registry / build-and-push (push) Successful in 12s
This commit is contained in:
69
server.js
69
server.js
@@ -297,7 +297,7 @@ async function runWatchtowerOnce() {
|
||||
'com.centurylinklabs.watchtower.enable': 'false'
|
||||
},
|
||||
HostConfig: {
|
||||
AutoRemove: true,
|
||||
AutoRemove: false,
|
||||
Binds: [
|
||||
'/var/run/docker.sock:/var/run/docker.sock',
|
||||
`${WATCHTOWER_CONFIG_PATH}:/config.json:ro`
|
||||
@@ -317,12 +317,61 @@ async function runWatchtowerOnce() {
|
||||
await dockerRequest(`/containers/${created.Id}/start`, { method: 'POST' });
|
||||
return {
|
||||
id: created.Id.slice(0, 12),
|
||||
fullId: created.Id,
|
||||
name,
|
||||
image: WATCHTOWER_RUN_IMAGE,
|
||||
startedAt: new Date().toISOString()
|
||||
};
|
||||
}
|
||||
|
||||
async function removeContainer(id) {
|
||||
await dockerRequest(`/containers/${encodeURIComponent(id)}?force=1`, { method: 'DELETE' });
|
||||
}
|
||||
|
||||
async function getWatchtowerRun(runId, cleanup = false) {
|
||||
const id = normalizeContainerName(runId);
|
||||
if (!id || !/^[a-fA-F0-9]{12,64}$/.test(id)) {
|
||||
const error = new Error('Ungueltige Watchtower-Run-ID.');
|
||||
error.statusCode = 400;
|
||||
throw error;
|
||||
}
|
||||
|
||||
const [inspect, logs] = await Promise.all([
|
||||
dockerRequest(`/containers/${encodeURIComponent(id)}/json`),
|
||||
dockerLogs(id, 260).catch((error) => [`watchtower run logs unavailable: ${error.message}`])
|
||||
]);
|
||||
|
||||
const labels = inspect.Config?.Labels || {};
|
||||
if (labels['com.mischlabs.role'] !== 'manual-watchtower-run') {
|
||||
const error = new Error('Container gehoert nicht zu manuellen Watchtower-Laeufen.');
|
||||
error.statusCode = 403;
|
||||
throw error;
|
||||
}
|
||||
|
||||
const state = inspect.State || {};
|
||||
const parsed = Array.isArray(logs) ? parseWatchtower(logs) : null;
|
||||
const payload = {
|
||||
id: inspect.Id.slice(0, 12),
|
||||
fullId: inspect.Id,
|
||||
name: normalizeContainerName(inspect.Name),
|
||||
image: inspect.Config?.Image || WATCHTOWER_RUN_IMAGE,
|
||||
state: state.Status || 'unknown',
|
||||
running: Boolean(state.Running),
|
||||
exitCode: state.ExitCode,
|
||||
startedAt: state.StartedAt || null,
|
||||
finishedAt: state.FinishedAt && !state.FinishedAt.startsWith('0001-') ? state.FinishedAt : null,
|
||||
session: parsed,
|
||||
tail: Array.isArray(logs) ? logs.slice(-20) : logs
|
||||
};
|
||||
|
||||
if (cleanup && !payload.running) {
|
||||
removeContainer(inspect.Id).catch(() => {});
|
||||
payload.cleanedUp = true;
|
||||
}
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
async function getDisks() {
|
||||
const disks = [];
|
||||
|
||||
@@ -549,6 +598,24 @@ const server = http.createServer(async (req, res) => {
|
||||
return;
|
||||
}
|
||||
|
||||
const watchtowerRunMatch = req.url?.match(/^\/api\/watchtower\/runs\/([^/?#]+)(?:[?#].*)?$/);
|
||||
if (watchtowerRunMatch) {
|
||||
if (req.method !== 'GET') {
|
||||
json(res, 405, { error: 'Method not allowed' });
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await verifyAdminRequest(req);
|
||||
const requestUrl = new URL(req.url, `http://${req.headers.host}`);
|
||||
const cleanup = requestUrl.searchParams.get('cleanup') === '1';
|
||||
json(res, 200, await getWatchtowerRun(decodeURIComponent(watchtowerRunMatch[1]), cleanup));
|
||||
} catch (error) {
|
||||
json(res, error.statusCode || 500, { error: error.message });
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
await serveStatic(req, res);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user