mirror of
https://github.com/nicotsx/ironmount.git
synced 2025-12-10 12:10:51 +01:00
feat(backend): backup service with retention policy
This commit is contained in:
@@ -23,6 +23,12 @@ import {
|
||||
deleteRepository,
|
||||
getRepository,
|
||||
listSnapshots,
|
||||
listBackupSchedules,
|
||||
createBackupSchedule,
|
||||
deleteBackupSchedule,
|
||||
getBackupSchedule,
|
||||
updateBackupSchedule,
|
||||
runBackupNow,
|
||||
} from "../sdk.gen";
|
||||
import { queryOptions, type UseMutationOptions, type DefaultError } from "@tanstack/react-query";
|
||||
import type {
|
||||
@@ -59,6 +65,16 @@ import type {
|
||||
DeleteRepositoryResponse,
|
||||
GetRepositoryData,
|
||||
ListSnapshotsData,
|
||||
ListBackupSchedulesData,
|
||||
CreateBackupScheduleData,
|
||||
CreateBackupScheduleResponse,
|
||||
DeleteBackupScheduleData,
|
||||
DeleteBackupScheduleResponse,
|
||||
GetBackupScheduleData,
|
||||
UpdateBackupScheduleData,
|
||||
UpdateBackupScheduleResponse,
|
||||
RunBackupNowData,
|
||||
RunBackupNowResponse,
|
||||
} from "../types.gen";
|
||||
import { client as _heyApiClient } from "../client.gen";
|
||||
|
||||
@@ -693,3 +709,174 @@ export const listSnapshotsOptions = (options: Options<ListSnapshotsData>) => {
|
||||
queryKey: listSnapshotsQueryKey(options),
|
||||
});
|
||||
};
|
||||
|
||||
export const listBackupSchedulesQueryKey = (options?: Options<ListBackupSchedulesData>) =>
|
||||
createQueryKey("listBackupSchedules", options);
|
||||
|
||||
/**
|
||||
* List all backup schedules
|
||||
*/
|
||||
export const listBackupSchedulesOptions = (options?: Options<ListBackupSchedulesData>) => {
|
||||
return queryOptions({
|
||||
queryFn: async ({ queryKey, signal }) => {
|
||||
const { data } = await listBackupSchedules({
|
||||
...options,
|
||||
...queryKey[0],
|
||||
signal,
|
||||
throwOnError: true,
|
||||
});
|
||||
return data;
|
||||
},
|
||||
queryKey: listBackupSchedulesQueryKey(options),
|
||||
});
|
||||
};
|
||||
|
||||
export const createBackupScheduleQueryKey = (options?: Options<CreateBackupScheduleData>) =>
|
||||
createQueryKey("createBackupSchedule", options);
|
||||
|
||||
/**
|
||||
* Create a new backup schedule for a volume
|
||||
*/
|
||||
export const createBackupScheduleOptions = (options?: Options<CreateBackupScheduleData>) => {
|
||||
return queryOptions({
|
||||
queryFn: async ({ queryKey, signal }) => {
|
||||
const { data } = await createBackupSchedule({
|
||||
...options,
|
||||
...queryKey[0],
|
||||
signal,
|
||||
throwOnError: true,
|
||||
});
|
||||
return data;
|
||||
},
|
||||
queryKey: createBackupScheduleQueryKey(options),
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new backup schedule for a volume
|
||||
*/
|
||||
export const createBackupScheduleMutation = (
|
||||
options?: Partial<Options<CreateBackupScheduleData>>,
|
||||
): UseMutationOptions<CreateBackupScheduleResponse, DefaultError, Options<CreateBackupScheduleData>> => {
|
||||
const mutationOptions: UseMutationOptions<
|
||||
CreateBackupScheduleResponse,
|
||||
DefaultError,
|
||||
Options<CreateBackupScheduleData>
|
||||
> = {
|
||||
mutationFn: async (localOptions) => {
|
||||
const { data } = await createBackupSchedule({
|
||||
...options,
|
||||
...localOptions,
|
||||
throwOnError: true,
|
||||
});
|
||||
return data;
|
||||
},
|
||||
};
|
||||
return mutationOptions;
|
||||
};
|
||||
|
||||
/**
|
||||
* Delete a backup schedule
|
||||
*/
|
||||
export const deleteBackupScheduleMutation = (
|
||||
options?: Partial<Options<DeleteBackupScheduleData>>,
|
||||
): UseMutationOptions<DeleteBackupScheduleResponse, DefaultError, Options<DeleteBackupScheduleData>> => {
|
||||
const mutationOptions: UseMutationOptions<
|
||||
DeleteBackupScheduleResponse,
|
||||
DefaultError,
|
||||
Options<DeleteBackupScheduleData>
|
||||
> = {
|
||||
mutationFn: async (localOptions) => {
|
||||
const { data } = await deleteBackupSchedule({
|
||||
...options,
|
||||
...localOptions,
|
||||
throwOnError: true,
|
||||
});
|
||||
return data;
|
||||
},
|
||||
};
|
||||
return mutationOptions;
|
||||
};
|
||||
|
||||
export const getBackupScheduleQueryKey = (options: Options<GetBackupScheduleData>) =>
|
||||
createQueryKey("getBackupSchedule", options);
|
||||
|
||||
/**
|
||||
* Get a backup schedule by ID
|
||||
*/
|
||||
export const getBackupScheduleOptions = (options: Options<GetBackupScheduleData>) => {
|
||||
return queryOptions({
|
||||
queryFn: async ({ queryKey, signal }) => {
|
||||
const { data } = await getBackupSchedule({
|
||||
...options,
|
||||
...queryKey[0],
|
||||
signal,
|
||||
throwOnError: true,
|
||||
});
|
||||
return data;
|
||||
},
|
||||
queryKey: getBackupScheduleQueryKey(options),
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Update a backup schedule
|
||||
*/
|
||||
export const updateBackupScheduleMutation = (
|
||||
options?: Partial<Options<UpdateBackupScheduleData>>,
|
||||
): UseMutationOptions<UpdateBackupScheduleResponse, DefaultError, Options<UpdateBackupScheduleData>> => {
|
||||
const mutationOptions: UseMutationOptions<
|
||||
UpdateBackupScheduleResponse,
|
||||
DefaultError,
|
||||
Options<UpdateBackupScheduleData>
|
||||
> = {
|
||||
mutationFn: async (localOptions) => {
|
||||
const { data } = await updateBackupSchedule({
|
||||
...options,
|
||||
...localOptions,
|
||||
throwOnError: true,
|
||||
});
|
||||
return data;
|
||||
},
|
||||
};
|
||||
return mutationOptions;
|
||||
};
|
||||
|
||||
export const runBackupNowQueryKey = (options: Options<RunBackupNowData>) => createQueryKey("runBackupNow", options);
|
||||
|
||||
/**
|
||||
* Trigger a backup immediately for a schedule
|
||||
*/
|
||||
export const runBackupNowOptions = (options: Options<RunBackupNowData>) => {
|
||||
return queryOptions({
|
||||
queryFn: async ({ queryKey, signal }) => {
|
||||
const { data } = await runBackupNow({
|
||||
...options,
|
||||
...queryKey[0],
|
||||
signal,
|
||||
throwOnError: true,
|
||||
});
|
||||
return data;
|
||||
},
|
||||
queryKey: runBackupNowQueryKey(options),
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Trigger a backup immediately for a schedule
|
||||
*/
|
||||
export const runBackupNowMutation = (
|
||||
options?: Partial<Options<RunBackupNowData>>,
|
||||
): UseMutationOptions<RunBackupNowResponse, DefaultError, Options<RunBackupNowData>> => {
|
||||
const mutationOptions: UseMutationOptions<RunBackupNowResponse, DefaultError, Options<RunBackupNowData>> = {
|
||||
mutationFn: async (localOptions) => {
|
||||
const { data } = await runBackupNow({
|
||||
...options,
|
||||
...localOptions,
|
||||
throwOnError: true,
|
||||
});
|
||||
return data;
|
||||
},
|
||||
};
|
||||
return mutationOptions;
|
||||
};
|
||||
|
||||
@@ -54,6 +54,18 @@ import type {
|
||||
GetRepositoryResponses,
|
||||
ListSnapshotsData,
|
||||
ListSnapshotsResponses,
|
||||
ListBackupSchedulesData,
|
||||
ListBackupSchedulesResponses,
|
||||
CreateBackupScheduleData,
|
||||
CreateBackupScheduleResponses,
|
||||
DeleteBackupScheduleData,
|
||||
DeleteBackupScheduleResponses,
|
||||
GetBackupScheduleData,
|
||||
GetBackupScheduleResponses,
|
||||
UpdateBackupScheduleData,
|
||||
UpdateBackupScheduleResponses,
|
||||
RunBackupNowData,
|
||||
RunBackupNowResponses,
|
||||
} from "./types.gen";
|
||||
import { client as _heyApiClient } from "./client.gen";
|
||||
|
||||
@@ -335,3 +347,83 @@ export const listSnapshots = <ThrowOnError extends boolean = false>(
|
||||
...options,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* List all backup schedules
|
||||
*/
|
||||
export const listBackupSchedules = <ThrowOnError extends boolean = false>(
|
||||
options?: Options<ListBackupSchedulesData, ThrowOnError>,
|
||||
) => {
|
||||
return (options?.client ?? _heyApiClient).get<ListBackupSchedulesResponses, unknown, ThrowOnError>({
|
||||
url: "/api/v1/backups",
|
||||
...options,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new backup schedule for a volume
|
||||
*/
|
||||
export const createBackupSchedule = <ThrowOnError extends boolean = false>(
|
||||
options?: Options<CreateBackupScheduleData, ThrowOnError>,
|
||||
) => {
|
||||
return (options?.client ?? _heyApiClient).post<CreateBackupScheduleResponses, unknown, ThrowOnError>({
|
||||
url: "/api/v1/backups",
|
||||
...options,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
...options?.headers,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Delete a backup schedule
|
||||
*/
|
||||
export const deleteBackupSchedule = <ThrowOnError extends boolean = false>(
|
||||
options: Options<DeleteBackupScheduleData, ThrowOnError>,
|
||||
) => {
|
||||
return (options.client ?? _heyApiClient).delete<DeleteBackupScheduleResponses, unknown, ThrowOnError>({
|
||||
url: "/api/v1/backups/{scheduleId}",
|
||||
...options,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a backup schedule by ID
|
||||
*/
|
||||
export const getBackupSchedule = <ThrowOnError extends boolean = false>(
|
||||
options: Options<GetBackupScheduleData, ThrowOnError>,
|
||||
) => {
|
||||
return (options.client ?? _heyApiClient).get<GetBackupScheduleResponses, unknown, ThrowOnError>({
|
||||
url: "/api/v1/backups/{scheduleId}",
|
||||
...options,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Update a backup schedule
|
||||
*/
|
||||
export const updateBackupSchedule = <ThrowOnError extends boolean = false>(
|
||||
options: Options<UpdateBackupScheduleData, ThrowOnError>,
|
||||
) => {
|
||||
return (options.client ?? _heyApiClient).patch<UpdateBackupScheduleResponses, unknown, ThrowOnError>({
|
||||
url: "/api/v1/backups/{scheduleId}",
|
||||
...options,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
...options.headers,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Trigger a backup immediately for a schedule
|
||||
*/
|
||||
export const runBackupNow = <ThrowOnError extends boolean = false>(
|
||||
options: Options<RunBackupNowData, ThrowOnError>,
|
||||
) => {
|
||||
return (options.client ?? _heyApiClient).post<RunBackupNowResponses, unknown, ThrowOnError>({
|
||||
url: "/api/v1/backups/{scheduleId}/run",
|
||||
...options,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -804,6 +804,258 @@ export type ListSnapshotsResponses = {
|
||||
|
||||
export type ListSnapshotsResponse = ListSnapshotsResponses[keyof ListSnapshotsResponses];
|
||||
|
||||
export type ListBackupSchedulesData = {
|
||||
body?: never;
|
||||
path?: never;
|
||||
query?: never;
|
||||
url: "/api/v1/backups";
|
||||
};
|
||||
|
||||
export type ListBackupSchedulesResponses = {
|
||||
/**
|
||||
* List of backup schedules
|
||||
*/
|
||||
200: {
|
||||
schedules: Array<{
|
||||
createdAt: number;
|
||||
cronExpression: string;
|
||||
enabled: boolean;
|
||||
excludePatterns: Array<string>;
|
||||
id: number;
|
||||
includePatterns: Array<string>;
|
||||
lastBackupAt: number | null;
|
||||
lastBackupError: string | null;
|
||||
lastBackupStatus: "error" | "success" | null;
|
||||
nextBackupAt: number | null;
|
||||
repositoryId: string;
|
||||
repositoryName: string;
|
||||
retentionPolicy: {
|
||||
keepDaily?: number;
|
||||
keepHourly?: number;
|
||||
keepLast?: number;
|
||||
keepMonthly?: number;
|
||||
keepWeekly?: number;
|
||||
keepWithinDuration?: string;
|
||||
keepYearly?: number;
|
||||
} | null;
|
||||
updatedAt: number;
|
||||
volumeId: number;
|
||||
volumeName: string;
|
||||
}>;
|
||||
};
|
||||
};
|
||||
|
||||
export type ListBackupSchedulesResponse = ListBackupSchedulesResponses[keyof ListBackupSchedulesResponses];
|
||||
|
||||
export type CreateBackupScheduleData = {
|
||||
body?: {
|
||||
cronExpression: string;
|
||||
enabled: boolean;
|
||||
repositoryId: string;
|
||||
volumeId: number;
|
||||
excludePatterns?: Array<string>;
|
||||
includePatterns?: Array<string>;
|
||||
retentionPolicy?: {
|
||||
keepDaily?: number;
|
||||
keepHourly?: number;
|
||||
keepLast?: number;
|
||||
keepMonthly?: number;
|
||||
keepWeekly?: number;
|
||||
keepWithinDuration?: string;
|
||||
keepYearly?: number;
|
||||
};
|
||||
tags?: Array<string>;
|
||||
};
|
||||
path?: never;
|
||||
query?: never;
|
||||
url: "/api/v1/backups";
|
||||
};
|
||||
|
||||
export type CreateBackupScheduleResponses = {
|
||||
/**
|
||||
* Backup schedule created successfully
|
||||
*/
|
||||
201: {
|
||||
message: string;
|
||||
schedule: {
|
||||
createdAt: number;
|
||||
cronExpression: string;
|
||||
enabled: boolean;
|
||||
excludePatterns: Array<string>;
|
||||
id: number;
|
||||
includePatterns: Array<string>;
|
||||
lastBackupAt: number | null;
|
||||
lastBackupError: string | null;
|
||||
lastBackupStatus: "error" | "success" | null;
|
||||
nextBackupAt: number | null;
|
||||
repositoryId: string;
|
||||
repositoryName: string;
|
||||
retentionPolicy: {
|
||||
keepDaily?: number;
|
||||
keepHourly?: number;
|
||||
keepLast?: number;
|
||||
keepMonthly?: number;
|
||||
keepWeekly?: number;
|
||||
keepWithinDuration?: string;
|
||||
keepYearly?: number;
|
||||
} | null;
|
||||
updatedAt: number;
|
||||
volumeId: number;
|
||||
volumeName: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
export type CreateBackupScheduleResponse = CreateBackupScheduleResponses[keyof CreateBackupScheduleResponses];
|
||||
|
||||
export type DeleteBackupScheduleData = {
|
||||
body?: never;
|
||||
path: {
|
||||
scheduleId: string;
|
||||
};
|
||||
query?: never;
|
||||
url: "/api/v1/backups/{scheduleId}";
|
||||
};
|
||||
|
||||
export type DeleteBackupScheduleResponses = {
|
||||
/**
|
||||
* Backup schedule deleted successfully
|
||||
*/
|
||||
200: {
|
||||
message: string;
|
||||
};
|
||||
};
|
||||
|
||||
export type DeleteBackupScheduleResponse = DeleteBackupScheduleResponses[keyof DeleteBackupScheduleResponses];
|
||||
|
||||
export type GetBackupScheduleData = {
|
||||
body?: never;
|
||||
path: {
|
||||
scheduleId: string;
|
||||
};
|
||||
query?: never;
|
||||
url: "/api/v1/backups/{scheduleId}";
|
||||
};
|
||||
|
||||
export type GetBackupScheduleResponses = {
|
||||
/**
|
||||
* Backup schedule details
|
||||
*/
|
||||
200: {
|
||||
schedule: {
|
||||
createdAt: number;
|
||||
cronExpression: string;
|
||||
enabled: boolean;
|
||||
excludePatterns: Array<string>;
|
||||
id: number;
|
||||
includePatterns: Array<string>;
|
||||
lastBackupAt: number | null;
|
||||
lastBackupError: string | null;
|
||||
lastBackupStatus: "error" | "success" | null;
|
||||
nextBackupAt: number | null;
|
||||
repositoryId: string;
|
||||
repositoryName: string;
|
||||
retentionPolicy: {
|
||||
keepDaily?: number;
|
||||
keepHourly?: number;
|
||||
keepLast?: number;
|
||||
keepMonthly?: number;
|
||||
keepWeekly?: number;
|
||||
keepWithinDuration?: string;
|
||||
keepYearly?: number;
|
||||
} | null;
|
||||
updatedAt: number;
|
||||
volumeId: number;
|
||||
volumeName: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
export type GetBackupScheduleResponse = GetBackupScheduleResponses[keyof GetBackupScheduleResponses];
|
||||
|
||||
export type UpdateBackupScheduleData = {
|
||||
body?: {
|
||||
cronExpression?: string;
|
||||
enabled?: boolean;
|
||||
excludePatterns?: Array<string>;
|
||||
includePatterns?: Array<string>;
|
||||
repositoryId?: string;
|
||||
retentionPolicy?: {
|
||||
keepDaily?: number;
|
||||
keepHourly?: number;
|
||||
keepLast?: number;
|
||||
keepMonthly?: number;
|
||||
keepWeekly?: number;
|
||||
keepWithinDuration?: string;
|
||||
keepYearly?: number;
|
||||
};
|
||||
tags?: Array<string>;
|
||||
};
|
||||
path: {
|
||||
scheduleId: string;
|
||||
};
|
||||
query?: never;
|
||||
url: "/api/v1/backups/{scheduleId}";
|
||||
};
|
||||
|
||||
export type UpdateBackupScheduleResponses = {
|
||||
/**
|
||||
* Backup schedule updated successfully
|
||||
*/
|
||||
200: {
|
||||
message: string;
|
||||
schedule: {
|
||||
createdAt: number;
|
||||
cronExpression: string;
|
||||
enabled: boolean;
|
||||
excludePatterns: Array<string>;
|
||||
id: number;
|
||||
includePatterns: Array<string>;
|
||||
lastBackupAt: number | null;
|
||||
lastBackupError: string | null;
|
||||
lastBackupStatus: "error" | "success" | null;
|
||||
nextBackupAt: number | null;
|
||||
repositoryId: string;
|
||||
repositoryName: string;
|
||||
retentionPolicy: {
|
||||
keepDaily?: number;
|
||||
keepHourly?: number;
|
||||
keepLast?: number;
|
||||
keepMonthly?: number;
|
||||
keepWeekly?: number;
|
||||
keepWithinDuration?: string;
|
||||
keepYearly?: number;
|
||||
} | null;
|
||||
updatedAt: number;
|
||||
volumeId: number;
|
||||
volumeName: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
export type UpdateBackupScheduleResponse = UpdateBackupScheduleResponses[keyof UpdateBackupScheduleResponses];
|
||||
|
||||
export type RunBackupNowData = {
|
||||
body?: never;
|
||||
path: {
|
||||
scheduleId: string;
|
||||
};
|
||||
query?: never;
|
||||
url: "/api/v1/backups/{scheduleId}/run";
|
||||
};
|
||||
|
||||
export type RunBackupNowResponses = {
|
||||
/**
|
||||
* Backup started successfully
|
||||
*/
|
||||
200: {
|
||||
backupStarted: boolean;
|
||||
message: string;
|
||||
};
|
||||
};
|
||||
|
||||
export type RunBackupNowResponse = RunBackupNowResponses[keyof RunBackupNowResponses];
|
||||
|
||||
export type ClientOptions = {
|
||||
baseUrl: "http://192.168.2.42:4096" | (string & {});
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user