Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-gtools / synnefo / ganeti / eventd.py @ b85320d0

History | View | Annotate | Download (11.5 kB)

1 b024b97a Georgios Gousios
#!/usr/bin/env python
2 737b0e28 Vangelis Koukis
# -*- coding: utf-8 -*-
3 b024b97a Georgios Gousios
#
4 737b0e28 Vangelis Koukis
# Copyright 2011 GRNET S.A. All rights reserved.
5 737b0e28 Vangelis Koukis
#
6 737b0e28 Vangelis Koukis
# Redistribution and use in source and binary forms, with or
7 737b0e28 Vangelis Koukis
# without modification, are permitted provided that the following
8 737b0e28 Vangelis Koukis
# conditions are met:
9 737b0e28 Vangelis Koukis
#
10 737b0e28 Vangelis Koukis
#   1. Redistributions of source code must retain the above
11 737b0e28 Vangelis Koukis
#      copyright notice, this list of conditions and the following
12 737b0e28 Vangelis Koukis
#      disclaimer.
13 737b0e28 Vangelis Koukis
#
14 737b0e28 Vangelis Koukis
#   2. Redistributions in binary form must reproduce the above
15 737b0e28 Vangelis Koukis
#      copyright notice, this list of conditions and the following
16 737b0e28 Vangelis Koukis
#      disclaimer in the documentation and/or other materials
17 737b0e28 Vangelis Koukis
#      provided with the distribution.
18 737b0e28 Vangelis Koukis
#
19 737b0e28 Vangelis Koukis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
20 737b0e28 Vangelis Koukis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 737b0e28 Vangelis Koukis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 737b0e28 Vangelis Koukis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
23 737b0e28 Vangelis Koukis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 737b0e28 Vangelis Koukis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 737b0e28 Vangelis Koukis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26 737b0e28 Vangelis Koukis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27 737b0e28 Vangelis Koukis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 737b0e28 Vangelis Koukis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29 737b0e28 Vangelis Koukis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 737b0e28 Vangelis Koukis
# POSSIBILITY OF SUCH DAMAGE.
31 737b0e28 Vangelis Koukis
#
32 737b0e28 Vangelis Koukis
# The views and conclusions contained in the software and
33 737b0e28 Vangelis Koukis
# documentation are those of the authors and should not be
34 737b0e28 Vangelis Koukis
# interpreted as representing official policies, either expressed
35 737b0e28 Vangelis Koukis
# or implied, of GRNET S.A.
36 737b0e28 Vangelis Koukis
#
37 45ebfd48 Vangelis Koukis
38 737b0e28 Vangelis Koukis
"""Ganeti notification daemon with AMQP support
39 b024b97a Georgios Gousios

40 b024b97a Georgios Gousios
A daemon to monitor the Ganeti job queue and publish job progress
41 80bd5072 Georgios Gousios
and Ganeti VM state notifications to the ganeti exchange
42 b024b97a Georgios Gousios
"""
43 b024b97a Georgios Gousios
44 b024b97a Georgios Gousios
import sys
45 b024b97a Georgios Gousios
import os
46 b024b97a Georgios Gousios
path = os.path.normpath(os.path.join(os.getcwd(), '..'))
47 b024b97a Georgios Gousios
sys.path.append(path)
48 b024b97a Georgios Gousios
49 b024b97a Georgios Gousios
import json
50 b024b97a Georgios Gousios
import logging
51 b024b97a Georgios Gousios
import pyinotify
52 b024b97a Georgios Gousios
import daemon
53 b024b97a Georgios Gousios
import daemon.pidlockfile
54 348f53de Georgios Gousios
import socket
55 b024b97a Georgios Gousios
from signal import signal, SIGINT, SIGTERM
56 b024b97a Georgios Gousios
57 b024b97a Georgios Gousios
from ganeti import utils
58 b024b97a Georgios Gousios
from ganeti import jqueue
59 b024b97a Georgios Gousios
from ganeti import constants
60 b024b97a Georgios Gousios
from ganeti import serializer
61 b024b97a Georgios Gousios
62 6d6b8f88 Kostas Papadimitriou
from synnefo import settings
63 c4e55622 Christos Stavrakakis
from synnefo.lib.amqp import AMQPClient
64 c4e55622 Christos Stavrakakis
65 c4e55622 Christos Stavrakakis
def get_time_from_status(op, job):
66 c4e55622 Christos Stavrakakis
    """Generate a unique message identifier for a ganeti job.
67 c4e55622 Christos Stavrakakis

68 c4e55622 Christos Stavrakakis
    The identifier is based on the timestamp of the job. Since a ganeti
69 c4e55622 Christos Stavrakakis
    job passes from multiple states, we need to pick the timestamp that
70 c4e55622 Christos Stavrakakis
    corresponds to each state.
71 c4e55622 Christos Stavrakakis

72 c4e55622 Christos Stavrakakis
    """
