Приветствую!
В предыдущей статье я писал о SparrowHub — репозиторий готовых утилит для системного администрирования. Что же, время прошло, и теперь хочется рассказать о том КАК разрабатывать эти самые утилиты и загружать их на SparrowHub для повторного использования кем-либо.
Прежде чем показать конкретный пример написания плагина, хочу немного раскрыть идеологию фреймворка Sparrow, на котором собственно и разрабатываются скрипты.
Во-первых, Sparrow не навязывает какого-то жесткого DSL для разработки скриптов. У вас есть на выбор три языка, поддерживаемых Sparrow:
- Perl
- Ruby
- Bash
Таким образом, вы просто пишите обычный скрипт, который делает нужную вам работу и "оборачиваете" его в плагин, и, вуаля — он готов к загрузке на SparrowHub и для повторного использования. Ну, я немножко упростил, не совсем конечно так. Разрабатывая скрипт, вы все же придерживаетесь некоторых соглашений ( например на именования скриптовых файлов и т.д. ) для того что бы ваша утилита могла быть упакована в плагин в "sparrow" формате.
Другой особенностью Sparrow плагинов является встроенная система тестирования работы скриптов. Встроенная, потому что из коробки у вас есть возможность совершить дополнительные проверки работы скриптов, кроме банального кода завершения. Данная система проверок в ряде случаев может оказаться очень полезной. Детали станут ясны на конкретном примере.
Ну и третья, связанная с предыдущей, особенность Sparrow плагинов, это то, что результат их работы выводится в TAP формате. В двух словах TAP — специальный протокол ( плюс формат вывода ), разработанный для тестирования программных модулей, он является стандартным для написания unit тестов в Perl, но не привязан к конкретному языку программирования и имеет поддержку во многих системах и языках.
Таким образом, в Sparrow предпринята попытка ( насколько удачная покажет практика ;) ) совместить написание скриптов системного администрирования с системой тестирования работы самих скриптов. Похожие идеи можно увидеть в различных системах управления конфигурациями, например в chef — это minitest chef handler и новая разработка chef inspec.
Итак, напишем простейший Sparrow плагин.
Допустим, требуется установить пакет nginx и настроить запускаемый nginx сервер. Разобьем задачу на два сценария — собственно установка самого пакета и настройка сервера. Под настройкой будем понимать добавление сервера в автозагрузку, старт сервера и простейший тест на то, что сервер доступен по порту 80. Операционная система — Ubuntu. Сразу же оговорюсь, что пример достаточно умозрительный и тривиальный, любой системный администратор или программист способен выполнить подобную задачу, но хорошо подходит для объяснения того как пишутся плагины Sparrow.
Итак, у нас есть два сценария:
- установка пакета
- настойка сервера
Сценарий установки
В качестве языка, на котором будем писать плагин, выберем Bash т.к. в данной постановке задачи ( очень простые действия на уровне настройки операционные системы ) он больше всего подходит к нашей предметной области. В принципе, все тоже самое можно реализовать на Perl или Ruby.
В терминах Sparrow запускаемые сценарий — это история, в том смысле что есть некий скрипт, который можно запустить и который выводит что-то в stdout ( оставляет след, образно выражаясь ). После выполнения скрипта Sparrow позволяет сделать два типа проверок:
- проверить, что код завершения успешный ( == 0 )
- проверить, что в текстовом выводе скрипта содержатся определенные данные ( проверка на соответствие строкам и регулярным выражениям )
Правила на именование скрипта простое — базовое имя должно быть story
с соответствующим языку сценария расширением:
- Bash — story.bash
- Perl — story.pl
- Ruby — story.rb
Итак, в случае с Bash имеем такую историю:
$ cat story.bash
sudo DEBIAN_FRONTEND=noninteractive apt-get -y install nginx >/dev/null
dpkg -s nginx | grep Status:
Запустив, данный скрипт руками посмотрим его вывод:
$ bash story.bash
Status: install ok installed
Теперь несложно написать проверку для корректности работы данного скрипта. В Sparrow это делается с помощью так называемых проверочных файлов. У каждой истории должен быть свой проверочный файл, он должен лежать в той же директории что и запускаемый сценарий и называться story.check. Содержимое проверочного файла должно быть создано на языке проверочных правил Outthentic::DSL, который был разработан специально для анализа текстового вывода произвольных программ. DSL предлагает большой набор возможностей, из которых на практике может потребоваться только проверка на построчное включение заданных строк и соответствие регулярному выражению. Итак, story.check
будет таким:
$ cat story.check
install ok installed
Отлично, теперь можно запустить нашу истории посредством Sparrow. Это будет прототипом нашего плагина. Для этого установим из CPAN модуль Sparrow, который предоставляет средства разработки и запуска Sparrow плагинов.
$ cpanm Sparrow
Отлично, перейдя в директорию, где лежит наш сценарий запустим его посредством утилиты strun
— это клиент для запуска сценариев в формате Sparrow:
$ strun
/tmp/.outthentic/30382/home/melezhik/projects/nginx-example/story.t ..
# Status: install ok installed
ok 1 - output match 'Status: install ok installed'
1..1
ok
All tests successful.
Files=1, Tests=1, 1 wallclock secs ( 0.01 usr 0.00 sys + 0.51 cusr 0.03 csys = 0.55 CPU)
Result: PASS
Как уже говорилось, мы получили результат работы нашего сценария в виде TAP отчета, по которому видно что скрипт отработал корректно. Что здесь произошло? strun
запустил сценарий и проверил что:
- код завершения успешный
- сценарий вывел в stdout строчку 'Status: install ok installed'
Сценарий настройки
Далее, аналогичным образом создадим сценарий настройки nginx сервера вместе с проверочный файлом. Так как каждая история должна находится в своей директории создадим для сценария настройки отдельную директорию:
$ mkdir nginx-setup
$ cd nginx-setup
Сценарий настройки будет очень простым:
$ cat nginx-setup/story.bash
sudo update-rc.d nginx defaults
sudo service nginx start
sudo service nginx status
curl -sf -o /dev/null 127.0.0.1
Для начала можно просто запустить сценарий руками и посмотреть вывод
System start/stop links for /etc/init.d/nginx already exist.
* nginx is running
Теперь можно создать проверочный файл:
$ cat nginx-setup/story.check
nginx is running
Отлично, снова запустим наша сценарии уже через strun
клиент:
$ strun
/tmp/.outthentic/32332/home/melezhik/projects/nginx-example/nginx-setup/story.t ..
# System start/stop links for /etc/init.d/nginx already exist.
# * nginx is running
ok 1 - output match 'nginx is running'
1..1
ok
/tmp/.outthentic/32332/home/melezhik/projects/nginx-example/story.t ..............
# Status: install ok installed
ok 1 - output match 'Status: install ok installed'
1..1
ok
All tests successful.
Files=2, Tests=2, 1 wallclock secs ( 0.01 usr 0.00 sys + 0.58 cusr 0.08 csys = 0.67 CPU)
Result: PASS
Убеждаемся, что мы достигли заданной цели. Nginx установлен, запущен, добавлен в автозагрузку и доступен по 80 порту.
Внимательный читатель увидит однако одну особенность в написанном нами наборе скриптов, а именно — сценарий установки nginx запускается после сценария настройки. Все дело в том, что по умолчанию все истории запускаемые клиентом strun
считаются независимыми и никак не связанными, порядок их запуска, вообще говоря, не гарантирован и даже больше — разные истории могут быть запущены в параллельном режиме ( читайте документацию по параметрам утилиты prove, которой strun диспетчеризирует запуск тестов ).
Очевидно, что при таком поведении, запуск плагина в первый раз, когда пакет nginx еще не установлен в системе, даст нам ошибку.
Что же нам делать? Как обеспечить запуск сценариев в заданной последовательности. Нам нужно сначала установить пакет nginx, а затем уже произвести настройку сервера. Для этого в Sparrow существует понятие модулей или второстепенных ( downstream ) историй.
Основные и второстепенные сценарии
Второстепенные истории — это сценарии, которые вы можете вызвать ПЕРЕД выполнением какого-то основного сценария ( основная ( upstream ) истории ). В нашем случае — основной сценарий будет сценарий настройки, а вторичным — сценарием сценарий установки пакета. Вторичные сценарии никогда не запускаются клиентом strun
напрямую, вы должны сделать их вызов явно в основном сценарии. Вот как это делается:
Что бы сценарий стал вторичным необходимо поместить соответствующую историю в директорию под названием ./modules
, таким образом strun
поймет, что данная история второстепенная:
$ mkdir -p modules/nginx-install
$ mv story.bash story.check modules/nginx-install
Для вызова второстепенной истории воспользуемся так называемый hook
файлом — основным механизмом в Sparrow, позволяющим расширять логику работы strun
клиента и добавлять вызовы стороннего кода перед выполнением основного сценария:
$ cat nginx-setup/hook.bash
run_story nginx-install
Не вдаваясь здесь в детали Hook API скажу лишь, что в данном примере в хук файле мы вызываем второстепенную историю nginx-install
с помощью функции run_story
. Обратите внимание, что аргумент функции — путь до директории, в которой находится второстепенная история, из которого исключается фрагмент modules
.
Итак запустим переработанный код:
$ strun
/tmp/.outthentic/367/home/melezhik/projects/nginx-example/nginx-setup/story.t ..
# Status: install ok installed
ok 1 - output match 'Status: install ok installed'
# System start/stop links for /etc/init.d/nginx already exist.
# * nginx is running
ok 2 - output match 'nginx is running'
1..2
ok
All tests successful.
Files=1, Tests=2, 1 wallclock secs ( 0.01 usr 0.00 sys + 0.54 cusr 0.06 csys = 0.61 CPU)
Result: PASS
Отлично, судя по выводу убеждаемся, что сценарий установки запускается перед сценарием настройки, чего и хотелось.
Подробнее про основные и второстепенные истории читайте в документации по клиенту strun
.
Загрузка плагина в центральный репозиторий SparrowHub
Протестировав работу сценариев и убедившись, что все работает как надо, мы готовы поделится нашим скриптом с остальным миром и загрузить его в SparrowHub — центральный репозитарий. Для этого нужно сделать два простых шага:
- зарегистрироваться на сайте https://sparrowhub.org
- залогиниться и получить токен разработчика плагинов
После этого, вы сможете загружать плагины под своим авторством.
В корне нашего проекта, где лежат истории создадим файл с метаданными плагина:
$ cat sparrow.json
{
"name" : "nginx-example",
"version" : "0.1.0",
"description" : "simple nginx server installer for Ubuntu",
"url" : "https://github.com/melezhik/nginx-example.git"
}
Формат файла подробно описан здесь, не будем подробно останавливаться на нем. Важно лишь сказать, что Sparrow поддерживает версионирование плагинов, позволяя загружать и устанавливать разные версии одного плагина.
Из в директории со скриптами запустим команду sparrow менеджера, указав свои идентификаторы на SparrowHub
$ export sph_user=melezhik
$ export sph_token=FOO-BAR-BAZ-FOO-BAR-BAZ
$ sparrow plg upload
sparrow.json file validated ...
plugin nginx-example version 0.001000 upload OK
Все отлично. Плагин загружен и находится в SparrowHub репозитарии. Мы можем зайти на другой сервер и воспользоваться данным плагином:
$ ssh some-other-host
$ sparrow index update
$ sparrow plg install nginx-example
$ sparrow plg run nginx-example
Заключение
Нет возможности описать в данной статье все возможности и тонкости системы Sparrow и среды разработки Outthentic. Приведу тезисно, что еще можно было бы раскрыть. ( Если у читателя будет интерес об этом можно будет в следующих статьях ).
- Outthenitc API для Perl и Ruby
- Параметры для второстепенных историй
- Outthentic::DSL — валидатор обычного текста ( генераторы проверочных правил, асерты, кепчи, текстовые блоки и т.д. )
- Конфигурация Sparrow плагинов ( Задачи, runtime параметры, YAML конфигурационные файлы и в формате Config::General )
PS Надеюсь на конструктивную критику :) и конечно же на привлечение новых разработчиков плагинов в проект SparrowHub.
Спасибо!
Автор: alexey_melezhik