Как написать поддерживаемые сценарии JavaScript ala 'Bash с расширенными функциями создания отчетов? - PullRequest
1 голос
/ 15 апреля 2019

Я хотел бы написать скрипт для выполнения процедуры резервного копирования для нескольких компьютеров в офисе.Как я могу написать таким образом, чтобы я мог контролировать путь выполнения, а также легко читать и изменять?Нужны ли ООП и SOLID?

Сценарий должен убедиться, что компьютер жив, если нет WoL, и оставить его в исходном состоянии после резервного копирования.

Кроме того, сценарий должен выполнитьпара базовых проверок работоспособности, таких как smartctl -H, и после этого выполните команды rsync ... и brtbk ... для выполнения фактического резервного копирования.

Я бы хотел, чтобы скрипт генерировал одностраничный отчет, отправляемый на адрес электронной почтыс четким заголовком, указывающим, нужно ли мне исследовать, или я могу игнорировать электронную почту.

Я уже пытался написать это в vanilla JS с помощью async / await, но не удалось из-за сложной конфигурации 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,
}

1 Ответ

0 голосов
/ 15 апреля 2019

Я думаю, что сделал это.

Требуется 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() легко читается и позволяет легко модифицировать.

...