@futo-org/backups-orchestrator-api 0.3.1 → 0.4.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.
Files changed (70) hide show
  1. package/dist/backends/backend.d.ts +2 -2
  2. package/dist/backends/backend.js +2 -5
  3. package/dist/backends/backend.js.map +1 -1
  4. package/dist/backends/local.backend.d.ts +1 -0
  5. package/dist/backends/local.backend.js +3 -0
  6. package/dist/backends/local.backend.js.map +1 -1
  7. package/dist/backends/s3.backend.d.ts +1 -0
  8. package/dist/backends/s3.backend.js +3 -0
  9. package/dist/backends/s3.backend.js.map +1 -1
  10. package/dist/backends/yucca.backend.d.ts +19 -3
  11. package/dist/backends/yucca.backend.js +47 -22
  12. package/dist/backends/yucca.backend.js.map +1 -1
  13. package/dist/const.d.ts +2 -1
  14. package/dist/const.js +3 -2
  15. package/dist/const.js.map +1 -1
  16. package/dist/controllers/onboarding.controller.d.ts +2 -0
  17. package/dist/controllers/onboarding.controller.js +18 -0
  18. package/dist/controllers/onboarding.controller.js.map +1 -1
  19. package/dist/dto/onboarding.dto.d.ts +4 -0
  20. package/dist/dto/onboarding.dto.js +16 -0
  21. package/dist/dto/onboarding.dto.js.map +1 -1
  22. package/dist/enum.d.ts +10 -0
  23. package/dist/enum.js +13 -1
  24. package/dist/enum.js.map +1 -1
  25. package/dist/interceptors/telemetry-error.interceptor.d.ts +8 -0
  26. package/dist/interceptors/telemetry-error.interceptor.js +47 -0
  27. package/dist/interceptors/telemetry-error.interceptor.js.map +1 -0
  28. package/dist/moduleConfig.d.ts +1 -1
  29. package/dist/orchestrationApi.module.d.ts +5 -3
  30. package/dist/orchestrationApi.module.js +13 -4
  31. package/dist/orchestrationApi.module.js.map +1 -1
  32. package/dist/repositories/backend.repository.d.ts +2 -0
  33. package/dist/repositories/backend.repository.js +8 -3
  34. package/dist/repositories/backend.repository.js.map +1 -1
  35. package/dist/repositories/bootstrap.repository.d.ts +9 -0
  36. package/dist/repositories/bootstrap.repository.js +33 -0
  37. package/dist/repositories/bootstrap.repository.js.map +1 -0
  38. package/dist/repositories/config.repository.d.ts +2 -0
  39. package/dist/repositories/config.repository.js +6 -0
  40. package/dist/repositories/config.repository.js.map +1 -1
  41. package/dist/repositories/restic.repository.d.ts +32 -3
  42. package/dist/repositories/restic.repository.js +3 -7
  43. package/dist/repositories/restic.repository.js.map +1 -1
  44. package/dist/schema/tables/backend.table.d.ts +1 -0
  45. package/dist/schema/tables/backend.table.js.map +1 -1
  46. package/dist/services/auth.service.d.ts +3 -1
  47. package/dist/services/auth.service.js +19 -7
  48. package/dist/services/auth.service.js.map +1 -1
  49. package/dist/services/backend.service.d.ts +3 -3
  50. package/dist/services/backend.service.js +12 -8
  51. package/dist/services/backend.service.js.map +1 -1
  52. package/dist/services/bootstrap.service.d.ts +3 -1
  53. package/dist/services/bootstrap.service.js +16 -6
  54. package/dist/services/bootstrap.service.js.map +1 -1
  55. package/dist/services/integrations.service.d.ts +3 -1
  56. package/dist/services/integrations.service.js +10 -2
  57. package/dist/services/integrations.service.js.map +1 -1
  58. package/dist/services/onboarding.service.d.ts +7 -1
  59. package/dist/services/onboarding.service.js +37 -2
  60. package/dist/services/onboarding.service.js.map +1 -1
  61. package/dist/services/repository.service.d.ts +3 -1
  62. package/dist/services/repository.service.js +178 -75
  63. package/dist/services/repository.service.js.map +1 -1
  64. package/dist/services/schedule.service.d.ts +3 -1
  65. package/dist/services/schedule.service.js +26 -2
  66. package/dist/services/schedule.service.js.map +1 -1
  67. package/dist/services/telemetry.service.d.ts +9 -0
  68. package/dist/services/telemetry.service.js +59 -0
  69. package/dist/services/telemetry.service.js.map +1 -0
  70. package/package.json +3 -3