73 c4e55622 Christos Stavrakakis
    status = op.status
74 c4e55622 Christos Stavrakakis
    if status == constants.JOB_STATUS_QUEUED:
75 c4e55622 Christos Stavrakakis
        return job.received_timestamp
76 39ccdb18 Christos Stavrakakis
    try: # Compatibility with Ganeti version
77 39ccdb18 Christos Stavrakakis
        if status == constants.JOB_STATUS_WAITLOCK:
78 39ccdb18 Christos Stavrakakis
            return op.start_timestamp
79 39ccdb18 Christos Stavrakakis
    except AttributeError:
80 39ccdb18 Christos Stavrakakis
        if status == constants.JOB_STATUS_WAITING:
81 39ccdb18 Christos Stavrakakis
            return op.start_timestamp
82 c4e55622 Christos Stavrakakis
    if status == constants.JOB_STATUS_CANCELING:
83 c4e55622 Christos Stavrakakis
        return op.start_timestamp
84 c4e55622 Christos Stavrakakis
    if status == constants.JOB_STATUS_RUNNING:
85 c4e55622 Christos Stavrakakis
        return op.exec_timestamp
86 c4e55622 Christos Stavrakakis
    if status in constants.JOBS_FINALIZED:
87 c4e55622 Christos Stavrakakis
        # success, canceled, error
88 c4e55622 Christos Stavrakakis
        return op.end_timestamp
89 c4e55622 Christos Stavrakakis
90 c4e55622 Christos Stavrakakis
    raise InvalidBackendState(status, job)
91 c4e55622 Christos Stavrakakis
92 c4e55622 Christos Stavrakakis
93 c4e55622 Christos Stavrakakis
class InvalidBackendStatus(Exception):
94 c4e55622 Christos Stavrakakis
    def __init__(self, status, job):
95 c4e55622 Christos Stavrakakis
        self.status = status
96 c4e55622 Christos Stavrakakis
        self.job = job
97 c4e55622 Christos Stavrakakis
98 c4e55622 Christos Stavrakakis
    def __str__(self):
99 c4e55622 Christos Stavrakakis
        return repr("Invalid backend status: %s in job %s"
100 c4e55622 Christos Stavrakakis
                    % (self.status, self.job))
101 c4e55622 Christos Stavrakakis
102 39ccdb18 Christos Stavrakakis
def prefix_from_name(name):
103 39ccdb18 Christos Stavrakakis
    return name.split('-')[0]
104 39ccdb18 Christos Stavrakakis
105 39ccdb18 Christos Stavrakakis
106 39ccdb18 Christos Stavrakakis
def get_field(from_, field):
107 39ccdb18 Christos Stavrakakis
    try:
108 39ccdb18 Christos Stavrakakis
        return getattr(from_, field)
109 39ccdb18 Christos Stavrakakis
    except AttributeError:
110 39ccdb18 Christos Stavrakakis
        None
111 39ccdb18 Christos Stavrakakis
112 45ebfd48 Vangelis Koukis
113 b024b97a Georgios Gousios
class JobFileHandler(pyinotify.ProcessEvent):
114 348f53de Georgios Gousios
    def __init__(self, logger):
115 348f53de Georgios Gousios
        pyinotify.ProcessEvent.__init__(self)
116 348f53de Georgios Gousios
        self.logger = logger
117 b85320d0 Christos Stavrakakis
        self.client = AMQPClient(confirm_buffer=25)
118 c4e55622 Christos Stavrakakis
        handler_logger.info("Attempting to connect to RabbitMQ hosts")
119 c4e55622 Christos Stavrakakis
        self.client.connect()
120 db400d82 Christos Stavrakakis
        self.client.exchange_declare(settings.EXCHANGE_GANETI, type='topic')
121 c4e55622 Christos Stavrakakis
        handler_logger.info("Connected succesfully")
