changed to incubator
added new install script updated security updated ETA
This commit is contained in:
@@ -7,6 +7,7 @@ RESTIC_KEEP_HOURLY=0
|
||||
RESTIC_KEEP_DAILY=7
|
||||
RESTIC_KEEP_WEEKLY=0
|
||||
RESTIC_KEEP_MONTHLY=0
|
||||
RESTIC_RETRY_LOCK="5m"
|
||||
HOST="0.0.0.0"
|
||||
PORT=3000
|
||||
API_TOKEN="change-me-to-at-least-32-characters"
|
||||
|
||||
@@ -34,6 +34,7 @@ export const config = {
|
||||
RESTIC_REPOSITORY: process.env.RESTIC_REPOSITORY || '',
|
||||
RESTIC_PASSWORD: process.env.RESTIC_PASSWORD || '',
|
||||
},
|
||||
resticRetryLock: process.env.RESTIC_RETRY_LOCK || '5m',
|
||||
retention: {
|
||||
keepHourly: Number(process.env.RESTIC_KEEP_HOURLY || 0),
|
||||
keepDaily: Number(process.env.RESTIC_KEEP_DAILY || 7),
|
||||
@@ -60,6 +61,7 @@ export const editableEnv = [
|
||||
{ key: 'RESTIC_KEEP_DAILY', label: 'Keep daily snapshots', required: false, secret: false },
|
||||
{ key: 'RESTIC_KEEP_WEEKLY', label: 'Keep weekly snapshots', required: false, secret: false },
|
||||
{ key: 'RESTIC_KEEP_MONTHLY', label: 'Keep monthly snapshots', required: false, secret: false },
|
||||
{ key: 'RESTIC_RETRY_LOCK', label: 'Restic lock retry duration', required: false, secret: false },
|
||||
{ key: 'PORT', label: 'API port', required: false, secret: false },
|
||||
{ key: 'HOST', label: 'API bind host', required: false, secret: false },
|
||||
{ key: 'API_TOKEN', label: 'API token', required: true, secret: true },
|
||||
@@ -161,6 +163,7 @@ function applyRuntimeEnv(values) {
|
||||
config.resticEnv.AWS_SECRET_ACCESS_KEY = process.env.AWS_SECRET_ACCESS_KEY || '';
|
||||
config.resticEnv.RESTIC_REPOSITORY = process.env.RESTIC_REPOSITORY || '';
|
||||
config.resticEnv.RESTIC_PASSWORD = process.env.RESTIC_PASSWORD || '';
|
||||
config.resticRetryLock = process.env.RESTIC_RETRY_LOCK || '5m';
|
||||
config.retention.keepHourly = Number(process.env.RESTIC_KEEP_HOURLY || 0);
|
||||
config.retention.keepDaily = Number(process.env.RESTIC_KEEP_DAILY || 7);
|
||||
config.retention.keepWeekly = Number(process.env.RESTIC_KEEP_WEEKLY || 0);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { spawn } from 'node:child_process';
|
||||
import { PassThrough, Transform } from 'node:stream';
|
||||
import { resticProcessEnv } from './config.js';
|
||||
import { config, resticProcessEnv } from './config.js';
|
||||
|
||||
export class CommandError extends Error {
|
||||
constructor(message, result) {
|
||||
@@ -68,14 +68,14 @@ export function spawnCommand(command, args = [], options = {}) {
|
||||
}
|
||||
|
||||
export function runRestic(args, options = {}) {
|
||||
return spawnCommand('restic', args, {
|
||||
return spawnCommand('restic', resticArgs(args, options), {
|
||||
...options,
|
||||
env: resticProcessEnv(),
|
||||
});
|
||||
}
|
||||
|
||||
export async function resticSnapshotFileSize(snapshotId, filename) {
|
||||
const result = await runRestic(['ls', '--json', snapshotId]);
|
||||
const result = await runRestic(['--no-lock', 'ls', '--json', snapshotId], { retryLock: false });
|
||||
const wanted = `/${filename}`;
|
||||
for (const line of result.stdout.split('\n')) {
|
||||
if (!line.trim()) continue;
|
||||
@@ -89,6 +89,12 @@ export async function resticSnapshotFileSize(snapshotId, filename) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
export function resticArgs(args, options = {}) {
|
||||
if (options.retryLock === false || !config.resticRetryLock) return args;
|
||||
if (args.includes('--no-lock') || args.includes('--retry-lock')) return args;
|
||||
return ['--retry-lock', config.resticRetryLock, ...args];
|
||||
}
|
||||
|
||||
export function createProgressStream(totalBytes, onProgress) {
|
||||
let currentBytes = 0;
|
||||
return new Transform({
|
||||
|
||||
@@ -6,7 +6,7 @@ import path from 'node:path';
|
||||
import { finished } from 'node:stream/promises';
|
||||
import { setTimeout as delay } from 'node:timers/promises';
|
||||
import { config } from '../config.js';
|
||||
import { createProgressStream, resticSnapshotFileSize, spawnCommand, runRestic } from '../executor.js';
|
||||
import { createProgressStream, resticArgs, resticSnapshotFileSize, spawnCommand, runRestic } from '../executor.js';
|
||||
import { appendJobLog, createJob, finishJob, setJobProgress, setJobRunning, setJobStep } from '../jobs.js';
|
||||
import { validateVmExists } from '../validators.js';
|
||||
|
||||
@@ -70,7 +70,7 @@ export async function runBackupJob(job, instance = null) {
|
||||
});
|
||||
});
|
||||
try {
|
||||
const result = await spawnCommand('restic', ['backup', '--stdin', '--stdin-filename', `${job.vmName}.raw`, '--tag', job.vmName, '--tag', 'data', '--tag', 'virtual-machine'], {
|
||||
const result = await spawnCommand('restic', resticArgs(['backup', '--stdin', '--stdin-filename', `${job.vmName}.raw`, '--tag', job.vmName, '--tag', 'data', '--tag', 'virtual-machine']), {
|
||||
env: { ...process.env, ...config.resticEnv },
|
||||
input: snapshotStream.pipe(progressStream),
|
||||
log: (line) => appendJobLog(job, line),
|
||||
@@ -140,7 +140,7 @@ async function runContainerBackupJob(job) {
|
||||
});
|
||||
let resticOk = false;
|
||||
try {
|
||||
const result = await spawnCommand('restic', ['backup', '--stdin', '--stdin-filename', `${job.vmName}.zfs`, '--tag', job.vmName, '--tag', 'data', '--tag', 'container'], {
|
||||
const result = await spawnCommand('restic', resticArgs(['backup', '--stdin', '--stdin-filename', `${job.vmName}.zfs`, '--tag', job.vmName, '--tag', 'data', '--tag', 'container']), {
|
||||
env: { ...process.env, ...config.resticEnv },
|
||||
input: zfs.stdout.pipe(progressStream),
|
||||
log: (line) => appendJobLog(job, line),
|
||||
|
||||
Reference in New Issue
Block a user