- Установка патчей в Linux – работа с утилитой patch
- Что такое патч?
- Синтаксис и основные опции команды patch
- Применение патчей к отдельным файлам
- Работа с проектами
- OTA обновление устройств с Linux
- Вступление
- Workflow
- 0. Сервер
- 1. Установка чистой ОС
- 2. Подготовка эталонного (golden) образа
- 3. Копирование эталонного образа
- 4. Преобразование эталонного образа при помощи mender-convert
- 5. Подготовка устройства (provisioning)
- 6. Авторизация устройства
- 7. Подготовка пакета обновления (artifact)
- 8. Deploy
- Выводы
Установка патчей в Linux – работа с утилитой patch
Практически каждый разработчик программного обеспечения (ПО), программист или верстальщик сталкивается (и довольно часто) с необходимостью модификации некоторой части рабочего проекта или даже нескольких строк кода. Особенно это актуально, когда в разработке участвует несколько человек, которые могут вносить правки в разных частях проекта. Для удобства и автоматизации действий по составлению таких правок используются специализированные утилиты. Одной из таких является утилита patch и о ней более подробно будет рассказано в данной статье.
Что такое патч?
Говоря о патчах вкупе с утилитой patch, следует подразумевать, что это касается исключительно текстовых данных. Другими словами, происходит работа с исходными кодами проекта, будь то код C++, PHP, HTML и т. д. Вообще, все самые «суровые» программисты или разработчики в процессе своей совместной работы над проектом обмениваются исключительно отдельными правками, а не пересылают друг другу актуальные версии проектов целиком.
Сама правка, т. е. текстовые изменения в исходном коде проектов (для одного его файла или сразу для нескольких) и есть патч или «заплатка». Патч, помимо самих изменений кода содержит также и некоторую служебную информацию, необходимую для правильного «наложения заплатки», т. е. для установки патча. Таким образом, патч — это текстовый файл определённого формата, содержащий в себе данные и инструкции для приведения конечного файла (или проекта) к нужному или актуальному виду.
Утилита patch умеет быстро и эффективно распоряжаться данными из файла-патча, используя для этого хранящиеся в нём инструкции. И таким образом выполняет все рутинные действия по редактированию. Пользователю (разработчику) необходимо лишь правильно выполнить соответствующую команду, задав все необходимые аргументы и опции.
Синтаксис и основные опции команды patch
Нет ничего удивительного в том, что утилита patch относится к категории ПО, которое обязательно должно быть установлено на любой машине для разработки программ, да и вообще для ведения разработки. Практически любой дистрибутив Linux предоставляет утилиту patch предустановленной по-умолчанию.
Стоит также отметить, что по своей функциональности, patch довольно сложна и обладает, без преувеличения, просто огромным набором опций. По этой причине в данной статье будут приведены только самые распространённые приёмы при работе с этой утилитой и только сопутствующие им опции команд. Синтаксис команды patch следующий:
Здесь originalfile – это файл, который необходимо «пропатчить» до актуального состояния. А patchfile – файл-патч. Сразу возникает вопрос: а откуда берётся этот файл-патч? Ответ: он генерируется другой утилитой — diff, которая находит построчные различия между файлами. Либо же патч может быть составлен вручную, автором, если он знаком с соответствующим форматом. Но это бывает крайне редко, обычно прибегают к помощи diff или её аналогов.
В следующей таблице приведены опции команды patch, которые используются наиболее часто:
Опция | Значение |
-i patchfile | Читает информацию из патч-файла, указываемого параметром patchfile. |
-r rejectfile, —reject-file=rejectfile | |
-N, —forward | Когда патч не применяется, то утилита patch обычно пытается определить, выглядит ли ситуация так, как если бы патч уже был применён. Опция -N отключает такое поведение. |
-pnum, strip=num | Обрезает части пути к файлу, разделяемые символом косой черты до уровня, указанного в параметре num. Например: p0 оставит путь /u/john/src/blurfl/blurfl.cpp неизменным, а p4 обрежет тот же путь до blurfl/blurfl.cpp. |
-o outputfile, —output=outputfile | Отправляет вывод в указываемый в параметре outputfile файл. Не следует использовать эту опцию, если в качестве outputfile указывается файл, который должен быть пропатчен. Если в качестве outputfile указать символ дефиса «-», то вывод будет направляться в стандартный поток STD_OUT. |
-E, —remove-empty-file | Удаляет файлы, оказавшиеся пустыми после применения патча. Эта опция имеет смысл, когда используемые патчи имеют не контекстный формат. |
—dry-run | Печатает результаты применения патча без реальной модификации файлов. Полезно для быстрого и безопасного тестирования патчей. |
-R, —reverse | Откатывает все изменения (если они возможны), т. е. отменяет установку патча. |
-c, —context | Интерпретирует файл патча как обычный контекстный формат, генерируемый утилитой diff. |
-b, —backup | Создаёт резервную копию оригинального файла вместо его удаления. |
Применение патчей к отдельным файлам
Прежде, чем начать рассмотрение практических примеров, необходимо сказать несколько слов о той самой утилите, которая и создаёт патчи — diff. Она может генерировать патчи трёх типов — простой, контекстный и контекстный унифицированный. Простой гораздо более компактный по размеру, чем контекстные, но последние гораздо более удобочитаемы и понятны для восприятия пользователем. Для того, чтобы сгенерировать простой патч, для команды diff никаких специальных опций не требуется. А для генерации контекстного или унифицированного контекстного патчей предназначены опции -с и -u соответственно:
Пусть имеется файл с кодом C++ ChildClass.cpp:
И пусть в этот файл было внесено следующее изменение: метод valueSqr() был переименован в calcSqr(). Тогда контекстный патч (файл contextpatch) будет выглядеть следующим образом:
Теперь, чтобы пропатчить старую версию ChildClass.cpp, нужно выполнить команду:
В результате будет получен файл ChildClass_new.cpp с актуальным содержимым.
Работа с проектами
С помощью утилиты patch можно также применять патчи для нескольких файлов, причём расположенных в разных каталогах. Это удобно, когда изменения проводятся в масштабах целого проекта. Но в этом случае и сам патч должен быть особым образом подготовлен утилитой diff.
Пусть имеется старый проект в каталоге base-project. Внутри него имеются подкаталоги include и src, в которых, в свою очередь находятся файлы с изменениями — ChildClass.h (в каталоге include) и ChildClass.cpp (в каталоге src). Сам изменённый (актуальный) проект был помещён в отдельный каталог new-project. Подготовка патча будет выглядеть следующим образом:
Сгенерированный файл-патч project-patch:
Следует обратить внимание, что в данных примерах указываются относительные пути. Файл-патч будет помещён в текущий активный каталог.
Чтобы применить патч нужно выполнить следующую команду:
Как видно, вместо ключа -i можно использовать символ «
Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.
Источник
OTA обновление устройств с Linux
Вступление
Недавно у меня возникла задача обновлять удалённо некоторое двузначное число IoT-устройств с Linux через интернет. Задачу нужно было решить быстро. Времени и желания изобретать что-то своё не было совсем. Устанавливать обновления вручную по ssh — нереально. Автоматизировать установку по ssh тоже, устройства могут неожиданно выключаться или терять сеть.
Поиск решений по обновлению IoT устройств показал, что, судя по всему, мне больше всего подходит Mender:
end-to-end решение — клиент + сервер + инструменты
A/B обновление rootfs — на устройстве есть два одинаковых раздела rootfs A и B. Система загружается с активного раздела A, устанавливает обновление на раздел B, загружается с раздела B и в случае успеха делает его активным. В случае неудачного обновления активным остаётся раздел A.
работает с debian и yocto
не использует контейнеры
есть open-source версия под лицензией Apache v2
На сайте проекта можно почитать как всё это работает.
Кстати, Mender уже упоминался на хабре в статье @MooooM, но внедрить его тогда не получилось.
Workflow
Я продемонстрирую процесс обновления системы на примере Raspberry Pi 3B c Raspberry Pi OS. Карта памяти от 8 ГБ и выше.
В качестве сервера Mender будем использовать бесплатный демо-сервер hosted.mender.io (не более 10 устройств и 12 месяцев работы).
Подготовка образов будет производится на компьютере с Ubuntu 20.04.
В своей документации Mender рекомендуют примерно такой подход для устройств с debian:
Установка чистой ОС
Подготовка эталонного образа
Копирование эталонного образа на ПК
Преобразование эталонного образа при помощи mender-convert
Подготовка устройства (provisioning)
Подготовка пакета обновления (artifact)
Развёртывание обновления (deploy)
0. Сервер
1. Установка чистой ОС
Включаем последовательную консоль /boot/config.txt : enable_uart=1
2. Подготовка эталонного (golden) образа
Вставляем SD-карту в устройство(Raspberry Pi 3B) и подключаемся по uart при помощи minicom.
Меняем стандартный пароль при помощи raspi-config .
Настройте и проверьте подключение к интернету. Я подключил свою Raspberry по ethernet (не совсем over-the-air, знаю).
Создадим директорию /data , в которой будут храниться данные, которые должны сохраняться при обновлении образа системы.
Положим туда текстовый файл important_file.txt содержащий одну строку hello_habr .
3. Копирование эталонного образа
Выключаем устройство и вставляем SD-карту в компьютер:
Выводим список разделов:
Считываем образ с карты:
4. Преобразование эталонного образа при помощи mender-convert
Для подготовки образа нам понадобится mender-convert и Docker.
Проверяем ёмкость SD-карты, на которую будем устанавливать систему:
Переводим байты в мегабайты: 7910457344 / 1024 / 1024 = 7544 MB
Создаём файл с конфигурацией mender-convert ./configs/raspberrypi3_custom_config с вот таким содержимым:
MENDER_STORAGE_TOTAL_SIZE_MB — общий размер SD полученный ранее
MENDER_DATA_PART_SIZE_MB — размер раздела /data
MENDER_ADDON_CONNECT_INSTALL — флаг установки mender-connect (позволит запускать командную строку на удалённом устройстве и передавать файлы)
Создаём директорию ./rootfs_overlay/etc/mender . Это оверлей файловой системы который будет записан на наш эталонный образ при запуске mender-convert.
Создаём файл конфигурации mender-client ./rootfs_overlay/etc/mender/mender.conf :
TenantToken — токен который нужно посмотреть в hosted.mender.io (Settings->Organization and billing->Organization token).
Создаём файл конфигурации mender-connect ./rootfs_overlay/etc/mender/mender-connect.conf :
Создаём директорию ./input и кладём в неё образ golden-image-1.img полученный ранее.
MENDER_ARTIFACT_NAME — название релиза, которое будет отображаться в hosted.mender.io.
Дальше происходит магия:
в образ устанавливается U-Boot
в Raspberry OS доустанавливается mender-client и mender-connect
создаются A и B разделы rootfs исходя из общего размера SD-карты, а также размера раздела data
данные из директории /data автоматически переносятся на новый раздел, который не будет перезаписываться при обновлении системы
Подробнее можно посмотреть в ./logs/convert.log.XXXX .
На выходе получаем:
./deploy/golden-image-1-raspberrypi3-mender.img — преобразованный образ системы для записи на SD-карту
./deploy/golden-image-1-raspberrypi3-mender.mender — архив с обновлением, который загружается на сервер Mender(519МБ) и потом скачивается устройствами.
5. Подготовка устройства (provisioning)
Записываем образ golden-image-1-raspberrypi3-mender.img на SD-карту:
Теперь разделы выглядят так:
Вывод uart при загрузке (у нас теперь есть U-Boot):
6. Авторизация устройства
Через пару минут после включения устройства на главной странице hosted.mender.io должно появиться сообщение о том, что новое устройство ожидает аутентификации. После подтверждения статус устройства поменяется с pending на accepted.
Через раздел Troubleshoot можно запустить удалённый терминал на устройстве (работает через mender-connect). При этом, на устройстве не включен ssh-сервер. Есть возможность передавать файлы через вкладку File transfer.
Теперь мы можем обновлять устройство по воздуху и физический доступ к нему больше не понадобится.
7. Подготовка пакета обновления (artifact)
Возвращаемся к нашему эталонному образу (golden-image-1.img). Загружаем ОС и вносим необходимые изменения. Я, например, сделаю MQTT-клиента, который шлёт на брокер температуру процессора (под спойлером).
Создаём systemd таймер: /etc/systemd/system/mqtt.timer
Создаём сервис, который будет вызываться таймером mqtt.timer: /etc/systemd/system/mqtt.service
Скрипт, который будет вызываться сервисом mqtt.service: /home/pi/mosquitto_pub.sh
Делаем скрипт исполняемым:
После внесения изменений снова считываем образ с карты:
Преобразовываем образ при помощи mender-convert:
Загружаем в hosted.mender.io новый релиз golden-image-2-raspberrypi3-mender.mender. Заодно можно загрузить первый релиз, если захотим откатиться.
8. Deploy
Развёртывание (deploy) можно создать для отдельного устройства, группы устройств или сразу для всех. После создания развёртывания в течении пяти минут устройство проверит есть ли для него доступное обновление и начнёт загрузку.
После обновления проверим, начало ли устройство отправлять сообщения по MQTT (под спойлером):
Создайте подключение к mqtt://test.mosquitto.org, порт: 1883.
Подпишитесь на топик habr/#
Наблюдаем, как устройство остывает после недавнего апдейта:
Выводы
Mender позволяет довольно легко добавить функцию обновления образа системы по воздуху в существующее устройство.
Внедрение Mender никак не повлияло на процесс разарботки эталонного образа и последующих обновлений. Эталонный образ служит лишь источником для создания пакетов обновления.
Open-source версия Mender позволяет делать намного больше, чем показано в этой статье, например, state-scripts, identy и inventory устройств и т.д. Open-source версию сервера Mender можно самостоятельно развернуть в облаке используя Kubernetes.
Рекомендую внимательно изучить список фич доступных в open-source и коммерческих версиях. Open-source версия вполне работоспособна, но её может не хватить для того чтобы закрыть все потребности крупного проекта (нет автоматического перезапуска процесса обновления, дельта-апдейтов, мониторинга сервисов и т.д.).
Было бы интересно сравнить Mender c RAUC или swupdate в качестве клиента и hawkBit в качестве бэкенда.
Источник