@@ -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
- constructor(backend: BackendRepository, repository: RepositoryRepository, schedule: ScheduleRepository, config: ConfigRepository);
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
- constructor(backend, repository, schedule, config) {
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;AAGlE,IAAM,iBAAiB,GAAvB,MAAM,iBAAiB;IAET;IACA;IACA;IACA;IAJnB,YACmB,OAA0B,EAC1B,UAAgC,EAChC,QAA4B,EAC5B,MAAwB;QAHxB,YAAO,GAAP,OAAO,CAAmB;QAC1B,eAAU,GAAV,UAAU,CAAsB;QAChC,aAAQ,GAAR,QAAQ,CAAoB;QAC5B,WAAM,GAAN,MAAM,CAAkB;IACxC,CAAC;IAEJ,KAAK,CAAC,gBAAgB;QACpB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;QAClD,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC;QACpD,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;QAE/C,OAAO;YACL,eAAe,EAAE,MAAM,IAAI,CAAC,MAAM,CAAC,eAAe,EAAE;YACpD,UAAU,EAAE,QAAQ,CAAC,MAAM,GAAG,CAAC;YAC/B,SAAS,EAAE,YAAY,CAAC,MAAM,GAAG,CAAC;YAClC,WAAW,EAAE,SAAS,CAAC,MAAM,GAAG,CAAC;YACjC,qBAAqB,EAAE,MAAM,IAAI,CAAC,MAAM,CAAC,qBAAqB,EAAE;SACjE,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,kBAAkB;QACtB,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,sBAAsB,EAAE,CAAC;QAE/D,OAAO;YACL,WAAW;SACZ,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,iBAAiB,CAAC,GAAW;QACjC,MAAM,IAAI,CAAC,MAAM,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,kBAAkB;QACtB,MAAM,IAAI,CAAC,MAAM,CAAC,mBAAmB,EAAE,CAAC;IAC1C,CAAC;IAED,KAAK,CAAC,eAAe;QACnB,MAAM,IAAI,CAAC,MAAM,CAAC,eAAe,EAAE,CAAC;IACtC,CAAC;CACF,CAAA;AAzCY,8CAAiB;4BAAjB,iBAAiB;IAD7B,IAAA,mBAAU,GAAE;qCAGiB,sCAAiB;QACd,4CAAoB;QACtB,wCAAkB;QACpB,oCAAgB;GALhC,iBAAiB,CAyC7B"}
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
- 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);
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
- constructor(tasks, events, backend, config, database, restic, runHistory, repository, repositoryPath, repositoryLocalMetrics, moduleConfig, storage, bootstrap) {
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, configuration } of backends) {
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 backendInstance.updateRepository(remoteId, dto));
252
+ ({ repository: remote } = await backend.updateRepository(remoteId, dto));
250
253
  }
251
254
  else {
252
- ({ repository: remote } = await backendInstance.getRepository(remoteId));
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: backend.configuration.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 backendInstance = backend_1.Backend.from(backend.configuration, this.moduleConfig.get());
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,8 +347,7 @@ let RepositoryService = class RepositoryService {
339
347
  });
340
348
  if (metrics.sizeBytes) {
341
349
  const { backendId, remoteId } = await this.repository.get(id);
342
- const { configuration } = await this.backend.getBackend(backendId);
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
  }
@@ -351,11 +358,16 @@ let RepositoryService = class RepositoryService {
351
358
  }
