Inotify или автоматизация рутинных операций с помощью incron

    До сих пор на хабре еще никто не упоминал о такой удобной подсистеме ядра linux, как inotify и использовании ее в автоматизации работы системного администратора. Хотелось бы восполнить этот пробел.

    Что такое inotify


    Inotify — это подсистема ядра Linux, которая позволяет получать уведомления об изменениях в файловой системе. Т.е. простыми словами — эта штука дает нам информацию о создании или изменении любого файла или директории в используемой файловой системе.
    Inotify появилась в ядре аж в версии 2.6.13 и прошла проверку временем. Для ее использования написано несколько утилит, работу с одной из которых мы и рассмотрим.


    incron


    incron — это демон, который следит за событиями в файловой системе с помощью inotify и выполняет команду при наступлении указанного в задании события, аналогично тому, как делает это его тезка cron при наступлении указанного времени.

    Устанавливаем демон средствами своего дистрибутива. У меня это выглядит вот так:

    kolvir ~ # emerge incron

    После установки стартуем демон и добавляем его в списк служб, которые запускаются при старте системы.
    Теперь можно добавлять задания. Выполняется это командой incrontab -e. Можно конечно редактировать файлы и вручную… они находятся в директории /var/spool/incrontab, но лучше все же воспользоваться специально предназначенной для этого утилитой.
    Здесь существует небольшая тонкость. Если при установке у вас создался файл /etc/incron.allow и в нем нету вашего имени пользователя, то следует его туда добавить, иначе вам будет запрещено работать с incron и incrontab. Если же этого файла в системе нет, то по умолчанию доступ будет разрешен всем пользователям.
    Итак, проблемы с доступом мы решили. Теперь набираем incrontab -e и видим перед собой, пока еще, чистый файл, открытый в текстовом редакторе, который у вас в системе прописан по умолчанию.
    Сейчас я расскажу, что туда нужно писать:

    формат crontab-файла для incron

    Cинтаксис crontab будет даже проще чем у классического cron.
    Каждая строчка конфига должна быть следующего вида:

    <путь> <событие> <команда>

    Теперь расшифруем что же здесь нужно писать в каждом столце: Путь — здесь надо указать полный путь к файлу или директории, за которыми мы намерены следить. Команда — тут указывается какой скрипт или какую команду требуется выполнить по наступлении события. Событие — здесь нужно указать одно из следующих видов событий:

    IN_ACCESS — К файлу обращались (чтение)
    IN_ATTRIB — Изменены метаданные (права, дата создания/редактирования, расширенные атрибуты, и т.д.)
    IN_CLOSE_WRITE — Файл, открытый для записи, был закрыт
    IN_CLOSE_NOWRITE — Файл, не открытый для записи, был закрыт
    IN_CREATE — Файл/директория создан(а) в отслеживаемой директории
    IN_DELETE — Файл/директория удален(а) в отслеживаемой директории
    IN_DELETE_SELF — Отслеживаемый(ая) файл/директория был(а) удален(а)
    IN_MODIFY — Файл был изменен
    IN_MOVE_SELF — Отслеживаемый(ая) файл/директория был(а) перемещен(а)
    IN_MOVED_FROM — Файл был перемещен из отслеживаемой директории
    IN_MOVED_TO — Файл перемещен в отслеживаемую директорию
    IN_OPEN — Файл был открыт

    Также в команде можно использовать следующие внутренние переменные (очень удобные для логирования ИМХО):

    $$ знак $
    $@ объект нашей слежки (директория)
    $# имя созданного файла
    $% флаг события (текстом)
    $& флаг события (цифрой)

    Несколько примеров

    Итак. Знаниями вооружились, теперь можно начинать автоматизировать. Наверняка многие уже поняли что и как можно сделать с помощью incron, но я все же напишу несколько примеров, для остальных.

    Возьмем для примера crontab-файл взятый с моего домашнего сервера:

    /etc IN_MODIFY /bin/backup
    /etc/bind/pri/ IN_MODIFY rndc reload
    /etc/bind/pri/named.conf IN_MODIFY /etc/init.d/named restart
    /etc/apache2/ IN_MODIFY /etc/init.d/apache2 restart
    /etc/squid/squid.conf IN_MODIFY /etc/init.d/squid restart
    /etc/squidGuard/ IN_MODIFY /etc/init.d/squid restart
    /etc/conf.d/firewall.sh IN_MODIFY /etc/conf.d/firewall.sh


    В первой строке, при модификации любого файла из директории /etc запускается скрипт резервного копирования, который сохраняет все важные файлы из /etc. Благодаря утилите rsync я могу копировать только измененные файлы экономя трафик и не загружая канал попусту, но сейчас речь не об этом =).
    Далее идут обычные операции перезапуска служб, при изменении их конфигурационных файлов. Как же здорово не делать это вручную каждый раз!
    И в последней строчке происходит запуск скрипта конфигурации файрвола, если тот был изменен.

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

    /mnt/samba/public/shutdown IN_CLOSE_WRITE shutdown now

    Здесь мы выключаем компьютер, если в расшаренной папке, кто-то создал или отредактировал файл shutdown.

    Ссылки

    Подробнее о программном интерфейсе, а также об остальных утилитах можно узнать здесь: ru.wikipedia.org/wiki/Inotify или здесь: www.ibm.com/developerworks/ru/library/l-ubuntu-inotify
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 46
    • +3
      Про перезапуск демонов при изменении конфига — действиетльно клево. Спасибо.
      • +1
        Как раз Dilesoft недавно искал такую штуку!
        • 0
          Ему бы она не подошла (ИМХО), так как для бекапа конфигов требуется гарантированно работающий механизм. А вот поменяли вы конфиги в single-user mode, когда следящий демон не работает — и конфиги не забекапились.

          Сейчас в LKML обсуждают новый механизм — fanotify, в который, может быть, будет добавлено «гарантированное» получение уведомлений про изменение файлов (если уведомление не получено сейчас, то оно будет получено при следующем старте демона, возможно даже после перезагрузки).
          • 0
            Ну, это у него надо спросить, подойдет ли…
            • НЛО прилетело и опубликовало эту надпись здесь
              • 0
                Демон не работает, когда:
                * система в single-user mode;
                * демон кто-то выключил вручную и ещё не включил обратно (или вообще забыл включить);
                * демон упал;
                *…
                • НЛО прилетело и опубликовало эту надпись здесь
                  • +4
                    Это runlevel 1 :)
                    • 0
                      Выполняет роль безопачного режима венды. В юниксах в этом ражиме возможен только один пользователь — рут. И как правило не чтартуют никакие службы — ака демоны. Используется при устрвнении аварий, воссьановлении рут пароля и нпример в фрибсд этот режим используют при обноылении системы.
                      • 0
                        В юниксах в этом ражиме возможен только один пользователь — рут.

                        Неправда. su sername и вперёд. Можно даже «рассвет вручную» сделать и иксы запустить (сначала hald стартовать, ещё несколько сервисов и startx от юзера).
                  • 0
                    на файловой системе ntfs-3g — точно не работает =)
                • 0
                  для автоматизации репостинга с лепры?
                • НЛО прилетело и опубликовало эту надпись здесь
                  • 0
                    А поддерживаются ли исключения?

                    Скажем, inotifywait я могу дать команду — «следи за /etc, КРОМЕ /etc/udev.d» потому, что бекапить /etc/udev.d (с динамически создаваемыми правилами) мне не нужно.

                    Вообще, в список «целей» попадает gentoo-переменная CONFIG_PROTECT, а в список «исключений» — переменная CONFIG_PROTECT_MASK
                    • 0
                      Нет. Такой возможности там нет, к сожалению.
                      • 0
                        А нельзя как-нибудь отдельно фильтровать? Ну, я просто в танке. :)
                        • 0
                          Можно, но это же лишняя работа.

                          Кроме того, есть ещё одно неудобство. Мне-то надо действия выполнять не сразу, а через некоторую задержку. Редактирую я пачку конфигов, закончил — вот тут-то и настало время бекапа. Для этого, видимо, incron не очень подходит, либо с ним нужно искать другое решение задачи.

                          А вот inotifywait как раз позволяет написать такой shell-скрипт, с ним я задачу решил ;)
                          • +1
                            grep в целевом скрипте. Фильтруйте — не перефильтруйте :)
                            • 0
                              Логичнее просто не вешать триггер inotify на ненужные объекты, чем вешать на все и потом следить за тем, нужный или ненужный объект сработал?
                              • 0
                                Ещё одно соображение. Если в /etc создать поддиректорию — скрипт elve подхватит её и повесит на неё триггер автоматом? А это нужно.
                                • 0
                                  Автоматом повесится. Я проверял
                                • +2
                                  Ок, повестье на /etc/myconfig.conf и не вешайте на /etc/udev.d.
                                  Триггер вешается на inode (отсюда и название, suprise), и против этого не попрёшь.
                          • 0
                            Ага, клевая штука, используем inotifywait для сбора множества мелких js и css файлов в 2 больших и последующего сжатия. Очень удобно — сохраняешь изменения в любом из мелких файлов, inotifywait отслеживает изменение в указанной директории и поддиректориях, и запускает команду сборки.
                            • +5
                              ухтыжка! какие просторы открывается для админов-параноиков… кто-то попытался посмотреть /etc/shadow сразу СМС, кто-то сделал su — сразу СМС… сладость :)
                              • 0
                                Кстати в Unix есть подобный механизм, слегка другой правда.
                                В Widows, тоже, но там идеология сильно отличается.
                                • +1
                                  Оговорка прямо по Фрейду :) «widow» — «вдова» по-английски
                                  • +1
                                    Вот, нашёл у себя в исходниках:
                                    man 2 kqueue (для FreeBSD и Darwin)

                                    У меня была идея, написать на python кроссплатформенного демона, реагирующего на такого-рода события, но дальше «ядра» для Windows и Linux дело не продвинулось — времени нет.
                                  • +1
                                    Спасибо за топик.

                                    ИМХО, перезапуск сервиса по любому изменению конфига для «боевых» серверов всё-таки не есть хорошо, ведь после редактирования конфигурация сервиса может быть просто нерабочей (зависимые сервисы, конфигурация в несколькоих файлах, сервис долго перезапускается и т.д.). А это непроизводительные простои и тоска пользователям.

                                    Лично у меня, например, есть привычка говорить ":w" несколько раз в процессе редактирования (а изменения бывают объёмными) конфига — IM_MODIFY будет выстреливать при каждой записи?
                                    • 0
                                      Да, при каждой.
                                      • 0
                                        Тогда можно по закрытию файла делать перезапуск. Это мой простенький пример. Вариаций очень много.
                                        • 0
                                          Главная вариация — блокировки надо предусмотреть.
                                      • +1
                                        Я вижу интерес к теме имеется. Значит скоро напишу про использование утилит из пакета inotify-tools если, конечно, merlin_rterm меня не опередит =)
                                        • 0
                                          Интересная штука.
                                          Только поправьте «$% флаг события (тестом)» — наверное, имелось в виду «текстом».
                                          • 0
                                            Большое спасибо. Опечатку поправил.
                                          • 0
                                            Штука интересная, но не стоит её использовать для конфигов, стоит подыскать примеры получше.

                                            Кстати очень интересный вопрос как эта подсистема выдаёт MODIFY, ведь операции записи могут идти кусками. Варианты — по закрытию файла или после записи каждого куска…
                                            • 0
                                              Пример взят из жизни. Если вы можете предложить что-то более интересное, я буду только рад узнать ваши варианты использования этой программы.

                                              Про запись кусками не думал. У меня маленькие конфиги. Они сразу пишутся =).
                                              • 0
                                                > У меня маленькие конфиги. Они сразу пишутся =).
                                                Не стоит на это рассчитывать.

                                                Из примеров — наш админ планирует использовать данную штуку для оповещения изменений конфигов. Т.е. конфиг поменялся -> сообщение на jabber о том кто его его поменял, когда и т.д.
                                              • +1
                                                Вообще-то, была другая задумка — автоматический бекап новой версии конфигов в svn. «Нулевая» версия (до запуска сервиса) бекапится руками, а все последующие — автоматом; при желании, в таком архиве можно будет найти любые версии любых конфигов.
                                              • 0
                                                Нет защиты от множественного запуска например команды backup при копировании нескольких файлов сразу в /etc
                                                • 0
                                                  Да. Именно поэтому само копирование выполняется с помощью rsync.
                                                  Думаю, что мне удастся реализовать все более красиво с помощью пакета inotify-tools.
                                                  • 0
                                                    Как я делал:
                                                    1. Запускается subshell отдельным потоком в фоне (потом объясню, зачем)
                                                    2. При получении события действие только планируется, т.е. subshellу через какой-то механизм типа файла в /dev/shm сообщается, что через минуту нужно будет выполнить svn update. А сразу делается только svn add при создании файла, или svn delete при удалении (модификацию svn update заметит само). Если в течение минуты другой файл отредактировать, то время выполнения svn update «отодвинется».
                                                    3. Subshell устроен так: он ждёт изменений в файле в /dev/shm (сейчас я сделал банальный polling, но ничто не мешает реализовать там при помощи того же самого inotifywait). Через минуту, после того как последнее редактирование было произведено, выполнить svn update.

                                                    Собственно, вот и вся логика. С учётом инициализации (разбора переменных Gentoo и построения параметров inotifywait), весь скрипт уместится в строк 50 кода.

                                                    P.S. Предлагаю доделать это (наконец) и написать сюда статью.
                                                • 0
                                                  Кстати это было бы супер — на все свои сервера ставить такую штуку, единый svn/git/hg/bzr реп и мы сразу же видим изменение конфигурации на сервере. Пойду поразбираюсь как бы это на питоне сваять.
                                                  • 0
                                                    Спасибо, написал скрипт, который каждый раз при вставке flash`ки делает резервную копию на жёсткий диск через rsync, теперь не так страшно потерять её :)
                                                    • 0
                                                      Думаю, логичнее было бы сделать это через udev.
                                                    • 0
                                                      Кстати, вместо squid restart Вы бы лучше делали squid -k reconfigure — избежите множества проблем ;)
                                                      • НЛО прилетело и опубликовало эту надпись здесь

                                                        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.