Skip to content

Commit dcc05a1

Browse files
authored
Fix logging when backup fails (#2392)
* on create backup do no longer call processExit internally - because this leads to unwanted success-like code running in parallel * refactor file name * use writeJson * do not prettify the json, as we need to save space
1 parent 409e469 commit dcc05a1

File tree

3 files changed

+53
-23
lines changed

3 files changed

+53
-23
lines changed

packages/cli/src/lib/setup.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import type { Client as ObjectsInRedisClient } from '@iobroker/db-objects-redis'
2323
import type { Client as StateRedisClient } from '@iobroker/db-states-redis';
2424
import type { PluginHandlerSettings } from '@iobroker/plugin-base/types';
2525
import { getRepository } from './setup/utils';
26+
import { IoBrokerError } from './setup/customError';
2627

2728
tools.ensureDNSOrder();
2829

@@ -1331,9 +1332,9 @@ async function processCommand(
13311332
console.log(`Backup created: ${filePath!}`);
13321333
console.log('This backup can only be restored with js-controller version up from 4.1');
13331334
return void callback(EXIT_CODES.NO_ERROR);
1334-
} catch (err) {
1335-
console.log(`Cannot create backup: ${err}`);
1336-
return void callback(EXIT_CODES.CANNOT_EXTRACT_FROM_ZIP);
1335+
} catch (e) {
1336+
console.log(`Cannot create backup: ${e.message}`);
1337+
return void callback(e instanceof IoBrokerError ? e.code : EXIT_CODES.CANNOT_EXTRACT_FROM_ZIP);
13371338
}
13381339
});
13391340
break;
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import type { EXIT_CODES } from '@iobroker/js-controller-common';
2+
3+
export interface IoBrokerErrorOptions {
4+
/** The error message */
5+
message: string;
6+
/** An ioBroker error code */
7+
code: EXIT_CODES;
8+
}
9+
10+
/**
11+
* A custom ioBroker CLI error to propagate the exit code down
12+
*/
13+
export class IoBrokerError extends Error {
14+
readonly code: EXIT_CODES;
15+
constructor(options: IoBrokerErrorOptions) {
16+
super(options.message);
17+
18+
this.name = this.constructor.name;
19+
20+
Error.captureStackTrace(this, this.constructor);
21+
22+
// you may also assign additional properties to your error
23+
this.code = options.code;
24+
}
25+
}

packages/cli/src/lib/setup/setupBackup.ts

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,15 @@
88
*/
99

1010
import fs from 'fs-extra';
11-
import { tools } from '@iobroker/js-controller-common';
11+
import { EXIT_CODES, tools } from '@iobroker/js-controller-common';
1212
import path from 'path';
1313
import { Upload } from './setupUpload';
14-
import { EXIT_CODES } from '@iobroker/js-controller-common';
1514
import { exec as execAsync } from 'promisify-child-process';
1615
import tar from 'tar';
1716
import type { Client as StatesRedisClient } from '@iobroker/db-states-redis';
1817
import type { Client as ObjectsRedisClient } from '@iobroker/db-objects-redis';
1918
import type { CleanDatabaseHandler, ProcessExitCallback, RestartController } from '../_Types';
19+
import { IoBrokerError } from './customError';
2020

2121
const hostname = tools.getHostName();
2222

