Пользователь
0,0
рейтинг
8 августа 2009 в 17:31

Администрирование → 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
Беляев Ростислав @elve
карма
23,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Администрирование

Комментарии (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 — избежите множества проблем ;)
  • НЛО прилетело и опубликовало эту надпись здесь

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