Типы задач в Jira: основы, не зная которых рабочие процессы обречены на провал
Рассмотрим главную сущность Jira Software Atlassian — Issue. Она же тикет, таск и задача. Не все
Для удобного процесса разработки, быстрого переключения между проектами и эффективного взаимодействия бекэнд и фронтенд команд мы в WB—Tech работаем в виртуальном окружении Vagrant и VirtualBox.
Vagrant — кросс-платформенное ПО для создания виртуальной среды разработки. Для ускорения развёртывания виртуальной машины можно использовать компилированные, версированные боксы. Версийность боксов в Vagrant описывается при помощи JSON документа.
{ "name": "box_name", "description": "This box description.", "versions": [ { "version": "42.0", "providers": [ { "name": "virtualbox", "url": "http://somewhere.com/precise64_010_virtualbox.box", "checksum_type": "sha1", "checksum": "foo" } ] } ] }
В самом Vagrantfile указать путь к метаданным в атрибуте config.vm.box_url.
config.vm.box = "box_name" config.vm.box_version = "42.0" config.vm.box_url = "http://somewhere.com/path/to/metadata.json"
Лайфхак: при обновлении версии бокса мы используем Nginx с дополнительным модулем, потому что описывать документ каждый раз вручную не практично. Формирование метаданных сделано при помощи простого скрипта на Lua. Мы хостим боксы самостоятельно с помощью Lua.
Lua — скриптовый язык программирования. По возможностям, идеологии и реализации язык ближе всего к JavaScript, однако отличается более мощными и гибкими конструкциями.
Несмотря на то что Lua не содержит понятия класса и объекта в явном виде, механизмы ООП, в том числе множественное наследование, легко реализуются с использованием метатаблиц. Эти таблицы также отвечают за перегрузку операций и прочее.
Реализуемая модель ООП — прототипная (как и в JavaScript). Интерпретатор языка — свободно распространяемый с открытыми исходными текстами на языке C.
Описание приведено для операционных систем семейства Debian.
$ sudo apt-get -y install make nginx-extras lua5.1 luarocks
$ # install lua modules
$ sudo luarocks install luaposix
$ sudo luarocks install JSON4Lua
Фраза “Hello world!” на Lua так же проста, как и на Python.
Lua 5.1.5 Copyright (C) 1994-2012 Lua.org, PUC-Rio > print "Hello world!" Hello world!
Теперь попробуем тоже самое при помощи полнофункционального Nginx Lua API.
server { listen 80; location /hello-world { content_by_lua ' ngx.header.content_type = "text/plain" ngx.say("Hello world!") '; } }
$ curl http://10.1.1.111/hello-world Hello world!
Для исполнения скрипта служит директива content_by_lua, для которого Nginx получает ответ через API. Если скрипт большой, не обязательно описывать его внутри конфигурации, можно подключить через директиву content_by_lua_file.
На сервере мы складываем боксы в директорию hosted, создавая поддиректорию для каждого проекта. Сами боксы со строго указанным форматом имени {provider}-{version.subversion}.box.
Формируется такое дерево.
$ tree hosted/ hosted/ ├── foo │ ├── docker-1.0.box │ ├── docker-1.3.box │ ├── virtualbox-1.0.box │ ├── virtualbox-1.4.box │ └── virtualbox-1.7.box └── bar ├── virtualbox-1.0.box ├── virtualbox-1.1.box └── virtualbox-1.2.box 2 directories, 8 files
Настроим Nginx так, чтобы для любого бокса начиналось скачивание, а для имени проекта возвращались вычисленные метаданные.
server { listen 80; set $box_url 'http://10.1.1.111/%s/%s-%s.box'; set $box_prefix '/home/vagrant/proj/hosted/'; location ~ /*\.box$ { root /home/vagrant/proj/hosted; # just return box } location ~ /(?<box_name>\w+)/?$ { content_by_lua_file /home/vagrant/proj/app/handler.lua; } }
Переменные $box_url и $box_prefix будут использоваться при формировании метаданных.
Теперь сформируем метаданные для версирования Vagrant боксов. Идея в том, что по запросу Lua будет осуществлять поиск сохранённых боксов в заданной директории на сервере, вычислять их хеш-суммы и создавать ответ в формате метаданных Vagrant.
Используя glob из библиотеки posix, найдём все боксы.
local box_root = ngx.var.box_prefix .. ngx.var.box_name .. '/' local posix = require "posix" local glob = posix.glob (box_root .. '*.box') -- Если боксы не найдены, можно сразу возвращать 404 if not glob then ngx.status = ngx.HTTP_NOT_FOUND return ngx.exit (ngx.HTTP_NOT_FOUND) end
Итерациями пройдём по найденным боксам и сформируем словарь с найденными версиями.
local versions = {} -- Discover the boxes for _, box in ipairs (glob) do -- Обрабатываем найденый бокс, определяя версию и формируя описание local provider, version = make_provider (box) if version then if versions[version] == nil then -- Если версия встречается впервые, создаем запись для новой версии versions[version] = { version = version, providers = {provider} } else -- Если версия уже была описана, обновляем список провайдеров table.insert (versions[version]['providers'], provider) end end end
Для вычисления хеш-суммы больших файлов боксов используем утилиты
OC — sha1sum, sha256sum, md5sum с помощью вызова процесса через io.popen.
local hash = 'sha1' function get_hash (filepath) -- Вычисляем хешсумму используя вызов консольной утилиты sha1sum local command = string.format ('%ssum %s | cut -d " " -f1', hash, filepath) local hashsum = assert (io.popen (command, 'r')) local result = string.gsub (hashsum:read ('*a'), '\n', '') hashsum:close () return result end
Функция make_provider выполняется для каждого найденного бокса. Подразумевается, что боксы хранятся на сервере со строго заданным форматом имени: {provider}-{version.subversion}.box
Разбираем версию и имя провайдера, после чего формируем словарь, описывающий данный бокс.
local function make_provider (filepath) -- Make vagrant provider from given file local box_provider, box_version = string.match ( filepath, string.format ('%s(%%a+)-(.+).box', box_root)) return { -- Название провайдера virtualbox или docker name = box_provider, -- Прямая ссылка на бокс, которую будет запрашивать vagrant url = string.format (ngx.var.box_url, ngx.var.box_name, box_provider, box_version), -- Алгоритм хешсуммы sha1, sha256, md5 checksum_type = hash, -- Строка со значением хешсуммы checksum = get_hash(filepath) }, box_version end
Обработав все боксы и сформировав список версий, обернем всё в дополнительный словарь.
-- Make result response local vagrant = { name = ngx.var.box_name, description = string.format ("Boxes for %s proj", ngx.var.box_name), versions = {} } for _, version in pairs (versions) do table.insert (vagrant['versions'], version) end
Ответ сервера JSON с найденными версиями.
ngx.header.content_type = "application/json; charset=utf-8" local json = require "json" ngx.say (json.encode (vagrant))
Полученный скрипт формирует JSON ответ c метаинформацией о боксах.
$ curl http://10.1.1.111/example | jq % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 943 0 943 0 0 13412 0 --:--:-- --:--:-- --:--:-- 13471
{ "versions": [ { "version": "1.7", "providers": [ { "url": "http://10.1.1.111/example/virtualbox-1.7.box", "checksum": "3221c0fd58a4b2430efc5eeaf09cb8eaf877f3a9", "name": "virtualbox", "checksum_type": "sha1" } ] }, { "version": "1.3", "providers": [ { "url": "http://10.1.1.111/example/docker-1.3.box", "checksum": "def7148aa7ded879dbf5944af4785c2b09aba97a", "name": "docker", "checksum_type": "sha1" } ] }, { "version": "1.4", "providers": [ { "url": "http://10.1.1.111/example/virtualbox-1.4.box", "checksum": "63b06d8c065f5c2522c356d4d6ceb718ec3f8198", "name": "virtualbox", "checksum_type": "sha1" } ] }, { "version": "1.0", "providers": [ { "url": "http://10.1.1.111/example/docker-1.0.box", "checksum": "65cb550765d251604dcfeedc36ea61f66ce205c4", "name": "docker", "checksum_type": "sha1" }, { "url": "http://10.1.1.111/example/virtualbox-1.0.box", "checksum": "c0a9d5c3d6679cfcc4b1374e3ad42465f3dd596e", "name": "virtualbox", "checksum_type": "sha1" } ] } ], "name": "example", "description": "Boxes for example proj" }
Полный пример скрипта можно посмотреть в репозитории на Github. И при желании поиграться, запустив настроенный Vagrant
.
Другие статьи серии о о программных решениях, которые мы используем в своей работе:
Если хотите убедиться, что всё делаете правильно или проконсультироваться по поводу разработки вашего проекта, напишите нам.