122 b024b97a Georgios Gousios
123 39ccdb18 Christos Stavrakakis
        self.op_handlers = {"INSTANCE": self.process_instance_op,
124 39ccdb18 Christos Stavrakakis
                            "NETWORK": self.process_network_op}
125 39ccdb18 Christos Stavrakakis
                            # "GROUP": self.process_group_op}
126 39ccdb18 Christos Stavrakakis
127 b024b97a Georgios Gousios
    def process_IN_CLOSE_WRITE(self, event):
128 80dcd124 Vangelis Koukis
        self.process_IN_MOVED_TO(event)
129 80dcd124 Vangelis Koukis
130 80dcd124 Vangelis Koukis
    def process_IN_MOVED_TO(self, event):
131 b024b97a Georgios Gousios
        jobfile = os.path.join(event.path, event.name)
132 b024b97a Georgios Gousios
        if not event.name.startswith("job-"):
133 b024b97a Georgios Gousios
            self.logger.debug("Not a job file: %s" % event.path)
134 b024b97a Georgios Gousios
            return
135 b024b97a Georgios Gousios
136 b024b97a Georgios Gousios
        try:
137 b024b97a Georgios Gousios
            data = utils.ReadFile(jobfile)
138 b024b97a Georgios Gousios
        except IOError:
139 b024b97a Georgios Gousios
            return
140 b024b97a Georgios Gousios
141 b024b97a Georgios Gousios
        data = serializer.LoadJson(data)
142 39ccdb18 Christos Stavrakakis
        try: # Compatibility with Ganeti version
143 4ed30eed Christos Stavrakakis
            job = jqueue._QueuedJob.Restore(None, data, False)
144 4ed30eed Christos Stavrakakis
        except TypeError:
145 4ed30eed Christos Stavrakakis
            job = jqueue._QueuedJob.Restore(None, data)
146 4ed30eed Christos Stavrakakis
147 39ccdb18 Christos Stavrakakis
        job_id = int(job.id)
148 b024b97a Georgios Gousios
149 b024b97a Georgios Gousios
        for op in job.ops:
150 39ccdb18 Christos Stavrakakis
            op_id = op.input.OP_ID
151 b024b97a Georgios Gousios
152 39ccdb18 Christos Stavrakakis
            msg = None
153 b024b97a Georgios Gousios
            try:
154 39ccdb18 Christos Stavrakakis
                handler_fn = self.op_handlers[op_id.split('_')[1]]
155 39ccdb18 Christos Stavrakakis
                msg, routekey = handler_fn(op, job_id)
156 39ccdb18 Christos Stavrakakis
            except KeyError:
157 b024b97a Georgios Gousios
                pass
158 b024b97a Georgios Gousios
159 39ccdb18 Christos Stavrakakis
            if not msg:
160 39ccdb18 Christos Stavrakakis
                self.logger.debug("Ignoring job: %s: %s", job_id, op_id)
161 07e4ab22 Christos Stavrakakis
                continue
162 07e4ab22 Christos Stavrakakis
163 39ccdb18 Christos Stavrakakis
            # Generate a unique message identifier
164 39ccdb18 Christos Stavrakakis
            event_time = get_time_from_status(op, job)
165 39ccdb18 Christos Stavrakakis
166 b024b97a Georgios Gousios
            # Get the last line of the op log as message
167 b024b97a Georgios Gousios
            try:
168 b024b97a Georgios Gousios
                logmsg = op.log[-1][-1]
169 b024b97a Georgios Gousios
            except IndexError:
170 b024b97a Georgios Gousios
                logmsg = None
171 348f53de Georgios Gousios
172 39ccdb18 Christos Stavrakakis
            # Add shared attributes for all operations
173 39ccdb18 Christos Stavrakakis
            msg.update({"event_time": event_time,
174 39ccdb18 Christos Stavrakakis
                        "operation": op_id,
175 39ccdb18 Christos Stavrakakis
                        "status": op.status,
176 39ccdb18 Christos Stavrakakis
                        "logmsg": logmsg,
177 39ccdb18 Christos Stavrakakis
                        "jobId": job_id})
178 c4e55622 Christos Stavrakakis
179 c4e55622 Christos Stavrakakis
            msg = json.dumps(msg)
180 39ccdb18 Christos Stavrakakis
            self.logger.debug("Delivering msg: %s (key=%s)", msg, routekey)
