Справочник

Команды и конфиг

Страница для поиска. Актуально для owlab v0.5.1 и owfeed v0.5.0. Полное описание конфига — schema/v1.json: он генерируется из кода, и его же читает ваш редактор.

owlab — разработка и проверка

КомандаЧто делает
owlab upСобрать и запустить роутеры. --rebuild выбрасывает старые.
owlab downОстановить их. --purge ещё и удаляет образы с дисками виртуалок.
owlab syncСкопировать исходники в живые роутеры и перезагрузить LuCI. --watch делает это на каждое сохранение.
owlab buildСобрать настоящий .apk/.ipk в OpenWrt SDK, положить в dist/<arch>/.
owlab testПоднять, поставить, проверить, погасить, вернуть 0 или 1. То же самое крутится в CI.
owlab installПоставить пакеты на живой роутер — файлом или по имени.
owlab shell / execОткрыть шелл или выполнить одну команду.
owlab logsЛог загрузки и сервисов. -f следит.
owlab openОткрыть LuCI в браузере.
owlab statusЧто запущено и на каких портах.
owlab releasesСравнить ваши пины с тем, что публикуют серверы загрузки.
owlab doctorПроверить машину: порты, ssh-ключи, переводы строк, QEMU, DNS.

Любая команда принимает id роутеров; без них работает со всеми. --config (или -c) можно ставить где угодно в строке. У test, status и releases есть --json.

Утверждения owlab test

owlab test --release 25.12.5 \
  --install 'dist/*/my-app-*' \
  --assert 'http 200 /cgi-bin/luci/admin/services/mine' \
  --assert 'service mined' \
  --assert 'uci mine.@mine[0].enabled' \
  --assert 'package my-app' \
  --assert 'file /usr/share/rpcd/acl.d/my-app.json' \
  --assert 'exec pgrep mined | grep -q .'
ВидПроходит, когда
http <код> <путь>Страница отвечает этим кодом и не является страницей ошибки. 2xx задаёт класс.
service <имя>/etc/init.d/<имя> running подтверждает это, либо ubus.
package <имя>Пакетный менеджер роутера считает его установленным.
uci <путь>Значение выставлено — так проверяют, что uci-defaults пакета отработали.
file <путь>Путь существует на роутере.
exec <команда>Команда вернула 0.

--feed URL вместе с --feed-key FILE ставит пакет по имени из подписанного индекса, а не из файла. --keep оставляет роутеры поднятыми, --json пишет отчёт в stdout.

owfeed — подпись, индекс, публикация

КомандаЧто делает
owfeed initСоздать заготовку owfeed.yml в текущем каталоге.
owfeed keygenСделать ключ подписи фида. С --usign — ключ для манифестов релиза.
owfeed lockВывести матрицу архитектур в owfeed.lock. --update печатает разницу.
owfeed buildУпаковать все пакеты из конфига в dist/<arch>/. Не компилирует.
owfeed signПоложить подпись внутрь каждого пакета.
owfeed indexРазложить пакеты по архитектурам и написать в каждой подписанный индекс.
owfeed doctorПроверить собранное дерево. --require-origin требует, чтобы каждый пакет называл свой репозиторий; --author-keys DIR — чтобы каждый нёс подпись ключом, зафиксированным в DIR.
owfeed smokeПоставить собранный фид на живой образ OpenWrt. --release 24.10 для старой линии.
owfeed verifyПроверить опубликованный фид снаружи, по его же документированному URL.
owfeed publishПропустить дерево через проверки и отдать цели публикации. Флага «всё равно опубликовать» нет.
owfeed releaseПодписать собранные пакеты и написать подписанный манифест для фида.
owfeed verify-artifactПроверить чужой релиз по подписи его автора.
owfeed install-snippetНапечатать инструкцию, по которой подписываются ваши пользователи. --format sh — только команды.
owfeed releasesЧто публикует сервер загрузки по каждой линии и в каком формате.

Глобальные флаги: -C DIR, --config PATH, --cache DIR, --frozen-lock, --no-network, -v.

Обычный порядок — build → sign → index → doctor. Каждый шаг принимает каталог и оставляет каталог. Подпись дописывает байты, поэтому индекс, собранный до подписи, перестаёт сходиться с файлами.

owlab.yaml

version: 1

project:                      # необязательно — только если sync надо подсказать
  install:                    # путь в исходниках → путь на роутере
    my-package/htdocs: /www
  build: ./build-css.sh       # выполнить перед каждым sync
  post_sync: |                # выполнить на роутере после каждого sync
    uci -q commit luci
  theme: footstrap            # выбирать эту тему после каждого sync

defaults:                     # подмешивается в каждый роутер ниже
  packages: ["+luci-app-sqm", "-ppp"]
  fixtures: [all]             # выдумать сети, клиентов, аренды DHCP
  extra_packages:             # поставить по URL, а не из фида
    - name: luci-app-example
      apk: https://…/luci-app-example-1.4.0-r1.apk
      ipk: https://…/luci-app-example-v1.4.0-r1-all.ipk

routers:
  - id: owrt2512
    release: "25.12.5"        # точные номера релизов
    distro: openwrt           # или immortalwrt
    fidelity: vm              # basic (контейнер) или vm (QEMU, настоящее ядро)
    ports: { http: 8080, ssh: 2222 }
    memory: 512M
    radios: 2                 # только vm — mac80211_hwsim

Незнакомые ключи считаются ошибкой намеренно, поэтому опечатка падает при загрузке, а не игнорируется молча.

