snapper: настройка снимков подтомов

Показать список подтомов можно командой btrfs subvolume list /. Выберем какой-нибудь, например /var/lib/pgsql.
Создадим новую конфигурацию (профиль) для этого подтома: snapper -c pgsql create-config /var/lib/pgsql, здесь pgsql произвольное имя:
# snapper list-configs
Config | Subvolume     
-------+---------------
root   | /             
pgsql  | /var/lib/pgsql

Далее, все команды нужно выполнять с ключом -c pgsql, чтобы оперировать нужным профилем.

# snapper -c pgsql get-config
...      
NUMBER_CLEANUP         | yes           
NUMBER_LIMIT           | 50            
NUMBER_LIMIT_IMPORTANT | 10            
NUMBER_MIN_AGE         | 1800          

Здесь NUMBER_CLEANUP разрешает удалять старые снимки если их число превышает NUMBER_LIMIT и одновременно возраст (в секундах) больше NUMBER_MIN_AGE.

TIMELINE_CLEANUP       | yes           
TIMELINE_CREATE        | yes           
TIMELINE_LIMIT_DAILY   | 10            
TIMELINE_LIMIT_HOURLY  | 10            
TIMELINE_LIMIT_MONTHLY | 10            
TIMELINE_LIMIT_YEARLY  | 10            
TIMELINE_MIN_AGE       | 1800

Здесь соответствующая настройка разрешает автоматическое создание снимков раз в час. Команда TIMELINE_CLEANUP удаляет старые снимки, используя следующие правила: удаляется снимок только если он старше TIMELINE_MIN_AGE секунд и одновременно после удаления останутся TIMELINE_LIMIT_* снимков с соответствующими интервалами.
Таким образом, в вышеописанном стандартном случае всегда будут доступны снимки: 10 с интервалом в час с текущего момента, 10 с интервалом в один день с текущего момента, 10 с интервалом в один месяц и так далее.

Конвертация CVS в Mercurial

В системе контроля версий CVS есть так называемые модули с амперсандом, представляющие собой поддиректорию общую для нескольких модулей. Концепция похожая на сабмодули в git или сабрепозитории в mercurial.

Поскольку CVS немного устарел, нужно куда-то переехать. К сожалению, правильную работу с моделями с амперсандом не поддерживает ни одна из найденных утилит миграции. Об инкрементальной миграции (когда существуют два параллельных репозитория (разных систем контроля), которые каким-то чудом остаются друг с другом синхронизированы) тоже придется забыть.

Краткая схема действий. Сначала все модули из CVS конвертируются в формат fastimport, далее полученные дампы преобразуются и конвертируются в mercurial. Mercurial имеет в данной ситуации преимущество над git в том, что сабрепозитории управляются просто служебными файлами в дереве репозитория.

Все CVS модули можно разделить на две категории: те, которые содержат в себе модули с амперсандом, и те, которые нет (сами являются ими). Второй набор конвертируется просто. Для преобразования первого набора нужно пойти в cvsroot и вставить символические ссылки в те места, где должны были быть директории, соответствующие модулям с амперсандом. После преобразования каждый модуль из первого набора потеряет связь со своими вложенными модулями, и файлы с путями, соответствующими им, окажутся преобразованы несколько раз — один раз в репозитории относящимся к вложенному модулю и по разу в каждом репозитории модуля первого типа. Перед импортом в mercurial данная связь будет восстановлена.

Использование cvs2git из пакета cvs2svn не требует особой внимательности, кроме параметра COMMIT_THRESHOLD который склеивает коммиты. Дело в том, что в CVS каждый файл имеет свою историю, а в формате fast-import (как в git и mercurial) историю имеет весь репозиторий, поэтому отдельные изменения файлов надо слепить в прообразы будущих коммитов. По-умолчанию COMMIT_THRESHOLD равен 5 минутам, это значит, что изменения всех файлов попадающих в пятиминутное окно будут слеплены в один коммит.
Кроме того, можно задать отображение тегов, отображение авторов и другие параметры.

Для преобразования из формата fastimport в репозиторий mercurial используется расширение hg-fastimport. Отметим, что изначальный автор забросил этот проект и считает его неудачным, а более правильным подходом к преобразованию называет другой свой проект. Видимо поэтому расширение очень странным образом обрабатывает TAG.FIXUP ветви (в CVS можно было накладывать теги на те ревизии файлов, которые во времени друг с другом вообще никогда не встречались, поэтому для отображения таких тегов создается отдельная специальная ветка), что обычно требует подправления кода.

