我想编写一个脚本来为办公室中的多台计算机执行备份过程。如何编写可以精确控制执行路径并且易于阅读和修改的方式?我需要OOP和SOLID吗?
该脚本应确保计算机处于运行状态,如果无法运行,请在备份后使其保持初始状态。
此外,该脚本还应执行一些基本的运行状况检查,例如smartctl -H
,然后执行rsync ...
和brtbk ...
命令进行实际备份。
我希望脚本生成一页报告,该报告发送到电子邮件地址,并带有清晰的标题,指示我应该进行调查还是忽略电子邮件。
我已经尝试使用async / await在香草JS中编写此代码,但是由于我想出了一个复杂的配置JSON而失败了。
var task = {
type: 'main',
config: {
host: '10.5.1.158',
mac: 'e0:d5:5e:ee:de:3d',
},
task: {
type: 'ensureAlive',
task: [
{
type: 'smartCheck',
dev: '/dev/sda'
},
{
type: 'smartCheck',
dev: '/dev/sdb'
},
{
type: 'failEarly',
task: [
{
type: 'rsync',
config: {
from: `root@{{config.ip}}:/home/VirtualBox\ VMs/a15:/backups/a15/vms/a15/`,
to: '/backups/a15/',
}
},
{
type: 'btrfsSnapshot',
config: {
dir: '/backups/a15/',
},
}
]
}
]
}
};
async function run(ctx, task) {
if (!task) {
return;
}
if (Array.isArray(task)) {
for (var i = 0; i < task.length; i++) {
await run(ctx, task[i]);
}
return;
}
var config = Object.assign({}, ctx.config || {}, task.config || {});
var f = ctx.getFunction(task.type);
try {
var result = await f(config);
task.output = result;
} catch (error) {
task.output = Output({ isOk: false, errorMessage: error.message, errorStack: error.stack })
}
var newCtx = Object.assign({}, ctx, { config });
await run(newCtx, task.task);
}
重复出现的run
函数变得太复杂,无法理解和修改/添加功能。
无论是JSON还是实际的JavaScript,我都希望得到这样简单的内容。伪代码如下:
async function a15(report) {
var wasAlive = wakeUp();
try {
await smartCheck();
} catch (error) {
report.addError(error);
}
try {
await smartCheck();
} catch (error) {
report.addError(error);
}
try {
await rsync();
await btrbk();
} catch (error) {
report.addError(error);
}
if (!wasAlive) {
shutDown();
}
}
我在做什么错?这有可能吗?
为进一步澄清,我想附加尝试的其他配置布局。
另一种配置尝试,碰巧太复杂了,无法编程。由于此配置是平坦的,因此主要困难与将指示主机处于活动状态(位于wakeUp
)的变量传递到配置末尾(位于shutDown
)有关。
var a15: TaskDescription[] = [
{
type: 'wakeUp',
config: {
host: '10.5.1.252',
mac: 'e0:d5:5e:ee:de:3d'.replace(/:/g, ''),
timeout: '5',
user: 'root',
privateKey: '/Users/epi/.ssh/id_rsa',
},
},
{
type: 'smartCheck',
config: {
dev: '/dev/sda',
},
},
{
type: 'smartCheck',
config: {
dev: '/dev/sdb',
},
},
{
type: 'command',
configTemplateFromConfig: true,
config: {
command: 'rsync -a --inplace --delete -e ssh root@{{host}}:/home/santelab/VirtualBox\ VMs/a15:/mnt/samsung_m3/a15/ /backups/a15/'
},
},
{
type: 'command',
config: {
command: 'btrbk -c /mnt/samsung_m3/a15.conf run'
},
},
{
type: 'shutDown',
runIf: 'wasAlive',
config: {
host: '10.5.1.252',
mac: 'e0:d5:5e:ee:de:3d'.replace(/:/g, ''),
timeout: '5',
user: 'root',
privateKey: '/Users/epi/.ssh/id_rsa',
},
},
];
export interface TaskDescription {
type: string;
config?: TaskConfig;
configTemplateFromConfig?: boolean;
ignoreError?: boolean;
runIf?: string;
}
export type TaskConfig = {
[key: string]: string,
}
答案 0 :(得分:0)
我想我做到了。
有2个关键概念是必需的:
这是用TypeScript写的localhost的概念证明。我也可以使用JavaScript。
import { WakeUp, Config as WakeUpConfig, Result as WakeUpResult } from './WakeUp';
import { SmartCheck, Config as SmartCheckConfig } from './SmartCheck';
import { Command, Config as CommandConfig, Result as CommandResult } from './Command';
import * as I from './interfaces';
async function* localhost() {
var wakeUpResult = (yield WakeUp({ host: 'localhost', mac: 'e0:d5:5e:ee:de:3d', timeout: 5, tries: 20 })) as WakeUpResult;
if (wakeUpResult.error) { return; }
var echoResult = (yield Command({ command: `echo test` })) as CommandResult;
if (echoResult.error) { return; }
if (!wakeUpResult.value) {
yield Command({ command: 'echo shutdown' });
}
}
(async function () {
var iterator = localhost();
var lastResult: IteratorResult<any> = { value: undefined, done: false };
do {
lastResult = await iterator.next(lastResult.value);
} while (!lastResult.done);
})()
我认为核心localhost()
易于阅读,并且可以轻松修改。