Назад | Перейти на главную страницу

Как я могу запустить скрипт после того, как rsyncdaemon получил изменения файла в определенной папке?

У меня есть несколько серверов, на которых работает rsyncd. Я использую не ssh-туннель, а собственный протокол rsync. Одна папка синхронизированных файлов содержит файлы, которые должны сформировать ISO-образ. Каждый раз, когда файл в этой папке загружается (отправляется с удаленного компьютера на этот сервер), он должен автоматически воссоздать файл iso. В идеале это должно вызывать только изменение содержимого или размера файла, потому что я хочу показать дату последнего изменения iso на веб-странице, где пользователи могут загрузить и записать ее.

Поскольку iso большой, я хочу создать его на каждом сервере, если изменится только один файл. Я не хочу синхронизировать сам iso

Это скорее ответ Жилю, но я хотел немного отформатировать код; отличный способ отслеживать измененные файлы - хранить md5sum из md5sums каталога, ala:

find /path/to/iso/data/ -type f -exec md5sum {} + | awk '{print $1}' | sort | md5sum | awk '{print $1}'

... что дает вам вывод типа:

b843afc89097f0abc062e0d0e14d480b

Если вы сохраните это на каждой итерации вашего cron, это довольно быстрый и эффективный способ определить, изменилось ли содержимое на целевом объекте. Вы даже можете создать оболочку для демона xinetd rsync; замените вызов двоичного файла в /etc/xinetd.d/rsync:

server          = /usr/bin/rsync

... со сценарием:

server          = /path/to/script.sh

А затем в вашем сценарии сравнивайте и выполняйте действия каждый раз, когда демон завершает работу с действительным статусом 0. Это намного более автоматизировано, чем задание cron, с тем преимуществом, что оно запускается только в том случае, если вы закодируете его для выхода rsync 0. Что-то вроде ... (здесь псевдо-код):

#!/bin/sh

/usr/bin/rsync "$*"

if [ $? -eq 0 ]; then
  OLDVALUE=`cat /var/cache/isodata.txt`
  NEWVALUE=`find /path/to/iso/data/ -type f -exec md5sum {} + | awk '{print $1}' | sort | md5sum | awk '{print $1}'`
  if [ ${OLDVALUE} != ${NEWVALUE} ]; then
    -- run ISO making code --
    echo ${NEWVALUE} > /var/cache/isodata.txt
  fi
fi

Это общая идея для начала.

Старомодный, переносимый и неуклюжий способ - запускать скрипт генерации iso через регулярные промежутки времени либо через cron, либо с помощью while sleep цикл (предпочтительно, если интервал не намного больше, чем время, необходимое для регенерации ISO). Чтобы избежать регенерации ISO, если файлы не изменились, делайте это, только если [ -n "$(find -cnewer foo.iso -print -quit)" ]. Обратите внимание, что это не сработает, если некоторые файлы были удалены, но не были изменены или добавлены.

Лучшим, но непереносимым способом является использование API мониторинга изменений файлов вашей платформы: fam в IRIX и некоторых других системах, kqueue в * BSD, inotify в Linux и т. Д. Все можно легко настроить для запуска команды, если файл изменения (включая каталог); Я не знаю, все ли они могут смотреть дерево каталогов.

Другой способ - поместить файлы в файловую систему пользовательского уровня (например, FUSE), которая просто передает вызовы в базовое хранилище, за исключением того, что модификации запускают регенерацию ISO.

Что бы вы ни делали, обратите внимание, что файл может измениться, пока вы регенерируете ISO; в этом случае у вас есть две стратегии. Вы можете дождаться завершения генерации и начать заново, что расточительно. Или вы можете остановить создание iso и начать заново, но это может привести к долгому времени без обновления iso, если файлы продолжают изменяться быстрее, чем iso может быть восстановлен. Разумным решением является сочетание двух, когда вы убиваете генерацию iso, если только ISO не был сгенерирован более X раз.