Формат fastimport представляет из себя файл (или несколько), задающий дерево репозитория в топологическом порядке. Каждый узел дерева, который затем станет коммитом, помечается уникальным текстовым идентификатором, например ":1000000003". После преобразования модулей второго типа в соответствующих новых репозиториях будет лежать файл .hg/shamap, с отображением коммитов mercurial в идентификаторы fastimport. Кроме того, каждый узел дерева в текстовом виде содержит список измененных файлов, например
M 100644 :30 sub/Makefile
здесь :30 — маркер блоба, т.е. фактически содержания файла. Используя путь файла можно идентифицировать все файлы занесенные к нам из вложенных модулей. Нам бы хотелось преобразовать fastimport дамп таким образом чтобы в этих местах возникли ссылки на внешние репозитории, например так
M 160000 2d1eb0523f244f7bb1d58f016583a25ba3d40426 sub

Для этого предлагается следующих алгоритм. У нас есть два дерева в виде дампов fastimport: дерево вложенного репозитория и дерево основного. Кроме того, есть отображение маркеров узлов вложенного репозитория на хэш коммита. Обойдя каждое из деревьев для каждого узла, мы можем полностью восстановить состояние, т.е. набор всех существовавших файлов и их содержимое. Кроме того, для основного репозитория возможно определить состояние вложенной директории (будущего сабрепозитория). На рисунке схематично изображены узлы основного дерева (пронумерованы арабскими цифрами) и узлы дерева сабрепозитория (пронумерованы латинскими буквами). Черными стрелками показана очередность коммитов, стрелка идет от более нового коммита к его предку.
Далее, сравнивая состояния вложенного репозитория и соответствующие под-состояния основного репозитория, можно построить отображение узлов основного дерева на вложенное (красные стрелки на рисунке).

Возможны ситуации когда связь многозначная. Вообразим, что в предложенном примере G откатывает F, поэтому имеет такое же содержимое что и E, кроме того, в другой ветке есть C с таким же содержимым. Сообщения коммитов могут отсутствовать, время коммитов может отличаеться. В данной ситуации предлагаются следующие критерии разрешения конфликта.

Так как основное дерево обходится в топологическом порядке, то к моменту когда мы оказывается в узле 5 узел 4 уже обработан и мы знаем что ему соответствует узел D. Для всех возможных кандидатов C, E, G рассчитаем расстояние между ними и узлом D. Узел D не достижим из C, поэтому C отбрасывается. Оставшийся выбор производится на основании сообщения коммита и близости времени. Либо можно представить простой алгоритм, который за не полиномиальное время назначит соответствие, однако без информации о времени и сообщениях коммитов все-равно не обойтись.

Таким образом, у нас есть отображение меток дерева основного репозитория на метки (или хэши) вложенного репозитория. Этой информации достаточно, чтобы заменить все нужные вхождения об изменениях файлов в дампе. После этого, дамп можно скормить в hg-fastimport.

Наиболее удобным способом расположения иерархии репозиториев на сервере оказался следующий. Каждый вложенный репозиторий кладется в корень иерархии, кроме того, в каждый проект. Причем этим вторичным клонам мы запретим запись. А на первичный репозиторий навесим хуки, которые будут дергать pull во всех клонах.
[extensions]
hgext.acl=

[hooks]
pretxnchangegroup.acl = python:hgext.acl.hook

[acl]
sources = serve push bundle

[acl.deny]
** = *

[paths]
default = /repos/subrepo

OBS: локальная сборка под ARM

Когда требуется локально пересобрать пакет под одну из архитектур ARM, например для тестирования сборки, можно воспользоваться следующим медленным подходом.

osc build --clean --alternative-project openSUSE:Factory:ARM qemu armv7l name.spec

Здесь указывается, что используется альтернативный проект для сборки — openSUSE:Factory:ARM (версию подставить по желанию), используется репозиторий qemu, который есть в этом проекте. Поэтому и указывается этот альтернативный проект.

