How to upate Home Assistant Core?

21:35 Рубрика: Умный дом

Here are the steps to update HA in a venv (old but I think they are still valid):

$ sudo systemctl stop home-assistant@homeassistant.service 
$ sudo su -s /bin/bash homeassistant
$ source /srv/homeassistant/bin/activate
$ pip3 install --upgrade homeassistant
$ deactivate
$ sudo systemctl start home-assistant@homeassistant.service

If necessary change the user “homeassistant” in the second line to whatever user you used to install HA.

(c)

Is there a way to downgrade Andrdoid System WebView?

21:33 Рубрика: Android

Please find my steps to downgrade Webview here

Step1: Uninstall update for Android Webview

Step2: download an older version from the given link, https://android-system-webview.en.uptodown.com/android/versions

Step 3: adb connect IP-OF-device

Step 4: adb remount

Step 5: adb push android-system-webview.apk /system

Step 6: adb shell pm install -r -d /system/android-system-webview.apk

(c)

Bloodred Hourglass - Perdition

23:07 Рубрика: Видео

Bloodred Hourglass -Valkyrie

22:52 Рубрика: Видео

Amorphis - Dark Path

00:36 Рубрика: Видео

In the twilight when he steps forth
In the bend of the dark path
When he catches up with you
You won’t know if he’s on your side
Or if he will turn against you

And in the dead of a moonless night
As your path turns into the black
You become one with the darkness
And in the dead of a moonless night
Who knows if you are brothers
Or if you will turn against each other


And it the dusk when he finds you
Hidden in the shadows
He must judge your allegiance
He won’t know if you’re on his side
Or if you will turn against him

And in the dead of a moonless night
As your path turns into the black
You become one with the darkness
And in the dead of a moonless night
Who knows if you are brothers
Or if you will turn against each other
Далее

Tray icon under Mate Desktop on Linux has irrelevant appearance and doesn't handle mouse events properly

22:43 Рубрика: Linux

I found a great workaround:

dbus-launch someQtApp someAppOptions

It works completely OK under Mate. The icon displays the images properly and mouse clicks are handled as they should.

Thanks to http://askubuntu.com/questions/732967/dropbox-icon-is-not-working-xubuntu-14-04-lts-64 .

This workaround works for Telegram Desktop and for caja-dropbox (caja-dropbox is the Dropbox for Mate). For Dropbox, its additional setting is required to not autostart it on system startup: uncheck that in Dropbox Preferences.

(c)

https://radiooooo.com/

02:27 Рубрика: Всячина

https://radiooooo.com/

15 базовых советов по Git для эффективной работы каждый день

02:23 Рубрика: Linux

(с) Эта заметка — попытка объяснить те базовые настройки и приёмы, которыми я пользуюсь каждый день. Рецепты не претендуют быть ноу-хау, но могут помочь с освоением ежедневной гигиены работы с репозиторием.

1. Используй свежее

 

Я предпочитаю работать в консоли и большая часть команд и советов в этой заметке будет про консольный клиент. Это своего рода первая рекомендация — используйте консольный клиент для ежедневной работы с репозиторием и регулярно его обновляйте. В консольном клиенте в первую очередь появляются новые возможности и исправления ошибок.

 

> git --version
git version 2.27.0

 

2. Настрой инструмент

 

Настройте себе публичный email не аффилированный с текущей компанией. Это позволит вам тонко настраивать идентификацию под разные репозитории и не задумываться о настройках по умолчанию, а GitHub будет показывать вашу активность, даже если вы смените место работы.

 

> git config --global user.email "gurugray@yandex.ru"

> cd company_project
> git config user.email "gurugray@manychat.com"

 

Если вы не пользуетесь консолью и vim'ом для редактирования, то вам стоит настроить и ваш редактор:

 

> git config --global core.editor "code --wait"

 

3. Настрой autocomplete

 

В моей практике не часто встречается разработчик, который не настраивал автокомплит если работал в консоли. Однако если вы переходите с другого инструмента, отсутствие этой функциональности сильно вас затормозит.

 

Git из коробки предоставляет набор скриптов для автокомплита, но если ваш shell, как у меня, более экзотичен — найдите и поставьте автокомплит именно для него.

 

4. Ускоряй часто используемое

 

Настройте себе псевдонимы (aliases) для быстрой работы. Для каждого человека удобство ощущается по-разному и я не рекомендую увлекаться однобуквенными псевдонимами, особенно если вы часто работаете на других рабочих станциях или используете ssh для удалённой работы на серверах — вам либо придётся тратить время на борьбу с различиями, либо растаскивать свой файл настроек по всем машинам (что не всегда плохо, конечно). Также не старайтесь заменить псевдонимами любое сочетание команд — половину вы забудете, а к половине привыкните более, чем оно того заслуживает.

 

