summaryrefslogtreecommitdiffstats
path: root/src/lib/Bcfg2/Server/FileMonitor/Inotify.py
blob: 8dcca70c27486a05fd04dc7cf5ed21ebd036a89e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
""" Inotify driver for file alteration events """

import os
import stat
import logging
import operator
import pyinotify
from Bcfg2.Server.FileMonitor import Event
from Bcfg2.Server.FileMonitor.Pseudo import Pseudo

logger = logging.getLogger(__name__)

class Inotify(Pseudo, pyinotify.ProcessEvent):
    __priority__ = 1
    mask = pyinotify.IN_CREATE | pyinotify.IN_DELETE | pyinotify.IN_MODIFY
    action_map = {pyinotify.IN_CREATE: 'created',
                  pyinotify.IN_DELETE: 'deleted',
                  pyinotify.IN_MODIFY: 'changed'}

    def __init__(self, ignore=None, debug=False):
        Pseudo.__init__(self, ignore=ignore, debug=debug)
        self.wm = pyinotify.WatchManager()
        self.notifier = pyinotify.ThreadedNotifier(self.wm, self)
        self.notifier.start()

    def fileno(self):
        return self.wm.get_fd()

    def process_default(self, ievent):
        action = ievent.maskname
        for amask, aname in self.action_map.items():
            if ievent.mask & amask:
                action = aname
                break
        # FAM-style file monitors return the full path to the parent
        # directory that is being watched, relative paths to anything
        # contained within the directory
        watch = self.wm.watches[ievent.wd]
        if watch.path == ievent.pathname:
            path = ievent.pathname
        else:
            # relative path
            path = os.path.basename(ievent.pathname)
        evt = Event(ievent.wd, path, action)
        print "created event %s" % evt
        self.events.append(evt)

    def AddMonitor(self, path, obj):
        res = self.wm.add_watch(path, self.mask, quiet=False)
        if not res:
            # if we didn't get a return, but we also didn't get an
            # exception, we're already watching this directory, so we
            # need to find the watch descriptor for it
            for wd, watch in self.wm.watches.items():
                if watch.path == path:
                    wd = watch.wd
        else:
            wd = res[path]

        # inotify doesn't produce initial 'exists' events, so we
        # inherit from Pseudo to produce those
        return Pseudo.AddMonitor(self, path, obj, handleID=wd)

    def shutdown(self):
        self.notifier.stop()