@@ -201,7 +201,7 @@ export class BackupRestore {
201201
*
202202
* @param name - backup name
203203
*/
204-
private _packBackup(name: string): Promise<string> | void {
204+
private _packBackup(name: string): Promise<string> {
205205
// 2021_10_25 BF (TODO): store letsencrypt files too
206206
const letsEncrypt = `${this.configDir}/letsencrypt`;
207207
if (fs.existsSync(letsEncrypt)) {
@@ -210,27 +210,27 @@ export class BackupRestore {
210210
} catch (e) {
211211
console.error(`host.${hostname} Could not backup "${letsEncrypt}" directory: ${e.message}`);
212212
this.removeTempBackupDir();
213-
return void this.processExit(EXIT_CODES.CANNOT_COPY_DIR);
213+
throw new IoBrokerError({ message: e.message, code: EXIT_CODES.CANNOT_COPY_DIR });
214214
}
215215
}
216216

217-
return new Promise(resolve => {
217+
return new Promise((resolve, reject) => {
218218
const f = fs.createWriteStream(name);
219219
f.on('finish', () => {
220220
this.removeTempBackupDir();
221221
resolve(path.normalize(name));
222222
});
223223

224-
f.on('error', err => {
225-
console.error(`host.${hostname} Cannot pack directory ${tmpDir}/backup: ${err.message}`);
226-
this.processExit(EXIT_CODES.CANNOT_GZIP_DIRECTORY);
224+
f.on('error', e => {
225+
console.error(`host.${hostname} Cannot pack directory ${tmpDir}/backup: ${e.message}`);
226+
reject(new IoBrokerError({ message: e.message, code: EXIT_CODES.CANNOT_GZIP_DIRECTORY }));
227227
});
228228

229229
try {
230230
tar.create({ gzip: true, cwd: `${tmpDir}/` }, ['backup']).pipe(f);
231-
} catch (err) {
232-
console.error(`host.${hostname} Cannot pack directory ${tmpDir}/backup: ${err.message}`);
233-
return void this.processExit(EXIT_CODES.CANNOT_GZIP_DIRECTORY);
231+
} catch (e) {
232+
console.error(`host.${hostname} Cannot pack directory ${tmpDir}/backup: ${e.message}`);
233+
reject(new IoBrokerError({ message: e.message, code: EXIT_CODES.CANNOT_GZIP_DIRECTORY }));
234234
}
235235
});
236236
}
@@ -241,7 +241,7 @@ export class BackupRestore {
241241
* @param name - name of the backup
242242
* @param noConfig - do not store configs
243243
*/
244-
async createBackup(name: string, noConfig?: boolean): Promise<string | void> {
244+
async createBackup(name: string, noConfig?: boolean): Promise<string> {
245245
if (!name) {
246246
const d = new Date();
247247
name =
@@ -379,23 +379,23 @@ export class BackupRestore {
379379
if (object.value) {
380380
object.value.common.name = object.value._id;
381381
object.value.common.hostname = this.HOSTNAME_PLACEHOLDER;
382-
if (object.value.native && object.value.native.os) {
382+
if (object.value.native?.os) {
383383
object.value.native.os.hostname = this.HOSTNAME_PLACEHOLDER;
384384
}
385385
}
386386
}
387387
}
388388

389389
// Read all files
390-
if (object.value.type === 'meta' && object.value.common && object.value.common.type === 'meta.user') {
390+
if (object.value.type === 'meta' && object.value.common?.type === 'meta.user') {
391391
// do not process "xxx.0. " and "xxx.0."
392392
if (object.id.trim() === object.id && object.id[object.id.length - 1] !== '.') {
393393
await this.copyDir(object.id, '', `${tmpDir}/backup/files/${object.id}`);
394394
}
395395
}
396396

397397
// Read all files
398-
if (object.value.type === 'instance' && object.value.common && object.value.common.dataFolder) {
398+
if (object.value.type === 'instance' && object.value.common?.dataFolder) {
399399
let dataFolderPath = object.value.common.dataFolder;
400400

401401
if (dataFolderPath[0] !== '/' && !dataFolderPath.match(/^\w:/)) {
@@ -410,7 +410,7 @@ export class BackupRestore {
410410
`host.${hostname} Could not backup "${dataFolderPath}" directory: ${e.message}`
411411
);
412412
this.removeTempBackupDir();
413-
return void this.processExit(EXIT_CODES.CANNOT_COPY_DIR);
413+
throw new IoBrokerError({ message: e.message, code: EXIT_CODES.CANNOT_COPY_DIR });
414414
}
415415
}
416416
}
@@ -434,16 +434,20 @@ export class BackupRestore {
434434
console.log(`host.${hostname} ${result.objects?.length || 'no'} objects saved`);
435435

436436
try {
437-
fs.writeFileSync(`${tmpDir}/backup/backup.json`, JSON.stringify(result, null, 2));
437+
await fs.writeJSON(`${tmpDir}/backup/backup.json`, result, { spaces: 0 });
438438
result = null; // ... to allow GC to clean it up because no longer needed
439439

440440
this._validateBackupAfterCreation();
441441
return await this._packBackup(name);
442-
} catch (err) {
443-
console.error(`host.${hostname} Backup not created: ${err.message}`);
442+
} catch (e) {
443+
console.error(`host.${hostname} Backup not created: ${e.message}`);
444444
this.removeTempBackupDir();
445445

446-
return void this.processExit(EXIT_CODES.CANNOT_EXTRACT_FROM_ZIP);
446+
if (e instanceof IoBrokerError) {
447+
throw e;
448+
}
449+
450+
throw new IoBrokerError({ message: e.message, code: EXIT_CODES.CANNOT_EXTRACT_FROM_ZIP });
447451
}
448452
}
449453

0 commit comments

Comments
 (0)