owfeed.yml

version: 1

feed:
  name: my-feed               # из имени выводятся все остальные имена файлов
  url: https://feed.example.org
  maintainer: "Вы <you@example.org>"

releases:
  - line: "25.12"
    default: true             # эту линию рекламирует install-snippet
    format: apk
    arches: auto              # берётся с downloads.openwrt.org
  - line: "24.10"
    format: ipk

signing:
  key: env:OWFEED_SIGN_KEY    # EC prime256v1, подписывает индексы и пакеты apk
  usign-key: env:OWFEED_USIGN_KEY   # usign, подписывает индексы opkg
  sign-packages: true         # false: подписывать только индекс, не чужие файлы
  author-keys: ./keys         # каждый пакет обязан быть подписан ключом отсюда
  keyring-package: true       # выпускает -keyring, который везёт ключ на роутеры
  also-sign: []               # на время ротации: старый ключ, чтобы подписи ехали обе

packages:
  - name: luci-app-mine
    build: mkpkg              # упаковать разложенный каталог; owfeed не компилирует
    arch: noarch              # никогда не "all" — apk его отвергает
    version: 1.0.0-r1         # либо version-from: makefile:./Makefile
    files: ./staging/luci-app-mine
    conffiles: ["/etc/config/mine"]
    depends: ["luci-base"]
    i18n: { from: ./po }      # компилирует .po в .lmo, который читает LuCI
    releases: ["25.12"]       # без этой строки пакет идёт во все линии

Полный список полей с описаниями: schema/v1.json. Добавьте эту строку в начало конфига, и редактор начнёт подсказывать и проверять:

# yaml-language-server: $schema=https://owfeed.org/schema/v1.json

Переменные окружения

ПеременнаяЧьяЗачем
OWFEED_SIGN_KEYowfeedКлюч EC, которым подписываются индексы и пакеты apk.
OWFEED_USIGN_KEYowfeedКлюч usign, которым подписываются индексы opkg. Это только соглашение: signing.usign-key называет любую переменную, значения по умолчанию нет.
OWFEED_RELEASE_KEYowfeedКлюч usign, которым подписывается манифест релиза.
OWFEED_RELEASE_DATEowfeedЗадать время в манифесте, чтобы сборка была воспроизводимой.
OWLAB_CONFIGowlabГде лежит owlab.yaml.
OWLAB_PUBKEYowlabКакой публичный ключ ставить на роутеры. По умолчанию все ~/.ssh/id_*.pub.
OWLAB_ROOT_PASSWORDowlabЗадать пароль root. По умолчанию пароля нет.

Коды возврата owfeed

CI может повторить попытку при недоступности апстрима, но не должен повторять проваленную проверку. Поэтому 7 и 8 — разные коды.

КодЧто значит
0Успех
1Внутренняя ошибка — баг либо то, что инструмент не смог классифицировать
2Ошибка в конфиге
3Сборка не удалась
4Проблема с ключом
5Не собрался индекс
6Не удалась публикация
7Проверка провалена — повторять нельзя
8Апстрим недоступен — повторить можно
9owfeed.lock разошёлся с апстримом

Словарь

apk
Пакетный менеджер OpenWrt начиная с 25.12. Читает один бинарный индекс на архитектуру и проверяет его по ключу из /etc/apk/keys.
opkg
Пакетный менеджер на 24.10 и старее. Читает текстовый индекс и проверяет его через usign. Форматы apk он не понимает совсем.
фид (feed)
Каталог с пакетами и подписанными индексами, отданный по HTTPS. Ни серверного софта, ни базы данных: подойдёт что угодно, что умеет отдавать статические файлы.
индекс
Файл со списком всех пакетов фида, их версий и хешей. У apk это packages.adb, у opkg — Packages и Packages.gz. Доверие живёт здесь: индекс подписан, а каждый пакет сверяется с хешем, который в нём записан.
noarch и all
Два названия для пакета, который работает на любой архитектуре. apk требует noarch и отвергает all как неустановимое, opkg знает только all. Поэтому одна сборка пишет и dist/noarch/, и dist/all/.
usign
Схема подписи на ed25519, которая уже есть в OpenWrt, так что роутер проверяет подпись без единого установленного пакета. Ею подписывают индексы opkg и манифесты релизов. Ключи ищутся по id, поэтому для opkg важно имя файла ключа.
conffiles
Список конфигурационных файлов, которыми владеет пакет. Всё, что лежит в /etc/config/ и не объявлено здесь, молча заменяется вашими значениями по умолчанию на каждом обновлении прошивки.
.lmo
Скомпилированный формат переводов, который читает LuCI. Класть в пакет .po бесполезно: укажите на них i18n.from:, и они скомпилируются при сборке.
sysupgrade
Обновление прошивки с сохранением заранее перечисленных файлов. /etc/apk/keys/*.pem и список репозиториев в этот перечень по умолчанию не входят — перечислите их в /lib/upgrade/keep.d/<feed>, который sysupgrade читает наравне с /etc/sysupgrade.conf.
dist/<arch>/
Контракт артефактов: один каталог на архитектуру, названный так, как её пишет downloads.openwrt.org. Архитектура — это каталог, а не имя файла.
-r<n>
Ревизия пакета, всегда в конце версии. После ~ apk читает хеш коммита, поэтому там допустимы только шестнадцатеричные цифры: пишите 1.0_beta1, а не 1.0~beta.