mirror of
https://github.com/nicotsx/ironmount.git
synced 2025-12-10 12:10:51 +01:00
refactor(schemas): move restic schemas to a subfolder
This commit is contained in:
@@ -1,12 +1,10 @@
|
|||||||
|
import type { BackendStatus, BackendType, volumeConfigSchema } from "@ironmount/schemas";
|
||||||
import type {
|
import type {
|
||||||
BackendStatus,
|
|
||||||
BackendType,
|
|
||||||
CompressionMode,
|
CompressionMode,
|
||||||
RepositoryBackend,
|
RepositoryBackend,
|
||||||
RepositoryStatus,
|
|
||||||
repositoryConfigSchema,
|
repositoryConfigSchema,
|
||||||
volumeConfigSchema,
|
RepositoryStatus,
|
||||||
} from "@ironmount/schemas";
|
} from "@ironmount/schemas/restic";
|
||||||
import { sql } from "drizzle-orm";
|
import { sql } from "drizzle-orm";
|
||||||
import { int, sqliteTable, text } from "drizzle-orm/sqlite-core";
|
import { int, sqliteTable, text } from "drizzle-orm/sqlite-core";
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import crypto from "node:crypto";
|
import crypto from "node:crypto";
|
||||||
import fs from "node:fs/promises";
|
import fs from "node:fs/promises";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import type { RepositoryConfig } from "@ironmount/schemas";
|
import type { RepositoryConfig } from "@ironmount/schemas/restic";
|
||||||
import { type } from "arktype";
|
import { type } from "arktype";
|
||||||
import { $ } from "bun";
|
import { $ } from "bun";
|
||||||
import { RESTIC_PASS_FILE } from "../core/constants";
|
import { RESTIC_PASS_FILE } from "../core/constants";
|
||||||
@@ -38,6 +38,8 @@ const ensurePassfile = async () => {
|
|||||||
|
|
||||||
const buildRepoUrl = (config: RepositoryConfig): string => {
|
const buildRepoUrl = (config: RepositoryConfig): string => {
|
||||||
switch (config.backend) {
|
switch (config.backend) {
|
||||||
|
case "local":
|
||||||
|
return config.path;
|
||||||
case "s3":
|
case "s3":
|
||||||
return `s3:${config.endpoint}/${config.bucket}`;
|
return `s3:${config.endpoint}/${config.bucket}`;
|
||||||
default: {
|
default: {
|
||||||
@@ -47,7 +49,9 @@ const buildRepoUrl = (config: RepositoryConfig): string => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const buildEnv = async (config: RepositoryConfig) => {
|
const buildEnv = async (config: RepositoryConfig) => {
|
||||||
const env: Record<string, string> = {};
|
const env: Record<string, string> = {
|
||||||
|
RESTIC_PASSWORD_FILE: RESTIC_PASS_FILE,
|
||||||
|
};
|
||||||
|
|
||||||
switch (config.backend) {
|
switch (config.backend) {
|
||||||
case "s3":
|
case "s3":
|
||||||
@@ -65,7 +69,7 @@ const init = async (config: RepositoryConfig) => {
|
|||||||
const repoUrl = buildRepoUrl(config);
|
const repoUrl = buildRepoUrl(config);
|
||||||
const env = await buildEnv(config);
|
const env = await buildEnv(config);
|
||||||
|
|
||||||
const res = await $`restic init --repo ${repoUrl} --password-file ${RESTIC_PASS_FILE} --json`.env(env).nothrow();
|
const res = await $`restic init --repo ${repoUrl} --json`.env(env).nothrow();
|
||||||
|
|
||||||
if (res.exitCode !== 0) {
|
if (res.exitCode !== 0) {
|
||||||
logger.error(`Restic init failed: ${res.stderr}`);
|
logger.error(`Restic init failed: ${res.stderr}`);
|
||||||
@@ -80,9 +84,7 @@ const backup = async (config: RepositoryConfig, source: string) => {
|
|||||||
const repoUrl = buildRepoUrl(config);
|
const repoUrl = buildRepoUrl(config);
|
||||||
const env = await buildEnv(config);
|
const env = await buildEnv(config);
|
||||||
|
|
||||||
const res = await $`restic --repo ${repoUrl} backup ${source} --password-file /data/secrets/restic.pass --json`
|
const res = await $`restic --repo ${repoUrl} backup ${source} --json`.env(env).nothrow();
|
||||||
.env(env)
|
|
||||||
.nothrow();
|
|
||||||
|
|
||||||
if (res.exitCode !== 0) {
|
if (res.exitCode !== 0) {
|
||||||
logger.error(`Restic backup failed: ${res.stderr}`);
|
logger.error(`Restic backup failed: ${res.stderr}`);
|
||||||
@@ -99,8 +101,23 @@ const backup = async (config: RepositoryConfig, source: string) => {
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const restore = async (config: RepositoryConfig, snapshotId: string, target: string) => {
|
||||||
|
const repoUrl = buildRepoUrl(config);
|
||||||
|
const env = await buildEnv(config);
|
||||||
|
|
||||||
|
const res = await $`restic --repo ${repoUrl} restore ${snapshotId} --target ${target} --json`.env(env).nothrow();
|
||||||
|
|
||||||
|
if (res.exitCode !== 0) {
|
||||||
|
logger.error(`Restic restore failed: ${res.stderr}`);
|
||||||
|
throw new Error(`Restic restore failed: ${res.stderr}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info(`Restic restore completed for snapshot ${snapshotId} to target ${target}`);
|
||||||
|
};
|
||||||
|
|
||||||
export const restic = {
|
export const restic = {
|
||||||
ensurePassfile,
|
ensurePassfile,
|
||||||
init,
|
init,
|
||||||
backup,
|
backup,
|
||||||
|
restore,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,6 +4,16 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"main": "./src/index.ts",
|
"main": "./src/index.ts",
|
||||||
"types": "./src/index.ts",
|
"types": "./src/index.ts",
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"import": "./src/index.ts",
|
||||||
|
"require": "./src/index.ts"
|
||||||
|
},
|
||||||
|
"./restic": {
|
||||||
|
"import": "./src/restic.ts",
|
||||||
|
"require": "./src/restic.ts"
|
||||||
|
}
|
||||||
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"arktype": ">=2"
|
"arktype": ">=2"
|
||||||
|
|||||||
@@ -53,41 +53,3 @@ export const BACKEND_STATUS = {
|
|||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export type BackendStatus = keyof typeof BACKEND_STATUS;
|
export type BackendStatus = keyof typeof BACKEND_STATUS;
|
||||||
|
|
||||||
export const REPOSITORY_BACKENDS = {
|
|
||||||
local: "local",
|
|
||||||
sftp: "sftp",
|
|
||||||
s3: "s3",
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
export type RepositoryBackend = keyof typeof REPOSITORY_BACKENDS;
|
|
||||||
|
|
||||||
export const s3RepositoryConfigSchema = type({
|
|
||||||
backend: "'s3'",
|
|
||||||
endpoint: "string",
|
|
||||||
bucket: "string",
|
|
||||||
accessKeyId: "string",
|
|
||||||
secretAccessKey: "string",
|
|
||||||
});
|
|
||||||
|
|
||||||
export const repositoryConfigSchema = s3RepositoryConfigSchema;
|
|
||||||
|
|
||||||
export type RepositoryConfig = typeof repositoryConfigSchema.infer;
|
|
||||||
|
|
||||||
export const COMPRESSION_MODES = {
|
|
||||||
off: "off",
|
|
||||||
auto: "auto",
|
|
||||||
fastest: "fastest",
|
|
||||||
better: "better",
|
|
||||||
max: "max",
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
export type CompressionMode = keyof typeof COMPRESSION_MODES;
|
|
||||||
|
|
||||||
export const REPOSITORY_STATUS = {
|
|
||||||
healthy: "healthy",
|
|
||||||
error: "error",
|
|
||||||
unknown: "unknown",
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
export type RepositoryStatus = keyof typeof REPOSITORY_STATUS;
|
|
||||||
|
|||||||
44
packages/schemas/src/restic.ts
Normal file
44
packages/schemas/src/restic.ts
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import { type } from "arktype";
|
||||||
|
|
||||||
|
export const REPOSITORY_BACKENDS = {
|
||||||
|
local: "local",
|
||||||
|
sftp: "sftp",
|
||||||
|
s3: "s3",
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export type RepositoryBackend = keyof typeof REPOSITORY_BACKENDS;
|
||||||
|
|
||||||
|
export const s3RepositoryConfigSchema = type({
|
||||||
|
backend: "'s3'",
|
||||||
|
endpoint: "string",
|
||||||
|
bucket: "string",
|
||||||
|
accessKeyId: "string",
|
||||||
|
secretAccessKey: "string",
|
||||||
|
});
|
||||||
|
|
||||||
|
export const localRepositoryConfigSchema = type({
|
||||||
|
backend: "'local'",
|
||||||
|
path: "string",
|
||||||
|
});
|
||||||
|
|
||||||
|
export const repositoryConfigSchema = s3RepositoryConfigSchema.or(localRepositoryConfigSchema);
|
||||||
|
|
||||||
|
export type RepositoryConfig = typeof repositoryConfigSchema.infer;
|
||||||
|
|
||||||
|
export const COMPRESSION_MODES = {
|
||||||
|
off: "off",
|
||||||
|
auto: "auto",
|
||||||
|
fastest: "fastest",
|
||||||
|
better: "better",
|
||||||
|
max: "max",
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export type CompressionMode = keyof typeof COMPRESSION_MODES;
|
||||||
|
|
||||||
|
export const REPOSITORY_STATUS = {
|
||||||
|
healthy: "healthy",
|
||||||
|
error: "error",
|
||||||
|
unknown: "unknown",
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export type RepositoryStatus = keyof typeof REPOSITORY_STATUS;
|
||||||
Reference in New Issue
Block a user