@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.
- 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 +19 -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 +178 -75
- 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 +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
|
-
|
|
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":";;;;;;;;;;;;AAAA,2CAA4C;AAE5C,kCAA0D;AAC1D,2EAAuE;AACvE,+EAA2E;AAC3E,yEAAqE;AACrE,iFAA6E;AAC7E,6EAAyE;AACzE,2DAAuD;AAGhD,IAAM,iBAAiB,GAAvB,MAAM,iBAAiB;IAET;IACA;IACA;IACA;IACA;IACA;IANnB,YACmB,OAA0B,EAC1B,UAAgC,EAChC,QAA4B,EAC5B,MAAwB,EACxB,SAA8B,EAC9B,SAA2B;QAL3B,YAAO,GAAP,OAAO,CAAmB;QAC1B,eAAU,GAAV,UAAU,CAAsB;QAChC,aAAQ,GAAR,QAAQ,CAAoB;QAC5B,WAAM,GAAN,MAAM,CAAkB;QACxB,cAAS,GAAT,SAAS,CAAqB;QAC9B,cAAS,GAAT,SAAS,CAAkB;IAC3C,CAAC;IAEJ,KAAK,CAAC,gBAAgB;QACpB,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,CAAC;QAE1C,IAAI,MAAM,KAAK,sBAAe,CAAC,KAAK,EAAE,CAAC;YACrC,IAAI,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC;YACtC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;YAEvC,OAAO;gBACL,MAAM;gBACN,KAAK;gBACL,YAAY,EAAE,qBAAc,CAAC,IAAI;gBACjC,eAAe,EAAE,KAAK;gBACtB,UAAU,EAAE,KAAK;gBACjB,SAAS,EAAE,KAAK;gBAChB,WAAW,EAAE,KAAK;gBAClB,qBAAqB,EAAE,KAAK;aAC7B,CAAC;QACJ,CAAC;QAED,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,MAAM,EAAE,sBAAe,CAAC,KAAK;YAC7B,YAAY,EAAE,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC,qBAAc,CAAC,IAAI,CAAC,CAAC,CAAC,qBAAc,CAAC,IAAI;YAC5F,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;IAED,KAAK,CAAC,eAAe;QACnB,MAAM,IAAI,CAAC,MAAM,CAAC,eAAe,EAAE,CAAC;QAEpC,IAAI,CAAC,SAAS,CAAC,mBAAmB,CAAC,2BAA2B,EAAE,EAAE,CAAC,CAAC;IACtE,CAAC;IAED,WAAW;QACT,IAAI,CAAC,SAAS,CAAC,mBAAmB,CAChC,iBAAiB,EACjB;YACE,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE;SACjC,EACD,IAAI,CACL,CAAC;IACJ,CAAC;CACF,CAAA;AA/EY,8CAAiB;4BAAjB,iBAAiB;IAD7B,IAAA,mBAAU,GAAE;qCAGiB,sCAAiB;QACd,4CAAoB;QACtB,wCAAkB;QACpB,oCAAgB;QACb,0CAAmB;QACnB,oCAAgB;GAPnC,iBAAiB,CA+E7B"}
|
|
@@ -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,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 {
|
|
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 {
|
|
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
|
-
|
|
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,
|
|
515
|
+
this.telemetry.submitStructuredLog('Running repository import', {
|
|
516
|
+
repositoryId: id,
|
|
499
517
|
backendId,
|
|
500
|
-
retentionPolicy: restic_1.DEFAULT_RETENTION_POLICY,
|
|
501
518
|
});
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
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
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
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
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
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
|