watcher.py: Vykonání určité akce, když se změní struktura dat
Lepší nadpis příspěvku mě nenapadl, ale myslím, že když budete číst dál, tak určitě pochopíte, k čemu je to dobré.
Situace
Na serveru mám sdílený adresář /PUBLIC exportovaný přes NFS. Jak z názvu plyne, jedná se o veřejné úložiště, ale ve smyslu, že může číst a zapisovat jen skupina „public“ a její členové. Výchozí skupina uživatelů je ale „Domain users“ a proto bylo zapotřebí, aby se při nakopírování, přesunutí, vytvoření souboru/adresáře do /PUBLIC změnila jeho skupina na „public“.
Změna skupiny
Při vytváření souboru/adresáře jsem toho docílil tak, že jsem nastavil dědičnost skupiny
chmod -R g+s /PUBLIC
problém ale samozřejmě nastal ve chvíli, když do /PUBLIC byl soubor/adresář přesunut nebo zkopírován. Zůstala mu totiž jeho původní skupina a to bylo v tomto případě nežádoucí.
Změna práv
Další problém byl v právech. Uživatelé vytvářeli soubory s umask 022 (soubory 644 a adresáře 755), ale já potřeboval aby to bylo 660 a 770 (samozřejmě pouze ve sdíleném adresáři). Tzn. aby mohli zapisovat a číst všichni uživatelé ve skupině. Toho jsem docílil pomocí ACL.
setfacl -Rdm u::rwX,g::rwX,o::- /PUBLIC
Přichází ale opět na řadu kopírování a přesouvání. Práva, stejně jako skupina, zůstala nezměněná.
Historie nastavení
Proto jsem se rozhodl dát do cronu skript, který mi v 10ti minutových intervalech bude práva měnit. Mělo to ale své nevýhody. Dalo by se vydržet, že uživatel musel čekat pár minut na změnu práv. Ale horší bylo, že když kopíroval do /PUBLIC větší soubor déle jak těch 10 minut, proběhla změna práv a kopírování se přerušilo.
Proto nastoupil incron. Ten ale bohužel neuměl pracovat rekurzivně. Tzn. že uměl hlídat opravdu jen složku /PUBLIC, ale když uživatel něco nakopíroval do /PUBLIC/Dokumenty, incron o tom nevěděl.
Konečné řešení
Hledal jsem tedy dál a našel jsem watcher.py, který toto umí.
Hlavní doména tohoto programu je, že jeho démon hlídá vámi definovaný adresář (v našem případe /PUBLIC) a hlídá změny, které se uvnitř něho odehrávají (a to i v jeho podadresářích). Na základě toho umí vyvolávat akce, spouštět skripty atd.
Nyní mi tedy watcher.py hlídá /PUBLIC a když se v něm objeví nějaký soubor/adresář, tak spustí skriptík, který mu změní práva.
Instalace
Stáhneme si watcher.py a jeho konfigurační soubor. Já to udělal pro přehlednost tak, že jsem watcher.py přejmenoval na watcher a nakopíroval (nebo můžete vytvořit symlink) do /etc/init.d. Nyní ho spustíme klasickým příkazem
/etc/init.d/warcher start
Nezapomeňte v tomto souboru ještě uměnit cestu ke konfiguračnímu souboru, ten jsem uložil jako /etc/watcher/watcher.conf. Jeho obsah mám zhruba takovýto:
Aby se nám démon watcher spouštěl po startu serveru, přidáme jeho symlink do patřičného runlevellu.
Konfigurace
Konfigurační soubor (ten co už máme v /etc/watcher/watcher.conf) je pěkně komentovaný
; ---------------------- ; General Settings ; ---------------------- [DEFAULT] ; where to store output logfile=/var/log/watcher.log ;logfile=/dev/null ; where to save the PID file pidfile=/tmp/watcher.pid ; ---------------------- ; Job Setups ; ---------------------- [job1] ; directory or file to watch. Probably should be abs path. watch=/shares/PUBLIC ; list of events to watch for. ; supported events: ; 'access' - File was accessed (read) (*) ; 'attribute_change' - Metadata changed (permissions, timestamps, extended attributes, etc.) (*) ; 'write_close' - File opened for writing was closed (*) ; 'nowrite_close' - File not opened for writing was closed (*) ; 'create' - File/directory created in watched directory (*) ; 'delete' - File/directory deleted from watched directory (*) ; 'self_delete' - Watched file/directory was itself deleted ; 'modify' - File was modified (*) ; 'self_move' - Watched file/directory was itself moved ; 'move_from' - File moved out of watched directory (*) ; 'move_to' - File moved into watched directory (*) ; 'open' - File was opened (*) ; 'all' - Any of the above events are fired ; 'move' - A combination of 'move_from' and 'move_to' ; 'close' - A combination of 'write_close' and 'nowrite_close' ; ; When monitoring a directory, the events marked with an asterisk (*) above ; can occur for files in the directory, in which case the name field in the ; returned event data identifies the name of the file within the directory. events=create ;events=all ; if true, watcher will monitor directories recursively for changes recursive=true ; the command to run. Can be any command. It's run as whatever user started watcher. ; The following wildards may be used inside command specification: ; $$ dollar sign ; $watched watched filesystem path (see above) ; $filename event-related file name ; $tflags event flags (textually) ; $nflags event flags (numerically) ; $dest_file this will manage recursion better if included as the dest (especially when copying or similar) ; if $dest_file was left out of the command below, Watcher won't properly ; handle newly created directories when watching recursively. It's fine ; to leave out when recursive is false or you won't be creating new ; directories. ;command=cp -r $filename /home/user/Documents/$dest_file command=/usr/local/scripts/public-perm $filename [job2] watch=/AUDIO events=create,move_to recursive=true command=/usr/local/scripts/audio-perm $filename
Vytvořil jsem dva joby, kde jsem zadal, který adresář se má hlídat a jakou akci za jakých podmínek vykonat. Pokud tedy něco vytvoříme nebo přesuneme do kontrolovaného adresáře, spustí se skript. Např. /usr/local/scripts/audio-perm, v mém případě s následujícím obsahem:
#!/bin/bash sleep 3 && /bin/chmod -R ugo= "$1" /bin/chmod -R u=rwX,g=rX,o= "$1" /bin/chown -R :audio "$1"
Měním tedy práva a skupinu ($1 je aktuálně přenášený soubor/adresář) s 3 vteřinovým zpožděním. To proto, aby se akce provedla až po dokončení přenosu souboru. Pokud budete tedy potřebovat větší soubory, je lepší tento interval prodloužit (nenašel jsem totiž jinou možnost, jak akci automaticky provést až po dokončení zápisu).
Další možnosti
Ve sdílení mám např. adresář, kam uživatelé přidávají dokumenty. Proto jsem watcher nastavil tak, aby mi při vytvoření nového souboru přišel o této situaci mail s informací, že na serveru je nový soubor (vč. jeho názvu). Stačilo přidat do skriptu něco takového:
# odesle informaci o novem souboru do mailu /usr/sbin/sendmail odkud@example.net <<END From: Film Watcher <no-reply@example.net> Subject: Novy soubor na serveru TO: Film Watcher <komu@example.net> Na serveru se objevil novy soubor: $1 END
Závěr
Watcher plní svojí funkci velice dobře. Je zde spousta možností, jaké akce provádět, fantazii se meze nekladou.
Zdroje informací
http://www.splitbrain.org/blog/2011-01/07-watcher_a_recursive_incron_alternative
http://www.abclinuxu.cz/poradna/linux/show/352581
Super, dikys za navod a tip. Hodne mi to pomohlou a usetrilo cas:)