feat: implement Docker disk usage retrieval and enhance system prune functionality

This commit is contained in:
SaelixCode
2026-02-27 15:43:45 -05:00
parent 07f4d18a22
commit ec90911e14
4 changed files with 174 additions and 27 deletions
+16 -17
View File
@@ -811,33 +811,32 @@ app.post('/api/system/prune/orphans', async (req: Request, res: Response) => {
app.post('/api/system/prune/system', async (req: Request, res: Response) => {
try {
const { target } = req.body; // 'containers', 'images', 'networks'
let command = '';
if (target === 'containers') {
command = 'docker container prune -f';
} else if (target === 'images') {
command = 'docker image prune -a -f';
} else if (target === 'networks') {
command = 'docker network prune -f';
} else {
const { target } = req.body; // 'containers', 'images', 'networks', 'volumes'
if (!['containers', 'images', 'networks', 'volumes'].includes(target)) {
return res.status(400).json({ error: 'Invalid prune target' });
}
const { stdout, stderr } = await execAsync(command, {
env: {
...process.env,
PATH: process.env.PATH || '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
}
});
const dockerController = DockerController.getInstance();
const result = await dockerController.pruneSystem(target);
res.json({ message: 'Prune completed', stdout, stderr });
res.json({ message: 'Prune completed', ...result });
} catch (error: any) {
console.error('System prune error:', error);
res.status(500).json({ error: 'System prune failed', details: error.message });
}
});
app.get('/api/system/docker-df', async (req: Request, res: Response) => {
try {
const dockerController = DockerController.getInstance();
const df = await dockerController.getDiskUsage();
res.json(df);
} catch (error) {
console.error('Failed to fetch docker disk usage:', error);
res.status(500).json({ error: 'Failed to fetch docker disk usage' });
}
});
// Serve static files in production (for Docker deployment)
if (process.env.NODE_ENV === 'production') {
app.use(express.static('public'));
+59
View File
@@ -24,6 +24,65 @@ class DockerController {
return DockerController.instance;
}
public async getDiskUsage() {
const df = await this.docker.df();
const calculateReclaimableContainers = (items: any[]) => {
if (!items || !Array.isArray(items)) return 0;
return items.filter(i => i.State !== 'running').reduce((acc, item) => {
let size = item.SizeRw || item.SizeRootFs || 0;
if (item.UsageData && typeof item.UsageData.Size === 'number') {
size = item.UsageData.Size;
}
return acc + size;
}, 0);
};
const calculateReclaimableImages = (items: any[]) => {
if (!items || !Array.isArray(items)) return 0;
return items.filter(i => i.Containers === 0).reduce((acc, item) => {
let size = item.VirtualSize || item.Size || item.SharedSize || 0;
if (item.UsageData && typeof item.UsageData.Size === 'number') {
size = item.UsageData.Size;
}
return acc + size;
}, 0);
};
const calculateReclaimableVolumes = (items: any[]) => {
if (!items || !Array.isArray(items)) return 0;
return items.filter(i => i.UsageData?.RefCount === 0).reduce((acc, item) => {
let size = item.UsageData?.Size || 0;
return acc + size;
}, 0);
};
return {
reclaimableImages: df.Images ? calculateReclaimableImages(df.Images) : 0,
reclaimableContainers: df.Containers ? calculateReclaimableContainers(df.Containers) : 0,
reclaimableVolumes: df.Volumes ? calculateReclaimableVolumes(df.Volumes) : 0,
};
}
public async pruneSystem(target: 'containers' | 'images' | 'networks' | 'volumes') {
let result: any = {};
if (target === 'containers') {
result = await this.docker.pruneContainers();
} else if (target === 'images') {
// Remove all unused images, not just dangling ones
result = await this.docker.pruneImages({ filters: { dangling: { 'false': true } } });
} else if (target === 'networks') {
result = await this.docker.pruneNetworks();
} else if (target === 'volumes') {
result = await this.docker.pruneVolumes();
}
return {
success: true,
reclaimedBytes: result?.SpaceReclaimed || 0
};
}
public async getRunningContainers() {
const containers = await this.docker.listContainers({ all: false });
return containers;