352
359
  async createBackup(id, signal) {
353
360
  if (!this.tasks.canStart(id)) {
361
+ this.telemetry.submitStructuredLog('Backup rejected, task already running', {
362
+ repositoryId: id,
363
+ });
354
364
  throw new common_1.BadRequestException('Task already running!');
355
365
  }
366
+ this.telemetry.submitStructuredLog('Running backup', {
367
+ repositoryId: id,
368
+ });
356
369
  const { backendId, remoteId } = await this.repository.get(id);
357
- const { configuration } = await this.backend.getBackend(backendId);
358
- const backend = backend_1.Backend.from(configuration, this.moduleConfig.get());
370
+ const { backend } = await this.backend.getBackend(backendId);
359
371
  const { endpoint, key } = await this.getResticParameters(id);
360
372
  const paths = await this.repositoryPath.get(id);
361
373
  if (paths.length === 0) {
@@ -374,10 +386,17 @@ let RepositoryService = class RepositoryService {
374
386
  try {
375
387
  const taskSignal = this.tasks.startTask(id, enum_1.TaskType.Backup, logId, signal);
376
388
  await this.restic.unlockAll(endpoint, key);
377
- await this.restic.backup(endpoint, key, paths, log, taskSignal);
389
+ const summary = await this.restic.backup(endpoint, key, paths, log, taskSignal);
390
+ this.telemetry.submitStructuredLog('Finished backup to primary backend', {
391
+ repositoryId: id,
392
+ summary,
393
+ });
378
394
  const { retentionPolicy: policy } = await this.repository.get(id);
379
395
  if (policy) {
380
396
  await this.runForgetAndPrune(endpoint, key, policy, log, taskSignal);
397
+ this.telemetry.submitStructuredLog('Finished prune on primary backend', {
398
+ repositoryId: id,
399
+ });
381
400
  }
382
401
  }
383
402
  finally {
@@ -395,6 +414,10 @@ let RepositoryService = class RepositoryService {
395
414
  lastBackupDuration,
396
415
  },
397
416
  });
417
+ this.telemetry.submitStructuredLog('Backup finished', {
418
+ repositoryId: id,
419
+ error,
420
+ });
398
421
  if (error) {
399
422
  fail(error);
400
423
  }
@@ -431,12 +454,19 @@ let RepositoryService = class RepositoryService {
431
454
  }
432
455
  async pruneRepository(id, signal) {
433
456
  if (!this.tasks.canStart(id)) {
457
+ this.telemetry.submitStructuredLog('Repository prune rejected, task already running', {
458
+ repositoryId: id,
459
+ });
434
460
  throw new common_1.BadRequestException('Task already running!');
435
461
  }
436
462
  const { retentionPolicy: policy } = await this.repository.get(id);
437
463
  if (!policy) {
438
464
  throw new common_1.BadRequestException('No retention policy configured for this repository');
439
465
  }
466
+ this.telemetry.submitStructuredLog('Running repository prune', {
467
+ repositoryId: id,
468
+ retentionPolicy: policy,
469
+ });
440
470
  const { endpoint, key } = await this.getResticParameters(id);
441
471
  return new Promise((resolve) => {
442
472
  const task = new Promise((complete, fail) => void this.runHistory.createLog(id, enum_1.TaskType.Forget, async (log, logId) => {
@@ -453,6 +483,10 @@ let RepositoryService = class RepositoryService {
453
483
  void this.updateLocalMetrics(id, {
454
484
  resticParameters: { endpoint, key },
455
485
  });
486
+ this.telemetry.submitStructuredLog('Finished repository prune', {
487
+ repositoryId: id,
488
+ error,
489
+ });
456
490
  if (error) {
457
491
  fail(error);
458
492
  }
@@ -478,51 +512,67 @@ let RepositoryService = class RepositoryService {
478
512
  }
479
513
  }
480
514
  async importRepository(id, backendId) {
481
- const { configuration } = await this.backend.getBackend(backendId);
482
- const backend = backend_1.Backend.from(configuration, this.moduleConfig.get());
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,
515
+ this.telemetry.submitStructuredLog('Running repository import', {
516
+ repositoryId: id,
499
517
  backendId,
500
- retentionPolicy: restic_1.DEFAULT_RETENTION_POLICY,
501
518
  });
502
- const repository = {
503
- ...(await this.getLocalRepository(localId, { paths, retentionPolicy: restic_1.DEFAULT_RETENTION_POLICY })),
504
- ...remote,
505
- id: localId,
506
- backends: {
507
- primary: {
508
- id: backendId,
509
- online: true,
510
- type: configuration.type,
519
+ try {
520
+ const { configuration, backend } = await this.backend.getBackend(backendId);
521
+ const { repository: remote } = await backend.getRepository(id);
522
+ const localId = (0, node_crypto_1.randomUUID)();
523
+ const endpoint = await backend.getResticEndpoint(remote.id);
524
+ const key = await this.config.deriveEncryptionKey(`repository-${remote.id}`);
525
+ await this.restic.keyList(endpoint, key);
526
+ let paths = [];
527
+ try {
528
+ const snapshots = await this.restic.snapshots(endpoint, key);
529
+ snapshots.sort((a, b) => +b.time - +a.time);
530
+ paths = snapshots[0].paths;
531
+ }
532
+ catch {
533
+ }
534
+ await this.repository.create({
535
+ id: localId,
536
+ remoteId: remote.id,
537
+ backendId,
538
+ retentionPolicy: restic_1.DEFAULT_RETENTION_POLICY,
539
+ });
540
+ const repository = {
541
+ ...(await this.getLocalRepository(localId, { paths, retentionPolicy: restic_1.DEFAULT_RETENTION_POLICY })),
542
+ ...remote,
543
+ id: localId,
544
+ backends: {
545
+ primary: {
546
+ id: backendId,
547
+ online: true,
548
+ type: configuration.type,
549
+ },
550
+ secondary: [],
511
551
  },
512
- secondary: [],
513
- },
514
- };
515
- this.events.publish({
516
- type: 'RepositoryCreate',
517
- repository,
518
- });
519
- return {
520
- repository,
521
- };
552
+ };
553
+ this.telemetry.submitStructuredLog('Finished repository import', {
554
+ repositoryId: id,
555
+ backendId,
556
+ });
557
+ this.events.publish({
558
+ type: 'RepositoryCreate',
559
+ repository,
560
+ });
561
+ return {
562
+ repository,
563
+ };
564
+ }
565
+ catch (error) {
566
+ this.telemetry.submitStructuredLog('Finished repository import', {
567
+ repositoryId: id,
568
+ backendId,
569
+ error,
570
+ });
571
+ throw error;
572
+ }
522
573
  }
523
574
  async reconfigureRepositoryPrimaryBackend(id, dto) {
524
- const { configuration } = await this.backend.getBackend(dto.backendId);
525
- const backend = backend_1.Backend.from(configuration, this.moduleConfig.get());
575
+ const { backend, configuration } = await this.backend.getBackend(dto.backendId);
526
576
  const { repository: remote } = await backend.createRepository({
527
577
  name: 'Restored Repository',
528
578
  worm: false,
@@ -566,7 +616,12 @@ let RepositoryService = class RepositoryService {
566
616
  };
567
617
  }
568
618
  async restoreSnapshot(id, snapshotId, dto) {
619
+ this.telemetry.submitStructuredLog('Running repository snapshot restore', {
620
+ repositoryId: id,
621
+ snapshotId,
622
+ });
569
623
  return new Promise((resolve) => {
624
+ let summary;
570
625
  const task = new Promise((complete, fail) => void this.runHistory.createLog(id, enum_1.TaskType.Restore, async (log, logId) => {
571
626
  resolve({
572
627
  task,
@@ -575,12 +630,18 @@ let RepositoryService = class RepositoryService {
575
630
  const { endpoint, key } = await this.getResticParameters(id);
576
631
  try {
577
632
  const signal = this.tasks.startTask(id, enum_1.TaskType.Restore, logId);
578
- await this.restic.restore(endpoint, key, snapshotId, dto, log, signal);
633
+ summary = await this.restic.restore(endpoint, key, snapshotId, dto, log, signal);
579
634
  }
580
635
  finally {
581
636
  this.tasks.endTask(id);
582
637
  }
583
638
  }, (error) => {
639
+ this.telemetry.submitStructuredLog('Finished repository snapshot restore', {
640
+ repositoryId: id,
641
+ snapshotId,
642
+ summary,
643
+ error,
644
+ });
584
645
  if (error) {
585
646
  fail(error);
586
647
  }
@@ -592,7 +653,12 @@ let RepositoryService = class RepositoryService {
592
653
  });
593
654
  }
594
655
  async restoreFromPoint(id, snapshotId, backendId, dto) {
656
+ this.telemetry.submitStructuredLog('Running repository restore from point', {
657
+ repositoryId: id,
658
+ snapshotId,
659
+ });
595
660
  return new Promise((resolve) => {
661
+ let summary;
596
662
  const task = new Promise((complete, fail) => void this.runHistory.createEphemeralLog(async (log, logId) => {
597
663
  resolve({
598
664
  task,
@@ -601,7 +667,7 @@ let RepositoryService = class RepositoryService {
601
667
  const { endpoint, key } = await this.getResticParameters({ backendId, remoteId: id });
602
668
  try {
603
669
  const signal = this.tasks.startTask(id, enum_1.TaskType.Restore, logId);
604
- await this.restic.restore(endpoint, key, snapshotId, { include: dto.include }, log, signal);
670
+ summary = await this.restic.restore(endpoint, key, snapshotId, { include: dto.include }, log, signal);
605
671
  if (dto.yuccaConfig) {
606
672
  const target = await this.storage.tempdir();
607
673
  await this.restic.restore(endpoint, key, snapshotId, { include: [dto.yuccaConfig], target }, log, signal);
@@ -619,6 +685,12 @@ let RepositoryService = class RepositoryService {
619
685
  this.tasks.endTask(id);
620
686
  }
621
687
  }, (error) => {
688
+ this.telemetry.submitStructuredLog('Finished repository restore from point', {
689
+ repositoryId: id,
690
+ snapshotId,
691
+ summary,
692
+ error,
693
+ });
622
694
  if (error) {
623
695
  fail(error);
624
696
  }
@@ -631,36 +703,66 @@ let RepositoryService = class RepositoryService {
631
703
  }
632
704
  async forgetSnapshot(id, snapshotId) {
633
705
  if (!this.tasks.canStart(id)) {
706
+ this.telemetry.submitStructuredLog('Repository snapshot forget rejected, task already running', {
707
+ repositoryId: id,
708
+ snapshotId,
709
+ });
634
710
  throw new common_1.BadRequestException('Task already running!');
635
711
  }
712
+ this.telemetry.submitStructuredLog('Running repository snapshot forget', {
713
+ repositoryId: id,
714
+ snapshotId,
715
+ });
636
716
  const { endpoint, key } = await this.getResticParameters(id);
717
+ let error;
637
718
  try {
638
719
  const signal = this.tasks.startTask(id, enum_1.TaskType.Forget);
639
720
  await this.restic.unlockAll(endpoint, key);
640
721
  await this.restic.forget(endpoint, key, snapshotId, true, signal);
641
722
  }
723
+ catch (error_) {
724
+ error = error_;
725
+ }
642
726
  finally {
643
727
  this.tasks.endTask(id);
644
728
  }
729
+ this.telemetry.submitStructuredLog('Finished repository snapshot forget', {
730
+ repositoryId: id,
731
+ snapshotId,
732
+ error,
733
+ });
734
+ if (error) {
735
+ throw error;
736
+ }
645
737
  await this.updateLocalMetrics(id, {
646
738
  resticParameters: { endpoint, key },
647
739
  });
648
740
  }
649
741
  async getSnapshotListing(id, snapshotId, dto) {
650
742
  const path = dto.path ?? '/';
651
- const { endpoint, key } = await this.getResticParameters(id);
652
- const files = await this.restic.ls(endpoint, key, snapshotId, path);
653
- return {
654
- parent: (0, node_path_1.dirname)(path),
655
- path,
656
- items: files
657
- .filter((file) => file.message_type === 'node')
658
- .filter((file) => file.path !== path)
659
- .map((file) => ({
660
- path: file.path,
661
- isDirectory: file.type === 'dir',
662
- })),
663
- };
743
+ try {
744
+ const { endpoint, key } = await this.getResticParameters(id);
745
+ const files = await this.restic.ls(endpoint, key, snapshotId, path);
746
+ return {
747
+ parent: (0, node_path_1.dirname)(path),
748
+ path,
749
+ items: files
750
+ .filter((file) => file.message_type === 'node')
751
+ .filter((file) => file.path !== path)
752
+ .map((file) => ({
753
+ path: file.path,
754
+ isDirectory: file.type === 'dir',
755
+ })),
756
+ };
757
+ }
758
+ catch (error) {
759
+ this.telemetry.submitStructuredLog('Failed to get repository snapshot listing', {
760
+ repositoryId: id,
761
+ snapshotId,
762
+ error,
763
+ });
764
+ throw error;
765
+ }
664
766
  }
665
767
  async getRunHistory(id) {
666
768
  const runs = await this.runHistory.getAll(id);
@@ -688,6 +790,7 @@ exports.RepositoryService = RepositoryService = __decorate([
688
790
  repositoryLocalMetrics_repository_1.RepositoryLocalMetricsRepository,
689
791
  moduleConfig_repository_1.ModuleConfigRepository,
690
792
  storage_repository_1.StorageRepository,
691
- bootstrap_service_1.BootstrapService])
793
+ bootstrap_service_1.BootstrapService,
794
+ telemetry_service_1.TelemetryService])
692
795
  ], RepositoryService);
693
796
  //# sourceMappingURL=repository.service.js.map