mirror of
https://github.com/khoaliber/dockhand.git
synced 2026-03-06 05:39:05 +00:00
Initial commit
This commit is contained in:
111
routes/api/containers/check-updates/+server.ts
Normal file
111
routes/api/containers/check-updates/+server.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
import { json } from '@sveltejs/kit';
|
||||
import type { RequestHandler } from './$types';
|
||||
import { authorize } from '$lib/server/authorize';
|
||||
import { listContainers, inspectContainer, checkImageUpdateAvailable } from '$lib/server/docker';
|
||||
import { clearPendingContainerUpdates, addPendingContainerUpdate } from '$lib/server/db';
|
||||
|
||||
export interface UpdateCheckResult {
|
||||
containerId: string;
|
||||
containerName: string;
|
||||
imageName: string;
|
||||
hasUpdate: boolean;
|
||||
currentDigest?: string;
|
||||
newDigest?: string;
|
||||
error?: string;
|
||||
isLocalImage?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check all containers for available image updates.
|
||||
* Returns all results at once after checking in parallel.
|
||||
*/
|
||||
export const POST: RequestHandler = async ({ url, cookies }) => {
|
||||
const auth = await authorize(cookies);
|
||||
|
||||
const envId = url.searchParams.get('env');
|
||||
const envIdNum = envId ? parseInt(envId) : undefined;
|
||||
|
||||
// Need at least view permission
|
||||
if (auth.authEnabled && !await auth.can('containers', 'view', envIdNum)) {
|
||||
return json({ error: 'Permission denied' }, { status: 403 });
|
||||
}
|
||||
|
||||
try {
|
||||
// Clear existing pending updates for this environment before checking
|
||||
if (envIdNum) {
|
||||
await clearPendingContainerUpdates(envIdNum);
|
||||
}
|
||||
|
||||
const containers = await listContainers(true, envIdNum);
|
||||
|
||||
// Check container for updates
|
||||
const checkContainer = async (container: typeof containers[0]): Promise<UpdateCheckResult> => {
|
||||
try {
|
||||
// Get container's image name from config
|
||||
const inspectData = await inspectContainer(container.id, envIdNum) as any;
|
||||
const imageName = inspectData.Config?.Image;
|
||||
const currentImageId = inspectData.Image;
|
||||
|
||||
if (!imageName) {
|
||||
return {
|
||||
containerId: container.id,
|
||||
containerName: container.name,
|
||||
imageName: container.image,
|
||||
hasUpdate: false,
|
||||
error: 'Could not determine image name'
|
||||
};
|
||||
}
|
||||
|
||||
// Use shared update detection function
|
||||
const result = await checkImageUpdateAvailable(imageName, currentImageId, envIdNum);
|
||||
|
||||
return {
|
||||
containerId: container.id,
|
||||
containerName: container.name,
|
||||
imageName,
|
||||
hasUpdate: result.hasUpdate,
|
||||
currentDigest: result.currentDigest,
|
||||
newDigest: result.registryDigest,
|
||||
error: result.error,
|
||||
isLocalImage: result.isLocalImage
|
||||
};
|
||||
} catch (error: any) {
|
||||
return {
|
||||
containerId: container.id,
|
||||
containerName: container.name,
|
||||
imageName: container.image,
|
||||
hasUpdate: false,
|
||||
error: error.message
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// Check all containers in parallel
|
||||
const results = await Promise.all(containers.map(checkContainer));
|
||||
|
||||
const updatesFound = results.filter(r => r.hasUpdate).length;
|
||||
|
||||
// Save containers with updates to the database for persistence
|
||||
if (envIdNum) {
|
||||
for (const result of results) {
|
||||
if (result.hasUpdate) {
|
||||
await addPendingContainerUpdate(
|
||||
envIdNum,
|
||||
result.containerId,
|
||||
result.containerName,
|
||||
result.imageName
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return json({
|
||||
total: containers.length,
|
||||
updatesFound,
|
||||
results
|
||||
});
|
||||
} catch (error: any) {
|
||||
console.error('Error checking for updates:', error);
|
||||
return json({ error: 'Failed to check for updates', details: error.message }, { status: 500 });
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user