@ps-aux/nodebup 0.7.3 → 0.9.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/lib/bup/aggregate/AggregateBackupController.js +2 -2
- package/lib/bup/dir/DirBackupController.js +45 -0
- package/lib/bup/pg/PgBackupController.js +8 -4
- package/lib/cli/app.js +30 -5
- package/lib/ctx/Context.js +5 -5
- package/lib/log/AppLogger.js +8 -3
- package/lib/storage/{BackupClient.js → BackupBackend.js} +0 -0
- package/lib/storage/BackupStorage.js +33 -0
- package/lib/storage/BackupStorageProvider.js +50 -0
- package/lib/storage/StorageConfigProvider.js +6 -1
- package/lib/storage/rclone/{RCloneClientFactory.js → RCloneFactory.js} +8 -4
- package/lib/storage/rclone/RcloneBackupBackend.js +42 -0
- package/lib/storage/restic/ResticBackupBackend.js +41 -0
- package/lib/storage/restic/ResticClient.js +42 -6
- package/lib/storage/restic/ResticClient.spec.js +15 -2
- package/lib/storage/restic/ResticController.js +22 -7
- package/lib/storage/restic/{ResticClientFactory.js → ResticFactory.js} +8 -4
- package/package.json +1 -1
- package/lib/bup/dir/DataBackupController.js +0 -44
- package/lib/storage/BackupClientStorageBackend.js +0 -27
- package/lib/storage/StorageBackendProvider.js +0 -50
@@ -23,7 +23,7 @@ var _Path = require("../../fs/path/Path");
|
|
23
23
|
|
24
24
|
var _config = require("../../config");
|
25
25
|
|
26
|
-
var
|
26
|
+
var _BackupStorageProvider = require("../../storage/BackupStorageProvider");
|
27
27
|
|
28
28
|
var _dec, _dec2, _dec3, _dec4, _class;
|
29
29
|
|
@@ -31,7 +31,7 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
|
|
31
31
|
|
32
32
|
let AggregateBackupController = (_dec = (0, _inversify.injectable)(), _dec2 = function (target, key) {
|
33
33
|
return (0, _inversify.inject)(_ContextSymbols.AppConfig_)(target, undefined, 6);
|
34
|
-
}, _dec3 = Reflect.metadata("design:type", Function), _dec4 = Reflect.metadata("design:paramtypes", [typeof _Gpg.Gpg === "undefined" ? Object : _Gpg.Gpg, typeof _SshKeyManager.SshKeyManager === "undefined" ? Object : _SshKeyManager.SshKeyManager, typeof _Fs.Fs === "undefined" ? Object : _Fs.Fs, typeof _FsSyncer.FsSyncer === "undefined" ? Object : _FsSyncer.FsSyncer, typeof _AppLogger.AppLogger === "undefined" ? Object : _AppLogger.AppLogger, typeof
|
34
|
+
}, _dec3 = Reflect.metadata("design:type", Function), _dec4 = Reflect.metadata("design:paramtypes", [typeof _Gpg.Gpg === "undefined" ? Object : _Gpg.Gpg, typeof _SshKeyManager.SshKeyManager === "undefined" ? Object : _SshKeyManager.SshKeyManager, typeof _Fs.Fs === "undefined" ? Object : _Fs.Fs, typeof _FsSyncer.FsSyncer === "undefined" ? Object : _FsSyncer.FsSyncer, typeof _AppLogger.AppLogger === "undefined" ? Object : _AppLogger.AppLogger, typeof _BackupStorageProvider.BackupStorageProvider === "undefined" ? Object : _BackupStorageProvider.BackupStorageProvider, typeof _config.Config === "undefined" ? Object : _config.Config]), _dec(_class = _dec2(_class = _dec3(_class = _dec4(_class = class AggregateBackupController {
|
35
35
|
constructor(gpg, ssh, fs, fsSyncer, log, storageProvider, cfg) {
|
36
36
|
this.gpg = gpg;
|
37
37
|
this.ssh = ssh;
|
@@ -0,0 +1,45 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
4
|
+
value: true
|
5
|
+
});
|
6
|
+
exports.DirBackupController = void 0;
|
7
|
+
|
8
|
+
var _inversify = require("inversify");
|
9
|
+
|
10
|
+
var _AppLogger = require("../../log/AppLogger");
|
11
|
+
|
12
|
+
var _Path = require("../../fs/path/Path");
|
13
|
+
|
14
|
+
var _BackupStorageProvider = require("../../storage/BackupStorageProvider");
|
15
|
+
|
16
|
+
var _dec, _dec2, _dec3, _class;
|
17
|
+
|
18
|
+
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
19
|
+
|
20
|
+
let DirBackupController = (_dec = (0, _inversify.injectable)(), _dec2 = Reflect.metadata("design:type", Function), _dec3 = Reflect.metadata("design:paramtypes", [typeof _AppLogger.AppLogger === "undefined" ? Object : _AppLogger.AppLogger, typeof _BackupStorageProvider.BackupStorageProvider === "undefined" ? Object : _BackupStorageProvider.BackupStorageProvider]), _dec(_class = _dec2(_class = _dec3(_class = class DirBackupController {
|
21
|
+
constructor(log, storageProvider) {
|
22
|
+
this.log = log;
|
23
|
+
this.storageProvider = storageProvider;
|
24
|
+
|
25
|
+
_defineProperty(this, "backup", inp => {
|
26
|
+
const storage = this.storageProvider.provide();
|
27
|
+
|
28
|
+
const path = _Path.AbsPath.from(inp.path);
|
29
|
+
|
30
|
+
this.log.info(`Backing up from ${path} to '${storage}'`);
|
31
|
+
storage.store(path);
|
32
|
+
});
|
33
|
+
|
34
|
+
_defineProperty(this, "restore", inp => {
|
35
|
+
const storage = this.storageProvider.provide();
|
36
|
+
|
37
|
+
const path = _Path.AbsPath.from(inp.path);
|
38
|
+
|
39
|
+
this.log.info(`Restoring from '${storage}' to ${path}`);
|
40
|
+
storage.restore(path);
|
41
|
+
});
|
42
|
+
}
|
43
|
+
|
44
|
+
}) || _class) || _class) || _class);
|
45
|
+
exports.DirBackupController = DirBackupController;
|
@@ -15,7 +15,7 @@ var _Shell = require("../../tools/shell/Shell");
|
|
15
15
|
|
16
16
|
var _Path = require("../../fs/path/Path");
|
17
17
|
|
18
|
-
var
|
18
|
+
var _BackupStorageProvider = require("../../storage/BackupStorageProvider");
|
19
19
|
|
20
20
|
var _Zipper = require("../../tools/compression/Zipper");
|
21
21
|
|
@@ -37,7 +37,7 @@ const parseConnectionUrl = url => {
|
|
37
37
|
};
|
38
38
|
};
|
39
39
|
|
40
|
-
let PgBackupController = (_dec = (0, _inversify.injectable)(), _dec2 = Reflect.metadata("design:type", Function), _dec3 = Reflect.metadata("design:paramtypes", [typeof _Fs.Fs === "undefined" ? Object : _Fs.Fs, typeof _AppLogger.AppLogger === "undefined" ? Object : _AppLogger.AppLogger, typeof
|
40
|
+
let PgBackupController = (_dec = (0, _inversify.injectable)(), _dec2 = Reflect.metadata("design:type", Function), _dec3 = Reflect.metadata("design:paramtypes", [typeof _Fs.Fs === "undefined" ? Object : _Fs.Fs, typeof _AppLogger.AppLogger === "undefined" ? Object : _AppLogger.AppLogger, typeof _BackupStorageProvider.BackupStorageProvider === "undefined" ? Object : _BackupStorageProvider.BackupStorageProvider, typeof _Shell.Shell === "undefined" ? Object : _Shell.Shell, typeof _Zipper.Zipper === "undefined" ? Object : _Zipper.Zipper]), _dec(_class = _dec2(_class = _dec3(_class = (_temp = _class2 = class PgBackupController {
|
41
41
|
constructor( // private gpg: Gpg,
|
42
42
|
// private ssh: SshKeyManager,
|
43
43
|
fs, // private fsSyncer: FsSyncer,
|
@@ -73,7 +73,8 @@ let PgBackupController = (_dec = (0, _inversify.injectable)(), _dec2 = Reflect.m
|
|
73
73
|
const outputDir = _Path.AbsPath.from(dir);
|
74
74
|
|
75
75
|
this.log.info('Dumping database to a file');
|
76
|
-
const bashCmds = [`echo "*:*:*:*:${pass}" > ~/.pgpass`, `chmod 400 ~/.pgpass`, `pg_dumpall -d ${pgUrl}`]; //
|
76
|
+
const bashCmds = [`echo "*:*:*:*:${pass}" > ~/.pgpass`, `chmod 400 ~/.pgpass`, `pg_dumpall -d ${pgUrl}`]; // Don't forget that this itself might be run in docker
|
77
|
+
// therefore volume mounts are not usable (will apply to the location at host)
|
77
78
|
|
78
79
|
const b = this.sh.execAndReturnBuffer(`docker run --network host ` + `postgres:${version} ` + `bash -c '${bashCmds.join(' && ')}'`);
|
79
80
|
const dumpOut = outputDir.resolve(this.outFileName);
|
@@ -100,11 +101,14 @@ let PgBackupController = (_dec = (0, _inversify.injectable)(), _dec2 = Reflect.m
|
|
100
101
|
const dir = _Path.AbsPath.from(dirStr);
|
101
102
|
|
102
103
|
storage.restore(dir); // TODO check if the dir contains the with the expected name
|
104
|
+
// TODO add e2e test for docker
|
103
105
|
|
104
106
|
const zipFile = this.fs.listFiles(dir)[0];
|
105
107
|
this.zip.unzipDir(zipFile, dir);
|
106
108
|
this.fs.rmFile(zipFile);
|
107
|
-
const outFile = this.fs.listFiles(dir)[0];
|
109
|
+
const outFile = this.fs.listFiles(dir)[0]; // Don't forget that this itself might be run in docker
|
110
|
+
// therefore volume mounts are not usable (will apply to the location at host)
|
111
|
+
|
108
112
|
this.sh.exec(`docker run --network host -i ` + `postgres:${version} ` + `psql ${pgUrl} -v ON_ERROR_STOP=0 < ${outFile.str()}`);
|
109
113
|
});
|
110
114
|
});
|
package/lib/cli/app.js
CHANGED
@@ -17,7 +17,7 @@ var _AggregateBackupController = require("../bup/aggregate/AggregateBackupContro
|
|
17
17
|
|
18
18
|
var _ResticController = require("../storage/restic/ResticController");
|
19
19
|
|
20
|
-
var
|
20
|
+
var _DirBackupController = require("../bup/dir/DirBackupController");
|
21
21
|
|
22
22
|
var _PgBackupController = require("../bup/pg/PgBackupController");
|
23
23
|
|
@@ -43,27 +43,38 @@ const singleStorageOptions = [storageNameOpt, {
|
|
43
43
|
convertCase: true,
|
44
44
|
fromConfig: 'storage.credentials'
|
45
45
|
}];
|
46
|
+
const backupTagOption = {
|
47
|
+
name: 'backup-tag',
|
48
|
+
convertCase: true
|
49
|
+
};
|
50
|
+
const backupOptions = [backupTagOption];
|
51
|
+
const restoreOptions = [backupTagOption, {
|
52
|
+
name: 'backup-snapshot-id',
|
53
|
+
convertCase: true
|
54
|
+
}];
|
46
55
|
|
47
56
|
const createApp = () => _nclif.CliApp.of({
|
48
57
|
commands: {
|
49
|
-
|
58
|
+
dir: (0, _nclif.cmdGroup)({
|
50
59
|
options: singleStorageOptions,
|
51
60
|
commands: {
|
52
61
|
backup: (0, _nclif.cmd)({
|
53
62
|
description: 'Backup a dir to the given storage',
|
63
|
+
options: backupOptions,
|
54
64
|
positionals: [{
|
55
65
|
name: 'path',
|
56
66
|
required: true
|
57
67
|
}],
|
58
|
-
run: (cmd, c) => c.get(
|
68
|
+
run: (cmd, c) => c.get(_DirBackupController.DirBackupController).backup(cmd)
|
59
69
|
}),
|
60
70
|
restore: (0, _nclif.cmd)({
|
61
71
|
description: 'Restore the storage to the given dir',
|
72
|
+
options: restoreOptions,
|
62
73
|
positionals: [{
|
63
74
|
name: 'path',
|
64
75
|
required: true
|
65
76
|
}],
|
66
|
-
run: (cmd, c) => c.get(
|
77
|
+
run: (cmd, c) => c.get(_DirBackupController.DirBackupController).restore(cmd)
|
67
78
|
})
|
68
79
|
}
|
69
80
|
}),
|
@@ -90,10 +101,22 @@ const createApp = () => _nclif.CliApp.of({
|
|
90
101
|
|
91
102
|
exports.createApp = createApp;
|
92
103
|
const restic = (0, _nclif.cmdGroup)({
|
104
|
+
options: singleStorageOptions,
|
93
105
|
commands: {
|
94
106
|
'init-repo': (0, _nclif.cmd)({
|
95
|
-
options: singleStorageOptions,
|
96
107
|
run: (_, c) => c.get(_ResticController.ResticController).initRepo()
|
108
|
+
}),
|
109
|
+
snapshots: (0, _nclif.cmd)({
|
110
|
+
run: (_, c, p) => c.get(_ResticController.ResticController).listSnapshots(p.stdout)
|
111
|
+
}),
|
112
|
+
cmd: (0, _nclif.cmd)({
|
113
|
+
positionals: [{
|
114
|
+
name: 'cmd',
|
115
|
+
required: true
|
116
|
+
}],
|
117
|
+
run: ({
|
118
|
+
cmd
|
119
|
+
}, c, p) => c.get(_ResticController.ResticController).runResticCmd(cmd, p.stdout)
|
97
120
|
})
|
98
121
|
}
|
99
122
|
});
|
@@ -111,9 +134,11 @@ const pg = (0, _nclif.cmdGroup)({
|
|
111
134
|
}],
|
112
135
|
commands: {
|
113
136
|
backup: (0, _nclif.cmd)({
|
137
|
+
options: backupOptions,
|
114
138
|
run: (inp, c) => c.get(_PgBackupController.PgBackupController).backup(inp)
|
115
139
|
}),
|
116
140
|
restore: (0, _nclif.cmd)({
|
141
|
+
options: restoreOptions,
|
117
142
|
run: (inp, c) => c.get(_PgBackupController.PgBackupController).restore(inp)
|
118
143
|
})
|
119
144
|
}
|
package/lib/ctx/Context.js
CHANGED
@@ -23,17 +23,17 @@ var _AggregateBackupController = require("../bup/aggregate/AggregateBackupContro
|
|
23
23
|
|
24
24
|
var _AppLogger = require("../log/AppLogger");
|
25
25
|
|
26
|
-
var
|
26
|
+
var _BackupStorageProvider = require("../storage/BackupStorageProvider");
|
27
27
|
|
28
|
-
var
|
28
|
+
var _ResticFactory = require("../storage/restic/ResticFactory");
|
29
29
|
|
30
30
|
var _ResticController = require("../storage/restic/ResticController");
|
31
31
|
|
32
32
|
var _B2CredentialsProvider = require("../storage/b2/B2CredentialsProvider");
|
33
33
|
|
34
|
-
var
|
34
|
+
var _RCloneFactory = require("../storage/rclone/RCloneFactory");
|
35
35
|
|
36
|
-
var
|
36
|
+
var _DirBackupController = require("../bup/dir/DirBackupController");
|
37
37
|
|
38
38
|
var _StorageConfigProvider = require("../storage/StorageConfigProvider");
|
39
39
|
|
@@ -49,7 +49,7 @@ const createContext = (cfg, inp) => {
|
|
49
49
|
c.bind(_ContextSymbols.Log_).toConstantValue(log);
|
50
50
|
c.bind(_AppLogger.AppLogger).toConstantValue(log);
|
51
51
|
c.bind(_Fs.Fs).toConstantValue(new _Fs.Fs(cfg.pwd, log));
|
52
|
-
const self = [_Gpg.Gpg, _Shell.Shell, _FsSyncer.FsSyncer, _SshKeyManager.SshKeyManager,
|
52
|
+
const self = [_Gpg.Gpg, _Shell.Shell, _FsSyncer.FsSyncer, _SshKeyManager.SshKeyManager, _BackupStorageProvider.BackupStorageProvider, _StorageConfigProvider.StorageConfigProvider, _ResticFactory.ResticFactory, _AggregateBackupController.AggregateBackupController, _ResticController.ResticController, _B2CredentialsProvider.B2CredentialsProvider, _RCloneFactory.RCloneFactory, _DirBackupController.DirBackupController, _PgBackupController.PgBackupController, _Zipper.Zipper];
|
53
53
|
self.forEach(s => c.bind(s).toSelf());
|
54
54
|
return c;
|
55
55
|
};
|
package/lib/log/AppLogger.js
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
4
4
|
value: true
|
5
5
|
});
|
6
|
-
exports.AppLogger = void 0;
|
6
|
+
exports.logger = exports.AppLogger = void 0;
|
7
7
|
|
8
8
|
var _ConsoleLogger = require("./ConsoleLogger");
|
9
9
|
|
@@ -26,5 +26,10 @@ let AppLogger = (_dec = (0, _inversify.injectable)(), _dec2 = Reflect.metadata("
|
|
26
26
|
if (mute) this.log.setEnabled(false);
|
27
27
|
}
|
28
28
|
|
29
|
-
}) || _class) || _class) || _class);
|
30
|
-
|
29
|
+
}) || _class) || _class) || _class); // TODO make use of the name for logging
|
30
|
+
|
31
|
+
exports.AppLogger = AppLogger;
|
32
|
+
|
33
|
+
const logger = name => new AppLogger();
|
34
|
+
|
35
|
+
exports.logger = logger;
|
File without changes
|
@@ -0,0 +1,33 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
4
|
+
value: true
|
5
|
+
});
|
6
|
+
exports.BackupStorage = void 0;
|
7
|
+
|
8
|
+
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
9
|
+
|
10
|
+
class BackupStorage {
|
11
|
+
constructor(backend, props) {
|
12
|
+
this.backend = backend;
|
13
|
+
this.props = props;
|
14
|
+
|
15
|
+
_defineProperty(this, "store", from => {
|
16
|
+
const {
|
17
|
+
tag
|
18
|
+
} = this.props;
|
19
|
+
const tags = tag ? [tag] : undefined;
|
20
|
+
this.backend.backup(from, tags);
|
21
|
+
});
|
22
|
+
|
23
|
+
_defineProperty(this, "restore", to => {
|
24
|
+
const {
|
25
|
+
snapshotId
|
26
|
+
} = this.props;
|
27
|
+
if (snapshotId) this.backend.restoreSnapshot(to, snapshotId);else this.backend.restoreLatest(to);
|
28
|
+
});
|
29
|
+
}
|
30
|
+
|
31
|
+
}
|
32
|
+
|
33
|
+
exports.BackupStorage = BackupStorage;
|
@@ -0,0 +1,50 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
4
|
+
value: true
|
5
|
+
});
|
6
|
+
exports.BackupStorageProvider = void 0;
|
7
|
+
|
8
|
+
var _inversify = require("inversify");
|
9
|
+
|
10
|
+
var _types = require("./types");
|
11
|
+
|
12
|
+
var _ResticFactory = require("./restic/ResticFactory");
|
13
|
+
|
14
|
+
var _RCloneFactory = require("./rclone/RCloneFactory");
|
15
|
+
|
16
|
+
var _StorageConfigProvider = require("./StorageConfigProvider");
|
17
|
+
|
18
|
+
var _BackupStorage = require("./BackupStorage");
|
19
|
+
|
20
|
+
var _dec, _dec2, _dec3, _class;
|
21
|
+
|
22
|
+
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
23
|
+
|
24
|
+
let BackupStorageProvider = (_dec = (0, _inversify.injectable)(), _dec2 = Reflect.metadata("design:type", Function), _dec3 = Reflect.metadata("design:paramtypes", [typeof _ResticFactory.ResticFactory === "undefined" ? Object : _ResticFactory.ResticFactory, typeof _RCloneFactory.RCloneFactory === "undefined" ? Object : _RCloneFactory.RCloneFactory, typeof _StorageConfigProvider.StorageConfigProvider === "undefined" ? Object : _StorageConfigProvider.StorageConfigProvider]), _dec(_class = _dec2(_class = _dec3(_class = class BackupStorageProvider {
|
25
|
+
constructor(resticFac, rcloneFac, cfgProvider) {
|
26
|
+
this.resticFac = resticFac;
|
27
|
+
this.rcloneFac = rcloneFac;
|
28
|
+
this.cfgProvider = cfgProvider;
|
29
|
+
|
30
|
+
_defineProperty(this, "provide", () => {
|
31
|
+
const cfg = this.cfgProvider.provide();
|
32
|
+
const back = this.getBackend(cfg);
|
33
|
+
return new _BackupStorage.BackupStorage(back, cfg.backup);
|
34
|
+
});
|
35
|
+
|
36
|
+
_defineProperty(this, "getBackend", cfg => {
|
37
|
+
switch (cfg.type) {
|
38
|
+
case _types.StorageType.Restic:
|
39
|
+
return this.resticFac.createBackupBackend(cfg);
|
40
|
+
|
41
|
+
case _types.StorageType.RClone:
|
42
|
+
return this.rcloneFac.createBackupBackend(cfg);
|
43
|
+
}
|
44
|
+
|
45
|
+
throw new Error(`Unsupported storage type ${cfg.type}`);
|
46
|
+
});
|
47
|
+
}
|
48
|
+
|
49
|
+
}) || _class) || _class) || _class);
|
50
|
+
exports.BackupStorageProvider = BackupStorageProvider;
|
@@ -52,7 +52,12 @@ let StorageConfigProvider = (_dec = (0, _inversify.injectable)(), _dec2 = functi
|
|
52
52
|
res.repo = 'local:' + this.fs.expandStrPath(path);
|
53
53
|
}
|
54
54
|
|
55
|
-
return res
|
55
|
+
return { ...res,
|
56
|
+
backup: {
|
57
|
+
tag: this.inputs.backupTag,
|
58
|
+
snapshotId: this.inputs.backupSnapshotId
|
59
|
+
}
|
60
|
+
};
|
56
61
|
});
|
57
62
|
|
58
63
|
_defineProperty(this, "getByCliConfig", inp => {
|
@@ -3,7 +3,7 @@
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
4
4
|
value: true
|
5
5
|
});
|
6
|
-
exports.
|
6
|
+
exports.RCloneFactory = void 0;
|
7
7
|
|
8
8
|
var _inversify = require("inversify");
|
9
9
|
|
@@ -17,6 +17,8 @@ var _RcloneClient = require("./RcloneClient");
|
|
17
17
|
|
18
18
|
var _B2CredentialsProvider = require("../b2/B2CredentialsProvider");
|
19
19
|
|
20
|
+
var _RcloneBackupBackend = require("./RcloneBackupBackend");
|
21
|
+
|
20
22
|
var _dec, _dec2, _dec3, _class;
|
21
23
|
|
22
24
|
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
@@ -32,14 +34,16 @@ const parseRepoUrl = url => {
|
|
32
34
|
};
|
33
35
|
};
|
34
36
|
|
35
|
-
let
|
37
|
+
let RCloneFactory = (_dec = (0, _inversify.injectable)(), _dec2 = Reflect.metadata("design:type", Function), _dec3 = Reflect.metadata("design:paramtypes", [typeof _Shell.Shell === "undefined" ? Object : _Shell.Shell, typeof _AppLogger.AppLogger === "undefined" ? Object : _AppLogger.AppLogger, typeof _Fs.Fs === "undefined" ? Object : _Fs.Fs, typeof _B2CredentialsProvider.B2CredentialsProvider === "undefined" ? Object : _B2CredentialsProvider.B2CredentialsProvider]), _dec(_class = _dec2(_class = _dec3(_class = class RCloneFactory {
|
36
38
|
constructor(sh, log, fs, b2) {
|
37
39
|
this.sh = sh;
|
38
40
|
this.log = log;
|
39
41
|
this.fs = fs;
|
40
42
|
this.b2 = b2;
|
41
43
|
|
42
|
-
_defineProperty(this, "
|
44
|
+
_defineProperty(this, "createBackupBackend", cfg => new _RcloneBackupBackend.RcloneBackupBackend(this.createClient(cfg)));
|
45
|
+
|
46
|
+
_defineProperty(this, "createClient", cfg => {
|
43
47
|
const {
|
44
48
|
type,
|
45
49
|
location
|
@@ -66,4 +70,4 @@ let RCloneClientFactory = (_dec = (0, _inversify.injectable)(), _dec2 = Reflect.
|
|
66
70
|
}
|
67
71
|
|
68
72
|
}) || _class) || _class) || _class);
|
69
|
-
exports.
|
73
|
+
exports.RCloneFactory = RCloneFactory;
|
@@ -0,0 +1,42 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
4
|
+
value: true
|
5
|
+
});
|
6
|
+
exports.RcloneBackupBackend = void 0;
|
7
|
+
|
8
|
+
var _AppLogger = require("../../log/AppLogger");
|
9
|
+
|
10
|
+
var _nclif = require("@ps-aux/nclif");
|
11
|
+
|
12
|
+
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
13
|
+
|
14
|
+
class RcloneBackupBackend {
|
15
|
+
constructor(rclone) {
|
16
|
+
this.rclone = rclone;
|
17
|
+
|
18
|
+
_defineProperty(this, "log", (0, _AppLogger.logger)(RcloneBackupBackend.name));
|
19
|
+
|
20
|
+
_defineProperty(this, "backup", (from, tags) => {
|
21
|
+
if (tags) throw new _nclif.InvalidInputError(`Rclone does not support tags`);
|
22
|
+
this.log.info('Performing backup', {
|
23
|
+
from
|
24
|
+
});
|
25
|
+
this.rclone.backup(from);
|
26
|
+
});
|
27
|
+
|
28
|
+
_defineProperty(this, "restoreLatest", to => {
|
29
|
+
this.log.info('Restoring', {
|
30
|
+
to
|
31
|
+
});
|
32
|
+
this.rclone.restore(to);
|
33
|
+
});
|
34
|
+
|
35
|
+
_defineProperty(this, "restoreSnapshot", (to, snapshotId) => {
|
36
|
+
throw new _nclif.InvalidInputError(`Rclone does not support snaphosts`);
|
37
|
+
});
|
38
|
+
}
|
39
|
+
|
40
|
+
}
|
41
|
+
|
42
|
+
exports.RcloneBackupBackend = RcloneBackupBackend;
|
@@ -0,0 +1,41 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
4
|
+
value: true
|
5
|
+
});
|
6
|
+
exports.ResticBackupBackend = void 0;
|
7
|
+
|
8
|
+
var _Path = require("../../fs/path/Path");
|
9
|
+
|
10
|
+
var _AppLogger = require("../../log/AppLogger");
|
11
|
+
|
12
|
+
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
13
|
+
|
14
|
+
class ResticBackupBackend {
|
15
|
+
constructor(restic) {
|
16
|
+
this.restic = restic;
|
17
|
+
|
18
|
+
_defineProperty(this, "log", (0, _AppLogger.logger)(ResticBackupBackend.name));
|
19
|
+
|
20
|
+
_defineProperty(this, "backup", (from, tags = []) => {
|
21
|
+
this.log.info(`Performing backup from=${from}, tags=${tags}`);
|
22
|
+
this.restic.backup(from, _Path.RelativePath.from('.'), tags);
|
23
|
+
this.restic.forget();
|
24
|
+
});
|
25
|
+
|
26
|
+
_defineProperty(this, "restoreLatest", to => {
|
27
|
+
this.log.info(`Restoring latest snapshot to=${to}`);
|
28
|
+
this.restic.restore(to);
|
29
|
+
});
|
30
|
+
|
31
|
+
_defineProperty(this, "restoreSnapshot", (to, snapshotId) => {
|
32
|
+
this.log.info(`Restoring snapshot '${snapshotId}'`, {
|
33
|
+
to
|
34
|
+
});
|
35
|
+
this.restic.restore(to, snapshotId);
|
36
|
+
});
|
37
|
+
}
|
38
|
+
|
39
|
+
}
|
40
|
+
|
41
|
+
exports.ResticBackupBackend = ResticBackupBackend;
|
@@ -14,12 +14,11 @@ const normalizeUrl = url => {
|
|
14
14
|
|
15
15
|
return url;
|
16
16
|
};
|
17
|
+
|
17
18
|
/**
|
18
19
|
* Tested with: restic 0.9.6 compiled with go1.12.12 on linux/amd64
|
19
20
|
* TODO forwarding stdout to the logger
|
20
21
|
*/
|
21
|
-
|
22
|
-
|
23
22
|
class ResticClient {
|
24
23
|
constructor(cfg, shell, log) {
|
25
24
|
this.cfg = cfg;
|
@@ -35,19 +34,56 @@ class ResticClient {
|
|
35
34
|
});
|
36
35
|
});
|
37
36
|
|
38
|
-
_defineProperty(this, "
|
37
|
+
_defineProperty(this, "runCmd", cmd => {
|
38
|
+
return this.shell.execAndReturnBuffer(`restic ${cmd}`, {
|
39
|
+
env: this.env()
|
40
|
+
});
|
41
|
+
});
|
42
|
+
|
43
|
+
_defineProperty(this, "backup", (cwd, from, tags = []) => {
|
39
44
|
this.log.debug(`Running backup for repo=${this.url}`);
|
40
|
-
|
45
|
+
let cmd = `restic backup ${from.str()}`;
|
46
|
+
tags.forEach(t => {
|
47
|
+
cmd += ` --tag=${t}`;
|
48
|
+
});
|
49
|
+
this.shell.exec(cmd, {
|
41
50
|
cwd: cwd.str(),
|
42
51
|
env: this.env()
|
43
52
|
});
|
44
53
|
});
|
45
54
|
|
46
|
-
_defineProperty(this, "restore", to => {
|
55
|
+
_defineProperty(this, "restore", (to, snapshotId = 'latest') => {
|
47
56
|
this.log.debug('Running restore for repo=', this.url);
|
48
|
-
this.shell.exec(`restic restore
|
57
|
+
this.shell.exec(`restic restore ${snapshotId} --target ${to.str()}`, {
|
58
|
+
env: this.env()
|
59
|
+
});
|
60
|
+
});
|
61
|
+
|
62
|
+
_defineProperty(this, "forget", () => {
|
63
|
+
this.log.debug(`Pruning repo=${this.url}`);
|
64
|
+
const cfg = {
|
65
|
+
hourly: 12,
|
66
|
+
daily: 7,
|
67
|
+
weekly: 8,
|
68
|
+
monthly: 24
|
69
|
+
};
|
70
|
+
this.shell.exec(`restic forget --prune ` + `--tag '' ` + // Ignore the tagged snapshots
|
71
|
+
`--keep-hourly ${cfg.hourly} --keep-daily ${cfg.daily} ` + `--keep-weekly ${cfg.weekly} --keep-monthly ${cfg.monthly}`, {
|
72
|
+
env: this.env()
|
73
|
+
});
|
74
|
+
});
|
75
|
+
|
76
|
+
_defineProperty(this, "snapshots", () => {
|
77
|
+
this.log.debug(`Listing snapshots of repo=${this.url}`);
|
78
|
+
const out = this.shell.execAndReturnString(`restic snapshots --json`, {
|
49
79
|
env: this.env()
|
50
80
|
});
|
81
|
+
const res = JSON.parse(out);
|
82
|
+
return res.map(r => ({
|
83
|
+
id: r.id,
|
84
|
+
time: new Date(r.time),
|
85
|
+
tags: r.tags
|
86
|
+
}));
|
51
87
|
});
|
52
88
|
|
53
89
|
_defineProperty(this, "env", () => ({
|
@@ -34,8 +34,21 @@ describe('ResticClient', () => {
|
|
34
34
|
it('create repo', () => {
|
35
35
|
sut.prepareRepo();
|
36
36
|
});
|
37
|
-
it('push data', () => {
|
38
|
-
|
37
|
+
it('push data & forget', () => {
|
38
|
+
const from = _Path.AbsPath.from(backupDir);
|
39
|
+
|
40
|
+
const to = _Path.RelativePath.from('.');
|
41
|
+
|
42
|
+
sut.backup(from, to);
|
43
|
+
sut.backup(from, to, ['foo', 'bar']);
|
44
|
+
sut.forget();
|
45
|
+
sut.backup(from, to);
|
46
|
+
const res = sut.snapshots();
|
47
|
+
expect(res).toBeArrayOfSize(3);
|
48
|
+
const tagged = res[1];
|
49
|
+
expect(tagged.id).toBeDefined();
|
50
|
+
expect(tagged.time).toBeDate();
|
51
|
+
expect(tagged.tags).toEqual(['foo', 'bar']);
|
39
52
|
});
|
40
53
|
it('restore data', () => {
|
41
54
|
sut.restore(_Path.AbsPath.from(restoreDir));
|
@@ -11,7 +11,7 @@ var _ContextSymbols = require("../../ctx/ContextSymbols");
|
|
11
11
|
|
12
12
|
var _config = require("../../config");
|
13
13
|
|
14
|
-
var
|
14
|
+
var _ResticFactory = require("./ResticFactory");
|
15
15
|
|
16
16
|
var _AppLogger = require("../../log/AppLogger");
|
17
17
|
|
@@ -24,19 +24,34 @@ var _dec, _dec2, _dec3, _dec4, _class;
|
|
24
24
|
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
25
25
|
|
26
26
|
let ResticController = (_dec = (0, _inversify.injectable)(), _dec2 = function (target, key) {
|
27
|
-
return (0, _inversify.inject)(_ContextSymbols.AppConfig_)(target, undefined,
|
28
|
-
}, _dec3 = Reflect.metadata("design:type", Function), _dec4 = Reflect.metadata("design:paramtypes", [typeof
|
29
|
-
constructor(restFact,
|
27
|
+
return (0, _inversify.inject)(_ContextSymbols.AppConfig_)(target, undefined, 1);
|
28
|
+
}, _dec3 = Reflect.metadata("design:type", Function), _dec4 = Reflect.metadata("design:paramtypes", [typeof _ResticFactory.ResticFactory === "undefined" ? Object : _ResticFactory.ResticFactory, typeof _config.Config === "undefined" ? Object : _config.Config, typeof _StorageConfigProvider.StorageConfigProvider === "undefined" ? Object : _StorageConfigProvider.StorageConfigProvider]), _dec(_class = _dec2(_class = _dec3(_class = _dec4(_class = class ResticController {
|
29
|
+
constructor(restFact, cfg, storageConfigProvider) {
|
30
30
|
this.restFact = restFact;
|
31
|
-
this.log = log;
|
32
31
|
this.cfg = cfg;
|
33
32
|
this.storageConfigProvider = storageConfigProvider;
|
34
33
|
|
35
|
-
_defineProperty(this, "
|
34
|
+
_defineProperty(this, "log", (0, _AppLogger.logger)(ResticController.name));
|
35
|
+
|
36
|
+
_defineProperty(this, "client", () => {
|
36
37
|
const props = this.storageConfigProvider.provide();
|
37
38
|
if (props.type !== _types.StorageType.Restic) throw new Error('Storage is not Restic storage');
|
38
39
|
this.log.info('Initializing repo', props.repo);
|
39
|
-
this.restFact.
|
40
|
+
return this.restFact.createClient(props);
|
41
|
+
});
|
42
|
+
|
43
|
+
_defineProperty(this, "initRepo", () => {
|
44
|
+
this.client().prepareRepo();
|
45
|
+
});
|
46
|
+
|
47
|
+
_defineProperty(this, "listSnapshots", print => {
|
48
|
+
const res = this.client().snapshots();
|
49
|
+
print(JSON.stringify(res, null, 4));
|
50
|
+
});
|
51
|
+
|
52
|
+
_defineProperty(this, "runResticCmd", (cmd, print) => {
|
53
|
+
const res = this.client().runCmd(cmd);
|
54
|
+
print(res.toString());
|
40
55
|
});
|
41
56
|
}
|
42
57
|
|
@@ -3,7 +3,7 @@
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
4
4
|
value: true
|
5
5
|
});
|
6
|
-
exports.
|
6
|
+
exports.ResticFactory = void 0;
|
7
7
|
|
8
8
|
var _inversify = require("inversify");
|
9
9
|
|
@@ -17,18 +17,22 @@ var _Fs = require("../../fs/Fs");
|
|
17
17
|
|
18
18
|
var _B2CredentialsProvider = require("../b2/B2CredentialsProvider");
|
19
19
|
|
20
|
+
var _ResticBackupBackend = require("./ResticBackupBackend");
|
21
|
+
|
20
22
|
var _dec, _dec2, _dec3, _class;
|
21
23
|
|
22
24
|
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
23
25
|
|
24
|
-
let
|
26
|
+
let ResticFactory = (_dec = (0, _inversify.injectable)(), _dec2 = Reflect.metadata("design:type", Function), _dec3 = Reflect.metadata("design:paramtypes", [typeof _Shell.Shell === "undefined" ? Object : _Shell.Shell, typeof _AppLogger.AppLogger === "undefined" ? Object : _AppLogger.AppLogger, typeof _Fs.Fs === "undefined" ? Object : _Fs.Fs, typeof _B2CredentialsProvider.B2CredentialsProvider === "undefined" ? Object : _B2CredentialsProvider.B2CredentialsProvider]), _dec(_class = _dec2(_class = _dec3(_class = class ResticFactory {
|
25
27
|
constructor(sh, log, fs, b2) {
|
26
28
|
this.sh = sh;
|
27
29
|
this.log = log;
|
28
30
|
this.fs = fs;
|
29
31
|
this.b2 = b2;
|
30
32
|
|
31
|
-
_defineProperty(this, "
|
33
|
+
_defineProperty(this, "createBackupBackend", cfg => new _ResticBackupBackend.ResticBackupBackend(this.createClient(cfg)));
|
34
|
+
|
35
|
+
_defineProperty(this, "createClient", cfg => {
|
32
36
|
if (!cfg.encryptionPassword) throw new Error(`Restic needs encryptionPassword. Repo=${cfg.repo}`);
|
33
37
|
const props = {
|
34
38
|
repo: {
|
@@ -50,4 +54,4 @@ let ResticClientFactory = (_dec = (0, _inversify.injectable)(), _dec2 = Reflect.
|
|
50
54
|
}
|
51
55
|
|
52
56
|
}) || _class) || _class) || _class);
|
53
|
-
exports.
|
57
|
+
exports.ResticFactory = ResticFactory;
|
package/package.json
CHANGED
@@ -1,44 +0,0 @@
|
|
1
|
-
"use strict";
|
2
|
-
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
4
|
-
value: true
|
5
|
-
});
|
6
|
-
exports.DataBackupController = void 0;
|
7
|
-
|
8
|
-
var _inversify = require("inversify");
|
9
|
-
|
10
|
-
var _AppLogger = require("../../log/AppLogger");
|
11
|
-
|
12
|
-
var _Path = require("../../fs/path/Path");
|
13
|
-
|
14
|
-
var _StorageBackendProvider = require("../../storage/StorageBackendProvider");
|
15
|
-
|
16
|
-
var _dec, _dec2, _dec3, _class;
|
17
|
-
|
18
|
-
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
19
|
-
|
20
|
-
let DataBackupController = (_dec = (0, _inversify.injectable)(), _dec2 = Reflect.metadata("design:type", Function), _dec3 = Reflect.metadata("design:paramtypes", [typeof _AppLogger.AppLogger === "undefined" ? Object : _AppLogger.AppLogger, typeof _StorageBackendProvider.StorageBackendProvider === "undefined" ? Object : _StorageBackendProvider.StorageBackendProvider]), _dec(_class = _dec2(_class = _dec3(_class = class DataBackupController {
|
21
|
-
constructor(log, storageBackendProvider) {
|
22
|
-
this.log = log;
|
23
|
-
this.storageBackendProvider = storageBackendProvider;
|
24
|
-
|
25
|
-
_defineProperty(this, "storage", inp => {
|
26
|
-
const storage = this.storageBackendProvider.provide();
|
27
|
-
|
28
|
-
const path = _Path.AbsPath.from(inp.path);
|
29
|
-
|
30
|
-
return {
|
31
|
-
backup: () => {
|
32
|
-
this.log.info(`Backing up from ${path} to '${storage}'`);
|
33
|
-
storage.store(path);
|
34
|
-
},
|
35
|
-
restore: () => {
|
36
|
-
this.log.info(`Restoring from '${storage}' to ${path}`);
|
37
|
-
storage.restore(path);
|
38
|
-
}
|
39
|
-
};
|
40
|
-
});
|
41
|
-
}
|
42
|
-
|
43
|
-
}) || _class) || _class) || _class);
|
44
|
-
exports.DataBackupController = DataBackupController;
|
@@ -1,27 +0,0 @@
|
|
1
|
-
"use strict";
|
2
|
-
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
4
|
-
value: true
|
5
|
-
});
|
6
|
-
exports.BackupClientStorageBackend = void 0;
|
7
|
-
|
8
|
-
var _Path = require("../fs/path/Path");
|
9
|
-
|
10
|
-
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
11
|
-
|
12
|
-
class BackupClientStorageBackend {
|
13
|
-
constructor(client) {
|
14
|
-
this.client = client;
|
15
|
-
|
16
|
-
_defineProperty(this, "store", from => {
|
17
|
-
this.client.backup(from, _Path.RelativePath.from('.'));
|
18
|
-
});
|
19
|
-
|
20
|
-
_defineProperty(this, "restore", to => {
|
21
|
-
this.client.restore(to);
|
22
|
-
});
|
23
|
-
}
|
24
|
-
|
25
|
-
}
|
26
|
-
|
27
|
-
exports.BackupClientStorageBackend = BackupClientStorageBackend;
|
@@ -1,50 +0,0 @@
|
|
1
|
-
"use strict";
|
2
|
-
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
4
|
-
value: true
|
5
|
-
});
|
6
|
-
exports.StorageBackendProvider = void 0;
|
7
|
-
|
8
|
-
var _inversify = require("inversify");
|
9
|
-
|
10
|
-
var _types = require("./types");
|
11
|
-
|
12
|
-
var _ResticClientFactory = require("./restic/ResticClientFactory");
|
13
|
-
|
14
|
-
var _BackupClientStorageBackend = require("./BackupClientStorageBackend");
|
15
|
-
|
16
|
-
var _RCloneClientFactory = require("./rclone/RCloneClientFactory");
|
17
|
-
|
18
|
-
var _StorageConfigProvider = require("./StorageConfigProvider");
|
19
|
-
|
20
|
-
var _dec, _dec2, _dec3, _class;
|
21
|
-
|
22
|
-
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
23
|
-
|
24
|
-
let StorageBackendProvider = (_dec = (0, _inversify.injectable)(), _dec2 = Reflect.metadata("design:type", Function), _dec3 = Reflect.metadata("design:paramtypes", [typeof _ResticClientFactory.ResticClientFactory === "undefined" ? Object : _ResticClientFactory.ResticClientFactory, typeof _RCloneClientFactory.RCloneClientFactory === "undefined" ? Object : _RCloneClientFactory.RCloneClientFactory, typeof _StorageConfigProvider.StorageConfigProvider === "undefined" ? Object : _StorageConfigProvider.StorageConfigProvider]), _dec(_class = _dec2(_class = _dec3(_class = class StorageBackendProvider {
|
25
|
-
constructor(resticFac, rcloneFac, cfgProvider) {
|
26
|
-
this.resticFac = resticFac;
|
27
|
-
this.rcloneFac = rcloneFac;
|
28
|
-
this.cfgProvider = cfgProvider;
|
29
|
-
|
30
|
-
_defineProperty(this, "provide", () => {
|
31
|
-
const s = this.cfgProvider.provide();
|
32
|
-
let b = null;
|
33
|
-
|
34
|
-
switch (s.type) {
|
35
|
-
case _types.StorageType.Restic:
|
36
|
-
b = this.resticFac.create(s);
|
37
|
-
break;
|
38
|
-
|
39
|
-
case _types.StorageType.RClone:
|
40
|
-
b = this.rcloneFac.create(s);
|
41
|
-
break;
|
42
|
-
}
|
43
|
-
|
44
|
-
if (!b) throw new Error(`Unsupported storage type ${s.type}`);
|
45
|
-
return new _BackupClientStorageBackend.BackupClientStorageBackend(b);
|
46
|
-
});
|
47
|
-
}
|
48
|
-
|
49
|
-
}) || _class) || _class) || _class);
|
50
|
-
exports.StorageBackendProvider = StorageBackendProvider;
|