Я перешёл на Git с SVN, потому для меня базовые псевдонимы перекочевали оттуда, а "b" — единственный однобуквенный псевдоним.

 

> git config --global alias.st "status -sb"
> git config --global alias.co "checkout"
> git config --global alias.ci "commit -a"
> git config --global alias.b "branch"

 

5. Обзорность помогает решать проблемы

 

Я часто работаю с историей проекта — нужно понять, что и когда влилось, и какие состояния проекта этому предшествовали. Часто важно знать последовательность комитов и топологию дерева истории. Git из коробки помогает показать дерево истории проекта:

 

> git log --oneline --graph --branches

 

Но для полноты картины хочется видеть и авторов, и даты и в удобной расцветке, потому мой псевдоним выглядит не так дружелюбно с параметром --pretty=format::

 

> git log --graph --date=short --branches --pretty=format:'%C(yellow)%h%C(reset) %ad | %C(75)%s%C(reset) %C(yellow)%d%C(reset) [%an]'

 

6. Следуй протоколу

 

Всегда клонируйте репозиторий, в который вносите правки по git+ssh протоколу, это работает быстрее чем по http и сэкономит время в процессе работы:

 

> git clone git@github.com:gurugray/gurugray

 

7. Разделяй источники

 

Если вы работаете с репозиториями по «форковой» модели (когда к основному репозиторию есть доступ только на чтение, а все pull-request'ы подаются из форка) называйте основной репозиторий upstream это поможет не путаться в командах отведения веток и push'а в свой origin. Не забывайте про протокол, если репозиторий открыт только для чтения, то его можно клонировать без ssh-слоя, что тоже даст экономию времени в процессе работы:

 

> git clone git://github.com/gurugray/gurugray -o upstream

 

8. Контролируй процесс

 

Не используйте команду pull, это составная команда и делает несколько действий сразу. Часто при работе с репозиторием новички допускают ошибку не понимая, как эта команда обновляет текущую ветку, и замусоривают свою историю или неправильно работают с дефолтной веткой. Я рекомендую явно обновлять репозиторий локально, затем явно обновлять свою ветку:

 

> git fetch --all
> git rebase my_feature upstream/master

 

9. Не вводи себя в заблуждение

 

Никогда не храните дефолтную ветку локально, всегда отводите ветку от актуальной удалённой, это позволит избежать путаницы и точно знать от чего и в какое время вы отвели ветку:

 

> git fetch --all
> git checkout -b my_feature upstream/master

> git branch -D master

 

10. Не бойся исправлять

 

Если вы следите за чистотой истории и хотите исправить состояние проекта зафиксированное несколько комитов назад, то достаточно закомититься с параметром --fixup= и передать нужный хэш комита для последующего причёсывания истории

 

> git commit -m "Feature A is done"
> ...
> git commit -m "Feature B is done"
> git commit --fixup=fe2f857

 

> git log --oneline
a5050e7 fixup! Feature A is done
633e33f Feature B is done
...
fe2f857 Feature A is done
cb5db88 Previous commit

 

11. Не бойся быстро исправлять

 

Один из полезных псевдонимов — замена последнего комита текущим состоянием, позволяет «подклеить» текущее состояние к последнему зафиксированному, при этом не включая режим редактирования сообщения:

 

> git config --global alias.fixlast "commit --all --amend --no-edit"

 

12. Перебазируй

 

Научитесь и пользуйтесь командой rebase в интерактивном режиме и с параметром --autosquash с которым использование --fixup будет ещё более удобным, а сам ребейз помогает причёсывать историю и аккуратно оформить комиты, например по принятым у вас guidline'ам, до подачи pull-request'а для успешного его принятия.

 

> git rebase -i --autosquash cb5db88
pick fe2f857 Feature A is done
fixup a5050e7 fixup! Feature A is done
pick 733e2ff Feature B is done

 

> git log --oneline
633e33f Feature B is done
...
5778cbb Feature A is done
cb5db88 Previous commit

 

13. Сбрасывай ненужное

 

Научитесь и пользуйтесь командой reset она позволит легко манипулировать локальной историей и состоянием, например после череды правок и комитов на код-ревью «схлопнуть» последние ненужные состояния проще с её помощью:

 

> git reset @~4
> git commit --all

 

14. Контролируй деструктивный push

 

Если вы хотите запушить изменённую историю, советую использовать полный синаксис команды и не использовать ключ --force -f, это позволит не привыкать к настройкам по умолчанию и не приведёт к случайным перетираниям истории на сервере:

 

> git push origin +feature

 

15. Помни про летописца

 

Не забывайте про reflog эта команда поможет разобраться с проблемами в локальном репозитории если что-то пошло не так — спасательный круг для новичков, к которому они редко подходят:

 

> git reflog
> ...
> git reset --hard FOUND_HASH

 

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

 

Есть ещё много возможностей для тонкой настройки Git'а под себя и для решения более специфичных кейсов, но описанные выше возможности инструмента позволяют вам каждый день удобно работать не теряя в скорости.

отсюда

Далее

Karadio - интернет радио на базе ESP32

02:13 Рубрика: Умный дом

Это вторая статья о замечательном проекте Karadio, который создан хорошим программистом и я уверен человеком, - JP Cocatrix. Страница всех его проектов на Github.
Но речь пойдет сегодня о новой ступени развития проекта Karadio - интернет радио на базе ESP32.
Постараюсь очень четко и по делу написать в помощь тем, кто, как и я плохо понимает иностранные языки, электронику.  Однако, иметь такое интересное радио хочется всем. Будет и просто перевод с github и мои дополнения.

Проект находится на стадии тестирования,  уверен, это скоро изменится. Для вывода звука можно исплользовать внутренний DAC (ЦАП), находящийся в ESP32 или подключить внешний DAC, например такой на Aliexpress.Ссылка может перестать работать, но можно поиском найти по запросу I2S PCM5102 DAC или просто I2S DAC. 
При использовании внутреннего DAC ничего не нужно, кроме усилителя, например PA8403 (с регулятором громкости даже). Либо использовать уже знакомую нам связку ESP32 и VS1053, при этом будет возможность прослушивать потоки AAC, чего нельзя сказать о режиме DAC или PDM. На режиме PDM я не буду останавливаться, потому что смысл будет такой же, как и у внутреннего DAC. Я попробовал включить этот режим, но шум сильный, как во время дождя. Автор Karawin пояснил, что нужна фильтрация. Я не стал заморачиваться, потому что с внутренним DAC качество воспроизведения меня удовлетворило. Если что можно применить внешний DAC или VS1053. Еще есть режим I2SMERU для подключения какого-то особого усилителя, можете сами разузнать.
Сначала займемся прошивкой ESP32. Будем говорить о заливке уже скомпилированной прошивки в память. Все необходимое для прошивки можно взять тут. Программа для прошивки здесь. Сама прошивка в нескольких файлах тут и тут. Скриншот программы, поясняющий куда и что заливать тут. Все выставляете, как написано, но пути к прошивочным файлам у вас могут быть свои (не стоит использовать пути с кириллическими символами, лучше только латиницей). Т. е. распаковываете все файлы для прошивки в отдельную папку (можно назвать ее Flash) на диске C: , потом путем нажатия на многоточия в конце строк прописываете аккуратно все пути к этим файлам. Правее в поле вводите то, что написано, на скриншоте.
 

 

Все остальное прописываете, как на скрине, кроме порта COM, его вы меняете на свой. посмотреть его можно в Диспетчере устройств, при подключении ESP32 появится COM порт (если драйверы вы уже поставили). Драйверы зависят от вашей операционной системы  и типа USB- COM адаптера, который установлен на вашей ESP32. Скорость BAUD как на картинке. Подключаете ESP32 к компьютеру и нажимаете START (у меня было так, никаких кнопок на самой плате я не нажимал). Ждете окончания прошивки и отключаете плату от USB. Можно приступать к соединению всей периферии.

Схема соединений

Сильно схеме не доверяйте, доверяйте только себе, но нарочно я не ввожу в заблуждение. Батарейки изображены условно, необходимо подключить 5В. Сегодня измерял ток потребления 0,15А при малой громкости. Блока питания на 0,5 - 1А должно хватить. Питание зависит от усилителя.
Итак,  если вы используете VS1053, то соединения такие:
 VS1053----ESP32 (номера GPIO)

XCS-----  GPIO_NUM_32
RST-----  GPIO_NUM_12
XDCS----- GPIO_NUM_33
DREQ----- GPIO_NUM_34
MISO----- GPIO_NUM_19
MOSI----- GPIO_NUM_23
CLK-----  GPIO_NUM_18
 
У меня номера GPIO указаны на самой плате или смотрите распиновку
Если используете внешний DAC по I2S, то соединения такие:
I2S DAC----ESP32
LRCK-------- GPIO_25
BCLK------- GPIO_26
DATA------- GPIO_22
Если используете DAC самой платы ESP32, то GPIO 25 и 26 подключаете к правому и левому каналу усилителя, а также соединяете GND усилителя и GND ESP32. GPIO 22 при этом не нужен. Также и для PDM режим, только надо будет выбрать его в web интерфейсе и все (ну и про фильтр вспомните для этого режима).
На данный момент поддерживается использование дисплея  OLED SSD1306 128x64.
Подсоединяем так:
SSD1306-----ESP32
 
SCL------ GPIO_14
SDA------ GPIO_13
МСС -----3.3v (или 5v)
GND-------GND
 
 
Энкодер:
DT-------GPIO_16
CLK ----  GPIO_17
SW------- GPIO_5
GND ---GND
+-----+5V
 
 
Дополнительно можно подключить светодиод для индикации работы радио ---GPIO 4.

Включение 

Проверяете все соединения и подключаете питание. На схеме показано общее питание для всей схемы, но предпочтительнее использовать отдельное питание для ESP32 и усилителя, для того, чтобы избежать дополнительных шумов. В режиме DAC при общем питании шумы я не заметил и качество хорошее. Смотрите сами. 
Через некоторое время после включения ESP32 создаст точку доступа WifiKaradio с IP адресом 192.168.4.1. Подключаетесь к этой сети с компьютера и в браузере переходите по этому IP. Переходите на вкладку SETTING и находите настройки Wifi. Вписываете данные своего роутера и нажимаете Validate, радио может перезагрузиться. В роутере ищите какой адрес IP выдан радио. В некоторых роутерах можно оставить автоматическую раздачу IP (DHCP), но для отдельных устройств назначить постоянные адреса, чтобы каждый раз не отгадывать IP.
 
 
После перезагрузки переходите в SETTING в Sound Setting и выбираете режим вывода звука, затем нажимаете Validate.

После перезагрузки можете приступить к формированию своего списка радиостанций или скачать уже созданный на вкладке SETTING---Playlist.



 Сегодня поговорим о добавлении к Karadio32 внешней платы DAC PCM5102. При выводе 
через эту плату звук стал более чистым и появились басы. При минимальной громкости в Web 
интерфейсе искажений никаких нет.
На плате есть выход Line Out для подключения внешнего усилителя. Наушники в этот разъем 
не подключить, звука никакого нет абсолютно. 

Схема соединений.

Схему подсказал пользователь сообщества Karadio.
 
PCM5102              ESP32
LCK                         GPIO25
BCK                        GPIO26
DIN                          GPIO22
XMT(XSMT)           подтянуть к +5в через резистор 10кОм
FMT                          GND
SCL(SCK)                 GND
 
 
Могут быть незначительные различия в названиях пинов PCM5102, но догадаться можно.
Также на плате есть пины для подключения внешнего усилителя (у меня это PAM8403)  LOUT LROUT AGND. Питание подал 5в.
При использовании данной платы нужно выставить режим I2S в Web интерфейсе Karadio.
 
Далее

Основы Ansible, без которых ваши плейбуки — комок слипшихся макарон

02:04 Рубрика: Linux

Я делаю много ревью для чужого кода на Ансибл и много пишу сам. В ходе анализа ошибок (как чужих, так и своих), а так же некоторого количества собеседований, я понял основную ошибку, которую допускают пользователи Ансибла — они лезут в сложное, не освоив базового.

Для исправления этой вселенской несправедливости я решил написать введение в Ансибл для тех, кто его уже знает. Предупреждаю, это не пересказ манов, это лонгрид в котором много букв и нет картинок.

Ожидаемый уровень читателя — уже написано несколько тысяч строк ямла, уже что-то в продакшене, но "как-то всё криво".

Названия

Главная ошибка пользователя Ansible — это не знать как что называется. Если вы не знаете названий, вы не можете понимать то, что написано в документации. Живой пример: на собеседовании, человек, вроде бы заявлявший, что он много писал на Ансибле, не смог ответить на вопрос "из каких элементов состоит playbook'а?". А когда я подсказал, что "ожидался ответ, что playbook состоит из play", то последовал убийственный комментарий "мы этого не используем". Люди пишут на Ансибле за деньги и не используют play. На самом деле используют, но не знают, что это такое.

Так что начнём с простого: как что называется. Может быть вы это знаете, а может и нет, потому что не обратили внимания, когда читали документацию.

ansible-playbook исполняет playbook. Playbook — это файл с расширением yml/yaml, внутри которого что-то такое:

---
- hosts: group1
  roles:
    - role1

- hosts: group2,group3
  tasks:
    - debug:

 

Мы уже поняли, что весь этот файл — плейбука. Мы можем показать где тут роли (roles), где таски (tasks). Но где тут play? И чем отличается play от role или playbook?

В документации это всё есть. И это пропускают. Начинающие — потому что там слишком много и всё сразу не запомнишь. Опытные — потому что "тривиальные вещи". Если вы опытный — перечитывайте эти страницы хотя бы раз в пол-года, и ваш код станет классом лучше.

Итак, запоминайте: Playbook — это список, состоящий из play и import_playbook
Вот это — одна play:

- hosts: group1
  roles:
    - role1

и вот это тоже ещё одна play:

- hosts: group2,group3
  tasks:
    - debug:

Что же такое play? Зачем она?

Play — это ключевой элемент для playbook, потому что play и только play связывает список ролей и/или тасок с списком хостов, на которых их надо выполнять. В глубоких недрах документации можно найти упоминание про delegate_to, локальные lookup-плагины, network-cli-специфичные настройки, jump-хосты и т.д. Они позволяют слегка поменять место исполнения тасок. Но, забудьте про это. У каждой из этих хитрых опций есть очень специальные применения, и они точно не являются универсальными. А мы говорим про базовые вещи, которые должны знать и использовать все.

Если вы хотите "что-то" исполнить "где-то" — вы пишете play. Не роль. Не роль с модулями и делегейтами. Вы берёте и пишете play. В которой, в поле hosts вы перечисляете где исполнять, а в roles/tasks — что исполнять.

Просто же, да? А как может быть иначе?

Одним из характерных моментов, когда у людей возникает желание сделать это не через play, это "роль, которая всё настраивает". Хочется иметь роль, которая настраивает и сервера первого типа, и сервера второго типа.

Архетипичным примером является мониторинг. Хочется иметь роль monitoring, которая настроит мониторинг. Роль monitoring назначается на хосты мониторинга (в соотв. play). Но, выясняется, что для мониторинга нам надо поставить пакеты на хосты, которые мы мониторим. Почему бы не использовать delegate? А ещё надо настроить iptables. delegate? А ещё надо написать/поправить конфиг для СУБД, чтобы мониторинг пускала. delegate! А если креатив попёр, то можно сделать делегацию include_role во вложенном цикле по хитрому фильтру на список групп, а внутри include_role можно ещё делать delegate_to снова. И понеслось...

Благое пожелание — иметь одну-единственную роль monitoring, которая "всё делает" — ведёт нас кромешный ад из которого чаще всего один выход: всё переписать с нуля.

Где тут случилась ошибка? В тот момент, когда вы обнаружили, что для выполнения задачи "x" на хосте X вам надо пойти на хост Y и сделать там "y", вы должны были выполнить простое упражнение: пойти и написать play, которая на хосте Y делает y. Не дописывать что-то в "x", а написать с нуля. Пусть даже с захардкоженными переменными.

Вроде бы, в абзацах выше всё сказано правильно. Но это же не ваш случай! Потому что вы хотите написать переиспользуемый код, который DRY и похож на библиотеку, и нужно искать метод как это сделать.

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

Эта ошибка звучит так: роль — это библиотечная функция. Эта аналогия сгубила столько хороших начинаний, что просто грустно смотреть. Роль — не библиотечная функция. Она не может делать вычисления и она не может принимать решения уровня play. Напомните мне, какие решения принимает play?

Спасибо, вы правы. Play принимает решение (точнее, содержит в себе информацию) о том, какие таски и роли на каких хостах выполнять.

Если вы делегируете это решение на роль, да ещё и с вычислениями, вы обрекаете себя (и того, кто ваш код будет пытаться разобрать) на жалкое существование. Роль не решает где ей выполняться. Это решение принимает play. Роль делает то, что ей сказали, там, где ей сказали.

Почему заниматься программированием на Ансибле опасно и чем COBOL лучше Ансибла мы поговорим в главе про переменные и jinja. Пока что скажем одно — каждое ваше вычисление оставляет за собой нестираемый след из изменения глобальных переменных, и вы ничего с этим не можете сделать. Как только два "следа" пересеклись — всё пропало.

Замечание для въедливых: роль, безусловно, может влиять на control flow. Есть delegate_to и у него есть разумные применения. Есть meta: end host/play. Но! Помните, мы учим основы? Забыли про delegate_to. Мы говорим про самый простой и самый красивый код на Ансибл. Который легко читать, легко писать, легко отлаживать, легко тестировать и легко дописывать. Так что, ещё раз:

play и только play решает на каких хостах что исполняется.

В этом разделе мы разобрались с противостоянием play и role. Теперь поговорим про отношения tasks vs role.

Таски и Роли

Рассмотрим play:

- hosts: somegroup
  pre_tasks:
    - some_tasks1:
  roles:
     - role1
     - role2
  post_tasks:
     - some_task2:
     - some_task3:

Допустим, вам надо сделать foo. И выглядит это как foo: name=foobar state=present. Куда это писать? в pre? post? Создавать role?

… И куда делись tasks?

Мы снова начинаем с азов — устройство play. Если вы плаваете в этом вопросе, вы не можете использовать play как основу для всего остального, и ваш результат получается "шатким".

Устройство play: директива hosts, настройки самой play и секции pre_tasks, tasks, roles, post_tasks. Остальные параметры для play нам сейчас не важны.

Порядок их секций с тасками и ролями: pre_tasksrolestaskspost_tasks. Поскольку семантически порядок исполнения между tasks и roles не понятен, то best practices говорит, что мы добавляем секцию tasks, только если нет roles. Если есть roles, то все прилагающиеся таски помещаются в секции pre_tasks/post_tasks.

Остаётся только то, что семантически всё понятно: сначала pre_tasks, потом roles, потом post_tasks.

Но мы всё ещё не ответили на вопрос: а куда вызов модуля foo писать? Надо ли нам под каждый модуль писать целую роль? Или лучше иметь толстую роль подо всё? А если не роль, то куда писать — в pre или в post?

Если на на эти вопросы нет аргументированного ответа, то это признак отсутствия интуиции, то есть те самые "шаткие основы". Давайте разбираться. Сначала контрольный вопрос: Если у play есть pre_tasks и post_tasks (и нет ни tasks, ни roles), то может ли что-то сломаться, если я первую таску из post_tasks перенесу в конец pre_tasks?

Разумеется, формулировка вопроса намекает, что сломается. Но что именно?

… Хэндлеры. Чтение основ открывает важный факт: все хэндлеры flush'атся автоматом после каждой секции. Т.е. выполняются все таски из pre_tasks, потом все хэндлеры, которые были notify. Потом выполняются все роли и все хэндлеры, которые были notify в ролях. Потом post_tasks и их хэндлеры.

Таким образом, если вы таску перетащите из post_tasks в pre_tasks, то, потенциально, вы выполните её до выполнения handler'а. например, если в pre_tasks устанавливается и конфигурируется веб-сервер, а в post_tasks в него что-то засылается, то перенос этой таски в секцию pre_tasks приведёт к тому, что в момент "засылания" сервер будет ещё не запущен и всё сломается.

А теперь давайте ещё раз подумаем, а зачем нам pre_tasks и post_tasks? Например, для того, чтобы выполнить всё нужное (включая хэндлеры) до выполнения роли. А post_tasks позволит нам работать с результатами выполнения ролей (включая хэндлеры).

Въедливый знаток Ansible скажет нам, что есть meta: flush_handlers, но зачем нам flush_handlers, если мы можем положиться на порядок исполнения секций в play? Более того, использование meta: flush_handlers может нам доставить неожиданного с повторяющимися хэндлерами, сделать нам странные варнинги в случае использования when у block и т.д. Чем лучше вы знаете ансибл, тем больше нюансов вы сможете назвать для "хитрого" решения. А простое решение — использование натурального разделения между pre/roles/post — не вызывает нюансов.

И, возвращаемся, к нашему 'foo'. Куда его поместить? В pre, post или в roles? Очевидно, это зависит от того, нужны ли нам результаты работы хэндлера для foo. Если их нет, то foo не нужно класть ни в pre, ни в post — эти секции имеют специальный смысл — выполнение тасок до и после основного массива кода.

Теперь ответ на вопрос "роль или таска" сводится к тому, что уже есть в play — если там есть tasks, то надо дописать в tasks. Если есть roles — надо делать роль (пусть и из одной task). Напоминаю, tasks и roles одновременно не используются.

Понимание основ Ансибла даёт обоснованные ответы на, казалось бы, вопросы вкусовщины.

Таски и роли (часть вторая)

Теперь обсудим ситуацию, когда вы только начинаете писать плейбуку. Вам надо сделать foo, bar и baz. Это три таски, одна роль или три роли? Обобщая вопрос: в какой момент надо начинать писать роли? В чём смысл писать роли, когда можно писать таски?… А что такое роль?

Одна из грубейших ошибок (я про это уже говорил) — считать, что роль — это как функция в библиотеке у программы. Как выглядит обобщённое описание функции? Она принимает аргументы на вход, взаимодействует с side causes, делает side effects, возвращает значение.

Теперь, внимание. Что из этого можно сделать в роли? Вызвать side effects — всегда пожалуйста, это и есть суть всего Ансибла — делать сайд-эффекты. Иметь side causes? Элементарно. А вот с "передать значение и вернуть его" — вот тут-то и нет. Во-первых, вы не можете передать значение в роль. Вы можете выставить глобальную переменную со сроком жизни размером в play в секции vars для роли. Вы можете выставить глобальную переменную со сроком жизни в play внутри роли. Или даже со сроком жизни плейбуки (set_fact/register). Но вы не можете иметь "локальные переменные". Вы не можете "принимать значение" и "возвращать его".

Из этого вытекает главное: нельзя на ansible написать что-то и не вызвать сайд-эффекты. Изменение глобальных переменных — это всегда side effect для функции. В Rust, например, изменение глобальной переменной — это unsafe. А в Ансибл — единственный метод повлиять на значения для роли. Обратите внимание на используемые слова: не "передать значение в роль", а "изменить значения, которые использует роль". Между ролями нет изоляции. Между тасками и ролями нет изоляции.

Итого: роль — это не функция.

Что же хорошего есть в роли? Во-первых, у роли есть default values (/default/main.yaml), во-вторых у роли есть дополнительные каталоги для складывания файлов.

Чем же хороши default values? Тем, что в пирамиде Маслоу довольно извращённой таблице приоритетов переменных у Ансибла, role defaults — самые неприоритетные (за вычетом параметров командной строки ансибла). Это означает, что если вам надо предоставить значения по-умолчанию и не переживать что они перебъют значения из инвентори или групповых переменных, то дефолты роли — это единственное правильное место для вас. (Я немного вру — есть ещё |d(your_default_here), но если говорить про стационарные места — то только дефолты ролей).

Что ещё хорошего в ролях? Тем, что у них есть свои каталоги. Это каталоги для переменных, как постоянных (т.е. вычисляемых для роли), так и для динамических (есть такой то ли паттерн, то ли анти-паттерн — include_vars вместе с {{ ansible_distribution }}-{{ ansible_distribution_major_version }}.yml.). Это каталоги для files/templates/. Ещё, оно позволяет иметь роли свои модули и плагины (library/). Но, в сравнении с тасками у playbook'и (у которой тоже всё это может быть), польза тут только в том, что файлы свалены не в одну кучу, а несколько раздельных кучек.

Ещё одна деталь: можно пытаться делать роли, которые будут доступны для переиспользования (через galaxy). После появления коллекций распространение ролей можно считать почти забытым.

Таким образом, роли обладают двумя важными особенностями: у них есть дефолты (уникальная особенность) и они позволяют структурировать код.

Возвращаясь к исходному вопросу: когда делать таски а когда роли? Таски в плейбуке чаще всего используются либо как "клей" до/после ролей, либо как самостоятельный строительный элемент (тогда в коде не должно быть ролей). Груда нормальных тасок в перемешку с ролями — это однозначная неряшливость. Следует придерживаться конкретного стиля — либо таски, либо роли. Роли дают разделение сущностей и дефолты, таски позволяют прочитать код быстрее. Обычно в роли выносят более "стационарный" (важный и сложный) код, а в стиле тасок пишут вспомогательные скрипты.

Существует возможность делать import_role как таску, но если вы такое пишете, то будьте готовы к объяснительной для собственного чувства прекрасного, зачем вы это хотите делать.

Въедливый читатель может сказать, что роли могут импортировать роли, у ролей может быть зависимость через galaxy.yml, а ещё есть страшный и ужасный include_role — напоминаю, мы повышаем навыки в базовом Ансибле, а не в фигурной гимнастике.

Хэндлеры и таски

Давайте обсудим ещё одну очевидную вещь: хэндлеры. Умение их правильно использовать — это почти искусство. В чём разница между хэндлером и таской?

Так как мы вспоминаем основы, то вот пример:

- hosts: group1
  tasks:
    - foo:
      notify: handler1
  handlers:
     - name: handler1
       bar:

У роли handler'ы лежат в rolename/handlers/main.yaml. Handler'ы шарятся между всеми участниками play: pre/post_tasks могут дёргать handler'ы роли, а роль может дёргать handler'ы из плей. Однако, "кросс-ролевые" вызовы handler'ов вызывают куда больший wtf, чем повтор тривиального handler'а. (Ещё один элемент best practices — стараться не делать повторов имён handler'ов).

Основное различие в том, что таска выполняется (идемпотентно) всегда (плюс/минус теги и when), а хэндлер — по изменению состояния (notify срабатывает только если был changed). Чем это чревато? Например, тем, что при повторном запуске, если не было changed, то не будет и handler. А почему может быть так, что нам нужно выполнить handler когда не было changed у порождающей таски? Например, потому что что-то сломалось и changed был, а до хэндлера выполнение не дошло. Например, потому что сеть временно лежала. Конфиг поменялся, сервис не перезапущен. При следующем запуске конфиг уже не меняется, и сервис остаётся со старой версией конфига.

Ситуация с конфигом не решаемая (точнее, можно самим себе изобрести специальный протокол перезапуска с файловыми флагами и т.д., но это уже не 'basic ansible' ни в каком виде). Зато есть другая частая история: мы поставили приложение, записали его .service-файл, и теперь хотим его daemon_reload и state=started. И натуральное место для этого, кажется, хэндлер. Но если сделать его не хэндлером а таской в конце тасклиста или роли, то он будет идемпотентно выполняться каждый раз. Даже если плейбука сломалась на середине. Это совершенно не решает проблемы restarted (нельзя делать таску с атрибутом restarted, т.к. теряется идемпотентность), но однозначно стоит делать state=started, общая стабильность плейбуки возрастает, т.к. уменьшается количество связей и динамического состояния.

Ещё одно положительное свойство handler'а состоит в том, что он не засоряет вывод. Не было изменений — нет лишних skipped или ok в выводе — легче читать. Оно же является и отрицательным свойством — если опечатку в линейно исполняемой task'е вы найдёте на первый же прогон, то handler'ы будут выполнены только при changed, т.е. при некоторых условиях — очень редко. Например, первый раз в жизни спустя пять лет. И, разумеется, там будет опечатка в имени и всё сломается. А второй раз их не запустить — changed-то нет.

Отдельно надо говорить про доступность переменных. Например, если вы notify для таски с циклом, то что будет в переменных? Можно аналитическим путём догадаться, но не всегда это тривиально, особенно, если переменные приходят из разных мест.

… Так что handler'ы куда менее полезны и куда более проблемны, чем кажется. Если можно что-то красиво (без выкрутас) написать без хэндлеров лучше делать без них. Если красиво не получается — лучше с ними.

Въедливый читатель справедливо отмечает, что мы не обсудили listen, что handler может вызывать notify для другого handler'а, что handler может включать в себя import_tasks (который может делать include_role c with_items), что система хэндлеров в Ансибле тьюринг-полная, что хэндлеры из include_role прелюбопытнейшим образом пересекаются с хэндлерами из плей и т.д. — всё это явно не "основы").

Хотя есть один определённый WTF, который на самом деле фича, и о котором надо помнить. Если у вас таска выполняется с delegate_to и у неё есть notify, то соответствующий хэндлер выполняется без delegate_to, т.е. на хосте, на котором назначена play. (Хотя у хэндлера, разумеется, может быть delegate_to тоже).

Отдельно я хочу сказать пару слов про reusable roles. До появления коллекций была идея, что можно сделать универсальные роли, которые можно ansible-galaxy install и поехал. Работает на всех ОС всех вариантов во всех ситуациях. Так вот, моё мнение: это не работает. Любая роль с массовым include_vars, поддержкой 100500 случаев обречена на бездны corner case багов. Их можно затыкать массированным тестированием, но как с любым тестированием, либо у вас декартово произведение входных значений и тотальная функция, либо у вас "покрыты отдельные сценарии". Моё мнение — куда лучше, если роль линейная (цикломатическая сложность 1).

Чем меньше if'ов (явных или декларативных — в форме when или форме include_vars по набору переменных), тем лучше роль. Иногда приходится делать ветвления, но, повторю, чем их меньше, тем лучше. Так что вроде бы хорошая роль с galaxy (работает же!) с кучей when может быть менее предпочтительна, чем "своя" роль из пяти тасок. Момент, когда роль с galaxy лучше — когда вы что-то начинаете писать. Момент, когда она становится хуже — когда что-то ломается, и у вас есть подозрение, что это из-за "роли с galaxy". Вы её открываете, а там пять инклюдов, восемь таск-листов и стопка when'ов… И в этом надо разобраться. Вместо 5 тасок линейным списком, в котором и ломаться-то нечему.

В следующих частях

  • Немного про инвентори
  • групповые переменные, host_group_vars plugin, hostvars. Как из спагетти связать Гордиев узел. Scope и precedence переменных, модель памяти Ansible. "Так где же всё-таки хранить имя пользователя для базы данных?".
  • jinja: {{ jinja }} — nosql notype nosense мягкий пластилин. Оно всюду, даже там, где вы его не ожидаете. Немного про !!unsafe и вкусный yaml.

 

отсюда

Далее