Приветствую!


В предыдущей статье я писал о 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.


Спасибо!

Поделиться с друзьями
-->

Комментарии (8)


  1. gre
    16.05.2016 20:50

    А вот расскажите о своём опыте — какие скрипты с хаба Вы лично используете?
    Пример по установке nginx понятен, но лучше бы что-то более осязаемое — зачем мне нужен этот репозиторий, какие скрипты там есть, которые могут сэкономить полчаса моего времени?


    1. alexey_melezhik
      16.05.2016 21:52

      Хороший вопрос! Как вы понимаете, что автор всех плагинов sparrowhub, пока я. Цель как раз привлечь новых разработчиков. И я как раз пишу плагины, исходя из своих нужд, возможно кому-то они вообще не будут полезны. Но часть плагинов достаточно универсальных, например посмотрите logdog — плагин для поиска и группировки записей в логах с учётом заданного периода времени. Штука очень полезная, и кстати сложно реализуемая в bash однострочнике, писал её на Perl, использую её у себя для аудита логов ssh сервера и анализа загрузки плагинов со sparrowhub. Подробнее про настройку logdog и использование читайте статью на blogs.perl.org. Можно ещё посмотреть stale-proc-check — плагин по отслеживанию устаревших процессов на линукс серверах, переидически сталкиваемся с этой проблемой. Есть планы попробовать начать писать плагины для автоматизации сборки докер контейнеров, думаю что по сравнению с тем же шефом и ансимблом будет гораздо дешевле и самое главное гибче, т.к. всю внутрянку пишешь как хочешь хоть на bash, хоть на perl, а не идёшь через жестко заданный DSL, что иногда очень важно. А вобще говоря, буду рад понять какие задачи есть у других, тут как бы идея в том, что одни и те же повторяемые вещи выразить через плагины и дать другим людям их использовать — повторное использование сценариев администрирования.


      1. alexey_melezhik
        16.05.2016 22:08

        Да, небольшая поправка. В указанных статьях используется немного устаревший API sparrow. Для актуальной информации по API обращайтесь к документации по sparrow на MetaCPAN или гитхабе.


    1. alexey_melezhik
      17.05.2016 14:29

      вот кстати свеженький плагин — docker-engine — установка docker engine на Ubuntu Trusty 14.04 (LTS). Нужна будет поддержка других платформ — пишите. Набросал за час, разбираясь с докером. (;


  1. zyablitsky
    17.05.2016 07:24
    +1

    А в чем принчипиальные отличия и преимущества данного решения по сравнению с Chef, Ansible и т.д.?


    1. alexey_melezhik
      17.05.2016 09:25
      +1

      Приветствую! Хороший так же вопрос. Ожидаемый :)
      Вот что я думаю:


      1) sparrow не является альтернативой или заменой CM tools, таких как шеф или ансибл. Но вы можете использовать sparrow как для себя, для автоматизации задач на одном сервере, либо в связке с тем же шеф или ансибл для автоматизации на большом кол-ве серверов. Тот же шеф ставит Sparrow и набор плагинов ( плюс возможно доп-но конфиги к ним, что из шефа делать очень удобно кстати ) и запускает их как черные ящики, которые решают свои задачи. Те же плагины опять так же никто не мешает запускать руками, все зависит от контекста задач.


      2) таким образом sparrow это больше такой клей, как принято говорить, среда разработки и запуска различных сценариев. Плагины sparrow всегда решают какую-то небольшую задачку. В то время как в CM tools базовой единицей является как правило ресурс, ( файл, пакет, сервис; впрочем в шефе есть кукбуки, в ансибле — плейбуки, но базовой, элементарной еденицей является именно ресурс ).
      Иногда удобно собирать свои сценарии в терминах ресурсов ( что собственно и происходит в шефе и ансибле ), а иногда проще мыслить в терминах задач ( поставить конкретное приложение и настроить его ) — здесь область применения sparrow, т.к. в нем базовой единицей является некая решаемая задача, вся низкоуровневая логика инкапсулирована в самом плагине. Вот как можно еще на это посмотреть. Кто-то пишет плагин, никак не привязанный к конкретному CM tool.Такой плагин может быть использован как через шеф, как через ансибл, так и вручную ...


      3) sparrow не привязывает вас к какому-то DSL, в шефе вы пишите на chef DSL + ruby, на ансибле на его DSL и т.д. Sparrow дает возможность выбора языка для сценариев и из коробки добавляет ряд ценных возможностей — встроенное тестирования, конфигурация, и модульность ( второстепенные, основные истории ). Фактически поэтому порого вхождения в разработке на sparrow минимален.
      Обратной стороной такого подхода является более трудоемкая разработка кроссплатформенных сценариев. С другой стороны, это дает вам максимальную гибкость. Если в шефе вы упретесь в то, что базовый ресурс ( например package ) не работает по каким-то причинам ( например нет поддержки какой-нибудь OS) — вы ничего не сможете с этим поделать, вам придется просить разработчиков chef добавлять поддержку и ждать, когда это произойдет ( может не скоро ). Когда вы пишите сценарий на sparrow, вы всегда разрабатываете под ваше специфическое окружение, так как вам это нужно.


      Как-то так. Извиняюсь, если получился длинный ответ, вопрос действительно важный, и в двух словах на него не ответишь.


      1. zyablitsky
        17.05.2016 10:29

        Спасибо за такой развернутый ответ. Я пока доволен Ansible и все сервера у нас настроены с его использованием. Но чем больше разных инструментов и подходов, тем лучше для развития отрасли. Так что желаю вам удачи с вашим проектом. Дело это непростое, если хочется чтобы он действительно рос и развивался, а не остался своей личной песочницей.


        1. alexey_melezhik
          17.05.2016 12:25

          Спасибо! :)