Sparrow плагіни і Ansible модулі — порівняльний аналіз

Введення
Ansible модулі і sparrow плагіни являють собою будівельні блоки для вирішення найпростіших завдань з області configuration management і автоматизації деплоя. Ansible модулі користуються більш високорівневих сценаріях — плейбуках, написаних на мові YAML, в той час як sparrow плгагины аналогічним чином вбудовуються в sparrowdo сценарії написані на мові Perl6.
Дана стаття — вільний авторський переклад власного оригіналу з англійської.

Підтримка мов розробки
ansible — ви можете вибрати фактично будь-яка мова розробки для написання модулів.
"З коробки" ansible надає просунутий API для Python ( т. зв. shortcuts ). При розробці модулів на інших мовах ви повинні будете використовувати допоміжні бібліотеки ( нативні для кожної мови ) для спрощення процесу розробки та інтеграції в ansible.
sparrow — у вас є на вибір одні з трьох (*) мов — Perl5, Bash або Ruby. Для розробника плагінів sparrow надає уніфікований API ( доступний для будь-якого з трьох мов ), так само, як і у випадку з ansible спрощує процес розробки та інтеграції плагінів в систему sparrow. Цей API надає тільки базові можливості і не такий просунутий як API ansible для Python.
(*) найближчим часом планується додавання підтримки Python.
Дизайн
ansible — ansible модулі — автономні блоки програмного коли ( скрипти ) для рішення елементарних завдань. Ansible модулі не можу залежати або викликати інші ansible модулі.
sparrow — sparrow плагіни аналогічно ansible модулів — автономні, закриті блоки коду для вирішення елементарних завдань. Однак sparrow надає додатковий ступінь свободи на даному рівні розробки. Sparrow плагіни являють собою набори (suites) скриптів. Одні скрипти можуть викликати інші, передаючи їм параметри. Подібного роду дизайн дозволяє розбивати будь-яку задачу на скрипти, які взаємодіють один з одним. В якості прикладу можна розглянути простий випадок — установка і видалення пакетів. Ми можемо дивитися на цю задачу як на єдиний блок коду (скрипт), але при реалізації розбити на два скрипта: один для установки пакетів, інший — для видалення. Так само можна ввести третій скрипт, який буде розбирати вхідні параметри й робити диспетчеризацію викликів (*). Такий підхід докладно писаний у статті Еволюція sparrow плагінів.
(*) насправді так реалізований плагін package-generic.
Ось проста ілюстрація сказаного:
image
Інтеграція в інструмент управління конфігураціями
ansible — ansible модулі складова частина більш високорівневих сценаріїв конфігурування — ansible плейбуков. ansible плейбук — написаний на YAML сценарій, який декларує виклик ansible модулів з деякими заданими параметрами. Така конструкція в ansible називається завданням.
image
sparrow — подібно ansible модулів sparrow плагіни є складовою частиною
більш загальної системи — sparrowdo сценаріїв, написаних на мові Perl6. Подібно ansible — sparrowdo — система управління конфігураціями, але побудована на sparrow плагінах. Sparrow плагіни викликаються з параметрами всередині sparowdo сценаріїв.
image
Інтерфейс кінцевого користувача
ansible — ansible модулі, як вже було сказано, викликаються за допомогою YAML DSL коду, що декларує запуск модулів з переданими параметрами. Це відбувається в плейбуках. Можливий варіант запуску модулів консольним скриптом з параметрами передаються як аргументи командного рядка.
Нижче наведено приклад коду ansible плейбука для встановлення web сервера httpd допомогою менеджера пакетів yum ( однойменний ansible модуль ):
$ cat playbook.yml
---
- hosts: webservers
завдання:
- name: ensure apache is at the latest version
yum: name=httpd state=latest

sparrow — sparrow плагіни викликаються всередині sparrowdo сценаріїв Perl6 API. Параметри плагінів передаються у вигляді Perl6 хешей. Ви також можете використовувати консольний клієнт для запуску плагінів "є", минаючи sparrowdo ( схожим чином, як ви це можете робити ansible модулі ). Це може бути зручно при розробці та налагодженні плагінів. В такому режимі запуску у вас з'являється безліч додаткових можливостей передачі вхідних параметрів — командний рядок, формати JSON/YAML і Config::General
Далі наведено еквівалент попереднього ansible плейбука для встановлення web сервера httpd. Наведено два варіанти коду ( core-dsl і plugin API ) sparrowdo сценарію:
$ cat sparrowfile

# core-dsl API більш лаконічний, тому що він надає
# високорівневі "обгортки" для виклику плагінів
# але він реалізований тільки для обмеженого набору плагінів
package-install 'httpd';

# однак, якщо у вас немає реалізації через core-dsl
# ви завжди можете викликати будь-плагін,
# використовуючи plugin API
# що теж не дуже складно:

task-run 'ensure apache is at the latest version', 'package-generic', %(
list => 'httpd'
);

Передача та обробка вхідних параметрів
ansible — вхідні параметри модуля передаються у вигляді пар ключ=значення(*), в загальному випадку, при розробці модуля ви повинні забезпечити парсинг параметрів з метою "виділення" даних та їх призначення відповідним змінним, з метою подальшого використання в коді модуля. Під різні мови розробки існують численні "хелпери", що вирішують цю задачу.
(*) Можливий варіант передачі вкладених структур даних.
як уже говорилося ansible надає високорівневий API для Python, званий в документації ansible — shortcuts. Цей API дозволяє автоматично парсити вхідні параметри, генерувати аксессоры, визначати типи вхідних параметрів і робити їх перевірку, визначати дефолтні значення і тому подібне.
Нижче наведено шматочок anible модуля, що реалізує розбір вхідних параметрів за допомогою Python ansible API:
$ cat library/greetings.py
from ansible.module_utils.basic import *

def main():

fields = { "message": {"default": "Hi!", "type": "str" } }
module = ansibleModule(argument_spec=fields)
module.params['message']
# some other code here to return results
if __name__ == '__main__':
main()

sparrow — sparrow реалізує уніфікований API ( доступний для будь-якого з мов розробки ) для обробки вхідних параметрів плагіна, так що вам не доводиться парсити дані вручну.
Таким чином, незалежно від мови, на якому ви розробляєте плагін, ви отримуєте
"з коробки" API для доступу до вхідних даних фактично не написавши ні строчки допоміжного коду.
Також існує можливість визначати дефолтні значення для параметрів, у разі якщо останні не будуть задані явно.
Вбудована типізація і перевірка параметрів, як у випадку з ansible Python API відсутня.
Нижче наведено еквівалент згаданого ansible коду, розслідує вхідні параметри. В якості мови реалізації плагіна обраний Bash(*)
(*) що б показати як навіть на такому далеко не самому высокоуровневом мовою розробки можна легко писати sparrow плагіни, "не утикаючись" в обробку вхідних параметрів:
# це скрипт плагіна
$ cat story.bash
message=$(config message)

# це параметри за замовчуванням:
$ cat story.ini
message = Hi!

А ось як можна з допомогою того ж Bash розбирати вкладені вхідні параметри:
# виклик плагіна в sparrowdo сценарії
$ cat sparrowfile
task-run "run my task", 'foo-plugin', %(
foo => {
bar => {
baz => 'BAZ'
}
}
);

# код плагіна на Bash
# доступ до вхідних параметрів:
$ cat story.bash
baz=$(config foo.bar.baz)

Повертає значення
ansible — ansible модулі завжди повертають результат у вигляді JSON рядка. Причому сам JSON повинен мати спеціальну структуру. Детальніше про це можна почитати на сторінках документації ansible по розробці модулів.
Але ось, що хочеться відзначити щодо процесу повернення значень ansible модулів:
  • код завершення ( скрипта реалізує молудь ) ansible модулів ігнорується
  • єдиною вимогою щодо повернення з модуля — наявність в STDOUT рядка в форматі JSON. Структура JSON відповіді також повинна відповідати певним вимогам.
  • таким чином, якщо у відповіді від модуля ми не отримуємо валідний JSON це розцінюється як помилка
  • STDOUT/STDERR, що генерується модулем не видно (*) у висновку плейбука
    (*) — при певних умовах або написавши додатковий код це висновок все ж можна отримати, але тут я кажу про поведінку за замовчуванням
  • Для того, що б модуль повернув яке-небудь значення, воно повинно бути представлено у вигляді поля JSON структури, яку необхідно повернути в STDOUT
Наведу приклад з модулем currenttime повернути поточного часу:
$ cat library/currentime.py
import datetime
import json

date = str(datetime.datetime.now())
print json.dumps({
"time" : date
})

sparrow — sparrow плагіни, на відміну від ansible модулів можуть повертати всі що завгодно, sparrow не як не регламентує повертаються плагіном дані. ( Однак дивіться наступні секцію — "Обробка вихідних даних").
Ось що важливо знати про вихідних даних з точки зору sparrow:
  • код завершення плагіна ( результуючий, т. к. у випадку з sparrow ми можемо мати справу не з одним скриптом, а з кількома має значення. Якщо він ненульовий — це трактується як помилка виконання плагіна
  • STDOUT, генерований плагіном просто передається далі і видно в остаточному виведенні. Жодних "перепаковываний" або фільтрації результатів, як у випадку з ansible не відбувається. Ми завжди бачимо висновок як є, як якщо б ми просто запустили аналогічний скрипт з консолі
Далі я наведу еквівалент попереднього ansible модуля для виведення поточного часу. Буде на цей раз при написанні плагіна використовувати Perl5, у силу всього сказано код плагіна вийде тривіальним:
# скрипт плагіна
$ cat story.pl
print scalar localtime;

Обробка вихідних даних
ansible — ansible модулі завжди повинні повертати JSON, тому дуже легко маючи на виході структуровані дані перетворити їх на змінні і обробити десь "вище", насправді в ansible плейбуках. Хоча це і досить потужна фіча, її цінність в системах управління конфігураціями особисто для мене є спірною. Справа в тому, що до моменту (*) виконання списку завдань на цільовий сервер все вже повинно бути визначено у вигляді статичного, детермінованому списку, будь-яка спроба додати розгалуження і динаміку в такому вже сформованому списку тільки ускладнює, а не спрощує рішення загальної задачі — конвергенції сервера до заданого виду.
(*) тут важливо розуміти, що я як раз не проти динамічної генерації подібних списків завдань або ресурсів, якраз тут імперативний підхід цілком доречний, як це відбувається у випадку з chef або sparrowdo. Але можливо, я не так добре знаю ansible що б міркувати яким чином дані, які повертаються модулями використовуються далі в плейбуках.
Ось приклад простого модуля, який просто повертає переданий йому вхідний параметр, який далі "реєструється" в плейбуке і виводиться на консоль:
$ cat playbook.yml
- hosts: localhost
завдання:
- name: tell me what I say
echo:
message: "hi there!"
register: result
- debug: var=result

$ cat library/echo.py

from ansible.module_utils.basic import *

def main():

module = ansibleModule(argument_spec={})
response = {"you_said": module.params['message']}
module.exit_json(changed=True, meta=response)

if __name__ == '__main__':
main()

sparrow — як вже було сказано, sparrow "все одно" що плагін повідомляє в STDOUT, немає ніякої можливості використовувати ці дані далі. Насправді це не зовсім так.
З точки зору того, що ці дані ніяк не будуть оброблені далі — це правда, але ви має можливість визначити перевірочні правила з допомогою яких можна верифікувати висновок скрипта. Таке свого роду вбудоване тестування — характерна фіча sparrow плагінів. Перевірочні правила прописуються у вигляді конструкцій мови Outthentic::DSL і дозволяють робити різні текстові перевірки — відповідність тексту різних регулярним виразом, робота з окремими шматками тексту, які відповідають нашим виразами ( т. зв. captures ) і багато іншого. Про все це можна почитати на сторінках документації Outthenic::DSL.
Якщо верифікація не пройдена це трактується ( поряд з ненульовим кодом завершення ), як помилка виконання плагіна.
Таким чином написання подібного роду "самотестирующихся" скриптів дозволяє писати плагіни не тільки для завдань з області configuration management, але для задач тестування, моніторингу та аудиту.
Складно побудувати аналогію з попереднім ansible модулем, у силу всього сказаного, але
ось що-то наближено "схоже", що можна зробити в sparrow. Передати плагіну параметр, вивести його в STDOUT і написати перевірочне правило, що б переконається що на виході саме те, що було на вході:
# виклик плагіна в сценарії sparrowdo
$ cat sparrowfile
run-task "tell me what I say", "echo", %( message => 'hi there!' )

# реалізація плагіна і перевірочного правила
$ cat story.bash
echo you said $(config message)

$ cat story.check
generator: config()->{message}
Процес установки
ansible — більше кількість ansible поставляються як частина ansible, вони готові до використання, вам немає потреби якимось особливим чином встановлювати їх. Так само користувачі пишуть так звані custom модулі і, як правило, зберігають в якій-небудь системі контролю версій Git/Svn ( наприклад в github або gitlab ). Далі модулі у вигляді звичайних файлів чекаутятся на майстер сервер ( той, з якого запускають ansible завдання по ssh на цільових серверах ), знову ж таки в цьому випадку звістка деплой зводиться до звичайного чекауту з системи контролю версій.
Отже, екосистема модулів включає в себе дві великі підсистеми:
  • Основний репозиторій ansible ( main ansible repository — модулі, що поставляються разом з ansible
  • Користувальницькі модулі
Резюмуючи можна сказати, що в ansible реалізована push based схема деплоя, причому з відсутністю агента (agentless) на цільовому сервері. Модулі у вигляді файлів просто копіюються на сервер і вже там запускаються у вигляді скриптів.
Далі наводиться графічна схема процесу депллоя користувальницьких модулів ansible:
image
sparrow — у sparrow процес деплоя трохи інший. Хоча в цілому там взята на озброєння та ж push-based схема. Проте у випадку з sparrow тут присутній агент ( або клієнт, кому як зручніше ), який займається установкою плагінів.
Отже, sparrow плагіни не що інше як запаковані скрипти, поширювані подібно класичним система дистрибуції пакетів, таких як deb, rpm, CPAN,RubyGems.
sparrow надає менеджер по установці даних плагінів, цей же менеджер використовується для запуску плагінів. Менеджер повинен бути встановлений на цільовому сервері, що б все працювало.
sparrowdo компілює сценарії, розміщені на центральному (master) сервера мета дані, які у вигляді JSON файлів копіюється по scp на цільові машини, далі на тих же цільових машинах менеджер, використовуючи скопійовані дані викачує, встановлює налаштовує і, нарешті, запускається sparrow плагіни, результат повертається назад ( як і у випадку з ansible ) у вигляді відповіді на центральний сервер.
Отже, важливо розуміти, що на відміну від ansible установка плагінів — це не просто копіювання файлів на сервер, т. к. у випадку з sparrow копіюються не самі плагіни, а їх мета інформація, далі по мета інформації відбувається процес фактичного деплоймента.
sparrow плагіни розміщуються в центральному репозитарії sparrow плагінів — sparrowHub. Плагіни мають автора, версію, опис і документацію.
Ось як виглядає файл з мета інформацією вищезазначеного плагіна package-generic для установки пакетів:
{
"name" : "package-generic",
"version" : "0.2.16",
"description": "Generic package manager. Installs packages using OS specific package managers (yum,apt-get)",
"url" : "https://github.com/melezhik/package-generic"
}

У sparrow немає жорсткого поділу на кастомний і "core" плагіни. Будь-плагін, завантажений в sparrowHub, стає тут же доступним користувачам системи, і, таким чином його можна використовувати в sparrowdo сценаріях.
За бажанням користувачі можуть розміщувати свої плагіни на віддалених git архівів, в sparrow такі плагіни називаються приватними (private), при цьому дані плагіни без праці можуть бути використані у ваших сценаріях конфігурування, поряд з плагінами з sparrowHub ( т. зв. публічні плагіни )
Далі наводиться схема деплоймента плагінів в sparrow:
image
Залежно
ansible — в ansible немає можливості керувати залежностями на рівні модулів. Швидше за все ( я так добре знаю ansible, я припускаю ) це відбувається рівнем вище — в плейбуках. Таким чином, якщо ваш модуль залежить від якоїсь бібліотеки вам необхідно подбає про дозвіл залежностей десь в іншому місці, наприклад, викликавши встановлення залежностей в іншому місці плейбука.
sparrow — sparrow надає штатні можливості по управлінню залежностями (*) на рівні sparrow плагіна. Таким чином, якщо плагін залежить від будь-яких бібліотек, ви можете описати дані залежності прямо в плагіні і менеджер плагінів подбає про них
під час установки плагіна. Поки управління залежностями обмежується модулями CPAN для Perl5 допомогою файлу cpanfile і модулями RubyGems для Ruby за допомогою файлу Gemfile.
(*) — залежно обмежені поки CPAN для Perl5 і RubyGems для Ruby
Висновок
ansible завоював велику популярність не в останню чергу завдяки великій кількості готових модулів. Однак на мій особистий погляд процес розробки нових модулів має свої недоліки і сама архітектура не є хорошим рішенням для деяких завдань. Я знаходжу окремі фічі sparrow більш привабливими і цікавими в порівнянні з ansible. Це, звичайно, IMHO :), перерахую деякі моменти:
  • Плейбуки проти sparrowdo сценаріїв — sparrowdo надає імперативні можливості програмування конфігурацій за допомогою потужного і сучасно мови Perl6
    У той час як в ansible ви обмежені можливостями чисто декларативного YAML.
  • Скрипто-орієнтований дизайн — завдяки, орієнтованої на використання скриптів схемою, sparrow заохочує розбиття задачі на окремі шматки і написання для кожного окремого шматка скрипта, причому самі скрипти органічно взаємодіють одним з одним, за допомогою, переданих ними один одному параметрів ( те що в sparrow називається історії-модулі У випадку з ansible, ви, як правило обмежені схемою один модуль = один скрипт. Звичайно, і у випадку з ansible ви можете писати в подібному стилі ( декілька скриптів в модулі ), але ansible, звичайно ж, by design не пристосований для такого роду речей.
Отже, в практичному сенсі, часто при вирішення завдань і написанні рутинних скриптів ми розбиваємо проблему на кілька частин і маємо набір скриптів, взаємодіючих друг з дргуом, так чому ж не привнести цей підхід і сюди?
  • Життєвий цикл та управління модулями і плагінами — sparrow плагіни, ще більш обособленны і відокремлені від самого інструменту управління конфігураціями. Як я вже говорив, sparrow плагіни можу використовуватися sparrowdo. Де факто вони розробляються, налагоджують і хостятся і управляються поза рамками даної системи (sparrowdo) і використовуються в ній як чорні ящики. Все це робить процес розробки нових плагінів і їх використання всередині sparrowdo ще більш гнучким і простим.
  • Bash Shell скриптування — sparrow надає кращу, порівняно з ansible підтримку інтеграції звичайних bash shell-скриптів. В силу того, що останній накладає обмеження на дані повертаються і не виводить за замовчуванням потоки STDOUT/STDERR, в ряді випадків стає складно налагоджувати звичайні bash скрипти або розуміти йде не так. У той час як sparrow фактично прозоро транслює весь висновок від скриптів назад у звіт. Також відіграє чималу роль ігнорування в ansible коду завершення роботи скрипта, де на плечі розробника покладається "перевизначення" помилка на рівні повертає JSON. Sparrow в цьому випадку просто генерує помилку, діючи в конвекційному стилі виконання unix/linux команд.
  • Програмний API — sparrow надає уніфікований інтерфейс для всіх мов розробки плагінів. Це означає, що фактично кожен мову зі списку підтримуваних "має одні і ті ж права" з точки зору базового API надається системою. В той час, як модулі ansible здебільшого пишуться на python, в силу того, що підтримка для даного мови найбільш повна ( ansible python modules API )
  • Можливості тестування — sparrow надає вбудовані можливості тестування, що дозволяє дивитися на цей інструмент як на універсальний засіб автоматизації, яку можна використовувати у тому числі ( крім перерахованих ) у завданнях аудиту, моніторингу і тестування.
PS як завжди цікаво почути думку читача і його конструктивну критику. Традиційного опитувальника на цей раз не наводжу, стаття і так вийшла об'ємною.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.