cron
, которая позволяет планировать запуск различных задач в заданное время. Мы, кроме того, уже говорили о программе incron
, которая реагирует не на события, связанные со временем, а на изменения в файловой системе. Возможно, вам когда-нибудь надо было написать программу, которая, например, обнаруживает изменения в файле и автоматически прошивает какой-нибудь контроллер, или делает резервную копию файла, или отправляет файл по электронной почте. Для решения подобных задач вполне можно воспользоваться incron
. Мы обсуждали основы incron
, но надо сказать, что в работе этой утилиты есть некоторые особенности, которые сильно усложняют поиск и устранение неполадок, возникающих при её применении. Здесь я хочу рассказать о некоторых приёмах, которыми я пользовался для того чтобы привести в рабочее состояние проекты, основанные на incron
.
В моём случае речь идёт о разработке простой системы для работы с документами, хранящимися в директории, находящейся под контролем git
. А именно, при изменении Markdown-файла с расширением .md, находящегося в этой директории, генерируются эквивалентные ему .docx- и .pdf-документы. Аналогично — при измерении .docx-документа воссоздаются .md- и .pdf-файлы.
Работать с документами можно с помощью pandoc
. Эта программа поддерживает множество форматов документов. Главная сложность тут — запуск процедуры сразу после изменения файлов и обработка только тех файлов, которые были изменены. Это — не такая уж и сложная, хотя и нетривиальная задача. Поэтому у меня ушло некоторое время на то, чтобы заставить мою систему правильно работать.
Настройка incron
При настройке incron
можно столкнуться с некоторыми сложностями. Тут я исхожу из предположения о том, что у вас есть возможность установить incron
с помощью менеджера пакетов вроде apt
, и о том, что в вашей системе для запуска и остановки сервисов используется systemd
.
Но, правда, одной только установки для обеспечения нормальной работы incron
недостаточно. Так, ваше имя пользователя должно присутствовать в файле /etc/incron.allow
(и его не должно быть в файле /etc/incron.deny
). После того, как всё готово, пользоваться incron
очень просто. По крайней мере — до тех пор, пока не возникнут какие-нибудь проблемы. Справочные сведения по программе можно узнать, воспользовавшись командой man 5 incrontab
.
Вывод сведений о таблице событий, за которыми наблюдает incron
У каждого пользователя есть своя таблица событий, за которыми наблюдает incron
. Для редактирования таблицы можно воспользоваться такой командой:
incrontab -e
В каждой строке этой таблицы имеется три поля. В первом указана директория, за которой нужно наблюдать (наблюдать можно и за отдельными файлами). Во втором поле находится список событий, которые нужно отслеживать incron
, там же перечисляют и некоторые опции. В третьем поле имеется команда, которую нужно запустить.
В поле, описывающем команду, можно использовать специальные символы. Так, например, последовательность символов $@
даёт имя директории, $#
— имя файла, $%
— тип события в виде строки, $&
— числовой код события. Если в поле с командой требуется обычный знак $
— нужно воспользоваться конструкцией $$
.
События — это то, что описывается строками вроде IN_CREATE
, IN_DELETE
, IN_MODIFY
. В записях таблиц можно использовать любое количество событий, записывая их через запятую. Подробнее об этом я расскажу ниже. В таблице, кроме того, применяются опции наподобие IN_DONT_FOLLOW
, которая предотвращает разыменовывание символических ссылок. Ещё можно воспользоваться опцией recursive=false
, отключив тем самым мониторинг поддиректорий. Ещё одна опция, loopable=true
, предназначена для решения одной распространённой проблемы (отключение мониторинга событий до обработки текущего события), но решает она эту проблему не всегда.
В интернете иногда попадается устаревшая документация по incrontab
. В настоящее время работа над проектом ведётся на GitHub, но главный разработчик оставил проект в 2012 году, а работа над ним продолжилась лишь через 2 года, когда некто взялся за исправление ошибок. Иногда полезно бывает почитать исходный код используемой версии incron
для того чтобы разобраться в том, что именно происходит при работе программы.
Главная проблема incron
Главная проблема incron
— это кризис идентичности. И функционал программы, и её название недвусмысленно намекают на то, что она должна быть очень похожа на cron
. На первый взгляд — так оно и есть. Но дьявол кроется в деталях. Например, старые версии incron
не поддерживают использование комментариев в таблицах. Поэтому можно подумать, что нечто закомментировано, а на самом деле это будет не так. Кроме того, используя incron
очень сложно получить выходные данные от выполняемых команд. Сложно даже просто узнать о том, успешно или нет отработала программа. Нельзя сказать, что это невозможно, но узнать это нелегко. Современные версии программы позволяют использовать комментарии, но на включение в incron
этой возможности ушло много времени, поэтому у вас вполне может быть устаревшая версия incron
.
Ещё одна часто встречающаяся проблема заключается в том, что любое действие в программе, которое вызывает изменения в файловой системе, может привести к бесконечному циклу. Можно подумать, что incron
распознает такую ситуацию и что-то предпримет. Но вместо этого одна строка в вашем incrontab-файле может привести к нарушению работы всего демона.
Ещё сильнее всё усложняет то, что некоторые программы делают то, чего от них не ожидают, а это вносит нарушения в обработку некоторых событий. Например, может показаться, что если нужно узнать о том, что файл изменился, надо мониторить событие IN_MODIFY
. Такое ощущение, что это — вполне здравая мысль. Но большинство редакторов файлов работают иначе. Так, если файл редактируют, работа, на самом деле, ведётся над временным файлом. А когда файл в программе сохраняют, выполняется операция перемещения файла. Иногда программы, обладающие одинаковым функционалом, инициируют разные последовательности событий файловой системы. Например, утилиты scp
и rsync
обрабатывают файлы по-разному. Поэтому, чтобы обнаружить появление нового файла, понадобится, в зависимости от конкретной используемой утилиты, по-разному настраивать incron
.
Совет: работая над командами, применяемыми в incrontab-файле, тщательно исследуйте их, используя логирование
Вышеописанная ситуация ведёт нас к первому совету по работе с incron
. Он заключается в том, что, прежде чем выйти на готовое incrontab-правило, стоит создать временное правило, используя ключевое слово IN_ALL_EVENTS
, и применить простой скрипт для логирования сведений о том, что происходит, когда вы выполняете с файлом некоторые действия. Так вы можете проверить себя, поняв, работает ли всё так, как вы того ждёте. То, что получится, может вас удивить. Поэтому и рекомендуется, перед написанием реальных скриптов, понять то, какую именно последовательность событий файловой системы вызывает та или иная операция.
Пусть у нас имеется следующий скрипт, который мы назовём echoarg.sh
:
#!/bin/bash fn="$1" shift echo "$@" >>"$fn"
Скрипт это до крайности простой, но нас он вполне устраивает. Вот запись incrontab-таблицы, в которой он используется:
/home/user/tmp/itest IN_ALL_EVENTS /bin/bash echoarg.sh /home/user/tmp/echoarg.log $% - $@/$#
Конечно, в именах файлов нужны кавычки, но так как мы всего лишь их выводим, особого значения это не имеет. Тут надо обратить внимание на одну вещь: в некоторых системах incron
запрещено выполнять операции записи в папках наподобие /tmp
, а, возможно, даже запрещено мониторить файлы в подобных папках. Лучше всего экспериментировать с директориями, владельцем которых точно являетесь вы (в данном случае — это /home/user/tmp
). Вот результат выполнения команды touch foo
в директории ~/tmp/itest
:
IN_ATTRIB - /home/user/tmp/itest/foo IN_CREATE - /home/user/tmp/itest/foo IN_OPEN - /home/user/tmp/itest/foo IN_CLOSE_WRITE - /home/user/tmp/itest/foo
Ещё некоторые проблемы
В каждом дистрибутиве всё может быть устроено не так, как в других. Поэтому вам, возможно, придётся почитать документацию. Например, в системах, основанных на Debian, то немногое, что логирует incron
, попадает в system.log
. А в каких-то других распространённых дистрибутивах данные могут попадать в файл cron.log
.
Программа весьма привередливо относится к формату incrontab-таблиц. Так, лишний пробел между вторым и третьим полями нарушит работу системы. То же произойдёт и в том случае, если после имени программы будет идти символ табуляции. Оболочка воспримет этот знак и следующую за ним последовательность символов как часть имени программы.
Если говорить о командной оболочке, то можно отметить, что утилита incron
весьма разборчива в плане поиска оболочки и в плане настройки переменных окружения. Ваша версия incron
может вести себя не так, как моя, но я полагаю, что лучше всего будет для всего, что применяется в incrontab
, указывать полные пути. Стоит и явным образом указывать используемую командную оболочку. Если вам нужно что-то особенное в PATH
или в других переменных среды, выполните соответствующие настройки в скрипте. Если даже вы запускаете бинарный файл — имеет смысл написать небольшую обёртку, позволяющую настроить всё именно так, как нужно. Как минимум, проводя испытания, залогируйте переменные среды во временный файл. Благодаря этому не случится так, что вы неожиданно столкнётесь с отсутствием множества нужных вам переменных.
Использование команд вроде $(date)
обречено на неудачу. Дело в том, что incron
«съест» знак $
. Возможно, если такая команда вам нужна, вам повезёт с конструкцией $$(date)
.
Наш грандиозный проект
После того, как вы разобрались с тем, какие именно события вам нужно обрабатывать, вам нужно написать скрипт и как можно тщательнее его протестировать без использования incron
. В моём случае это был скрипт autopandoc.sh
, .pdf-функционал которого я решил реализовать позже:
#!/bin/bash if [ -z "$1" ] then exit 1 fi if [ ! -f "$1" ] then exit 2 fi dir=$(dirname "$1") ffilename=$(basename -- "$1") ext="${ffilename##*.}" filename="${ffilename%.*}" case "$ext" in doc*) newext="md" ;; md) newext="docx" ;; *) exit 3 esac if [ ! -f "$dir/generated" ] then mkdir "$dir/generated" fi exec pandoc "$1" -o "$dir/generated/$filename.$newext"
Этот скрипт довольно просто вызвать из командной строки, передав ему любые аргументы, представляющие директорию, файл и событие. Так можно удостовериться в том, что работает он именно так, как ожидается. Прошу поверить мне в том, что в таком виде скрипты отлаживать гораздо легче, чем при обработке incron-событий.
Первый вариант такого скрипта у меня не заработал так, как надо. При этом у меня было очень мало подсказок, которые позволили бы справиться с проблемой. Наблюдая за логами, я видел, что происходили события с файлами, но у меня не было свидетельств того, что запускался мой скрипт. При этом то, насколько он был простым, роли не играло. Оказалось, что для решения проблемы нужно было самостоятельно включить в таблицу /bin/bash
.
Далее, я столкнулся с проблемой посерьёзнее. Она заключалась в многократном срабатывании incron
при записи файлов в ту директорию, за которой ведётся наблюдение. Я создавал поддиректорию, это событие вызывало команду, которая создавала ещё одну поддиректорию, а на это событие программа реагировала снова. В итоге утилита incron
останавливалась. При этом речь идёт не о потоке, связанном с моим пользователем. Программа переставала работать для всех пользователей. Я так думаю, можно настроить systemd
на перезапуск incron
, но это, на самом деле, не решает проблему.
Есть несколько опций, позволяющих предотвратить реагирование incron
на изменения в одном и том же файле, но создание нового файла, всё равно, приводит к возникновению событий. И, честно говоря, если бы это было не так, то у нас имелась бы ещё одна проблема, связанная с поддержкой работы нескольких пользователей. Я решил мою задачу, но, прежде чем об этом рассказать, хочу поговорить о том, что происходит в ходе работы incron
.
Анализ файла журнала incron
Как я уже говорил, incron
может логировать данные в различные файлы. В деле анализа логов тем, кто пользуется KDE, пригодится приложение для просмотра системных журналов KSystemLog
. Эта утилита позволяет фильтровать и выводить записи о событиях по мере их появления. Журналы, конечно, можно анализировать и с помощью команды tail -f
. Но чтобы избавиться от информационного шума вам, при таком подходе, может понадобиться прибегнуть к grep
.
Если вы пользуетесь systemd
, вы можете попробовать такую команду:
journalctl -f -u incron.service
Это — нечто вроде tail -f
для лог-файла incron
. Наблюдение за тем, как incron
постоянно вызывает события для /my_dir/subdir/subdir/subdir…
многое расскажет вам о том, что происходит в вашем скрипте.
Дополнительные советы: запускайте демон сами, используйте strace, увеличьте max_user_watches
Сначала остановите демон incron
. Сделать это можно любым удобным для вас способом (например — с помощью команды systemctl stop incron
). После этого выполните команду incrond
с использованием опции -n
. Это позволит вам наблюдать за действиями программы. Учитывайте то, что программу надо запускать с root-правами.
Ещё один вариант исследования работы incron
заключается в использовании strace
для запуска программы. Это позволит узнать обо всех системных вызовах, выполняемых incron
. Поэтому, если вас интересует то, какие именно файлы открывает incron
, и то, к чему это приводит, вам стоит попробовать такую команду:
sudo strace incrond -n
Опция -n
позволяет программе работать на переднем плане. Не забудьте, после того, как завершите эксперименты, остановить incron
и запустить снова в виде сервиса. Конечно, если вы работаете на компьютере, которым пользуются и другие люди, то это — далеко не самая правильная идея.
Если вы приступили к реальной работе с incron
, вы можете обнаружить, что не укладываетесь в системный лимит файлов, которые может отслеживать один пользователь. Лимит задаётся с помощью max_user_watches
. Если это произошло — попробуйте такую команду:
sysctl fs.inotify.max_user_watches
Временно изменить лимит можно так:
sysctl -w fs.inotify.max_user_watches=1000000
Изменить его насовсем можно, отредактировав /etc/sysctl.conf
или добавив файл в /etc/sysctl.d
.
Итоги
После того, как решены все проблемы incron
, эта программа будет работать и решать возлагаемые на неё задачи. Если говорить об использовании incron
в продакшне, то меня беспокоит то, что один некорректно составленный скрипт способен остановить работу всего сервиса. Если вы пользуетесь systemd
, то тут имеются механизмы работы с юнитами path, предназначенными для отслеживания изменений путей в файловой системе. Проекты, реализующие похожий функционал, имеются и на GitHub, но они, правда, выглядят заброшенными.
Иногда incron
— это именно то, что нужно, а иногда лучше поискать альтернативу. Эта ситуация характерна для большинства Linux-инструментов. Но знание особенностей работы различных инструментов обычно себя оправдывает.
Сталкивались ли вы с проблемами incron, подобными тем, о которых рассказывает автор материала?
ссылка на оригинал статьи https://habr.com/ru/company/ruvds/blog/529828/
Добавить комментарий