181 c4e55622 Christos Stavrakakis
182 c4e55622 Christos Stavrakakis
            # Send the message to RabbitMQ
183 db400d82 Christos Stavrakakis
            self.client.basic_publish(settings.EXCHANGE_GANETI,
184 db400d82 Christos Stavrakakis
                                      routekey,
185 db400d82 Christos Stavrakakis
                                      msg)
186 39ccdb18 Christos Stavrakakis
187 39ccdb18 Christos Stavrakakis
    def process_instance_op(self, op, job_id):
188 39ccdb18 Christos Stavrakakis
        """ Process OP_INSTANCE_* opcodes.
189 39ccdb18 Christos Stavrakakis

190 39ccdb18 Christos Stavrakakis
        """
191 39ccdb18 Christos Stavrakakis
        input = op.input
192 39ccdb18 Christos Stavrakakis
        op_id = input.OP_ID
193 39ccdb18 Christos Stavrakakis
194 39ccdb18 Christos Stavrakakis
        instances = None
195 39ccdb18 Christos Stavrakakis
        instances = get_field(input, 'instance_name')
196 39ccdb18 Christos Stavrakakis
        if not instances:
197 39ccdb18 Christos Stavrakakis
            instances = get_field(input, 'instances')
198 39ccdb18 Christos Stavrakakis
            if not instances or len(instances) > 1:
199 39ccdb18 Christos Stavrakakis
                # Do not publish messages for jobs with no or multiple
200 39ccdb18 Christos Stavrakakis
                # instances.
201 39ccdb18 Christos Stavrakakis
                # Currently snf-dispatcher can not normally handle these messages
202 39ccdb18 Christos Stavrakakis
                return None, None
203 39ccdb18 Christos Stavrakakis
            else:
204 39ccdb18 Christos Stavrakakis
                instances = instances[0]
205 39ccdb18 Christos Stavrakakis
206 39ccdb18 Christos Stavrakakis
        self.logger.debug("Job: %d: %s(%s) %s", job_id, op_id,
207 39ccdb18 Christos Stavrakakis
                          instances, op.status)
208 39ccdb18 Christos Stavrakakis
209 39ccdb18 Christos Stavrakakis
        msg = {"type": "ganeti-op-status",
210 39ccdb18 Christos Stavrakakis
               "instance": instances,
211 39ccdb18 Christos Stavrakakis
               "operation": op_id}
212 39ccdb18 Christos Stavrakakis
213 39ccdb18 Christos Stavrakakis
        routekey = "ganeti.%s.event.op" % prefix_from_name(instances)
214 39ccdb18 Christos Stavrakakis
215 39ccdb18 Christos Stavrakakis
        return msg, routekey
216 39ccdb18 Christos Stavrakakis
217 39ccdb18 Christos Stavrakakis
    def process_network_op(self, op, job_id):
218 39ccdb18 Christos Stavrakakis
        """ Process OP_NETWORK_* opcodes.
219 39ccdb18 Christos Stavrakakis

220 39ccdb18 Christos Stavrakakis
        """
221 39ccdb18 Christos Stavrakakis
222 39ccdb18 Christos Stavrakakis
        input = op.input
223 39ccdb18 Christos Stavrakakis
        op_id = input.OP_ID
224 39ccdb18 Christos Stavrakakis
        network_name = get_field(input, 'network_name')
225 39ccdb18 Christos Stavrakakis
226 39ccdb18 Christos Stavrakakis
        if not network_name:
227 39ccdb18 Christos Stavrakakis
            return None, None
228 39ccdb18 Christos Stavrakakis
229 39ccdb18 Christos Stavrakakis
        self.logger.debug("Job: %d: %s(%s) %s", job_id, op_id,
230 39ccdb18 Christos Stavrakakis
                          network_name, op.status)
231 39ccdb18 Christos Stavrakakis
232 39ccdb18 Christos Stavrakakis
        msg = {'operation':    op_id,
233 39ccdb18 Christos Stavrakakis
               'type':         "ganeti-network-status",
234 39ccdb18 Christos Stavrakakis
               'network':      network_name,
235 39ccdb18 Christos Stavrakakis
               'subnet':       get_field(input, 'network'),
236 39ccdb18 Christos Stavrakakis
               # 'network_mode': get_field(input, 'network_mode'),
237 39ccdb18 Christos Stavrakakis
               # 'network_link': get_field(input, 'network_link'),
238 39ccdb18 Christos Stavrakakis
               'gateway':      get_field(input, 'gateway'),
239 39ccdb18 Christos Stavrakakis
               # 'reserved_ips': get_field(input, 'reserved_ips'),
240 39ccdb18 Christos Stavrakakis
               'group_name':   get_field(input, 'group_name')}
