Fabric автоматизация проектов
В очередной раз вызывая длинный набор команд запуска тестов, понял что хватит этих портянок. Первое что пришло в голову просто написать shell скрипт. Быстро, но не особо расширяемо. Хотелось что-нибудь на python. И действительно, оказалось такое есть. Называеться Fabric.
Одно из самых интересных штук которые fabric умеет делать, это ходить по разным хостам через ssh и выполнять команды, а также копировать файлы. При этом мы сохраняем всю мощь и гибкость языка python.
Давайте установим последнею версию.
sudo pip install fabric
Поведение fabric очень похоже на make. В каталоге надо создать файл fabfile.py
. И вызвать его fab task:args task2:args
. Если же надо запустить файл в другой директории, например по cron, надо передать путь в параметре -f
А теперь давайте сделаем простенький скрипт для запуска тестов django проекта.
from fabric.api import env
from fabric.context_managers import lcd, hide, cd
from fabric.operations import local, abort, put, sudo
__all__ = ['test']
env.hosts = [u"user@anotherhost:22"]
env.passwords = { u"user@anotherhost:22" : u"pass" }
def test( app=u"limited", setting=u"settings" ):
"""
Run django test. Args - app=limited, setting=2
"""
local( u"clear" )
local( u"echo '' > app.log" )
local( u"manage.py test {app} --settings={set}; return 0".format(app=app, set=setting))
local( u"cat app.log" )
Давайте посмотрим что тут произошло. Мы объявили задание test
с двумя аргументами. Их можно будет передать так:
fab test:limited,2
fab test:app=limited,setting=setting2
В массиве __all__
мы перечислим какие функции можно использовать как задания. Кстати первая строка комментариев функции идет как документация к заданию. Список всех заданий можно посмотреть так fab -l
. env.hosts
хранит массив все хостов на которые надо зайти и отработать задание. Пароли можно хранить в env.passwords
в виде словаря хост: пароль.
Функция local это исполнение команд только на локальной машине. Для удаленных команд используйте run и sudo. Сначала мы очищаем экран, очищаем лог файл, запускаем тест, выводим лог. Особо дотошные заметят, что в запуске теста есть еще команда return 0
, это такой маленький хак. При обнаружении ошибки в тестах, посылается код ошибки отличный от нуля и fabric делает аборт и не выводит вывод команды.
Теперь давайте напишем что-нибудь поинтересней. Например собрать документацию с sphinx и отправить ее на рабочий сервер.
def docs( ):
"""
Build documentation
If not found '1 warning' in stdout, abort
"""
with lcd( u"docs" ):
with hide( u"stdout" ):
local( u"make clean" )
r = local( u"make html", capture=True )
if r.find( u"1 warning" ) == -1:
abort( u"Not found '1 warning'" )
def deploy_docs( app=u"limitedfm" ):
"""
Deploy documentation to server
"""
docs( )
with hide( u"running", u"stdout" ):
put( u"docs/build/html", u"/var/www/{app}".format( app=app ), use_sudo=True )
Вся прелесть в том что мы можем вызывать другие задания в блоке кода. В этом примере мы написали docs
что бы собрать документацию, а вторым заданием deploy_docs
загрузить полученные странички на сервер. Как можно наблюдать очень удобно управлять выводом команд. Это функции hide, show, settings. Параметром capture
мы сказали подавить вывод команды. Так же мы сделали небольшую проверку. Если в выводе была строка '1 warning' значит все прошло успешно, если же число будет больше мы остановим процесс. В deploy_docs
мы просто залили директорию на удалены сервер. Кстати можно использовать rsync_project для минимизации объема передаваемых данных и увеличения скорости.
Еще можно упомянуть что есть декораторы для ограничения выполнения заданий только на отдельных хостах и простенькая интеграция с dajngo. Мне кажется для старта этого хватит, а все остальное можно посмотреть в документации.