@ps-aux/nodebup 0.7.2 → 0.8.1
Sign up to get free protection for your applications and to get access to all the features.
- package/lib/bup/aggregate/AggregateBackupController.js +2 -2
- package/lib/bup/dir/DirBackupController.js +45 -0
- package/lib/bup/pg/PgBackupController.js +9 -5
- package/lib/cli/app.js +21 -4
- 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 +36 -6
- package/lib/storage/restic/ResticClient.spec.js +15 -2
- package/lib/storage/restic/ResticController.js +17 -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,12 +101,15 @@ 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];
|
108
|
-
|
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
|
+
|
112
|
+
this.sh.exec(`docker run --network host -i ` + `postgres:${version} ` + `psql ${pgUrl} -v ON_ERROR_STOP=0 < ${outFile.str()}`);
|
109
113
|
});
|
110
114
|
});
|
111
115
|
}
|
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
|
}),
|
@@ -94,6 +105,10 @@ const restic = (0, _nclif.cmdGroup)({
|
|
94
105
|
'init-repo': (0, _nclif.cmd)({
|
95
106
|
options: singleStorageOptions,
|
96
107
|
run: (_, c) => c.get(_ResticController.ResticController).initRepo()
|
108
|
+
}),
|
109
|
+
snapshots: (0, _nclif.cmd)({
|
110
|
+
options: singleStorageOptions,
|
111
|
+
run: (_, c, p) => c.get(_ResticController.ResticController).listSnapshots(p.stdout)
|
97
112
|
})
|
98
113
|
}
|
99
114
|
});
|
@@ -111,9 +126,11 @@ const pg = (0, _nclif.cmdGroup)({
|
|
111
126
|
}],
|
112
127
|
commands: {
|
113
128
|
backup: (0, _nclif.cmd)({
|
129
|
+
options: backupOptions,
|
114
130
|
run: (inp, c) => c.get(_PgBackupController.PgBackupController).backup(inp)
|
115
131
|
}),
|
116
132
|
restore: (0, _nclif.cmd)({
|
133
|
+
options: restoreOptions,
|
117
134
|
run: (inp, c) => c.get(_PgBackupController.PgBackupController).restore(inp)
|
118
135
|
})
|
119
136
|
}
|
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,50 @@ class ResticClient {
|
|
35
34
|
});
|
36
35
|
});
|
37
36
|
|
38
|
-
_defineProperty(this, "backup", (cwd, from) => {
|
37
|
+
_defineProperty(this, "backup", (cwd, from, tags = []) => {
|
39
38
|
this.log.debug(`Running backup for repo=${this.url}`);
|
40
|
-
|
39
|
+
let cmd = `restic backup ${from.str()}`;
|
40
|
+
tags.forEach(t => {
|
41
|
+
cmd += ` --tag=${t}`;
|
42
|
+
});
|
43
|
+
this.shell.exec(cmd, {
|
41
44
|
cwd: cwd.str(),
|
42
45
|
env: this.env()
|
43
46
|
});
|
44
47
|
});
|
45
48
|
|
46
|
-
_defineProperty(this, "restore", to => {
|
49
|
+
_defineProperty(this, "restore", (to, snapshotId = 'latest') => {
|
47
50
|
this.log.debug('Running restore for repo=', this.url);
|
48
|
-
this.shell.exec(`restic restore
|
51
|
+
this.shell.exec(`restic restore ${snapshotId} --target ${to.str()}`, {
|
52
|
+
env: this.env()
|
53
|
+
});
|
54
|
+
});
|
55
|
+
|
56
|
+
_defineProperty(this, "forget", () => {
|
57
|
+
this.log.debug(`Pruning repo=${this.url}`);
|
58
|
+
const cfg = {
|
59
|
+
hourly: 12,
|
60
|
+
daily: 7,
|
61
|
+
weekly: 8,
|
62
|
+
monthly: 24
|
63
|
+
};
|
64
|
+
this.shell.exec(`restic forget --prune ` + `--tag '' ` + // Ignore the tagged snapshots
|
65
|
+
`--keep-hourly ${cfg.hourly} --keep-daily ${cfg.daily} ` + `--keep-weekly ${cfg.weekly} --keep-monthly ${cfg.monthly}`, {
|
66
|
+
env: this.env()
|
67
|
+
});
|
68
|
+
});
|
69
|
+
|
70
|
+
_defineProperty(this, "snapshots", () => {
|
71
|
+
this.log.debug(`Listing snapshots of repo=${this.url}`);
|
72
|
+
const out = this.shell.execAndReturnString(`restic snapshots --json`, {
|
49
73
|
env: this.env()
|
50
74
|
});
|
75
|
+
const res = JSON.parse(out);
|
76
|
+
return res.map(r => ({
|
77
|
+
id: r.id,
|
78
|
+
time: new Date(r.time),
|
79
|
+
tags: r.tags
|
80
|
+
}));
|
51
81
|
});
|
52
82
|
|
53
83
|
_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,29 @@ 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));
|
40
50
|
});
|
41
51
|
}
|
42
52
|
|
@@ -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;
|