Sparrowdo - инструмент провиженинга и конфигурирования виртуальных машин для тех:
Кто не хочет программировать на yaml (со всеми неудобствами как в Ansible).
Кому нужен простой DSL в декларативном стиле с поддержкой идемпотентности для базовых модулей (как и в Ansible).
Хочет быстро и просто расширять core функционал на различных языках разработки (не только Python).
Хочет писать сценарии на современном и мощном языке программирования - Rakulang
Миграция с Ansible. Далее инструмент рассматривается в сравнении с типовыми фичами ансибла.
Встроенный DSL
Аналогично ансиблу в sparrowdo представлен встроенный DSL по управлению и конфигурированию виртуальными машинами. DSL закрывает большинство типовых задач.
В качестве примера рассмотрим сценарий деплоймента приложения из собранного бинарного файла с простым конфигурационным файлом и запущенного как systemd сервис.
Вот как будет выглядеть sparrowdo сценарий:
#!raku user "app"; directory "/var/apps/app/bin"; directory-delete "/var/apps/app/tmp"; directory-create "/var/apps/app/tmp"; bash "wget {config()<distro_url>} -O app.tar.gz", %( :cwd</var/apps/app/tmp>, :description<download distro>, ); bash "tar -xzf app.tar.gz && cp app ../bin/", %( :cwd</var/apps/app/tmp>, ); # install systemd script for some service and reload systemd daemon systemd-service "long-dream", %( :user<app>, :workdir</var/apps/app>, :command<bin/app> ); # start service service-start "long-dream";
Выглядит все лаконично и просто - мы используем готовые функции из dsl, предоставляемым sparrowdo. Для того чтобы сценарий знал где забрать дистрибутив - необходимо в корне проекта со sparrowdo сценарием создать файл config.raku:
%( :distro_url<http://local.storage.co/app-0.01.tar.gz>, )
Неформальный обзор sparrowdo DSL можно прочесть тут
Расширение через модули
Расширяющие модули в sparrowdo называются плагинами, они пишутся на многих языках (включая Bash/Python/Golang/Perl/Ruby/Powershell). В качестве примера давайте напишем плагин, который будет делать health check нашего сервиса и возвращать его статус , чтобы в случае недоступности сервиса мы могли сделать какое-то действие - например вывести алерт в нашем отчете. Будем писать плагин на Bash:
Сначала создали корневую директорию для плагина:
mkdir -p files/tasks/health cd files/tasks/health
Затем сам плагин
task.bash
url=$(config url) if curl -sf $url; then echo "{ \"status\": \"ok\" }" > $cache_root_dir/state.json else echo "{ \"status\": \"fail\" }" > $cache_root_dir/state.json fi
Таким образом - расширение - это просто файл задачи - task.bash, лежащий в поддиректории откуда его можно вызвать в самом сценарии:
my %state = task-run "files/tasks/healh", %( :url<http://127.0.0.1/check>, ); if %state<status> ne "ok" { warn "bad health check from service: ", %state<status>; }
Фактически, плагин превращается в обычную функцию, которую мы можем вызвать и которая может вернуть что-то. Все очень просто.
Rakulang позволяет нам писать подобные сценарии очень гибко и просто , избавляя от сложности реализации стиле Ansible / yaml
Роли
В sparrowdo нет ролей, но есть плагины - очень просто превратить задачу проверки состояния сервиса из предыдущего примера в полноценный плагин, достаточно в корневом каталоге с задачей создать файл sparrow.json
sparrow.json
{ "name": "health", "version": "0.1.0", "description" : "my very first Sparrow6 plugin", "url" : "https://github.com/melezhik/sparrow-health-check", }
И далее загрузить плагин в Sparrow репозитарий ( аналог Ansible galaxy ):
cd files/tasks/health s6 --upload
Далее можно использовать плагин внутри любого другого sparrowdo сценария схожим образом:
my %state = task-run "health check", "health", %( :url<http://127.0.0.1/check>, );
Подробнее о sparrow плагинах и репозиториях можно почитать тут и тут.
Также репозиторий публичных плагинов доступен тут - https://sparrowhub.io
Инвентари файлы
В sparrowdo есть аналог инвентари файлов в Ansible, только более гибкий и использующий нативный формат Rakulang HashMaps. Вот простой пример как реализовать группу хостов:
hosts.raku
#!raku [ %( host => "192.168.0.1", tags => "frontend" ), %( host => "192.168.0.2", tags => "loadbalancer" ), %( host => "192.168.0.3", tags => "backend" ), %( host => "192.168.0.4", tags => "backend" ), %( host => "192.168.0.5", tags => "database" ), %( host => "192.168.0.6", tags => "database" ), %( host => "192.168.0.7", tags => "database" ), ]
Чтобы запустить sparrowdo сценарий только хостов группы backend, нужно воспользоваться cli параметром tags:
sparrowdo --tags=backend --host=hosts.raku
Инвентари файлы в sparrowdo имеют много других интересных фич, подробнее про hosts файлы можно почитать тут и тут
Шаблоны
Sparrowdo как и Ansible поддерживает шаблонизацию. Причем на выбор есть несколько движков, включая Jinja. По дефолту доступен Template6 - порт на Raku известного шаблонизатора Template Toolkit. Вот как будет выглядеть деплоймент конфигурационного файла для вышеупомянутого сервиса:
templates/service.tt
listen_port: [% port %] home_dir: [% home %] debug_mode: [% debug %]
И далее в sparrowdo сценарии:
#!raku my %state = task-run "deploy server config", "template6", %( vars => %( :80port, :home</var/app/service>, :debug, ), :target</etc/service/main.config>, :template_dir<templates>, :templates<service>, #:dry_run, ); if %state<status> != 0 { service-restart("long-dream") }
Host атрибуты
В sparrowdo переменные конфигурации хостов можно определить в двух местах:
В config.raku
В host файле ( инвентари )
Config.raku - это просто файл, содержащий произвольный Raku код, с требованием вернуть HashMap в последнем выражении. Этот механизм позволяет описывать различные конфигурации, не привязываясь к какому-то конкретному формату, например для выше приведенного сценария с сервисом:
%( 80port, :home</var/apps/>, )
Далее в сценарии просто ссылаемся на конфиг, используя функцию conf():
my $port = conf()<port>; my $home = conf()<home>;
Другим удобным способом определять переменные для хостов может быть hosts файл:
hosts.raku
#!raku [ %( :host<192.168.0.1>, tags => %( :home</var/app>, 80port, ), ), %( :host<192.168.0.2>, tags => %( :home</var/app>, 80port, ), ), ];
Далее в сценарии для доступа к атрибутам воспользуемся функцией tags():
my $port = tags()<port>; my $home = tags()<home>;
Можно также переопределять атрибуты при запуске сценария:
sparrowdo --tags=home=/var/servuces/,port=8089 --host=hosts.raku
Подробнее об атрибутах хостов и hosts файлах можно почитать тут и тут
UI
Sparrowdo может использоваться вместе со Sparky - web консолью для запуска сценариев. Но в отличии от Ansible tower - Sparky позволяет сделать намного больше - например асинхронно запускать сценарии или писать каскадные пайплайны, когда нам необходимо обновлять хосты в определенном порядке или когда одни группы хостов зависят состояния других групп хостов. Подробнее об этом читать тут и тут
Заключение
Sparrowdo позволяет конфигурировать виртуальные машины также как и Ansible, при этом добавляя гибкость и избавляя от недостатков, связанных с YAML форматом - а именно сложность масштабирования кода и отладки. Пишите что думаете, буду признателен за комментарии.
