1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 """A daemonize function (for Unices) and daemon mix-in class"""
19
20 __docformat__ = "restructuredtext en"
21
22 import os
23 import errno
24 import signal
25 import sys
26 import time
27 import warnings
28
29
31
32
33
34
35 if os.fork():
36 return 1
37
38 os.setsid()
39
40
41
42 if os.fork():
43 return 1
44
45 os.chdir('/')
46
47 os.umask(077)
48
49 null = os.open('/dev/null', os.O_RDWR)
50 for i in range(3):
51 try:
52 os.dup2(null, i)
53 except OSError, e:
54 if e.errno != errno.EBADF:
55 raise
56 os.close(null)
57
58 warnings.filterwarnings('ignore')
59
60 if pidfile:
61
62
63 piddir = os.path.dirname(pidfile)
64 if not os.path.exists(piddir):
65 os.makedirs(piddir)
66 f = file(pidfile, 'w')
67 f.write(str(os.getpid()))
68 f.close()
69 return None
70
71
73 """Mixin to make a daemon from watchers/queriers.
74 """
75
77 self.delay = configmod.DELAY
78 self.name = str(self.__class__).split('.')[-1]
79 self._pid_file = os.path.join('/tmp', '%s.pid'%self.name)
80 if os.path.exists(self._pid_file):
81 raise Exception('''Another instance of %s must be running.
82 If it i not the case, remove the file %s''' % (self.name, self._pid_file))
83 self._alive = 1
84 self._sleeping = 0
85 self.config = configmod
86
88 if not self.config.NODETACH:
89 if daemonize(self._pid_file) is None:
90
91 signal.signal(signal.SIGTERM, self.signal_handler)
92 signal.signal(signal.SIGHUP, self.signal_handler)
93 else:
94 return -1
95
97 """ optionally go in daemon mode and
98 do what concrete class has to do and pauses for delay between runs
99 If self.delay is negative, do a pause before starting
100 """
101 if self._daemonize() == -1:
102 return
103 if self.delay < 0:
104 self.delay = -self.delay
105 time.sleep(self.delay)
106 while 1:
107 try:
108 self._run()
109 except Exception, ex:
110
111
112 self.config.exception('Internal error: %s', ex)
113 if not self._alive:
114 break
115 try:
116 self._sleeping = 1
117 time.sleep(self.delay)
118 self._sleeping = 0
119 except SystemExit:
120 break
121 self.config.info('%s instance exited', self.name)
122
123 os.remove(self._pid_file)
124
126 if sig_num == signal.SIGTERM:
127 if self._sleeping:
128
129 self.config.debug('exit on SIGTERM')
130 sys.exit(0)
131 else:
132 self.config.debug('exit on SIGTERM (on next turn)')
133 self._alive = 0
134 elif sig_num == signal.SIGHUP:
135 self.config.info('reloading configuration on SIGHUP')
136 reload(self.config)
137
139 """should be overridden in the mixed class"""
140 raise NotImplementedError()
141
142
143 import logging
144 from logilab.common.logging_ext import set_log_methods
145 set_log_methods(DaemonMixIn, logging.getLogger('lgc.daemon'))
146
147
148
149 L_OPTIONS = ["help", "log=", "delay=", 'no-detach']
150 S_OPTIONS = 'hl:d:n'
151
153 print """ --help or -h
154 displays this message
155 --log <log_level>
156 log treshold (7 record everything, 0 record only emergency.)
157 Defaults to %s
158 --delay <delay>
159 the number of seconds between two runs.
160 Defaults to %s""" % (modconfig.LOG_TRESHOLD, modconfig.DELAY)
161
163 if opt_name in ('-h','--help'):
164 help_meth()
165 sys.exit(0)
166 elif opt_name in ('-l','--log'):
167 modconfig.LOG_TRESHOLD = int(opt_value)
168 elif opt_name in ('-d', '--delay'):
169 modconfig.DELAY = int(opt_value)
170 elif opt_name in ('-n', '--no-detach'):
171 modconfig.NODETACH = 1
172