Очередные грабли. При клонировании Linux машин, клонированные машины получают по DHCP тот же IP адрес, что и донор. Возникает конфликт интересов.
ㅤ
Проблема распространенная, лечится довольно просто.
1. Меняем MAC адреса на клонах
2. Меняем machine-id на клонах
В первом случае всё просто, делается через морду VBox, либо через консольные команды:
Новый MAC адрес можешь сгенерить такой командой:
Во втором случае это файл
Удаляем и генерим новый
Перезапускаем виртуальную машину. DHCP выдаёт этой машине новый IP адрес, который не будет конфликтовать с донором.
Вот и вся наука. Пользуйся.
🛠 #linux #linuxfactory
—
✅ @bashdays / @linuxfactory / @blog
ㅤ
Проблема распространенная, лечится довольно просто.
1. Меняем MAC адреса на клонах
2. Меняем machine-id на клонах
В первом случае всё просто, делается через морду VBox, либо через консольные команды:
ip link
sudo ip link set dev eth0 down
sudo ip link set dev eth0 address 00:11:22:33:44:55
sudo ip link set dev eth0 up
Новый MAC адрес можешь сгенерить такой командой:
printf '02:%02x:%02x:%02x:%02x:%02x\n' $((RANDOM%256)) $((RANDOM%256)) $((RANDOM%256)) $((RANDOM%256)) $((RANDOM%256))
Во втором случае это файл
/etc/machine-id
, в нем хранится уникальный идентификатор машины.ed76c4f179044828b51028aadf9f4981
Удаляем и генерим новый
machine-id
:sudo rm /etc/machine-id sudo systemd-machine-id-setup
Перезапускаем виртуальную машину. DHCP выдаёт этой машине новый IP адрес, который не будет конфликтовать с донором.
Вот и вся наука. Пользуйся.
—
Please open Telegram to view this post
VIEW IN TELEGRAM
Продолжаем тыкать SelectOS
На этот раз, я покажу как раскатать ОС в облаке из ISO образ (не из коробки).
ㅤ
Наступлю на несколько граблей, задебажу, пофиксю и пообщаюсь с саппортом. Короче будет интересно, го 👇
🦖 Ставим SelectOS в облако
Предыдущие посты:
- Пробуем SelectOS
- SelectOS в деле
🛠 #linux #review
—
✅ @bashdays / @linuxfactory / @blog
На этот раз, я покажу как раскатать ОС в облаке из ISO образ (не из коробки).
ㅤ
Наступлю на несколько граблей, задебажу, пофиксю и пообщаюсь с саппортом. Короче будет интересно, го 👇
Предыдущие посты:
- Пробуем SelectOS
- SelectOS в деле
—
Please open Telegram to view this post
VIEW IN TELEGRAM
2 30
Решил поделиться своим опытом использования Samba.
🔤 🔤 🔥 🔤 🔤 🔤 🔤
Ну, не то, чтобы прям Samba, но всякими smb-комбайнами.
ㅤ
Я сопровождаю небольшие конторки от 5 до 100 компов. Покупать виндовые серверы для такого количества — просто излишество. Если для маленьких конторок, для 10 машин, еще можно расшарить папку на win-pro, то дальше нужно думать.
Начал я с FreeNas, потом Nas4free, TrueNas, OMV, и когда поднабрался опыта, остановился на Samba без всяких web-интерфейсов.
Но я не об этом. Тем, кто думает, что можно легко заменить win-server на Samba Посвящается.
Основное отличие виндового и линуксового сервера — права доступа. У винды права реализованы лучше и гибче. Сейчас мне в комментах напишут про ACL, особенно те, кто их не использует.
Винда, устанавливает права на папку, и в зависимости от прав на папку — выставляются права на файл. При перемещении файла из папки в папку — права могут меняться. На линуксе файл получает права при создании, и потом с ними живет.
Большинство проблем, связанных с правами на Samba, связаны именно с ACL.
Ситуация следующая, два пользователя
Для некоторых папок приходится делать cron-скрипт для сброса прав. Может у кого-то есть опыт использования
Не знаю, как Вы, а я для себя решил отказаться от ACL. Потому что использовать
Рекомендую для маленьких контор использовать разрешения на шАры и обычные линуксовые права. Просто в этом случае расшаренных папок много.
Ну, про то, что таблицы символов для файловых систем не совпадают — я уже как-то писал. Проблема возникает, если в конторе часть пользователей на винде, часть на linux.
В общем, на мой взгляд пока нет полноценной замены для Win-сервера в качестве файлопомойки, для контор среднего и большого размера.
🛠 #windows #linux
—
✅ @bashdays / @linuxfactory / @blog
Ну, не то, чтобы прям Samba, но всякими smb-комбайнами.
ㅤ
Я сопровождаю небольшие конторки от 5 до 100 компов. Покупать виндовые серверы для такого количества — просто излишество. Если для маленьких конторок, для 10 машин, еще можно расшарить папку на win-pro, то дальше нужно думать.
Начал я с FreeNas, потом Nas4free, TrueNas, OMV, и когда поднабрался опыта, остановился на Samba без всяких web-интерфейсов.
Но я не об этом. Тем, кто думает, что можно легко заменить win-server на Samba Посвящается.
Основное отличие виндового и линуксового сервера — права доступа. У винды права реализованы лучше и гибче. Сейчас мне в комментах напишут про ACL, особенно те, кто их не использует.
Винда, устанавливает права на папку, и в зависимости от прав на папку — выставляются права на файл. При перемещении файла из папки в папку — права могут меняться. На линуксе файл получает права при создании, и потом с ними живет.
Большинство проблем, связанных с правами на Samba, связаны именно с ACL.
Ситуация следующая, два пользователя
U1
, U2
, три папки D1
, D2
, D3
. U1
имеет доступ D1
, D2
, U2
к D2
, D3
. На винде, если U1
, создаст файл в D1
, а потом перенесет в D2
- пользователь U2
будет иметь к нему доступ, а на линуксе нет.Для некоторых папок приходится делать cron-скрипт для сброса прав. Может у кого-то есть опыт использования
inotify
для этого, поделитесь.Не знаю, как Вы, а я для себя решил отказаться от ACL. Потому что использовать
getacl
setfacl
не удобно.Рекомендую для маленьких контор использовать разрешения на шАры и обычные линуксовые права. Просто в этом случае расшаренных папок много.
Ну, про то, что таблицы символов для файловых систем не совпадают — я уже как-то писал. Проблема возникает, если в конторе часть пользователей на винде, часть на linux.
В общем, на мой взгляд пока нет полноценной замены для Win-сервера в качестве файлопомойки, для контор среднего и большого размера.
—
Please open Telegram to view this post
VIEW IN TELEGRAM
Я тут недавно игрушку написал. Ну, как написал, реализовал.
🔤 🔤 🔥 🔤 🔤 🔤 🔤
Вариант 2048, оптимизированный по занимаемому экранному пространству.
Но у нас тут люди серьезные, поэтому рассмотрим проблемы, возникающие при реализации вывода скриптов.
Простой пример:
Код просто выводит символы
ㅤ
И тогда получаем:
Убрать эхо вывода на терминал просто:
Классная команда. После ее выполнения нажатые клавиши не отображаются.
Все работает, команды выполняются, результат отображается, а набранная команда — нет. Как при наборе пароля.
Вернуть все просто:
Но в скриптах желательно обрабатывать прерывания:
Применять исключительно для причинения добра.
🛠 #bash #linux #games
—
✅ @bashdays / @linuxfactory / @blog
Вариант 2048, оптимизированный по занимаемому экранному пространству.
➡️ Ознакомиться с игрушкой можно здесь.
Но у нас тут люди серьезные, поэтому рассмотрим проблемы, возникающие при реализации вывода скриптов.
Простой пример:
for i in {1..100};do
printf "#"
sleep .3
done
Код просто выводит символы
#
, примерно 3 штуки в секунду. Все работает нормально, пока пользователь не начинает что-то набирать на клавиатуре.ㅤ
И тогда получаем:
######sb#sf#bg#sfbg#wfgb#wg#fg#b###^[[A#^[[B#^[[D#^[[A#^[[B##
Убрать эхо вывода на терминал просто:
stty -echo
Классная команда. После ее выполнения нажатые клавиши не отображаются.
Все работает, команды выполняются, результат отображается, а набранная команда — нет. Как при наборе пароля.
Вернуть все просто:
stty echo
Но в скриптах желательно обрабатывать прерывания:
trap 'exit' INT HUP TERM
trap 'stty echo;tput cnorm' EXIT
# stop terminal echo
stty -echo
#hide cursor
tput civis
Применять исключительно для причинения добра.
man stty
man tput
help trap
—
Please open Telegram to view this post
VIEW IN TELEGRAM
Если тебе необходимо изменить файл сервиса в Linux, не нужно пиздовать ручками в папку
А бест-практика уже заложена в
Достаточно выполнить команду:
Откроется редактор с нужным сервисом. НО, редактировать ты будешь не корневой юнит, а
ㅤ
В моём случае с nginx будет открыт файл:
В нем я переопределяю нужные параметры для сервиса и НЕ трогаю основной файл юнита.
А если я хочу править корневой?
Да похуй, вот тебе команда:
Теперь будет открыт основной файл сервиса, можешь лезть в него своими шаловливыми ручонками и создавать проблемы.
1. Копирует оригинальный юнит-файл из
2. Открывает его в редакторе.
3. После сохранения — systemd использует именно эту копию в
Как проверить валидность файла юнита?
В ответ получишь:
Ага, ошибочка, правим и только после этого можно делать:
Короче учись работать правильно и всё у тебя будет хорошо!
С пятницей! Хороших тебе предстоящих выходных и береги себя!
🛠 #linux #tricks #debug #systemd
—
✅ @bashdays / @linuxfactory / @blog
/etc/systemd
искать и править его.Постоянно вижу этот кейс, чёто там ищут по папкам, ебутся. Правят оригинальный файл и все к хуям ломают.
А бест-практика уже заложена в
systemctl
!Достаточно выполнить команду:
sudo systemctl edit nginx
Откроется редактор с нужным сервисом. НО, редактировать ты будешь не корневой юнит, а
override
. То есть прокладку, которая переопределит параметры основного юнита.ㅤ
В моём случае с nginx будет открыт файл:
/etc/systemd/system/nginx.service.d/override.conf
В нем я переопределяю нужные параметры для сервиса и НЕ трогаю основной файл юнита.
А если я хочу править корневой?
Да похуй, вот тебе команда:
sudo systemctl edit --full nginx
Теперь будет открыт основной файл сервиса, можешь лезть в него своими шаловливыми ручонками и создавать проблемы.
1. Копирует оригинальный юнит-файл из
/lib/systemd/system/nginx.service
в /etc/systemd/system/nginx.service
2. Открывает его в редакторе.
3. После сохранения — systemd использует именно эту копию в
/etc/
.Это безопасный способ редактировать полные юниты, без риска перезаписи при обновлении пакетов.
Есть еще ключ --force, но про него погугли сам.
Как проверить валидность файла юнита?
systemd-analyze verify /etc/systemd/system/nginx.service
В ответ получишь:
/etc/systemd/system/nginx.service:31: Missing '=', ignoring line.
Ага, ошибочка, правим и только после этого можно делать:
sudo systemctl daemon-reload
sudo systemctl restart nginx
Короче учись работать правильно и всё у тебя будет хорошо!
С пятницей! Хороших тебе предстоящих выходных и береги себя!
—
Please open Telegram to view this post
VIEW IN TELEGRAM
7 203
Сегодня будем профилировать Linux сервисы.
В прошлый раз мы с тобой посмотрели, как без хуйни обращаться с юнитами.
Сегодня же посмотрим, как определить какие юниты дольше всего грузятся при старте системы.
Запускаем и смотрим:
По итогу получаем список юнитов и их время запуска.
В моём примере дольше всего грузится служба с докером.
ㅤ
Отрубаем службу и радуемся приросту в 17 секунд. Но НЕТ! На самом деле тут всё немного сложнее.
Иногда сам юнит стартует достаточно быстро, но сука ждет другой юнит, который «Блиц — скорость без границ».
Смотрим цепочку зависимостей:
Ага, то есть дело тут не только в юните докера, юнит ждет другой юнит, в нашем случае докер ждет пока на сервере поднимется сетка.
То есть
Почему так?
Docker по умолчанию может иметь
А чё делать?
Выйти из айти, купить яхту и поехать ловить крабов.
Если тебе нужно, чтобы Docker НЕ ждал сеть, поменяй юнит:
Ну или вообще убрать
После этого снова смотрим выхлоп через
Всё блядь! Теперь докер не тормозит загрузку, но после загрузки системы докер исправно работает.
Вот такими хитрыми манипуляциями можно профилировать это говнище. Не скажу что часто этим пользуюсь, но всегда держу на вооружении.
Забирай в копилку, для дебага маст-хев!
🛠 #linux #tricks #debug #systemd
—
✅ @bashdays / @linuxfactory / @blog
В прошлый раз мы с тобой посмотрели, как без хуйни обращаться с юнитами.
Сегодня же посмотрим, как определить какие юниты дольше всего грузятся при старте системы.
Это достаточно пиздатый хак, особенно при отладке медленного запуска системы. Ну и изобретать нам ничего не придется, всё уже придумали за нас.
Запускаем и смотрим:
systemd-analyze blame
По итогу получаем список юнитов и их время запуска.
17.084s docker.service
10.961s systemd-journal-flush.service
7.595s containerd.service
7.496s cloud-final.service
7.189s cloud-init-local.service
3.260s apt-daily-upgrade.service
2.522s cloud-init.service
2.095s dpkg-db-backup.service
1.991s networkd-dispatcher.service
1.963s chrony.service
В моём примере дольше всего грузится служба с докером.
ㅤ
Отрубаем службу и радуемся приросту в 17 секунд. Но НЕТ! На самом деле тут всё немного сложнее.
Иногда сам юнит стартует достаточно быстро, но сука ждет другой юнит, который «Блиц — скорость без границ».
Смотрим цепочку зависимостей:
systemd-analyze critical-chain
└─docker.socket @13.269s +8ms
└─sysinit.target @13.261s
└─cloud-init.service @10.735s +2.522s
└─systemd-networkd-online.service @12.806s +31ms
└─systemd-networkd.service @12.741s +59ms
Ага, то есть дело тут не только в юните докера, юнит ждет другой юнит, в нашем случае докер ждет пока на сервере поднимется сетка.
То есть
docker.service
зависит от systemd-networkd-wait-online.service
, ну и дальше пошли по цепочке.Почему так?
Docker по умолчанию может иметь
After=network-online.target
, а при использовании systemd-networkd
это приводит к ожиданию systemd-networkd-wait-online.service
.А чё делать?
Если тебе нужно, чтобы Docker НЕ ждал сеть, поменяй юнит:
sudo systemctl edit docker.service
[Unit]
After=network.target
Wants=network.target
Ну или вообще убрать
After=network-online.target
, если нет зависимости от сети на старте.После этого снова смотрим выхлоп через
blame
:4.739s cloud-init-local.service
4.041s containerd.service
2.329s dev-sda1.device
Всё блядь! Теперь докер не тормозит загрузку, но после загрузки системы докер исправно работает.
Вот такими хитрыми манипуляциями можно профилировать это говнище. Не скажу что часто этим пользуюсь, но всегда держу на вооружении.
Забирай в копилку, для дебага маст-хев!
—
Please open Telegram to view this post
VIEW IN TELEGRAM
3 125
Как безопасно тестировать юниты
Так, мы уже знаем как безопасно переопределять юниты, как их дебажить и ну и так по мелочи.
ㅤ
Но не знаем как всё это дело тестировать. А для тестирования тебе пригодится ключик
Идеально подходит, если ты тестишь, не уверен или не хочешь ничего портить.
А вот и сама команда:
Всё! Теперь правим юнит, тестируем. Временный файл с
И самое главное — все изменения сохранятся только до следующей перезагрузки системы.
А какая в этом польза?
1. Для временного изменения конфигурации
2. Для тестов или отладки (например, сменить
3. Чтобы не создавать перманентные изменения, которые могут повлиять на стабильность после перезагрузки.
Пример с nginx
Хочу временно запустить nginx с другим конфигом! Создаю рантайм.
Перезапускаю
А почему ExecStart идет дважды?
Хе брат, это очередная приколюха
Без этой хуйни
Думаю на этом можно закончить. Я неочевидную базу выдал, а ты стал еще сильнее. Изучай и ничего не бойся!
🛠 #linux #tricks #debug #systemd
—
✅ @bashdays / @linuxfactory / @blog
Так, мы уже знаем как безопасно переопределять юниты, как их дебажить и ну и так по мелочи.
ㅤ
Но не знаем как всё это дело тестировать. А для тестирования тебе пригодится ключик
--runtime
.Ключ --runtime — создаёт временное переопределение, которое исчезнет после перезагрузки.
Идеально подходит, если ты тестишь, не уверен или не хочешь ничего портить.
А вот и сама команда:
SYSTEMD_EDITOR=vim systemctl edit --runtime nginx
Как ты мог заметить, зачастую по умолчанию открывается nano редактор, но у многих с ним проблемы. Поэтому в команде сразу втыкаем нужный редактор, например mcedit или vim.
Всё! Теперь правим юнит, тестируем. Временный файл с
override
будет создан тут /run/systemd/
. И самое главное — все изменения сохранятся только до следующей перезагрузки системы.
А какая в этом польза?
1. Для временного изменения конфигурации
systemd
без затрагивания оригинального файла.2. Для тестов или отладки (например, сменить
ExecStart
для nginx
только на время текущей сессии).3. Чтобы не создавать перманентные изменения, которые могут повлиять на стабильность после перезагрузки.
Пример с nginx
Хочу временно запустить nginx с другим конфигом! Создаю рантайм.
[Service]
ExecStart=
ExecStart=/usr/sbin/nginx -c /home/user/nginx-bashdays.conf
Перезапускаю
nginx
и радуюсь результату, теперь nginx
запущен с другим конфигом.А почему ExecStart идет дважды?
Хе брат, это очередная приколюха
systemd
. Оно очищает предыдущее значение ExecStart
из основного юнита. А следующая строка задаёт новое значение. Без этой хуйни
systemd
бы просто добавил вторую команду, не заменив первую.Думаю на этом можно закончить. Я неочевидную базу выдал, а ты стал еще сильнее. Изучай и ничего не бойся!
—
Please open Telegram to view this post
VIEW IN TELEGRAM
1 53
Как разгребать гавно в юнитах
Ладно, не гавно, а override файлы, которых может быть нихуя не одна штука. Причем несколько для одного юнита.
ㅤ
Не знаю нахуя так делают, но временами такое встречается. Особенно на каких-то легаси серверах, которые работают со времен фидонета.
Короче, все что нам нужно это команда:
Эта команда отменяет все локальные изменения юнита
Короче достаточно прикольная штука, когда нахуевертил, но не знаешь как откатиться.
Команда удаляем override-файлы в:
И следом будет использован оригинальный unit-файл, который обычно расположен в
Когда это полезно?
Если ты вносил изменения через
Наглядные примеры приводить не буду, думаю и так все понятно, что было и что будет.
Ну а ты носи в это в голове и никогда не бойся экспериментировать. Любой факап — твой опыт.
🛠 #linux #tricks #debug #systemd
—
✅ @bashdays / @linuxfactory / @blog
Ладно, не гавно, а override файлы, которых может быть нихуя не одна штука. Причем несколько для одного юнита.
ㅤ
Не знаю нахуя так делают, но временами такое встречается. Особенно на каких-то легаси серверах, которые работают со времен фидонета.
Короче, все что нам нужно это команда:
sudo systemctl revert nginx
Эта команда отменяет все локальные изменения юнита
nginx
и возвращает его к состоянию по умолчанию, заданному в оригинальных unit-файлах, поставляемых системой или пакетом.Короче достаточно прикольная штука, когда нахуевертил, но не знаешь как откатиться.
Команда удаляем override-файлы в:
/etc/systemd/system/nginx.service.d/
/etc/systemd/system/nginx.service
И следом будет использован оригинальный unit-файл, который обычно расположен в
/lib/systemd/system/nginx.service
.Когда это полезно?
Если ты вносил изменения через
systemctl edit
, вручную правил nginx.service
, или добавлял drop-in'ы — и хочешь откатиться к дефолтной конфигурации, revert
делает это безопасно.Наглядные примеры приводить не буду, думаю и так все понятно, что было и что будет.
Ну а ты носи в это в голове и никогда не бойся экспериментировать. Любой факап — твой опыт.
Предыдущие посты на тему systemd ищи по тегу #systemd
—
Please open Telegram to view this post
VIEW IN TELEGRAM
4 61
Почему в юнитах не работает Environment.
Сразу пример:
Сделал юнит, но в скрипт
Тут снова приколы.
➡️ 1. Скрипт запускается не напрямую, а через интерпретатор.
Если в
ㅤ
Но если ты укажешь в
То переменная
Как правильно?
Вот так:
А сам скрипт:
Всё! Теперь переменная из юнита будет корректно передаваться в скрипт.
➡️ 2. Использовать EnvironmentFile=
Если у тебя дохуя переменных, то выносим их в отдельный файл, например сюда
А в самом юните прописываем:
Всё! Теперь переменные считываются из файла и скрипт их видит.
➡️ 3. Передавать переменные прямо в ExecStart
Тут особо и комментировать нечего, всё очевидно.
Как отладить и задебажить?
А вот так:
Вместо nginx подставляешь свой сервис и наблюдаешь все переменные которые передались. В наших примерах увидишь
Справедливо не только для собственных юнитов, но и для других, например для того же nginx или docker.
Как вариант, можешь добавить в скрипт такую хуйню:
И смотришь, какие переменные реально передаются в твой скрипт.
Еще одна база выдана, вроде очевидные вещи, но так глубоко в это никто не лезет. Пользуйся.
🛠 #linux #tricks #debug #systemd #bash
—
✅ @bashdays / @linuxfactory / @blog
Сразу пример:
[Service]
Environment="FOO=bar"
ExecStart=/bin/bash /usr/local/sbin/bashdays.sh
Сделал юнит, но в скрипт
bashdays.sh
не передаётся переменная FOO. Хотя логически всё правильно.Тут снова приколы.
Если в
ExecStart
указан скрипт с shebang’ом (#!/bin/bash
), systemd
запускает его как отдельный процесс, и переменные окружения передаются.ㅤ
Но если ты укажешь в
ExecStart
сам интерпретатор, вот так:ExecStart=/bin/bash /usr/local/sbin/bashdays.sh
То переменная
FOO
, заданная через Environment=
, не попадёт в подскрипт, потому что ExecStart
запускает bash
, а уже bash
запускает — скрипт, и переменные окружения само собой нихуя не передаются.Как правильно?
Вот так:
[Service]
Environment="FOO=bar"
ExecStart=/usr/local/sbin/bashdays.sh
А сам скрипт:
#!/bin/bash
echo "FOO is $FOO"
Всё! Теперь переменная из юнита будет корректно передаваться в скрипт.
Если у тебя дохуя переменных, то выносим их в отдельный файл, например сюда
/etc/bashdays-service.env
.FOO=bar
BAZ=qux
А в самом юните прописываем:
[Service]
EnvironmentFile=/etc/bashdays-service.env
ExecStart=/usr/local/sbin/bashdays.sh
Всё! Теперь переменные считываются из файла и скрипт их видит.
[Service]
ExecStart=/bin/bash -c 'FOO=bar exec /usr/local/sbin/bashdays.sh'
Тут особо и комментировать нечего, всё очевидно.
Как отладить и задебажить?
А вот так:
systemctl show nginx
Вместо nginx подставляешь свой сервис и наблюдаешь все переменные которые передались. В наших примерах увидишь
Environment=FOO=bar
.Справедливо не только для собственных юнитов, но и для других, например для того же nginx или docker.
Как вариант, можешь добавить в скрипт такую хуйню:
env > /tmp/env.log
И смотришь, какие переменные реально передаются в твой скрипт.
Еще одна база выдана, вроде очевидные вещи, но так глубоко в это никто не лезет. Пользуйся.
—
Please open Telegram to view this post
VIEW IN TELEGRAM
7 82
Три скрытых героя systemd
А вот и сами герои:
Это невидимые юниты
➡️ 1. Timer
Про
Пример:
Активируем:
Всё! Никаких тебе легаси кронтабов, все работает на юнитах, запускается бэкапилка, тикает таймер.
➡️ 2. Path
Работает как
Пример:
Теперь каждый раз когда в папке
➡️ 3. Socket
Заменяет ручной
ㅤ
Нихуя не понятно, но на примере сейчас всё прояснится.
Пример:
В примере, сервис НЕ работает постоянно, он стартует, только когда кто-то подключается к порту
Когда ты используешь
Как понять, какой экземпляр стартует?
Зачем нужны скрытые юниты?
1. Не нужен
2. Не нужен
3. Сервисы не висят без дела, запускаются только когда нужно
4. Журналирование через
Вот такие пироги. В повседневной работе я применяю
Ну а ты попробуй хотя бы перетащить свои кронджобы в
🛠 #linux #tricks #debug #systemd #bash
—
✅ @bashdays / @linuxfactory / @blog
А вот и сами герои:
timer
, path
и socket
Это невидимые юниты
systemd
, которые могут заменить cron
, inotify`и даже `xinetd
.Про
timer
ты наверняка слышал. Это альтернатива crontab. Позволяет запускать сервис по расписанию. Вместо того чтобы писать крон-джобы, ты создаёшь .service
и .timer
.Пример:
/etc/systemd/system/backup.service
[Unit]
Description=Backup job
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/backup.sh
/etc/systemd/system/backup.timer
[Unit]
Description=Run backup daily
[Timer]
OnCalendar=daily
Persistent=true
[Install]
WantedBy=timers.target
Активируем:
sudo systemctl enable --now backup.timer
Persistent=true
гарантирует запуск пропущенной задачи, если система была выключена.Всё! Никаких тебе легаси кронтабов, все работает на юнитах, запускается бэкапилка, тикает таймер.
Работает как
inotifywait
или File Watcher: следит за файлами/папками и запускает сервис при изменении.Пример:
/etc/systemd/system/upload.path
[Unit]
Description=Watch upload folder
[Path]
PathModified=/var/www/bashdays/upload
Unit=process-upload.service
[Install]
WantedBy=multi-user.target
/etc/systemd/system/process-upload.service
[Unit]
Description=Process uploaded files
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/process-upload.sh
Теперь каждый раз когда в папке
/var/www/bashdays/upload
что-то меняется, автоматически запускается скрипт process-upload.sh
.Тут уже от твоих предпочтений зависит, как и с чем это скрещивать, но кейсов можно придумать довольно дохуя. Например, проверка антивирусом, или запуск какого-нибудь ffmpeg.
Заменяет ручной
systemctl start
, активируя сервис при первом подключении к сокету. Аналог inetd/xinetd
ㅤ
Нихуя не понятно, но на примере сейчас всё прояснится.
Пример:
/etc/systemd/system/echo.socket
[Unit]
Description=Echo socket
[Socket]
ListenStream=12345
Accept=yes
[Install]
WantedBy=sockets.target
/etc/systemd/system/echo@.service
[Unit]
Description=Echo service
[Service]
ExecStart=/usr/bin/nc -l -p 12345 -e /bin/cat
StandardInput=socket
В примере, сервис НЕ работает постоянно, он стартует, только когда кто-то подключается к порту
12345
.Когда ты используешь
.socket
с Accept=yes
, systemd
открывает сокет сам и ждёт подключения. А когда подключение приходит — создаёт новый экземпляр сервиса, подставляя туда данные об этом соединении. После завершения — сервис умирает. Всё очень экономно и прозрачно.Как понять, какой экземпляр стартует?
systemd
запускает echo@<ID>.service
, где <ID>
— уникальный идентификатор подключения (например, PID или номер сокета).journalctl -u echo@*
Зачем нужны скрытые юниты?
1. Не нужен
cron
, всё централизовано в systemd
.2. Не нужен
inotify-tools
.3. Сервисы не висят без дела, запускаются только когда нужно
4. Журналирование через
journalctl
Вот такие пироги. В повседневной работе я применяю
timer
и path
, с сокетами как-то сильно не приходилось париться.Ну а ты попробуй хотя бы перетащить свои кронджобы в
timer
и порадоваться бест-практикам.—
Please open Telegram to view this post
VIEW IN TELEGRAM
9 101
Продолжаем ковырять systemd
Для того чтобы потыкать
Делается это так:
Ключ
ㅤ
Теперь этот юнит будет запускаться каждый раз при старте пользовательской сессии, а таймер начнет тикать.
Эта штука создаёт символическую ссылку в
Если тебе нужно разово запустить такой юнит, то
А как отлаживать?
➡️ 1. Сначала нужно убедиться что таймер активен:
Если всё ок, то увидишь
➡️ 2. Смотрим расписание запуска
-
-
-
-
➡️ 3. Проверяем выполнялся ли сервис
Команда покажет логи выполнения скрипта. Можно сузить диапазон, например так:
По дебагу это основное. Мелочи вроде синтаксических ошибок и т.п. рассматривать не будем, тут уже от кривизны рук все зависит.
Ну а так всё что нужно тебе знать. То есть у каждого пользователя могут быть свои юниты и сервисы, а не только у рута.
🛠 #linux #tricks #debug #systemd #bash
—
✅ @bashdays / @linuxfactory / @blog
Для того чтобы потыкать
systemd
не обязательно обладать рутовскими правами или судой-мудой. Да, ты не ослышался, всё можно запускать под обычным юзером.Делается это так:
systemctl --user enable bashdays.timer
Ключ
--user
означает, что команда применяется в пользовательском пространстве, а не на уровне всей системы.ㅤ
Теперь этот юнит будет запускаться каждый раз при старте пользовательской сессии, а таймер начнет тикать.
Эта штука создаёт символическую ссылку в
~/.config/systemd/user/
в директории default.target.wants/
Если тебе нужно разово запустить такой юнит, то
enable
меняем на start
. Вот и вся наука.А как отлаживать?
systemctl --user status bashdays.timer
Если всё ок, то увидишь
Active: active (waiting)
.systemctl --user list-timers
-
NEXT
— когда следующий запуск-
LEFT
— сколько осталось времени-
LAST
— когда запускался в прошлый раз-
UNIT
— имя таймераjournalctl --user-unit bashdays.service --since "1 hour ago"
Команда покажет логи выполнения скрипта. Можно сузить диапазон, например так:
journalctl --user-unit bashdays.service --since today
По дебагу это основное. Мелочи вроде синтаксических ошибок и т.п. рассматривать не будем, тут уже от кривизны рук все зависит.
Ну а так всё что нужно тебе знать. То есть у каждого пользователя могут быть свои юниты и сервисы, а не только у рута.
—
Please open Telegram to view this post
VIEW IN TELEGRAM
3 58
Продолжаем разбирать
ㅤ
Директива
Пример:
Этот юнит не запустится, если файл
Если путь НЕ существует,
Нахуя это надо?
1. Например, если
2. Можно создавать один юнит, который активируется только при наличии определённого модуля или плагина.
3. Иногда это используют в early boot-юнитах, чтобы запускать их только если что-то доступно (например, том LUKS).
Список основных Condition's (нажми на спойлер)
Дополнительно
Если заменить
То есть берем к примеру директиву
И получается:
Если
Статус будет такой:
Ну и все это дело можно комбинировать:
Если
Если существует, но не смонтирован — юнит заваливается.
Короче
🛠 #linux #tricks #debug #systemd #bash
—
✅ @bashdays / @linuxfactory / @blog
systemd
на кирпичики. Сегодня про кандишены (условия/ситуации).ㅤ
Директива
ConditionPathExists
используется в юнит-файлах systemd
и позволяет задать условие для запуска юнита: он будет запущен только если указанный файл или директория существует.Пример:
[Unit]
Description=Special Service
ConditionPathExists=/etc/bashdays-config
[Service]
ExecStart=/usr/local/bin/bashdays-handler
Этот юнит не запустится, если файл
/etc/bashdays-config
не существует. В статусе сервиса ты увидишь:ConditionPathExists=/etc/bashdays-config was not met
Если путь НЕ существует,
systemd
не будет запускать юнит. Вместо этого он будет считаться пропущенным (skipped), а не проваленным.Нахуя это надо?
1. Например, если
bashdays-config
существует, запускается сервис с особым поведением.2. Можно создавать один юнит, который активируется только при наличии определённого модуля или плагина.
3. Иногда это используют в early boot-юнитах, чтобы запускать их только если что-то доступно (например, том LUKS).
Список основных Condition's (нажми на спойлер)
ConditionPathExists — файл или каталог существует
ConditionPathIsDirectory — путь существует и это каталог
ConditionPathIsMountPoint — путь является точкой монтирования
ConditionFileIsExecutable — файл существует и он исполняемый
ConditionKernelCommandLine — есть ли параметр ядра с указанным значением
ConditionPathExistsGlob — совпадает ли хотя бы один путь по glob-шаблону
ConditionPathIsSymbolicLink — является ли путь символической ссылкой
ConditionFileNotEmpty — существует ли файл и не пуст ли он
ConditionEnvironment — установлена ли переменная окружения
ConditionArchitecture — архитектура CPU (например, x86_64, aarch64)
ConditionVirtualization — nип виртуализации (например, kvm, docker)
ConditionHost — имя хоста
ConditionMachineID — cовпадает ли machine-id
ConditionControlGroupController — есть ли указанный cgroup controller (например, cpu, memory)
ConditionNeedsUpdate — нуждается ли в обновлении (/usr или /etc)
ConditionFirstBoot — Первый ли это запуск после установки
ConditionACPower — Подключено ли питание от сети (для ноутбуков)
ConditionSecurity — Активен ли определённый LSM (например, selinux)
ConditionUser — Запускается ли от указанного пользователя
ConditionGroup — Запускается ли от указанной группы
ConditionCapability — Имеет ли процесс определённую capability
ConditionNetwork — Есть ли сеть (online, configured)
ConditionMemory — Есть ли минимум указанного объёма памяти
Дополнительно
Если заменить
Condition
на Assert
, условие не выполнено — юнит считается проваленным, а не пропущенным.То есть берем к примеру директиву
ConditionPathExists
и меняем её на AssertPathExists
. AssertPathExists=/etc/bashdays.conf
И получается:
ConditionPathExists
— юнит пропускается (не считается ошибкой)AssertPathExists
— юнит падает (считается ошибкой)Assert
полезен, когда ты строго требуешь, чтобы ресурс (например, внешний диск, NFS, или другой том) был смонтирован перед запуском сервиса. Если его нет — это ошибка, а не «ну и похуй».[Unit]
Description=Start backup script only if /mnt/backup is mounted
AssertPathIsMountPoint=/mnt/backup
[Service]
ExecStart=/usr/local/bin/backup.sh
Если
/mnt/backup
не смонтирован, systemd
выдаст ошибку, и сервис не запустится.Статус будет такой:
systemd[1]: Starting backup.service...
systemd[1]: backup.service: Failed with result 'assert'.
Ну и все это дело можно комбинировать:
ConditionPathExists=/mnt/backup
AssertPathIsMountPoint=/mnt/backup
Если
/mnt/backup
не существует — юнит пропускается.Если существует, но не смонтирован — юнит заваливается.
Короче
systemd
не такой уж простой, как кажется с первого взгляда. На нём можно прям заебись логику построить и получить желаемое. Так что недооценивать его явно не стоит, это прям заебись комбайн.—
Please open Telegram to view this post
VIEW IN TELEGRAM
6 70
Всем привет. Опять решил поделиться опытом своих провалов.
🔤 🔤 🔥 🔤 🔤 🔤 🔤
Вобщем, как-то раз я решил написать самоучитель по bash.
По традиции все учебники либо в html, либо в pdf. Я решил остановиться на pdf. Я начал писать в libreoffice, там есть экспорт в pdf. Пока писал - познакомился с markdown. И вдруг подумалось, markdown - такой классный, напрямик можно в гитхаб запихнуть. И в pdf конвертнуть с помощью pandoc можно. Вобщем, решил верстать в markdown.
ㅤ
Для начала познакомился с редакторами, которые умеют подсвечивать markdown (pluma, mousepad, geany) Вобщем, жить можно, но подсвечивается не всё.
После этого попробовал Apostrophe. Он уже умеет дополнительно показывать результат. Но работает медленно. Особенно на больших документах.
В общем - перепопробовал, - не нравится. Решил писать в mousepad, а потом конвертить с помощью pandoc.
Написал скрипт для удобства пользования - меняется дата файла - автоматом резервная копия версии и конвертация в фоне.
Начал работать и тут вскрылась куча недостатков markdown;
1. Нет нормального форматирования (заголовок нельзя центрировать)
2. Нет нормальных таблиц, один ущерб какой-то.
3. Проблема с кирилицей (решаемая), но с помощью дополнительного tex-файла настроек.
4. Нет возможности печатать некоторые символы UTF.
5. некоторые символы приходится маскировать, чтобы они не понимались, как управляющие.
Единственный плюс - подсветка синтаксиса bash.
В общем, после 19 главы я понял, что моего терпения не хватит закончить работу. Вернулся к libreoffice. За два дня освоил работу со стилями, и все пошло как по маслу. Кстати, экспорт в pdf тоже быстрее, на мой взгляд.
Может и не все получилось, сами знаете - первый блин комом.
Замечания и комментарии приветствуются.
С результатом можно ознакомиться здесь 👇
🅰️ 🅰️
➡️ https://github.com/tagd-tagd/self-instruction
🅰️ 🅰️
🛠 #bash #linux #utilites #markdown
—
✅ @bashdays / @linuxfactory / @blog
Вобщем, как-то раз я решил написать самоучитель по bash.
По традиции все учебники либо в html, либо в pdf. Я решил остановиться на pdf. Я начал писать в libreoffice, там есть экспорт в pdf. Пока писал - познакомился с markdown. И вдруг подумалось, markdown - такой классный, напрямик можно в гитхаб запихнуть. И в pdf конвертнуть с помощью pandoc можно. Вобщем, решил верстать в markdown.
ㅤ
Для начала познакомился с редакторами, которые умеют подсвечивать markdown (pluma, mousepad, geany) Вобщем, жить можно, но подсвечивается не всё.
После этого попробовал Apostrophe. Он уже умеет дополнительно показывать результат. Но работает медленно. Особенно на больших документах.
В общем - перепопробовал, - не нравится. Решил писать в mousepad, а потом конвертить с помощью pandoc.
Написал скрипт для удобства пользования - меняется дата файла - автоматом резервная копия версии и конвертация в фоне.
Начал работать и тут вскрылась куча недостатков markdown;
1. Нет нормального форматирования (заголовок нельзя центрировать)
2. Нет нормальных таблиц, один ущерб какой-то.
3. Проблема с кирилицей (решаемая), но с помощью дополнительного tex-файла настроек.
\usepackage{longtable}\setlength{\LTleft}{2em}
\setmainfont{Liberation Serif}
\setsansfont{Liberation Sans}
\setmonofont{Liberation Mono}
\newfontfamily\cyrillicfont{Liberation Sans}
\defaultfontfeatures{Scale=MatchLowercase, Mapping=tex-text}
\usepackage{polyglossia}
\setmainlanguage{russian}
\setotherlanguage{english}
4. Нет возможности печатать некоторые символы UTF.
5. некоторые символы приходится маскировать, чтобы они не понимались, как управляющие.
Единственный плюс - подсветка синтаксиса bash.
В общем, после 19 главы я понял, что моего терпения не хватит закончить работу. Вернулся к libreoffice. За два дня освоил работу со стилями, и все пошло как по маслу. Кстати, экспорт в pdf тоже быстрее, на мой взгляд.
Может и не все получилось, сами знаете - первый блин комом.
Замечания и комментарии приветствуются.
С результатом можно ознакомиться здесь 👇
—
Please open Telegram to view this post
VIEW IN TELEGRAM
3 93
Сегодня будем убивать неугодные сервисы. Нет, тут будет не про
Короче в юните можно указать параметр
ㅤ
Удобно применять для сервисов, которые не должны жить вечно. Нет ничего вечного! Например, временные задачи, вспомогательные демоны, скрипты и т.п.
А что будет если время вышло?
Как и написал выше — будет песда!
Этот сервис будет убит через 60 секунд после запуска — даже если скрипт ещё не завершился.
Если
Ждём до 10 секунд → если не завершился →
Частый паттерн
Сервис работает максимум 5 минут, и если завис —
А нахуя тут Restart=on-failure?
Оно говорит — «если сервис завершился аварийно — перезапусти его» А завершение по
Если не указать
Важный нюанс!
Если в юните используется
Такие дела, изучай!
🛠 #linux #tricks #debug #systemd #bash
—
✅ @bashdays / @linuxfactory / @blog
kill
и т.п. а будет все тот же systemd
.Короче в юните можно указать параметр
RuntimeMaxSec
, в нем задаём время жизни сервиса. Если сервис работает дольше указанного времени, то ему песда. Systemd
принудительно завершит его.ㅤ
Удобно применять для сервисов, которые не должны жить вечно. Нет ничего вечного! Например, временные задачи, вспомогательные демоны, скрипты и т.п.
[Service]
RuntimeMaxSec=30s
0s
, 5min
, 1h
, 2d
— интервалыinfinity
— отключение лимитаА что будет если время вышло?
Как и написал выше — будет песда!
Systemd
пошлет SIGTERM
. А если сервис сука живучий и не завершился, то в ход пойдет тяжелая артиллерия через TimeoutStopSec
, тут уже будет послан SIGKILL
. Но его нужно предварительно прописать.TimeoutStopSec=
— это время ожидания корректного завершения сервиса после того, как systemd послал ему сигнал SIGTERM
.[Service]
ExecStart=/usr/bin/python3 /opt/scripts/bashdays-task.py
RuntimeMaxSec=60
Этот сервис будет убит через 60 секунд после запуска — даже если скрипт ещё не завершился.
[Service]
ExecStart=/usr/bin/bashdays-daemon
RuntimeMaxSec=60
TimeoutStopSec=10
Если
bashdays-daemon
работает дольше 60 секунд → SIGTERM
Ждём до 10 секунд → если не завершился →
SIGKILL
Частый паттерн
RuntimeMaxSec=300
TimeoutStopSec=5
Restart=on-failure
Сервис работает максимум 5 минут, и если завис —
systemd
подождёт 5 секунд на аккуратное завершение, а потом прибьёт его нахуй.А нахуя тут Restart=on-failure?
Оно говорит — «если сервис завершился аварийно — перезапусти его» А завершение по
SIGKILL
из-за превышения времени жизни это и есть failure.Если не указать
TimeoutStopSec
, будет использоваться значение по умолчанию: 90 секунд — порой это дохуя, поэтому предпочтительнее задать его руками.Важный нюанс!
Если в юните используется
Restart=always
, то после убийства, сервис будет перезапущен и возможно сразу «помрёт» если не изменит своё поведение.Такие дела, изучай!
—
Please open Telegram to view this post
VIEW IN TELEGRAM
6 59
reexec VS reload
Порой народ путает команды
ㅤ
С виду вроде похожие, но нет. Спросил тут на досуге товарища — а ты знаешь чем они отличаются?
Да, ответил товариш,
Неее… так не нужно! Это хуйня! По крайней мере первая команда тебе тут не нужна для перезапуска и обновления сервисов.
Команда
После редактирования
Обычно проходится по каталогам:
То есть она перезагружает только конфигурацию юнитов, без перезапуска сервисов.
Так что не путай, в большинстве случаев тебе достаточно
🛠 #linux #tricks #debug #systemd
—
✅ @bashdays / @linuxfactory / @blog
Порой народ путает команды
systemctl daemon-reload
и systemctl daemon-reexec
. ㅤ
С виду вроде похожие, но нет. Спросил тут на досуге товарища — а ты знаешь чем они отличаются?
Да, ответил товариш,
reexec
это старая версия перечитывания сервисов и юнитов. Я обычно делаю так:systemctl daemon-reexec
systemctl daemon-reload
systemctl enable node_exporter
systemctl start node_exporter
Неее… так не нужно! Это хуйня! По крайней мере первая команда тебе тут не нужна для перезапуска и обновления сервисов.
Команда
systemctl daemon-reexec
перезапускает сам systemd
, это нужно например при обновлении бинарников systemd
, но никак не для перезапуска юнитов и сервисов.После редактирования
*.service / *.timer / *.mount
файлов, достаточно сделать daemon-reload
, эта команда перечитает unit-файлы.Обычно проходится по каталогам:
/etc/systemd/system/
/lib/systemd/system/
/usr/lib/systemd/system/
/run/systemd/system/
То есть она перезагружает только конфигурацию юнитов, без перезапуска сервисов.
Так что не путай, в большинстве случаев тебе достаточно
daemon-reload
.—
Please open Telegram to view this post
VIEW IN TELEGRAM
8 66
Имена файлов удаляются с помощью системных вызовов
ㅤ
Ну дак вот. Когда счетчик ссылок (имен) становится равен нулю — файл удаляется.
Физическое удаление (блоки маркируются свободными) происходит когда больше никто не удерживает файл. То есть процесс закрыл последний дескриптор ассоциированный с файлом.
Давай попробуем поймать (открыть файл) до того, как запустится вызов
Создаем искусственный временный файл:
Создаем и запускаем скрипт:
Что тут происходит?
Итоги:
Эта фишка демонстрирует, что можно удалить файл, но продолжить его использовать если он был открыт на момент удаления.
Это классическая Unix-модель: имя файла — не сам файл, а просто ссылка.
А тут как-то рассказывал, как восстанавливать удаленные файлы, в том числе и запущенные.
Чтиво почитать:
man 2 unlink
man 2 unlinkat
🛠 #linux #bash
—
✅ @bashdays / @linuxfactory / @blog
unlink
, unlinkat
.ㅤ
Ну дак вот. Когда счетчик ссылок (имен) становится равен нулю — файл удаляется.
Физическое удаление (блоки маркируются свободными) происходит когда больше никто не удерживает файл. То есть процесс закрыл последний дескриптор ассоциированный с файлом.
Давай попробуем поймать (открыть файл) до того, как запустится вызов
unlink
.Создаем искусственный временный файл:
printf '%s\n' {a..z} > /tmp/sh-thd-bashdays
Создаем и запускаем скрипт:
#!/bin/bash
file=/tmp/sh-thd-bashdays
exec 3< "$file"
rm -vf "$file" # Имени уже нет
read -N 4096 -ru 3 # Но мы читаем
printf '%s' $REPLY # Выводим
exec 3>&-
exit
Что тут происходит?
exec 3<
- файл открывается на чтение, привязывается к дескриптору 3
и с этого момента файл начинает жить в «памяти» в open file table ядра, даже если мы его ёбнем удалим. Дескриптор 3
теперь указывает на открытый файл, независимо от имени.rm -vf
- файл удаляется из файловой системы, имени больше нет, НО, его содержимое еще доступно, потому что он открыт.read -N 4096
- читаем до 4096 байт из открытого файла через дескриптор 3
.exec 3>&
- закрываем дескриптор 3
и после этого файл окончательно исчезнет, если его больше никто не держит, а ядро высвобождает ресурсы.Итоги:
Эта фишка демонстрирует, что можно удалить файл, но продолжить его использовать если он был открыт на момент удаления.
Это классическая Unix-модель: имя файла — не сам файл, а просто ссылка.
Если держишь дескриптор — файл всё ещё существует.
А тут как-то рассказывал, как восстанавливать удаленные файлы, в том числе и запущенные.
Чтиво почитать:
man 2 unlink
man 2 unlinkat
—
Please open Telegram to view this post
VIEW IN TELEGRAM
CRON в первый рабочий день месяца
ㅤ
Да, ключевой момент тут именно в «рабочий день».
Задачка вроде не тривиальная, но как оказалось
Мы с тобой не пальцем деланы, изобретем свой велосипед!
Чтобы реализовать желаемое, я изобрел такую кишку:
Выглядит монструозно, но блядь... Можно в сам скрипт проверку забить, но это еще один костыль.
Что тут происходит?
Короче…
То есть АПИха возвращает
Тут еще бы для
Всегда старайся указывать полные пути до программ и утилит. Это распространенный кейс, крон вроде отрабатывает, но ничего не работает. А оно просто не знает откуда запускать, то что ты ему прописал.
Если знаешь еще какие-то способы, велком в комментарии.
UPD: более корректные алгоритмы решения этой задачи смотрим в комментах, всем спасибо!
🛠 #bash #linux
—
✅ @bashdays ✅ @linuxfactory ✅ @blog
ㅤ
Да, ключевой момент тут именно в «рабочий день».
Задачка вроде не тривиальная, но как оказалось
cron
нихуя не умеет определять рабочий сегодня день или нет. И systemd timer
тоже не умеет. Никто ничо блядь не умеет.Мы с тобой не пальцем деланы, изобретем свой велосипед!
Чтобы реализовать желаемое, я изобрел такую кишку:
0 8 1-3 * * [ "$(date +\%u)" -lt 6 ] && [ "$(curl -s https://isdayoff.ru/$(date +\%Y\%m\%d))" = "0" ] && /usr/local/sbin/bashdays.sh
Выглядит монструозно, но блядь... Можно в сам скрипт проверку забить, но это еще один костыль.
Что тут происходит?
Короче…
0 8 1-3 * *
— Запуск 1–3 числа месяца в 08:00. Потому что первый рабочий день месяца может выпасть на 1-е число, если это будний день. 2-е число, если 1-е — выходной. 3-е число, если 1-е и 2-е — выходные (например, сб + вс).[ "$(date +%u)" -lt 6 ]
— Проверяем, что сегодня будний день (1–5 = Пн–Пт). Пусть тебя здесь 6ка не смущает. Она означает: день меньше 6, т.е. 1
, 2
, 3
, 4
, 5
— это будни (Пн – Пт).curl ... = "0"
— Проверка, что сегодня рабочий день по календарю РФ, выполняется через АПИху производственного календаря.&& /opt/scripts/first-workday.sh
— Выполняем только если сошлись оба условия.То есть АПИха возвращает
0
если сегодня будни. Если выходной, то оно вернет что-то другое.Тут еще бы для
curl
и date
указать что-то вроде CURL=$(which curl)
, а то крон частенько залупается и не знает откуда запускать эти команды. Всегда старайся указывать полные пути до программ и утилит. Это распространенный кейс, крон вроде отрабатывает, но ничего не работает. А оно просто не знает откуда запускать, то что ты ему прописал.
Да, есть зависимость от внешнего API и порой это пиздец хуёва. Отвалилась АПИха, скрипт не получил данные. Поэтому рекомендую сделать себе собственный микросервис с АПИхой и ни от кого не зависеть. Тем более если сервер в оффлайне, запрос на внешнюю АПИху он сделать не сможет.
Если знаешь еще какие-то способы, велком в комментарии.
UPD: более корректные алгоритмы решения этой задачи смотрим в комментах, всем спасибо!
—
Please open Telegram to view this post
VIEW IN TELEGRAM
6 56
Слыхал про
Если коротко, это штуки, которые не дают запустить второй экземпляр скрипта/программы, если первый ещё работает.
ㅤ
Всё это и многое другое входит в пакет
Например (нажми на спойлер):
Вернемся к
Допустим у тебя что-то запустилось по крону, не успело завершиться и через промежуток снова запускается. Наплодилось 100500 процессов, сервак встал раком, а потом и тебя поставили раком.
Давай на практике!
В первом терминале запускаем:
Во втором терминале запускаем:
И получаем:
По умолчанию
Теперь когда файл
Как lckdo работает с lock-файлом.
1. Файл
2. Блокировку держит процесс, который открыл файл и вызвал
3. Когда процесс завершается — блокировка автоматически снимается.
Даже если файл
Всё логично, вот еще одни пример с кроном:
Скрипт не будет запущен, если предыдущий запуск не завершился.
Такие дела. Бери на вооружение, возможно где-то в хозяйстве сгодится.
🛠 #linux
—
✅ @bashdays ✅ @linuxfactory ✅ @blog
with-lock-ex
, flock
, lckdo
?Если коротко, это штуки, которые не дают запустить второй экземпляр скрипта/программы, если первый ещё работает.
ㅤ
Всё это и многое другое входит в пакет
moreutils
, в убунтах из коробки я их не нашел, пришлось ставить. Но это детали. В этот пакет входит еще дюжина полезных хуёвин.Например (нажми на спойлер):
sudo apt install moreutils
chronic — показывает вывод команды, только если она завершилась с ошибкой.
combine — логические операции над двумя файлами (как `sort` + `comm`, но проще).
errno — выводит описание кода ошибки (EACCES 13 Permission denied).
ifdata — dыводит информацию о сетевых интерфейсах в скриптабельном виде.
ifne — выполняет команду только если предыдущая команда что-то вывела (if-not-empty).
isutf8 — проверяет, является ли файл валидным UTF-8.
и так далее…
Вернемся к
lckdo
(Lock and Do). Это обёртка вокруг flock
. Как и написал выше, оно не позволяет запуститься второму экземпляру программы/скрипты.Допустим у тебя что-то запустилось по крону, не успело завершиться и через промежуток снова запускается. Наплодилось 100500 процессов, сервак встал раком, а потом и тебя поставили раком.
lckdo
— cтавит блокировку на файл, если блокировка прошла — выполняет указанную команду, если не удалось — завершает выполнение (по умолчанию).Давай на практике!
В первом терминале запускаем:
lckdo /tmp/bashdays.lock bash -c 'echo start; sleep 60; echo done'
Во втором терминале запускаем:
lckdo /tmp/bashdays.lock echo "Hello bashdays"
И получаем:
lckdo: lockfile /tmp/bashdays.lock' is already locked
По умолчанию
lckdo
ничего не ждет, если нужно, чтобы он ждал до освобождения блокировки, добавляем -w
.lckdo -w /tmp/bashdays.lock echo "I'm free"
Теперь когда файл
/tmp/bashdays.lock
будет отпущен, отработает команда и выведет на экран I'm free
.Как lckdo работает с lock-файлом.
1. Файл
/tmp/bashdays.lock
сам по себе ничего не блокирует.2. Блокировку держит процесс, который открыл файл и вызвал
flock
/lckdo
на него.3. Когда процесс завершается — блокировка автоматически снимается.
Даже если файл
/tmp/bashdays.lock
остаётся на диске — он больше не заблокирован, и lckdo
снова сможет его использовать.Всё логично, вот еще одни пример с кроном:
* * * * * lckdo /tmp/bashdays.lock /usr/local/bin/bashdays.sh
Скрипт не будет запущен, если предыдущий запуск не завершился.
Такие дела. Бери на вооружение, возможно где-то в хозяйстве сгодится.
—
Please open Telegram to view this post
VIEW IN TELEGRAM
Сопроцессы. Практика. Часть Вторая.
🔤 🔤 🔥 🔤 🔤 🔤 🔤
coproc хорошо подходит для общения в клиент-серверном режиме. Для примера попробуем подключиться к POP3 серверу с шифрованием ssl прямо из bash-скрипта.
ㅤ
Сам ssl несколько сложноват для bash, поэтому в качестве посредника будем использовать openssl s_client.
Протокол и команды POP3 лучше посмотреть на википедии.
1. Cоздим сопроцесс. Для этого запустим openssl в режиме s_client. При этом из дескриптора POP3_CONN[0] можно читать данные от сопроцесса.
В дескриптор POP3_CONN[1] можно писать для сопроцесса.
При записи используем перенаправление >&${POP3_CONN[1] . При чтении тоже можно использовать перенаправление, но поскольку у команды read есть ключ -u красивее воспользоваться им.
2. Аутентифицируемся
3. Закроем сессию и дескрипторы.
Задержки 0.3 секунды при отправке нужны для того, чтобы сервер успел сформировать ответ.
Ошибки -ERR не обрабатывал. В случае чего команда read завершится по таймауту в 2 сек. (-t 2)
${REC//$'\r'/} конструкция удаляет cr, потому что POP3 сервер отвечает c lfcr.
help coproc
help read
man openssl
вики POP3
🛠 #bash #linux
—
✅ @bashdays ✅ @linuxfactory ✅ @blog
coproc хорошо подходит для общения в клиент-серверном режиме. Для примера попробуем подключиться к POP3 серверу с шифрованием ssl прямо из bash-скрипта.
ㅤ
Сам ssl несколько сложноват для bash, поэтому в качестве посредника будем использовать openssl s_client.
Протокол и команды POP3 лучше посмотреть на википедии.
1. Cоздим сопроцесс. Для этого запустим openssl в режиме s_client. При этом из дескриптора POP3_CONN[0] можно читать данные от сопроцесса.
В дескриптор POP3_CONN[1] можно писать для сопроцесса.
При записи используем перенаправление >&${POP3_CONN[1] . При чтении тоже можно использовать перенаправление, но поскольку у команды read есть ключ -u красивее воспользоваться им.
2. Аутентифицируемся
3. Закроем сессию и дескрипторы.
# Функция для отправки команд серверу
function SEND_CMD() {
sleep 0.3
echo "$@" >&${POP3_CONN[1]}
sleep 0.3
}
# аутентификация. Обычный логин
function POP3_LOGIN() {
declare REC
declare -a AREC
# проверка соединения
read -ert 2 -u ${POP3_CONN[0]} REC
read -ra AREC <<<${REC//$'\r'/}
if [[ "${AREC[0]}" == "+OK" ]];then
# Отправляем логин
SEND_CMD "USER $USER"
read -ert 2 -u ${POP3_CONN[0]} REC
read -ra AREC <<<${REC//$'\r'/}
if [[ "${AREC[0]}" == "+OK" ]];then
# Отправляем пароль
SEND_CMD "PASS $PASS"
read -ert 2 -u "${POP3_CONN[0]}" REC
read -ra AREC <<<${REC//$'\r'/}
if [[ "${AREC[0]}" == "+OK" ]];then
return 0 # аутентификация успешна
else
return 3 # не правильный пароль
fi
else
return 2 #не правильный login
fi
else
return 1 # ошибка соединения с сервером
fi
}
#Выход и закрытие дескрипторов.
function POP3_QUIT(){
SEND_CMD "QUIT"
# Закрываем coproc
exec ${POP3_CONN[0]}<&-
exec ${POP3_CONN[1]}>&-
}
Задержки 0.3 секунды при отправке нужны для того, чтобы сервер успел сформировать ответ.
Ошибки -ERR не обрабатывал. В случае чего команда read завершится по таймауту в 2 сек. (-t 2)
${REC//$'\r'/} конструкция удаляет cr, потому что POP3 сервер отвечает c lfcr.
#!/bin/bash
SERVER="server"
PORT=995
USER="user@server"
PASS="StrongPass"
# создаем сопроцесс и соединяемся с сервером pop3
coproc POP3_CONN { openssl s_client -connect "${SERVER}:${PORT}" -quiet 2>/dev/null;}
POP3_LOGIN
POP3_QUIT
help coproc
help read
man openssl
вики POP3
—
Please open Telegram to view this post
VIEW IN TELEGRAM
2 21
Сопроцессы. Практика. Часть Третья.
🔤 🔤 🔥 🔤 🔤 🔤 🔤
Это уже больше не сопроцессы, а про то, как принять почту в скрипте bash.
ㅤ
Соединение с POP3 сервером есть. Аутентификация тоже. Осталось написать что-нибудь полезное.
Финальный код
help coproc
help read
man openssl
🛠 #bash #linux
—
✅ @bashdays ✅ @linuxfactory ✅ @blog
Это уже больше не сопроцессы, а про то, как принять почту в скрипте bash.
ㅤ
Соединение с POP3 сервером есть. Аутентификация тоже. Осталось написать что-нибудь полезное.
# возвращает число писем в ящике
function POP3_STAT(){
declare -a AREC
declare REC
SEND_CMD "STAT"
read -ert 2 -u ${POP3_CONN[0]} REC
read -ra AREC <<<${REC//$'\r'/}
if [[ ${AREC[0]} == "+OK" ]];then
echo ${AREC[1]} # число сообщений
return 0
else
echo 0
return 1
fi
}
#Помечает к удалению указанное письмо
function POP3_DELE(){
declare -i MSG_NUM=${1:-1} # по умолчанию первое
declare -a AREC
declare REC
SEND_CMD "DELE $MSG_NUM" #удаляем указанное сообщение
read -ert 2 -u ${POP3_CONN[0]} REC
read -ra AREC <<<${REC//$'\r'/}
if [[ ${AREC[0]} == "+OK" ]];then
return 0
else
return 1
fi
}
# читает письмо с заголовками
function POP3_RETR(){
declare -i MSG_NUM=${1:-1} # по умолчанию первое
declare -a AREC
declare REC
SEND_CMD "RETR $MSG_NUM" #читаем указанное сообщение
read -ert 2 -u ${POP3_CONN[0]} REC
read -ra AREC <<<${REC//$'\r'/}
if [[ ${AREC[0]} == "+OK" ]];then
while read -r -t 2 -u ${POP3_CONN[0]} REC ; do
REC=${REC//$'\r'/}
echo "$REC"
if [[ "$REC" == "." ]];then
return 0 # msg end
fi
done
else
return 1
fi
}
# читает указанное число строк письма
function POP3_TOP(){
declare -i MSG_NUM=${1:-1} # по умолчанию первое
declare -i STR_NUM=${2:-1} # по умолчанию одна строка
declare -a AREC
declare REC
#читаем указанное сообщение
SEND_CMD "TOP $MSG_NUM $STR_NUM"
read -ert 2 -u ${POP3_CONN[0]} REC
read -ra AREC <<<${REC//$'\r'/}
if [[ ${AREC[0]} == "+OK" ]];then
while read -ert 2 -u ${POP3_CONN[0]} REC ; do
REC=${REC//$'\r'/}
echo "$REC"
if [[ "$REC" == "." ]];then
return 0
fi
done
else
return 1
fi
}
Финальный код
#!/bin/bash
SERVER="server"
PORT=995
USER="user@server"
PASS="StrongPass"
coproc POP3_CONN { openssl s_client -connect "${SERVER}:${PORT}" -quiet 2>/dev/null;}
POP3_LOGIN && echo POP3_LOGIN OK
MSG_NUM=$(POP3_STAT)
#цикл перебора сообщений
while ((MSG_NUM));do
POP3_TOP $MSG_NUM 1 # Заголовки + 1 строку сообщения
# POP3_RETR $MSG_NUM # сообщения целиком
# POP3_DELE $MSG_NUM # помечаем к удалению.
((--MSG_NUM))
done
POP3_QUIT
help coproc
help read
man openssl
—
Please open Telegram to view this post
VIEW IN TELEGRAM