Статья размещена автором Бетке Сергей Сергеевич

PowerShell: “позднее” связывание или “плагины” для сценариев

Я понимаю, что для скриптового языка (коим и является powershell) позднее связывание звучит абсурдно, мягко говоря (“раннего” там и быть не может). Но иного термина на нашёл.

Суть в следующем: имеем некую задачу, в рамках которой подзадачи появляются всё новые и новые. Например – анализируем мы журнал SMTP на предмет ошибок и потенциальных проблем. А вариантов анализа появляется всё больше и больше. Чтобы при этом сохранить читабельность сценария, логично разбить его на модули. Тут и возникла идея унификации “интерфейса” модуля (плагина такого своеобразного для конкретной задачи). И идея использования этого унифицированного интерфейса некими алгоритмами, которые знают только интерфейс модуля, но не знают имён модулей, их количества, и вообще – созданы были до “плагинов”.

Сразу перейду к примеру, иначе так и не будет ясно, о чём здесь написано.

Допустим, для некоторой задачи мы разработали унифицированный интерфейс модуля-“плагина”. И разработали два плагина: test1.psm1:

function EntryPoint () {
    'test1___';
};

и плагин test2.psm1:

function EntryPoint () {
    'test2___';
};

Для примера специально привёл такой вот “вырожденный” интерфейс модуля – всего один “метод”, без аргументов, возвращающий строку.

Теперь разработаем ещё один модуль с унифицированными алгоритмами, ориентированными только на описанный нами интерфейс модуля – testProcessing.psm1:

function Get-Plugins () {
    get-module |
        ? {$_.ExportedCommands.Contains('EntryPoint')} |
        % {$_.AsCustomObject()};
};

Да, пока мы реализовали только один “алгоритм” – вызываем для всех загруженных модулей, имеющих описанный выше интерфейс (то есть – для наших плагинов), метод EntryPoint.

Ну и “главный” файл сценария (типа main.ps1):

Import-Module '.\testProcessing' #-force Import-Module '.\test1' #-force Import-Module '.\test2' #-force $plugins = get-plugins();

$plugins | % {$_.entryPoint()};

Пример, безусловно, примитивен, но, тем не менее, демонстрирует ту самую возможность “позднего” связывания. Теперь для расширения функционала какого-либо сложного сценария (в моём случае – сценария анализа логов SMTP сервера) достаточно создать “плагин” (модуль с унифицированным интерфейсом) и подключить его через import-module, более – ничего не требуется. Сам же сценарий ориентирован на использование коллекции модулей.

Чтобы довести идею до верха маразма, приведу скорректированную версию main.ps1:

Import-Module '.\testProcessing' #-force
dir '.\plugins\*.psm1' | % {$_.fullName} | import-module #–force
$plugins = get-plugins();

$plugins | % {$_.entryPoint()};

Как видно, теперь наш сценарий в принципе до запуска не знает, какие плагины он будет использовать. Он “подгрузит” все плагины, которые обнаружит в подкаталоге plugins. Удобно в какой-то мере, main.ps1 вообще править теперь не надо при добавлении / удалении плагинов!

Но не всегда “удобно” использовать модуль как объект. В некоторых случаях нам могут потребоваться фильтрующие функции, которые никак не могут быть методами объекта. Поэтому предлагаю несколько иной механизм использования “плагинов”:

# найдём все плагины
$plugins = dir '.\plugins\*\*.psm1' | % {$_.fullName};

# используем плагины "по очереди"

$plugins `
    | import-module -force -passThru `
    | % {
        Select-SMTPLogSessionsByPlugin -log $log `
            | Get-SMTPLogPluginReport `
            | % {
...
            };
        $_;
    } `
    | remove-module
;

Идея в следующем: загружаем модули плагинов по очереди, и выгружаем сразу после использования. В приведённом примере Get-SMTPLogPluginReport и Select-SMTPLogSessionsByPlugin — “командлеты” из модуля плагина. И, как видно, такой подход позволил нам использовать фильтрующую функцию из модуля плагина в конвейере powershell.

Вот такое вот несколько извращённое применение паттерна проектирования “точка интерфейса” без классов и виртуальных методов, исключительно на модулях PowerShell!

P.S. Сейчас эту идею применяю для анализа журнала SMTP сервера. Как только закончу – выложу сценарии, уже построенные по вышеописанному модульному принципу.

Опубликовать комментарий

XHTML: Вы можете использовать следующие HTML теги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Tags Связь с комментариями статьи:
RSS комментарии
Обратная ссылка