Несмотря на то, что в данном примере указана архитектура armv7l, технически, это x86_64. В среду сборки будет установлен бинарный транслятор qemu, работающий через подсистему ядра binfmt. При инициализации ядро настраивается таким образом, что при виде сигнатуры ELF для архитектуры ARM вызывает бинарик как qemu-arm /usr/bin/..., подобно тому, как при виде символов "#!" в начале исполняемого файла вызывается указанный интерпретатор. Работает поэтому достаточно медленно.

К сожалению, с пакетами kiwi такое не проходит.

Сетевой стек на ATSAMD20

В предыдущих выпусках рассматривалась демонстрационная плата на базе 32-битного микроконтроллера ATSAMD20. Далее рассмотрим как прикрутить к нему сетевое приложение. Так как сам микроконтроллер не снабжен интерфейсом Ethernet, возьмем какое-нибудь готовое решение на базе ENC28J60 и прикрутим его через SPI.

Нам понадобится:
  • Atmel Software Framework — распространяемая под странным образом модифицированной BSD лицензией библиотека, реализующая удобный уровень индирекции при работе с переферией микроконтроллеров Atmel. Мы ей воспользуемся для работы через SPI. Внутри библиотеки весьма красивый код, понятный API и гора документации, исполненной в doxygen. Поэтому, основываясь на чувстве прекрасного, будем её использовать.
  • ec28j60driver — драйвер для ENC28J60, реализует высокоуровневые функции работы с Ethernet путем обмена через SPI. Возьмем этот, потому-что написан он не левой пяткой и был достаточно легко портирован для работы с Atmel Software Framework. (см. ветку asf)
  • lwIP — легковесный стек TCP/IP. Он отсылает или принимает Ethernet-пакеты через драйвер устройства и дальше разбирается что-же там внутри пришло. На сайте присутствует куча примеров.

Настройки для lwIP следующие:

lwoptions.h:
#define MEM_LIBC_MALLOC 1
#define MEMP_MEM_MALLOC 1
#define MEM_ALIGNMENT 4

cc.h:
#define BYTE_ORDER  LITTLE_ENDIAN

Стиль программирования приложений, определяемый использованием RAW API библиотеки lwIP, через 5 минут создает полное ощущение, что ты пишешь gen_server на erlang, но последний почему-то кривой, неудобный и недоделанный.

Далее в таблице приводится размер кода прошивки, получаемый при различных вариантах конфигурации:
config -O3 -Os
TCP/IP + DHCP + DEBUG(printf) 96k 82k
TCP/IP + DHCP 54k 40k
TCP/IP 45k 36k
UDP/IP + SNMP 54k 43k
UDP/IP 28k 24k

Как-то так оно и работает.

openSUSE 13.1 на BeagleBone Black

BeagleBone Black — одноплатный компьютер на основе процессора TI AM3358 (Cortex-A8), выпущенный весной прошлого года:

На нем вполне успешно может загрузиться и даже работать openSUSE 13.1. Готовые образы для нанесения на microSD карточку находятся здесь. Эти же самые образы должны в теории работать и на BeagleBone. Конечно, пока все на этапе интеграции и поиска ошибок, поэтому имеется подробная инструкция по запуску:
  1. Скачать, распаковать и сделать dd на карточку образ системы *.raw.xz
  2. Подключить отладочный TTL-RS232 порт (можно использовать, например, такой, но важно помнить, что разработчики BeagleBone Black не поставили на свою плату преобразователь уровней и сигнал с отладочного RS232 идет в виде 3.3V. Подключение через обычный COM-порт на большом компьютере обречено на провал.), руководствуясь распиновкой. Используя screen /dev/ttyUSB0 115200, во-первых, можно будет легко видеть все этапы начиная от работы u-boot. Во-вторых, запустится Yast2 firstboot и попросит вас задать root пароль, завести пользователя, установить временную зону и системное время (аналогично тому, как это происходит на соответствующем этапе установки с DVD), а для этого потребуется интерактивное взаимодействие.
  3. Помните, что для загрузки с внешней карты памяти при подаче питания на устройство нужно удерживать кнопку S2 (она же boot select switch). Подсказка — загрузившись с SD карты можно подмонтировать раздел встроенной MMC памяти и переименовать или удалить файл загрузчика MLO, после этого загрузка будет всегда начинаться с SD, но загрузиться с MMC больше не получится.

Технические подробности (тем, кто хочет продолжить ковыряния) изложены в списке рассылки: http://lists.opensuse.org/opensuse-arm/2014-01/msg00001.html.