javascript - 如何编写具有高级报告功能的可维护的 JavaScript ala' Bash 脚本?

标签 javascript linux oop system-administration

我想编写一个脚本来为办公室中的多台计算机执行备份程序。我怎样才能以一种可以精细控制执行路径并且易于阅读和修改的方式编写?我需要 OOP 和 SOLID 吗?

脚本应确保计算机处于事件状态,如果不是,则 WoL 它并在备份后将其保留在初始状态。

此外,该脚本应该执行一些基本的健康检查,例如 smartctl -H,然后执行 rsync ...brtbk ... 命令进行实际备份。

我希望脚本生成一份单页报告,发送到一个电子邮件地址,标题清晰,表明我是应该调查还是可以忽略该电子邮件。

我已经尝试使用 async/await 在 vanilla 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,
}

最佳答案

我想我做到了。

有 2 个关键概念是必需的:

  1. 从不抛出错误,始终返回包含错误和值的结果
  2. 使用生成器 - 产生魔法

这是用 TypeScript 编写的本地主机的概念证明。我也可以使用 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() 易于阅读并且易于修改。

关于javascript - 如何编写具有高级报告功能的可维护的 JavaScript ala' Bash 脚本?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55680327/

相关文章:

JavaScript 数学

javascript - 通过javascript中的元素索引访问eventListener中的元素

linux - 防止 gtk FileChooserDialog 在目录中的所有文件上调用 stat?

linux - 如何使帧缓冲区看起来像真正的显示器?

javascript - NodeJS Sendgrid 401 未经授权

javascript - 将 Div 内容复制到第二个 Div

linux - 使用 Linux 命令删除早于 1 天的子目录中的文件

java - 为什么equals和hashCode定义在Object中?

oop - 前端和后端之间的 DRY 原则

java - 为什么标准类有时具有看似不相关的方法?