@futo-org/backups-orchestrator-api 0.3.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/backends/backend.d.ts +2 -2
- package/dist/backends/backend.js +2 -5
- package/dist/backends/backend.js.map +1 -1
- package/dist/backends/local.backend.d.ts +1 -0
- package/dist/backends/local.backend.js +3 -0
- package/dist/backends/local.backend.js.map +1 -1
- package/dist/backends/s3.backend.d.ts +1 -0
- package/dist/backends/s3.backend.js +3 -0
- package/dist/backends/s3.backend.js.map +1 -1
- package/dist/backends/yucca.backend.d.ts +19 -3
- package/dist/backends/yucca.backend.js +47 -22
- package/dist/backends/yucca.backend.js.map +1 -1
- package/dist/const.d.ts +2 -1
- package/dist/const.js +3 -2
- package/dist/const.js.map +1 -1
- package/dist/controllers/onboarding.controller.d.ts +2 -0
- package/dist/controllers/onboarding.controller.js +18 -0
- package/dist/controllers/onboarding.controller.js.map +1 -1
- package/dist/dto/onboarding.dto.d.ts +4 -0
- package/dist/dto/onboarding.dto.js +16 -0
- package/dist/dto/onboarding.dto.js.map +1 -1
- package/dist/enum.d.ts +10 -0
- package/dist/enum.js +13 -1
- package/dist/enum.js.map +1 -1
- package/dist/interceptors/telemetry-error.interceptor.d.ts +8 -0
- package/dist/interceptors/telemetry-error.interceptor.js +47 -0
- package/dist/interceptors/telemetry-error.interceptor.js.map +1 -0
- package/dist/moduleConfig.d.ts +1 -1
- package/dist/orchestrationApi.module.d.ts +5 -3
- package/dist/orchestrationApi.module.js +13 -4
- package/dist/orchestrationApi.module.js.map +1 -1
- package/dist/repositories/backend.repository.d.ts +2 -0
- package/dist/repositories/backend.repository.js +8 -3
- package/dist/repositories/backend.repository.js.map +1 -1
- package/dist/repositories/bootstrap.repository.d.ts +9 -0
- package/dist/repositories/bootstrap.repository.js +33 -0
- package/dist/repositories/bootstrap.repository.js.map +1 -0
- package/dist/repositories/config.repository.d.ts +2 -0
- package/dist/repositories/config.repository.js +6 -0
- package/dist/repositories/config.repository.js.map +1 -1
- package/dist/repositories/restic.repository.d.ts +32 -3
- package/dist/repositories/restic.repository.js +3 -7
- package/dist/repositories/restic.repository.js.map +1 -1
- package/dist/schema/tables/backend.table.d.ts +1 -0
- package/dist/schema/tables/backend.table.js.map +1 -1
- package/dist/services/auth.service.d.ts +3 -1
- package/dist/services/auth.service.js +24 -7
- package/dist/services/auth.service.js.map +1 -1
- package/dist/services/backend.service.d.ts +3 -3
- package/dist/services/backend.service.js +12 -8
- package/dist/services/backend.service.js.map +1 -1
- package/dist/services/bootstrap.service.d.ts +3 -1
- package/dist/services/bootstrap.service.js +16 -6
- package/dist/services/bootstrap.service.js.map +1 -1
- package/dist/services/integrations.service.d.ts +3 -1
- package/dist/services/integrations.service.js +10 -2
- package/dist/services/integrations.service.js.map +1 -1
- package/dist/services/onboarding.service.d.ts +7 -1
- package/dist/services/onboarding.service.js +37 -2
- package/dist/services/onboarding.service.js.map +1 -1
- package/dist/services/repository.service.d.ts +3 -1
- package/dist/services/repository.service.js +188 -76
- package/dist/services/repository.service.js.map +1 -1
- package/dist/services/schedule.service.d.ts +3 -1
- package/dist/services/schedule.service.js +26 -2
- package/dist/services/schedule.service.js.map +1 -1
- package/dist/services/telemetry.service.d.ts +9 -0
- package/dist/services/telemetry.service.js +59 -0
- package/dist/services/telemetry.service.js.map +1 -0
- package/package.json +5 -4
|
@@ -1,17 +1,23 @@
|
|
|
1
1
|
import { CurrentRecoveryKeyResponse, OnboardingStatusResponseDto } from '../dto/onboarding.dto';
|
|
2
2
|
import { BackendRepository } from '../repositories/backend.repository';
|
|
3
|
+
import { BootstrapRepository } from '../repositories/bootstrap.repository';
|
|
3
4
|
import { ConfigRepository } from '../repositories/config.repository';
|
|
4
5
|
import { RepositoryRepository } from '../repositories/repository.repository';
|
|
5
6
|
import { ScheduleRepository } from '../repositories/schedule.repository';
|
|
7
|
+
import { TelemetryService } from './telemetry.service';
|
|
6
8
|
export declare class OnboardingService {
|
|
7
9
|
private readonly backend;
|
|
8
10
|
private readonly repository;
|
|
9
11
|
private readonly schedule;
|
|
10
12
|
private readonly config;
|
|
11
|
-
|
|
13
|
+
private readonly bootstrap;
|
|
14
|
+
private readonly telemetry;
|
|
15
|
+
constructor(backend: BackendRepository, repository: RepositoryRepository, schedule: ScheduleRepository, config: ConfigRepository, bootstrap: BootstrapRepository, telemetry: TelemetryService);
|
|
12
16
|
onboardingStatus(): Promise<OnboardingStatusResponseDto>;
|
|
13
17
|
currentRecoveryKey(): Promise<CurrentRecoveryKeyResponse>;
|
|
14
18
|
importRecoveryKey(key: string): Promise<void>;
|
|
15
19
|
confirmRecoveryKey(): Promise<void>;
|
|
16
20
|
skipExtraConfig(): Promise<void>;
|
|
21
|
+
enableTelemetry(): Promise<void>;
|
|
22
|
+
reportError(): void;
|
|
17
23
|
}
|
|
@@ -11,26 +11,50 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.OnboardingService = void 0;
|
|
13
13
|
const common_1 = require("@nestjs/common");
|
|
14
|
+
const enum_1 = require("../enum");
|
|
14
15
|
const backend_repository_1 = require("../repositories/backend.repository");
|
|
16
|
+
const bootstrap_repository_1 = require("../repositories/bootstrap.repository");
|
|
15
17
|
const config_repository_1 = require("../repositories/config.repository");
|
|
16
18
|
const repository_repository_1 = require("../repositories/repository.repository");
|
|
17
19
|
const schedule_repository_1 = require("../repositories/schedule.repository");
|
|
20
|
+
const telemetry_service_1 = require("./telemetry.service");
|
|
18
21
|
let OnboardingService = class OnboardingService {
|
|
19
22
|
backend;
|
|
20
23
|
repository;
|
|
21
24
|
schedule;
|
|
22
25
|
config;
|
|
23
|
-
|
|
26
|
+
bootstrap;
|
|
27
|
+
telemetry;
|
|
28
|
+
constructor(backend, repository, schedule, config, bootstrap, telemetry) {
|
|
24
29
|
this.backend = backend;
|
|
25
30
|
this.repository = repository;
|
|
26
31
|
this.schedule = schedule;
|
|
27
32
|
this.config = config;
|
|
33
|
+
this.bootstrap = bootstrap;
|
|
34
|
+
this.telemetry = telemetry;
|
|
28
35
|
}
|
|
29
36
|
async onboardingStatus() {
|
|
37
|
+
const status = this.bootstrap.getStatus();
|
|
38
|
+
if (status !== enum_1.BootstrapStatus.Ready) {
|
|
39
|
+
let error = this.bootstrap.getError();
|
|
40
|
+
error = error ? `${error}` : undefined;
|
|
41
|
+
return {
|
|
42
|
+
status,
|
|
43
|
+
error,
|
|
44
|
+
hasTelemetry: enum_1.TelemetryLevel.None,
|
|
45
|
+
hasOnboardedKey: false,
|
|
46
|
+
hasBackend: false,
|
|
47
|
+
hasBackup: false,
|
|
48
|
+
hasSchedule: false,
|
|
49
|
+
hasSkippedExtraConfig: false,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
30
52
|
const backends = await this.backend.getBackends();
|
|
31
53
|
const repositories = await this.repository.getAll();
|
|
32
54
|
const schedules = await this.schedule.getAll();
|
|
33
55
|
return {
|
|
56
|
+
status: enum_1.BootstrapStatus.Ready,
|
|
57
|
+
hasTelemetry: (await this.config.hasTelemetry()) ? enum_1.TelemetryLevel.Full : enum_1.TelemetryLevel.None,
|
|
34
58
|
hasOnboardedKey: await this.config.hasOnboardedKey(),
|
|
35
59
|
hasBackend: backends.length > 0,
|
|
36
60
|
hasBackup: repositories.length > 0,
|
|
@@ -53,6 +77,15 @@ let OnboardingService = class OnboardingService {
|
|
|
53
77
|
async skipExtraConfig() {
|
|
54
78
|
await this.config.skipExtraConfig();
|
|
55
79
|
}
|
|
80
|
+
async enableTelemetry() {
|
|
81
|
+
await this.config.enableTelemetry();
|
|
82
|
+
this.telemetry.submitStructuredLog('Telemetry consent granted', {});
|
|
83
|
+
}
|
|
84
|
+
reportError() {
|
|
85
|
+
this.telemetry.submitStructuredLog('Bootstrap error', {
|
|
86
|
+
error: this.bootstrap.getError(),
|
|
87
|
+
}, true);
|
|
88
|
+
}
|
|
56
89
|
};
|
|
57
90
|
exports.OnboardingService = OnboardingService;
|
|
58
91
|
exports.OnboardingService = OnboardingService = __decorate([
|
|
@@ -60,6 +93,8 @@ exports.OnboardingService = OnboardingService = __decorate([
|
|
|
60
93
|
__metadata("design:paramtypes", [backend_repository_1.BackendRepository,
|
|
61
94
|
repository_repository_1.RepositoryRepository,
|
|
62
95
|
schedule_repository_1.ScheduleRepository,
|
|
63
|
-
config_repository_1.ConfigRepository
|
|
96
|
+
config_repository_1.ConfigRepository,
|
|
97
|
+
bootstrap_repository_1.BootstrapRepository,
|
|
98
|
+
telemetry_service_1.TelemetryService])
|
|
64
99
|
], OnboardingService);
|
|
65
100
|
//# sourceMappingURL=onboarding.service.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"onboarding.service.js","sourceRoot":"","sources":["../../src/services/onboarding.service.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAA4C;AAE5C,2EAAuE;AACvE,yEAAqE;AACrE,iFAA6E;AAC7E,6EAAyE;
|
|
1
|
+
{"version":3,"file":"onboarding.service.js","sourceRoot":"","sources":["../../src/services/onboarding.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,6 +14,7 @@ import { RunHistoryRepository } from '../repositories/runHistory.repository';
|
|
|
14
14
|
import { RunningTasksRepository } from '../repositories/runningTasks.repository';
|
|
15
15
|
import { StorageRepository } from '../repositories/storage.repository';
|
|
16
16
|
import { BootstrapService } from './bootstrap.service';
|
|
17
|
+
import { TelemetryService } from './telemetry.service';
|
|
17
18
|
export declare class RepositoryService {
|
|
18
19
|
private readonly tasks;
|
|
19
20
|
private readonly events;
|
|
@@ -28,7 +29,8 @@ export declare class RepositoryService {
|
|
|
28
29
|
private readonly moduleConfig;
|
|
29
30
|
private readonly storage;
|
|
30
31
|
private readonly bootstrap;
|
|
31
|
-
|
|
32
|
+
private readonly telemetry;
|
|
33
|
+
constructor(tasks: RunningTasksRepository, events: EventsGateway, backend: BackendRepository, config: ConfigRepository, database: DatabaseRepository, restic: ResticRepository, runHistory: RunHistoryRepository, repository: RepositoryRepository, repositoryPath: RepositoryPathRepository, repositoryLocalMetrics: RepositoryLocalMetricsRepository, moduleConfig: ModuleConfigRepository, storage: StorageRepository, bootstrap: BootstrapService, telemetry: TelemetryService);
|
|
32
34
|
private getLocalRepository;
|
|
33
35
|
createRepository(dto: RepositoryCreateRequestDto, backendId?: string): Promise<RepositoryCreateResponseDto>;
|
|
34
36
|
getRepositories(): Promise<RepositoryListResponseDto>;
|
|
@@ -16,7 +16,6 @@ exports.RepositoryService = void 0;
|
|
|
16
16
|
const common_1 = require("@nestjs/common");
|
|
17
17
|
const node_crypto_1 = require("node:crypto");
|
|
18
18
|
const node_path_1 = require("node:path");
|
|
19
|
-
const backend_1 = require("../backends/backend");
|
|
20
19
|
const enum_1 = require("../enum");
|
|
21
20
|
const events_gateway_1 = require("../events/events.gateway");
|
|
22
21
|
const backend_repository_1 = require("../repositories/backend.repository");
|
|
@@ -32,6 +31,7 @@ const runningTasks_repository_1 = require("../repositories/runningTasks.reposito
|
|
|
32
31
|
const storage_repository_1 = require("../repositories/storage.repository");
|
|
33
32
|
const restic_1 = require("../utils/restic");
|
|
34
33
|
const bootstrap_service_1 = require("./bootstrap.service");
|
|
34
|
+
const telemetry_service_1 = require("./telemetry.service");
|
|
35
35
|
let RepositoryService = class RepositoryService {
|
|
36
36
|
tasks;
|
|
37
37
|
events;
|
|
@@ -46,7 +46,8 @@ let RepositoryService = class RepositoryService {
|
|
|
46
46
|
moduleConfig;
|
|
47
47
|
storage;
|
|
48
48
|
bootstrap;
|
|
49
|
-
|
|
49
|
+
telemetry;
|
|
50
|
+
constructor(tasks, events, backend, config, database, restic, runHistory, repository, repositoryPath, repositoryLocalMetrics, moduleConfig, storage, bootstrap, telemetry) {
|
|
50
51
|
this.tasks = tasks;
|
|
51
52
|
this.events = events;
|
|
52
53
|
this.backend = backend;
|
|
@@ -60,6 +61,7 @@ let RepositoryService = class RepositoryService {
|
|
|
60
61
|
this.moduleConfig = moduleConfig;
|
|
61
62
|
this.storage = storage;
|
|
62
63
|
this.bootstrap = bootstrap;
|
|
64
|
+
this.telemetry = telemetry;
|
|
63
65
|
}
|
|
64
66
|
async getLocalRepository(id, configuration, metrics) {
|
|
65
67
|
if (!configuration) {
|
|
@@ -77,8 +79,7 @@ let RepositoryService = class RepositoryService {
|
|
|
77
79
|
const backends = await this.backend.getBackends();
|
|
78
80
|
backendId = backends[0].id;
|
|
79
81
|
}
|
|
80
|
-
const { configuration } = await this.backend.getBackend(backendId);
|
|
81
|
-
const backend = backend_1.Backend.from(configuration, this.moduleConfig.get());
|
|
82
|
+
const { backend, configuration } = await this.backend.getBackend(backendId);
|
|
82
83
|
const { repository: remote } = await backend.createRepository(dto);
|
|
83
84
|
const id = (0, node_crypto_1.randomUUID)();
|
|
84
85
|
const endpoint = await backend.getResticEndpoint(remote.id);
|
|
@@ -107,6 +108,10 @@ let RepositoryService = class RepositoryService {
|
|
|
107
108
|
secondary: [],
|
|
108
109
|
},
|
|
109
110
|
};
|
|
111
|
+
this.telemetry.submitStructuredLog('Created repository', {
|
|
112
|
+
repositoryId: remote.id,
|
|
113
|
+
backendId,
|
|
114
|
+
});
|
|
110
115
|
this.events.publish({
|
|
111
116
|
type: 'RepositoryCreate',
|
|
112
117
|
repository,
|
|
@@ -120,8 +125,7 @@ let RepositoryService = class RepositoryService {
|
|
|
120
125
|
const repositories = [];
|
|
121
126
|
const backendsById = Object.fromEntries(backends.map((backend) => [backend.id, backend]));
|
|
122
127
|
const remoteRepositories = {};
|
|
123
|
-
for (const { id: backendId,
|
|
124
|
-
const backend = backend_1.Backend.from(configuration, this.moduleConfig.get());
|
|
128
|
+
for (const { id: backendId, backend } of backends) {
|
|
125
129
|
remoteRepositories[backendId] = {};
|
|
126
130
|
try {
|
|
127
131
|
const { repositories: list } = await backend.getRepositories();
|
|
@@ -242,14 +246,13 @@ let RepositoryService = class RepositoryService {
|
|
|
242
246
|
backendId = localRepository.backendId;
|
|
243
247
|
remoteId = localRepository.remoteId;
|
|
244
248
|
}
|
|
245
|
-
const backend = await this.backend.getBackend(backendId);
|
|
246
|
-
const backendInstance = backend_1.Backend.from(backend.configuration, this.moduleConfig.get());
|
|
249
|
+
const { backend, configuration } = await this.backend.getBackend(backendId);
|
|
247
250
|
let remote;
|
|
248
251
|
if (dto.name) {
|
|
249
|
-
({ repository: remote } = await
|
|
252
|
+
({ repository: remote } = await backend.updateRepository(remoteId, dto));
|
|
250
253
|
}
|
|
251
254
|
else {
|
|
252
|
-
({ repository: remote } = await
|
|
255
|
+
({ repository: remote } = await backend.getRepository(remoteId));
|
|
253
256
|
}
|
|
254
257
|
if (dto.paths) {
|
|
255
258
|
const currentPaths = new Set(await this.repositoryPath.get(id));
|
|
@@ -277,12 +280,15 @@ let RepositoryService = class RepositoryService {
|
|
|
277
280
|
backends: {
|
|
278
281
|
primary: {
|
|
279
282
|
id: backendId,
|
|
280
|
-
type:
|
|
283
|
+
type: configuration.type,
|
|
281
284
|
online: true,
|
|
282
285
|
},
|
|
283
286
|
secondary: [],
|
|
284
287
|
},
|
|
285
288
|
};
|
|
289
|
+
this.telemetry.submitStructuredLog('Updated repository', {
|
|
290
|
+
repositoryId: id,
|
|
291
|
+
});
|
|
286
292
|
this.events.publish({
|
|
287
293
|
type: 'RepositoryUpdate',
|
|
288
294
|
repositoryId: id,
|
|
@@ -294,6 +300,9 @@ let RepositoryService = class RepositoryService {
|
|
|
294
300
|
}
|
|
295
301
|
async deleteRepository(id) {
|
|
296
302
|
await this.repository.delete(id);
|
|
303
|
+
this.telemetry.submitStructuredLog('Deleted repository', {
|
|
304
|
+
repositoryId: id,
|
|
305
|
+
});
|
|
297
306
|
this.events.publish({
|
|
298
307
|
type: 'RepositoryDelete',
|
|
299
308
|
repositoryId: id,
|
|
@@ -313,9 +322,8 @@ let RepositoryService = class RepositoryService {
|
|
|
313
322
|
else {
|
|
314
323
|
({ backendId, remoteId } = repository);
|
|
315
324
|
}
|
|
316
|
-
const backend = await this.backend.getBackend(backendId);
|
|
317
|
-
const
|
|
318
|
-
const endpoint = await backendInstance.getResticEndpoint(remoteId);
|
|
325
|
+
const { backend } = await this.backend.getBackend(backendId);
|
|
326
|
+
const endpoint = await backend.getResticEndpoint(remoteId);
|
|
319
327
|
const key = await this.config.deriveEncryptionKey(`repository-${remoteId}`);
|
|
320
328
|
return { endpoint, key };
|
|
321
329
|
}
|
|
@@ -339,23 +347,31 @@ let RepositoryService = class RepositoryService {
|
|
|
339
347
|
});
|
|
340
348
|
if (metrics.sizeBytes) {
|
|
341
349
|
const { backendId, remoteId } = await this.repository.get(id);
|
|
342
|
-
const {
|
|
343
|
-
const backend = backend_1.Backend.from(configuration, this.moduleConfig.get());
|
|
350
|
+
const { backend } = await this.backend.getBackend(backendId);
|
|
344
351
|
if (backend.isMetricsCapable()) {
|
|
345
352
|
await backend.submitMetricRepositorySize(remoteId, metrics.sizeBytes);
|
|
346
353
|
}
|
|
347
354
|
}
|
|
348
355
|
}
|
|
349
|
-
catch {
|
|
356
|
+
catch (error) {
|
|
357
|
+
this.telemetry.submitStructuredLog('Failed to update repository metrics', {
|
|
358
|
+
repositoryId: id,
|
|
359
|
+
error,
|
|
360
|
+
});
|
|
350
361
|
}
|
|
351
362
|
}
|
|
352
363
|
async createBackup(id, signal) {
|
|
353
364
|
if (!this.tasks.canStart(id)) {
|
|
365
|
+
this.telemetry.submitStructuredLog('Backup rejected, task already running', {
|
|
366
|
+
repositoryId: id,
|
|
367
|
+
});
|
|
354
368
|
throw new common_1.BadRequestException('Task already running!');
|
|
355
369
|
}
|
|
370
|
+
this.telemetry.submitStructuredLog('Running backup', {
|
|
371
|
+
repositoryId: id,
|
|
372
|
+
});
|
|
356
373
|
const { backendId, remoteId } = await this.repository.get(id);
|
|
357
|
-
const {
|
|
358
|
-
const backend = backend_1.Backend.from(configuration, this.moduleConfig.get());
|
|
374
|
+
const { backend } = await this.backend.getBackend(backendId);
|
|
359
375
|
const { endpoint, key } = await this.getResticParameters(id);
|
|
360
376
|
const paths = await this.repositoryPath.get(id);
|
|
361
377
|
if (paths.length === 0) {
|
|
@@ -374,10 +390,17 @@ let RepositoryService = class RepositoryService {
|
|
|
374
390
|
try {
|
|
375
391
|
const taskSignal = this.tasks.startTask(id, enum_1.TaskType.Backup, logId, signal);
|
|
376
392
|
await this.restic.unlockAll(endpoint, key);
|
|
377
|
-
await this.restic.backup(endpoint, key, paths, log, taskSignal);
|
|
393
|
+
const summary = await this.restic.backup(endpoint, key, paths, log, taskSignal);
|
|
394
|
+
this.telemetry.submitStructuredLog('Finished backup to primary backend', {
|
|
395
|
+
repositoryId: id,
|
|
396
|
+
summary,
|
|
397
|
+
});
|
|
378
398
|
const { retentionPolicy: policy } = await this.repository.get(id);
|
|
379
399
|
if (policy) {
|
|
380
400
|
await this.runForgetAndPrune(endpoint, key, policy, log, taskSignal);
|
|
401
|
+
this.telemetry.submitStructuredLog('Finished prune on primary backend', {
|
|
402
|
+
repositoryId: id,
|
|
403
|
+
});
|
|
381
404
|
}
|
|
382
405
|
}
|
|
383
406
|
finally {
|
|
@@ -395,6 +418,10 @@ let RepositoryService = class RepositoryService {
|
|
|
395
418
|
lastBackupDuration,
|
|
396
419
|
},
|
|
397
420
|
});
|
|
421
|
+
this.telemetry.submitStructuredLog('Backup finished', {
|
|
422
|
+
repositoryId: id,
|
|
423
|
+
error,
|
|
424
|
+
});
|
|
398
425
|
if (error) {
|
|
399
426
|
fail(error);
|
|
400
427
|
}
|
|
@@ -431,12 +458,19 @@ let RepositoryService = class RepositoryService {
|
|
|
431
458
|
}
|
|
432
459
|
async pruneRepository(id, signal) {
|
|
433
460
|
if (!this.tasks.canStart(id)) {
|
|
461
|
+
this.telemetry.submitStructuredLog('Repository prune rejected, task already running', {
|
|
462
|
+
repositoryId: id,
|
|
463
|
+
});
|
|
434
464
|
throw new common_1.BadRequestException('Task already running!');
|
|
435
465
|
}
|
|
436
466
|
const { retentionPolicy: policy } = await this.repository.get(id);
|
|
437
467
|
if (!policy) {
|
|
438
468
|
throw new common_1.BadRequestException('No retention policy configured for this repository');
|
|
439
469
|
}
|
|
470
|
+
this.telemetry.submitStructuredLog('Running repository prune', {
|
|
471
|
+
repositoryId: id,
|
|
472
|
+
retentionPolicy: policy,
|
|
473
|
+
});
|
|
440
474
|
const { endpoint, key } = await this.getResticParameters(id);
|
|
441
475
|
return new Promise((resolve) => {
|
|
442
476
|
const task = new Promise((complete, fail) => void this.runHistory.createLog(id, enum_1.TaskType.Forget, async (log, logId) => {
|
|
@@ -453,6 +487,10 @@ let RepositoryService = class RepositoryService {
|
|
|
453
487
|
void this.updateLocalMetrics(id, {
|
|
454
488
|
resticParameters: { endpoint, key },
|
|
455
489
|
});
|
|
490
|
+
this.telemetry.submitStructuredLog('Finished repository prune', {
|
|
491
|
+
repositoryId: id,
|
|
492
|
+
error,
|
|
493
|
+
});
|
|
456
494
|
if (error) {
|
|
457
495
|
fail(error);
|
|
458
496
|
}
|
|
@@ -478,51 +516,72 @@ let RepositoryService = class RepositoryService {
|
|
|
478
516
|
}
|
|
479
517
|
}
|
|
480
518
|
async importRepository(id, backendId) {
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
const { repository: remote } = await backend.getRepository(id);
|
|
484
|
-
const localId = (0, node_crypto_1.randomUUID)();
|
|
485
|
-
const endpoint = await backend.getResticEndpoint(remote.id);
|
|
486
|
-
const key = await this.config.deriveEncryptionKey(`repository-${remote.id}`);
|
|
487
|
-
await this.restic.keyList(endpoint, key);
|
|
488
|
-
let paths = [];
|
|
489
|
-
try {
|
|
490
|
-
const snapshots = await this.restic.snapshots(endpoint, key);
|
|
491
|
-
snapshots.sort((a, b) => +b.time - +a.time);
|
|
492
|
-
paths = snapshots[0].paths;
|
|
493
|
-
}
|
|
494
|
-
catch {
|
|
495
|
-
}
|
|
496
|
-
await this.repository.create({
|
|
497
|
-
id: localId,
|
|
498
|
-
remoteId: remote.id,
|
|
519
|
+
this.telemetry.submitStructuredLog('Running repository import', {
|
|
520
|
+
repositoryId: id,
|
|
499
521
|
backendId,
|
|
500
|
-
retentionPolicy: restic_1.DEFAULT_RETENTION_POLICY,
|
|
501
522
|
});
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
523
|
+
try {
|
|
524
|
+
const { configuration, backend } = await this.backend.getBackend(backendId);
|
|
525
|
+
const { repository: remote } = await backend.getRepository(id);
|
|
526
|
+
const localId = (0, node_crypto_1.randomUUID)();
|
|
527
|
+
const endpoint = await backend.getResticEndpoint(remote.id);
|
|
528
|
+
const key = await this.config.deriveEncryptionKey(`repository-${remote.id}`);
|
|
529
|
+
await this.restic.keyList(endpoint, key);
|
|
530
|
+
let paths = [];
|
|
531
|
+
try {
|
|
532
|
+
const snapshots = await this.restic.snapshots(endpoint, key);
|
|
533
|
+
snapshots.sort((a, b) => +b.time - +a.time);
|
|
534
|
+
paths = snapshots[0].paths;
|
|
535
|
+
}
|
|
536
|
+
catch (error) {
|
|
537
|
+
this.telemetry.submitStructuredLog('Failed to infer backup paths during import', {
|
|
538
|
+
repositoryId: id,
|
|
539
|
+
backendId,
|
|
540
|
+
error,
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
await this.repository.create({
|
|
544
|
+
id: localId,
|
|
545
|
+
remoteId: remote.id,
|
|
546
|
+
backendId,
|
|
547
|
+
retentionPolicy: restic_1.DEFAULT_RETENTION_POLICY,
|
|
548
|
+
});
|
|
549
|
+
const repository = {
|
|
550
|
+
...(await this.getLocalRepository(localId, { paths, retentionPolicy: restic_1.DEFAULT_RETENTION_POLICY })),
|
|
551
|
+
...remote,
|
|
552
|
+
id: localId,
|
|
553
|
+
backends: {
|
|
554
|
+
primary: {
|
|
555
|
+
id: backendId,
|
|
556
|
+
online: true,
|
|
557
|
+
type: configuration.type,
|
|
558
|
+
},
|
|
559
|
+
secondary: [],
|
|
511
560
|
},
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
561
|
+
};
|
|
562
|
+
this.telemetry.submitStructuredLog('Finished repository import', {
|
|
563
|
+
repositoryId: id,
|
|
564
|
+
backendId,
|
|
565
|
+
});
|
|
566
|
+
this.events.publish({
|
|
567
|
+
type: 'RepositoryCreate',
|
|
568
|
+
repository,
|
|
569
|
+
});
|
|
570
|
+
return {
|
|
571
|
+
repository,
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
catch (error) {
|
|
575
|
+
this.telemetry.submitStructuredLog('Finished repository import', {
|
|
576
|
+
repositoryId: id,
|
|
577
|
+
backendId,
|
|
578
|
+
error,
|
|
579
|
+
});
|
|
580
|
+
throw error;
|
|
581
|
+
}
|
|
522
582
|
}
|
|
523
583
|
async reconfigureRepositoryPrimaryBackend(id, dto) {
|
|
524
|
-
const { configuration } = await this.backend.getBackend(dto.backendId);
|
|
525
|
-
const backend = backend_1.Backend.from(configuration, this.moduleConfig.get());
|
|
584
|
+
const { backend, configuration } = await this.backend.getBackend(dto.backendId);
|
|
526
585
|
const { repository: remote } = await backend.createRepository({
|
|
527
586
|
name: 'Restored Repository',
|
|
528
587
|
worm: false,
|
|
@@ -566,7 +625,12 @@ let RepositoryService = class RepositoryService {
|
|
|
566
625
|
};
|
|
567
626
|
}
|
|
568
627
|
async restoreSnapshot(id, snapshotId, dto) {
|
|
628
|
+
this.telemetry.submitStructuredLog('Running repository snapshot restore', {
|
|
629
|
+
repositoryId: id,
|
|
630
|
+
snapshotId,
|
|
631
|
+
});
|
|
569
632
|
return new Promise((resolve) => {
|
|
633
|
+
let summary;
|
|
570
634
|
const task = new Promise((complete, fail) => void this.runHistory.createLog(id, enum_1.TaskType.Restore, async (log, logId) => {
|
|
571
635
|
resolve({
|
|
572
636
|
task,
|
|
@@ -575,12 +639,18 @@ let RepositoryService = class RepositoryService {
|
|
|
575
639
|
const { endpoint, key } = await this.getResticParameters(id);
|
|
576
640
|
try {
|
|
577
641
|
const signal = this.tasks.startTask(id, enum_1.TaskType.Restore, logId);
|
|
578
|
-
await this.restic.restore(endpoint, key, snapshotId, dto, log, signal);
|
|
642
|
+
summary = await this.restic.restore(endpoint, key, snapshotId, dto, log, signal);
|
|
579
643
|
}
|
|
580
644
|
finally {
|
|
581
645
|
this.tasks.endTask(id);
|
|
582
646
|
}
|
|
583
647
|
}, (error) => {
|
|
648
|
+
this.telemetry.submitStructuredLog('Finished repository snapshot restore', {
|
|
649
|
+
repositoryId: id,
|
|
650
|
+
snapshotId,
|
|
651
|
+
summary,
|
|
652
|
+
error,
|
|
653
|
+
});
|
|
584
654
|
if (error) {
|
|
585
655
|
fail(error);
|
|
586
656
|
}
|
|
@@ -592,7 +662,12 @@ let RepositoryService = class RepositoryService {
|
|
|
592
662
|
});
|
|
593
663
|
}
|
|
594
664
|
async restoreFromPoint(id, snapshotId, backendId, dto) {
|
|
665
|
+
this.telemetry.submitStructuredLog('Running repository restore from point', {
|
|
666
|
+
repositoryId: id,
|
|
667
|
+
snapshotId,
|
|
668
|
+
});
|
|
595
669
|
return new Promise((resolve) => {
|
|
670
|
+
let summary;
|
|
596
671
|
const task = new Promise((complete, fail) => void this.runHistory.createEphemeralLog(async (log, logId) => {
|
|
597
672
|
resolve({
|
|
598
673
|
task,
|
|
@@ -601,7 +676,7 @@ let RepositoryService = class RepositoryService {
|
|
|
601
676
|
const { endpoint, key } = await this.getResticParameters({ backendId, remoteId: id });
|
|
602
677
|
try {
|
|
603
678
|
const signal = this.tasks.startTask(id, enum_1.TaskType.Restore, logId);
|
|
604
|
-
await this.restic.restore(endpoint, key, snapshotId, { include: dto.include }, log, signal);
|
|
679
|
+
summary = await this.restic.restore(endpoint, key, snapshotId, { include: dto.include }, log, signal);
|
|
605
680
|
if (dto.yuccaConfig) {
|
|
606
681
|
const target = await this.storage.tempdir();
|
|
607
682
|
await this.restic.restore(endpoint, key, snapshotId, { include: [dto.yuccaConfig], target }, log, signal);
|
|
@@ -619,6 +694,12 @@ let RepositoryService = class RepositoryService {
|
|
|
619
694
|
this.tasks.endTask(id);
|
|
620
695
|
}
|
|
621
696
|
}, (error) => {
|
|
697
|
+
this.telemetry.submitStructuredLog('Finished repository restore from point', {
|
|
698
|
+
repositoryId: id,
|
|
699
|
+
snapshotId,
|
|
700
|
+
summary,
|
|
701
|
+
error,
|
|
702
|
+
});
|
|
622
703
|
if (error) {
|
|
623
704
|
fail(error);
|
|
624
705
|
}
|
|
@@ -631,36 +712,66 @@ let RepositoryService = class RepositoryService {
|
|
|
631
712
|
}
|
|
632
713
|
async forgetSnapshot(id, snapshotId) {
|
|
633
714
|
if (!this.tasks.canStart(id)) {
|
|
715
|
+
this.telemetry.submitStructuredLog('Repository snapshot forget rejected, task already running', {
|
|
716
|
+
repositoryId: id,
|
|
717
|
+
snapshotId,
|
|
718
|
+
});
|
|
634
719
|
throw new common_1.BadRequestException('Task already running!');
|
|
635
720
|
}
|
|
721
|
+
this.telemetry.submitStructuredLog('Running repository snapshot forget', {
|
|
722
|
+
repositoryId: id,
|
|
723
|
+
snapshotId,
|
|
724
|
+
});
|
|
636
725
|
const { endpoint, key } = await this.getResticParameters(id);
|
|
726
|
+
let error;
|
|
637
727
|
try {
|
|
638
728
|
const signal = this.tasks.startTask(id, enum_1.TaskType.Forget);
|
|
639
729
|
await this.restic.unlockAll(endpoint, key);
|
|
640
730
|
await this.restic.forget(endpoint, key, snapshotId, true, signal);
|
|
641
731
|
}
|
|
732
|
+
catch (error_) {
|
|
733
|
+
error = error_;
|
|
734
|
+
}
|
|
642
735
|
finally {
|
|
643
736
|
this.tasks.endTask(id);
|
|
644
737
|
}
|
|
738
|
+
this.telemetry.submitStructuredLog('Finished repository snapshot forget', {
|
|
739
|
+
repositoryId: id,
|
|
740
|
+
snapshotId,
|
|
741
|
+
error,
|
|
742
|
+
});
|
|
743
|
+
if (error) {
|
|
744
|
+
throw error;
|
|
745
|
+
}
|
|
645
746
|
await this.updateLocalMetrics(id, {
|
|
646
747
|
resticParameters: { endpoint, key },
|
|
647
748
|
});
|
|
648
749
|
}
|
|
649
750
|
async getSnapshotListing(id, snapshotId, dto) {
|
|
650
751
|
const path = dto.path ?? '/';
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
752
|
+
try {
|
|
753
|
+
const { endpoint, key } = await this.getResticParameters(id);
|
|
754
|
+
const files = await this.restic.ls(endpoint, key, snapshotId, path);
|
|
755
|
+
return {
|
|
756
|
+
parent: (0, node_path_1.dirname)(path),
|
|
757
|
+
path,
|
|
758
|
+
items: files
|
|
759
|
+
.filter((file) => file.message_type === 'node')
|
|
760
|
+
.filter((file) => file.path !== path)
|
|
761
|
+
.map((file) => ({
|
|
762
|
+
path: file.path,
|
|
763
|
+
isDirectory: file.type === 'dir',
|
|
764
|
+
})),
|
|
765
|
+
};
|
|
766
|
+
}
|
|
767
|
+
catch (error) {
|
|
768
|
+
this.telemetry.submitStructuredLog('Failed to get repository snapshot listing', {
|
|
769
|
+
repositoryId: id,
|
|
770
|
+
snapshotId,
|
|
771
|
+
error,
|
|
772
|
+
});
|
|
773
|
+
throw error;
|
|
774
|
+
}
|
|
664
775
|
}
|
|
665
776
|
async getRunHistory(id) {
|
|
666
777
|
const runs = await this.runHistory.getAll(id);
|
|
@@ -688,6 +799,7 @@ exports.RepositoryService = RepositoryService = __decorate([
|
|
|
688
799
|
repositoryLocalMetrics_repository_1.RepositoryLocalMetricsRepository,
|
|
689
800
|
moduleConfig_repository_1.ModuleConfigRepository,
|
|
690
801
|
storage_repository_1.StorageRepository,
|
|
691
|
-
bootstrap_service_1.BootstrapService
|
|
802
|
+
bootstrap_service_1.BootstrapService,
|
|
803
|
+
telemetry_service_1.TelemetryService])
|
|
692
804
|
], RepositoryService);
|
|
693
805
|
//# sourceMappingURL=repository.service.js.map
|