241 39ccdb18 Christos Stavrakakis
242 39ccdb18 Christos Stavrakakis
        routekey = "ganeti.%s.event.network" % prefix_from_name(network_name)
243 39ccdb18 Christos Stavrakakis
244 39ccdb18 Christos Stavrakakis
        return msg, routekey
245 39ccdb18 Christos Stavrakakis
246 39ccdb18 Christos Stavrakakis
247 39ccdb18 Christos Stavrakakis
    # def process_group_op(self, op, job_id):
248 39ccdb18 Christos Stavrakakis
    #     """ Process OP_GROUP_* opcodes.
249 39ccdb18 Christos Stavrakakis
250 39ccdb18 Christos Stavrakakis
    #     """
251 39ccdb18 Christos Stavrakakis
    #     return None, None
252 39ccdb18 Christos Stavrakakis
253 39ccdb18 Christos Stavrakakis
254 39ccdb18 Christos Stavrakakis
255 39ccdb18 Christos Stavrakakis
256 39ccdb18 Christos Stavrakakis
257 b024b97a Georgios Gousios
handler_logger = None
258 b024b97a Georgios Gousios
def fatal_signal_handler(signum, frame):
259 b024b97a Georgios Gousios
    global handler_logger
260 b024b97a Georgios Gousios
261 b024b97a Georgios Gousios
    handler_logger.info("Caught fatal signal %d, will raise SystemExit",
262 2cd99e7a Georgios Gousios
                        signum)
263 b024b97a Georgios Gousios
    raise SystemExit
264 b024b97a Georgios Gousios
265 b024b97a Georgios Gousios
def parse_arguments(args):
266 b024b97a Georgios Gousios
    from optparse import OptionParser
267 b024b97a Georgios Gousios
268 b024b97a Georgios Gousios
    parser = OptionParser()
269 b024b97a Georgios Gousios
    parser.add_option("-d", "--debug", action="store_true", dest="debug",
270 2cd99e7a Georgios Gousios
                      help="Enable debugging information")
271 b024b97a Georgios Gousios
    parser.add_option("-l", "--log", dest="log_file",
272 45ebfd48 Vangelis Koukis
                      default="/var/log/snf-ganeti-eventd.log",
273 2cd99e7a Georgios Gousios
                      metavar="FILE",
274 2cd99e7a Georgios Gousios
                      help="Write log to FILE instead of %s" %
275 45ebfd48 Vangelis Koukis
                          "/var/log/snf-ganeti-eventd.log")
276 b024b97a Georgios Gousios
    parser.add_option('--pid-file', dest="pid_file",
277 45ebfd48 Vangelis Koukis
                      default="/var/run/snf-ganeti-eventd.pid",
278 2cd99e7a Georgios Gousios
                      metavar='PIDFILE',
279 2cd99e7a Georgios Gousios
                      help="Save PID to file (default: %s)" %
280 45ebfd48 Vangelis Koukis
                          "/var/run/snf-ganeti-eventd.pid")
281 b024b97a Georgios Gousios
282 b024b97a Georgios Gousios
    return parser.parse_args(args)
283 b024b97a Georgios Gousios
284 b024b97a Georgios Gousios
def main():
285 b024b97a Georgios Gousios
    global handler_logger
286 b024b97a Georgios Gousios
287 b024b97a Georgios Gousios
    (opts, args) = parse_arguments(sys.argv[1:])
288 b024b97a Georgios Gousios
289 b024b97a Georgios Gousios
    # Create pidfile
290 b024b97a Georgios Gousios
    pidf = daemon.pidlockfile.TimeoutPIDLockFile(opts.pid_file, 10)
291 b024b97a Georgios Gousios
292 b024b97a Georgios Gousios
    # Initialize logger
293 b024b97a Georgios Gousios
    lvl = logging.DEBUG if opts.debug else logging.INFO
294 03a4b970 Georgios Gousios
    logger = logging.getLogger("ganeti.eventd")
295 b024b97a Georgios Gousios
    logger.setLevel(lvl)
