Pull to refresh

Sparrow плагины и Ansible модули — сравнительный анализ

Reading time13 min
Views4.9K

Введение


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
  tasks:
  - 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
  tasks:
    - 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 modules python API )


  • Возможности тестирования — sparrow предоставляет встроенные возможности тестирования, позволяющее смотреть на этот инструмент как на универсальное средство автоматизации, которой можно использовать в том числе ( помимо перечисленных ) в задачах аудита, мониторинга и тестирования.

PS как всегда интересно услышать мнение читателя и его конструктивную критику. Традиционного опросника на этот раз не привожу, статья и так получилась объемной.

Tags:
Hubs:
+7
Comments26

Articles

Change theme settings