[devel] Hey, I've got a hasher in my pocket!
Paul Wolneykien
manowar на altlinux.org
Пн Дек 8 00:41:37 MSK 2014
Всем привет,
Речь пойдёт не совсем о «карманах» [1], а скорее о «кармашках» -- на
большее пока не замахиваюсь. Но тем не менее. Есть у меня
производственная необходимость получить в руки примерно такой вот
инструмент:
$ # Открываем карман для сборки пакетов в ~/pocket:
$ pocket init debian:stable pocketserver:a-product-repo
$ # В качестве источника пакетов при этом подключаются два
$ # репозитория: один -- дистрибутив "stable" из репозитория
$ # "Debian", а второй -- опубликованный на узле "pocketserver"
$ # репозиторий с микро-дистрибутивом "a-product-repo".
$ # Предполагается, что на pocketserver публикуются стабильные
$ # версии микро-дистрибутивов, т.е. таких наборов пакетов,
$ # которые дополняют базовый дистрибутив ОС "продуктовыми"
$ # функциями.
$ # Система догадывается, что собирать мы будем *.deb-пакеты.
$ # Либо потому, что мы работаем под Debian, либо потому, что
$ # первым источником пакетов у нас идёт "debian". Для особо
$ # тяжёлых случаев предусмотрена опция --flavour. Предполагается,
$ # что можно будет сказать --flavour=altlinux и --flavour=debian.
$ # Карман открыт, будем собирать туда пакеты. Примерно так:
$ git clone srv:somelib.git
$ cd somelib
$ vim ...
$ pocket build
$ # Допустим, что оно не собралось или собралось как-то не так.
$ # Чиним. Примерно вот так:
$ pocket sync
$ vim ...
$ pocket sync
$ # Предполагается, что по команде "sync" машина сама понимает
$ # в каком направлении копировать файлы: сперва из чрута в
$ # текущую, а затем наоборот (т.к. файлы в текущей теперь
$ # немного новее). Ошибка поправлена -- снова собираем. Точнее
$ # "дособираем" -- продолжаем процесс сборки с того места,
$ # где он прервался:
$ pocket build
$ # Будем считать, что на этот раз всё прошло успешно -- пакет
$ # собрался. Но мы хотим удостовериться и поэтому пересобираем
$ # его с нуля:
$ pocket rebuild
$ # Ура! Пакет пересобрался вчистую, т.е. с разворотом чрута
$ # с нуля. И лежит somelib_newver.deb в этом самом кармане
$ # (~/pocket).
$ # Повторяем процесс для someprog, которая основана на somelib:
$ cd ..; git clone srv:someprog.git; cd someprog; pocket build
$ # Естественно, что someprog у нас собирается с новой версией
$ # somelib, т.е. карман является дополнительным и самым
$ # приоритетным источником пакетов для самого себя. И теперь
$ # у нас в кармане два свежесобранных пакета: somelib_newver.deb
$ # и someprog_newver.deb. И теперь надо бы проверить, что мы
$ # там такого насобирали, работает ли оно вообще? Для этого
$ # публикуем карман под именем a-product-YYYYDDMM:
$ pocket publish /pockets/a-product-YYYYDDMM --mirror
Mirroring http://pocketserver/a-product-repo ...
Merge-in local packages:
Replacing somelib: oldver -> newver
Replacing someprog: oldver -> newver
Your pocket is available at http://myhost/pockets/a-product-YYYYDDMM
$ # Может быть даже "pocket open", посмотрим. По этой команде
$ # карман принимает вид полноценного репозитория, доступного
$ # снаружи как http://myhost/pockets/a-product-YYYYDDMM и
$ # пригодного для `apt-get update/install`. Здесь важно отметить,
$ # что опция `--mirror` привела к тому, что по указанному адресу
$ # опубликовано не только содержимое самого кармана, но и его
$ # целевого репозитория, каковым является "a-product-repo" с узла
$ # "pocketserver". Но зеркалится целевой репозиторий не как был,
$ # а с изменениями: с новыми, свежесобранными версиями somelib и
$ # someprog. (Кстати, а как можно было бы таким образом ещё и
$ # удалять пакеты, т.е. делать так, чтобы в новой копии целевого
$ # репозитория они отсутствовали? Можно через Conflicts/Obsoletes,
$ # наверное. Но явный способ удаления тоже нужен. Ещё не придумал
$ # как.)
$ # Тестируем новую версию "a-product-repo" на узле "testhost":
$ ssh root на testhost
[root на testhost ~]# # Вписываем опубликованный a-product-YYYYDDMM
[root на testhost ~]# # в sources.list:
[root на testhost ~]# vim /etc/apt/sources.list
[root на testhost ~]# # Обновляемся и проводим тестирование:
[root на testhost ~]# apt-get update
[root на testhost ~]# apt-get dist-upgrade
[root на testhost ~]# someprog --test
OK
[root на testhost ~]# exit
$ # Будем считать, что тестирование завершилось удачно. А это
$ # значит, что можно включать новые сборки в стабильный
$ # репозиторий на pocketserver:
$ pocket commit -m "New versions of somelib and someprog"
New build task #00101 at pocketserver
$ # Предполагаем, что система опять догадалась, что целевым
$ # репозиторием у нас является "a-pocket-repo", а сборочный
$ # сервер "pocketserver" обладает каким-то стандартным
$ # интерфейсом для засылки пакетов на сборку. Изменения
$ # отправляются пачкой: после обработки сборочного задания
$ # репозиторий на pocketserver должен прийти в соответствие
$ # с недавно опубликованным "a-product-YYYYDDMM" (если конечно
$ # не было других изменений от других пользователей).
Кроме функций, включённых в воображаемую демонстрацию выше, было бы
хорошо иметь ещё и `pocket snapshot`, которая позволяла бы
"замораживать" различные версии кармана на протяжении сеанса работы с
ним, и затем публиковать, а также отправлять на сборку такие именованные
версии. На мой взгляд, это было крайне удобно для тестирования, когда
приходится собирать несколько версий одного и того же пакета, например,
с различным вариантом фикса, и уже на месте выяснять, какая же версия
оказалась лучше. В связи с этим вторая штука, которой не нашлось места в
воображаемой сессии -- это автоподнятие релизов. Каждая сборка пакета в
карман попадает в него с обновлённой версией релиза, причём релиз
временно принимает в этом случае форму oldrel-YYYY-DD-MM-n, где n --
собственно автоинкрементное поле, а перед ним -- дата, перед ней --
старый номер релиза. Это, опять же, удобно при тестировании -- можно
отмечать, какая именно сборка оказалась удачной. И `apt-get
dist-upgrade` обновит пакет без специальных пинков. А при отправке
задания на сборочный сервер этот дополнительный хвост к номеру релиза
убирается.
А ещё `pocket shell`, конечно.
Примерно так. За основу взял hasher-priv, который без вопросов
собрался и работает на Debian, за что ldv@ отдельное большое спасибо! А
дальше, видимо, make, потому как "система рецептов" показалась мне для
решения этой задачи очень даже уместной.
На сегодняшний день добился того, что базовая система ставится в чрут
посредством debootstrap, более-менее стандартным образом, но под
управлением hasher-priv. И в этот чрут потом можно сходить через
`hasher-priv chrootuid1 fakeroot ...`. В качестве статических утилит для
взлёта была использована busybox-static. Как оказалось, в Debian она
очень кстати умеет кое-что из dpkg.
Исходный код:
http://git.altlinux.org/people/manowar/private/pocket.git
Павел.
P.S. Вероятно это -- очередной велосипед. Но я вот что-то не нашёл
пока способа сборки в изолированном окружении, такого же простого как
hasher. :-) Почему-то всем этим штукам или нужен root, или какие-нибудь
спецправа на супервизор. А ещё, конечно, хочется разных вышеописанных
вкусностей. Чтобы workflow был не сервероцентричным, а юзероцентричным!
Может быть даже межпользовательски-дружелюбным. :-)
---
[1] http://www.altlinux.org/Pockets
Подробная информация о списке рассылки Devel