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 форматом - а именно сложность масштабирования кода и отладки. Пишите что думаете, буду признателен за комментарии.