296 36cf1973 Vangelis Koukis
    formatter = logging.Formatter(
297 36cf1973 Vangelis Koukis
        "%(asctime)s %(module)s[%(process)d] %(levelname)s: %(message)s",
298 36cf1973 Vangelis Koukis
        "%Y-%m-%d %H:%M:%S")
299 b024b97a Georgios Gousios
    handler = logging.FileHandler(opts.log_file)
300 b024b97a Georgios Gousios
    handler.setFormatter(formatter)
301 b024b97a Georgios Gousios
    logger.addHandler(handler)
302 b024b97a Georgios Gousios
    handler_logger = logger
303 b024b97a Georgios Gousios
304 348f53de Georgios Gousios
    # Become a daemon:
305 348f53de Georgios Gousios
    # Redirect stdout and stderr to handler.stream to catch
306 348f53de Georgios Gousios
    # early errors in the daemonization process [e.g., pidfile creation]
307 348f53de Georgios Gousios
    # which will otherwise go to /dev/null.
308 348f53de Georgios Gousios
    daemon_context = daemon.DaemonContext(
309 348f53de Georgios Gousios
            pidfile=pidf,
310 348f53de Georgios Gousios
            umask=022,
311 348f53de Georgios Gousios
            stdout=handler.stream,
312 348f53de Georgios Gousios
            stderr=handler.stream,
313 348f53de Georgios Gousios
            files_preserve=[handler.stream])
314 348f53de Georgios Gousios
    daemon_context.open()
315 348f53de Georgios Gousios
    logger.info("Became a daemon")
316 348f53de Georgios Gousios
317 348f53de Georgios Gousios
    # Catch signals to ensure graceful shutdown
318 348f53de Georgios Gousios
    signal(SIGINT, fatal_signal_handler)
319 348f53de Georgios Gousios
    signal(SIGTERM, fatal_signal_handler)
320 348f53de Georgios Gousios
321 b024b97a Georgios Gousios
    # Monitor the Ganeti job queue, create and push notifications
322 b024b97a Georgios Gousios
    wm = pyinotify.WatchManager()
323 80dcd124 Vangelis Koukis
    mask = pyinotify.EventsCodes.ALL_FLAGS["IN_MOVED_TO"] | \
324 80dcd124 Vangelis Koukis
           pyinotify.EventsCodes.ALL_FLAGS["IN_CLOSE_WRITE"]
325 348f53de Georgios Gousios
    handler = JobFileHandler(logger)
326 b024b97a Georgios Gousios
    notifier = pyinotify.Notifier(wm, handler)
327 b024b97a Georgios Gousios
328 b024b97a Georgios Gousios
    try:
329 b024b97a Georgios Gousios
        # Fail if adding the inotify() watch fails for any reason
330 b024b97a Georgios Gousios
        res = wm.add_watch(constants.QUEUE_DIR, mask)
331 b024b97a Georgios Gousios
        if res[constants.QUEUE_DIR] < 0:
332 36cf1973 Vangelis Koukis
            raise Exception("pyinotify add_watch returned negative descriptor")
333 348f53de Georgios Gousios
334 b024b97a Georgios Gousios
        logger.info("Now watching %s" % constants.QUEUE_DIR)
335 b024b97a Georgios Gousios
336 b024b97a Georgios Gousios
        while True:    # loop forever
337 348f53de Georgios Gousios
            # process the queue of events as explained above
338 b024b97a Georgios Gousios
            notifier.process_events()
339 b024b97a Georgios Gousios
            if notifier.check_events():
340 b024b97a Georgios Gousios
                # read notified events and enqeue them
341 b024b97a Georgios Gousios
                notifier.read_events()
342 b024b97a Georgios Gousios
    except SystemExit:
343 b024b97a Georgios Gousios
        logger.info("SystemExit")
344 b024b97a Georgios Gousios
    except:
345 b024b97a Georgios Gousios
        logger.exception("Caught exception, terminating")
346 b024b97a Georgios Gousios
    finally:
347 b024b97a Georgios Gousios
        # destroy the inotify's instance on this interrupt (stop monitoring)
348 b024b97a Georgios Gousios
        notifier.stop()
349 b024b97a Georgios Gousios
        raise
350 b024b97a Georgios Gousios
351 b024b97a Georgios Gousios
if __name__ == "__main__":
352 b024b97a Georgios Gousios
    sys.exit(main())
353 b024b97a Georgios Gousios
354 348f53de Georgios Gousios
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai :