refactor(backups): tag snapshots by backup id and run forget by grouping first by tags

This commit is contained in:
Nicolas Meienberger
2025-11-04 20:09:38 +01:00
parent ecd517341c
commit 01c2a3669c
12 changed files with 66 additions and 268 deletions

View File

@@ -49,9 +49,9 @@ export const repositoriesController = new Hono()
})
.get("/:name/snapshots", listSnapshotsDto, validator("query", listSnapshotsFilters), async (c) => {
const { name } = c.req.param();
const { volumeId } = c.req.valid("query");
const { backupId } = c.req.valid("query");
const res = await repositoriesService.listSnapshots(name, Number(volumeId));
const res = await repositoriesService.listSnapshots(name, backupId);
const snapshots = res.map((snapshot) => {
const { summary } = snapshot;

View File

@@ -144,7 +144,7 @@ const listSnapshotsResponse = snapshotSchema.array();
export type ListSnapshotsDto = typeof listSnapshotsResponse.infer;
export const listSnapshotsFilters = type({
volumeId: "string?",
backupId: "string?",
});
export const listSnapshotsDto = describeRoute({

View File

@@ -8,7 +8,6 @@ import { repositoriesTable, volumesTable } from "../../db/schema";
import { toMessage } from "../../utils/errors";
import { restic } from "../../utils/restic";
import { cryptoUtils } from "../../utils/crypto";
import { getVolumePath } from "../volumes/helpers";
const listRepositories = async () => {
const repositories = await db.query.repositoriesTable.findMany({});
@@ -106,7 +105,15 @@ const deleteRepository = async (name: string) => {
await db.delete(repositoriesTable).where(eq(repositoriesTable.name, name));
};
const listSnapshots = async (name: string, volumeId?: number) => {
/**
* List snapshots for a given repository
* If backupId is provided, filter snapshots by that backup ID (tag)
* @param name Repository name
* @param backupId Optional backup ID to filter snapshots for a specific backup schedule
*
* @returns List of snapshots
*/
const listSnapshots = async (name: string, backupId?: string) => {
const repository = await db.query.repositoriesTable.findFirst({
where: eq(repositoriesTable.name, name),
});
@@ -115,20 +122,12 @@ const listSnapshots = async (name: string, volumeId?: number) => {
throw new NotFoundError("Repository not found");
}
let snapshots = await restic.snapshots(repository.config);
let snapshots = [];
if (volumeId) {
const volume = await db.query.volumesTable.findFirst({
where: eq(volumesTable.id, volumeId),
});
if (!volume) {
throw new NotFoundError("Volume not found");
}
snapshots = snapshots.filter((snapshot) => {
return snapshot.paths.some((path) => path.includes(getVolumePath(volume.name)));
});
if (backupId) {
snapshots = await restic.snapshots(repository.config, { tags: [backupId.toString()] });
} else {
snapshots = await restic.snapshots(repository.config);
}
return snapshots;