Skip to content
Newer
Older
100644 621 lines (469 sloc) 17 KB
641e838 @ask Cosmetics
authored
1 # -*- coding: utf-8 -*-
27caaad @ask Adds module docstrings
authored
2 """
641e838 @ask Cosmetics
authored
3 celery.platforms
4 ~~~~~~~~~~~~~~~~
27caaad @ask Adds module docstrings
authored
5
641e838 @ask Cosmetics
authored
6 Utilities dealing with platform specifics: signals, daemonization,
7 users, groups, and so on.
27caaad @ask Adds module docstrings
authored
8
6b52605 @ask Updates copyright years to include 2012
authored
9 :copyright: (c) 2009 - 2012 by Ask Solem.
641e838 @ask Cosmetics
authored
10 :license: BSD, see LICENSE for more details.
27caaad @ask Adds module docstrings
authored
11
12 """
17315f1 @ask create_daemon_context renamed -> detached and is now an actual context
authored
13 from __future__ import absolute_import
041cb3c @ask Tasks can now have callbacks and errbacks, and dependencies are recorded
authored
14 from __future__ import with_statement
17315f1 @ask create_daemon_context renamed -> detached and is now an actual context
authored
15
fa2d784 @ask Cosmetics and stuff
authored
16 import atexit
271ca68 celeryd now supports a --pidfile argument.
Ask Solem authored
17 import errno
9252863 @ask celeryd_multi Must use shlex.split(posix=False) on Windows.
authored
18 import os
19 import platform as _platform
20 import shlex
f0962a9 @ask platforms.signals: New interface for managing process signals.
authored
21 import signal as _signal
9252863 @ask celeryd_multi Must use shlex.split(posix=False) on Windows.
authored
22 import sys
17315f1 @ask create_daemon_context renamed -> detached and is now an actual context
authored
23
cbb791b @ask Clonedigger refactorings
authored
24 from contextlib import contextmanager
25
b6179c7 @ask Use new-style relative imports
authored
26 from .local import try_import
17315f1 @ask create_daemon_context renamed -> detached and is now an actual context
authored
27
3334afb @ask Now depends on billiard >= 2.7.3.3
authored
28 from billiard import current_process
cf522ee @ask Some small optimizations
authored
29 from kombu.utils.limits import TokenBucket
30
17315f1 @ask create_daemon_context renamed -> detached and is now an actual context
authored
31 _setproctitle = try_import("setproctitle")
32 resource = try_import("resource")
33 pwd = try_import("pwd")
34 grp = try_import("grp")
864402d pwd and grp not available on Windows. Closes #210. Thanks to klibertb
Ask Solem authored
35
3401d63 @ask celeryctl now exits with failure status or EX_UNAVAILABLE if no repli…
authored
36 EX_OK = getattr(os, "EX_OK", 0)
37 EX_FAILURE = 1
38 EX_UNAVAILABLE = getattr(os, "EX_UNAVAILABLE", 69)
53a7354 @ask PEP8ify + pyflakes
authored
39 EX_USAGE = getattr(os, "EX_USAGE", 64)
3401d63 @ask celeryctl now exits with failure status or EX_UNAVAILABLE if no repli…
authored
40
9252863 @ask celeryd_multi Must use shlex.split(posix=False) on Windows.
authored
41 SYSTEM = _platform.system()
42 IS_OSX = SYSTEM == "Darwin"
43 IS_WINDOWS = SYSTEM == "Windows"
44
271ca68 celeryd now supports a --pidfile argument.
Ask Solem authored
45 DAEMON_UMASK = 0
46 DAEMON_WORKDIR = "/"
f44a7c6 @ask Fixes typo /dev/nulll -> /dev/null. Closes #386. Thanks to jbiggar
authored
47 DAEMON_REDIRECT_TO = getattr(os, "devnull", "/dev/null")
271ca68 celeryd now supports a --pidfile argument.
Ask Solem authored
48
c8b639b @ask Loads of new tests
authored
49
50 PIDFILE_FLAGS = os.O_CREAT | os.O_EXCL | os.O_WRONLY
51 PIDFILE_MODE = ((os.R_OK | os.W_OK) << 6) | ((os.R_OK) << 3) | ((os.R_OK))
52
cf522ee @ask Some small optimizations
authored
53 _setps_bucket = TokenBucket(0.5) # 30/m, every 2 seconds
54
fa2d784 @ask Cosmetics and stuff
authored
55 PIDLOCKED = """ERROR: Pidfile (%s) already exists.
56 Seems we're already running? (PID: %s)"""
57
9252863 @ask celeryd_multi Must use shlex.split(posix=False) on Windows.
authored
58
59 def pyimplementation():
60 if hasattr(_platform, "python_implementation"):
61 return _platform.python_implementation()
62 elif sys.platform.startswith("java"):
7aa55c5 @ask Cosmetics
authored
63 return "Jython " + sys.platform
9252863 @ask celeryd_multi Must use shlex.split(posix=False) on Windows.
authored
64 elif hasattr(sys, "pypy_version_info"):
65 v = ".".join(map(str, sys.pypy_version_info[:3]))
66 if sys.pypy_version_info[3:]:
67 v += "-" + "".join(map(str, sys.pypy_version_info[3:]))
7aa55c5 @ask Cosmetics
authored
68 return "PyPy " + v
9252863 @ask celeryd_multi Must use shlex.split(posix=False) on Windows.
authored
69 else:
70 return "CPython"
27caaad @ask Adds module docstrings
authored
71
271ca68 celeryd now supports a --pidfile argument.
Ask Solem authored
72
eeb31f3 cleaned up celery.platforms.PIDFile
Ask Solem authored
73 class LockFailed(Exception):
27caaad @ask Adds module docstrings
authored
74 """Raised if a pidlock can't be acquired."""
eeb31f3 cleaned up celery.platforms.PIDFile
Ask Solem authored
75 pass
76
77
bc327d6 Daemonization+pidfile no longer depends on python-daemon/lockfile
Ask Solem authored
78 def get_fdmax(default=None):
27caaad @ask Adds module docstrings
authored
79 """Returns the maximum number of open file descriptors
80 on this system.
81
82 :keyword default: Value returned if there's no file
83 descriptor limit.
84
85 """
bc327d6 Daemonization+pidfile no longer depends on python-daemon/lockfile
Ask Solem authored
86 fdmax = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
87 if fdmax == resource.RLIM_INFINITY:
88 return default
89 return fdmax
90
5bd6f9a PEP8ify
Ask Solem authored
91
eeb31f3 cleaned up celery.platforms.PIDFile
Ask Solem authored
92 class PIDFile(object):
27caaad @ask Adds module docstrings
authored
93 """PID lock file.
94
95 This is the type returned by :func:`create_pidlock`.
96
97 **Should not be used directly, use the :func:`create_pidlock`
98 context instead**
99
100 """
101
102 #: Path to the pid lock file.
103 path = None
eeb31f3 cleaned up celery.platforms.PIDFile
Ask Solem authored
104
105 def __init__(self, path):
106 self.path = os.path.abspath(path)
107
108 def acquire(self):
27caaad @ask Adds module docstrings
authored
109 """Acquire lock."""
eeb31f3 cleaned up celery.platforms.PIDFile
Ask Solem authored
110 try:
111 self.write_pid()
112 except OSError, exc:
9530098 @ask Better exception and traceback handling.
authored
113 raise LockFailed, LockFailed(str(exc)), sys.exc_info()[2]
eeb31f3 cleaned up celery.platforms.PIDFile
Ask Solem authored
114 return self
17315f1 @ask create_daemon_context renamed -> detached and is now an actual context
authored
115 __enter__ = acquire
eeb31f3 cleaned up celery.platforms.PIDFile
Ask Solem authored
116
117 def is_locked(self):
27caaad @ask Adds module docstrings
authored
118 """Returns true if the pid lock exists."""
eeb31f3 cleaned up celery.platforms.PIDFile
Ask Solem authored
119 return os.path.exists(self.path)
120
17315f1 @ask create_daemon_context renamed -> detached and is now an actual context
authored
121 def release(self, *args):
27caaad @ask Adds module docstrings
authored
122 """Release lock."""
eeb31f3 cleaned up celery.platforms.PIDFile
Ask Solem authored
123 self.remove()
17315f1 @ask create_daemon_context renamed -> detached and is now an actual context
authored
124 __exit__ = release
eeb31f3 cleaned up celery.platforms.PIDFile
Ask Solem authored
125
126 def read_pid(self):
27caaad @ask Adds module docstrings
authored
127 """Reads and returns the current pid."""
eeb31f3 cleaned up celery.platforms.PIDFile
Ask Solem authored
128 try:
129 fh = open(self.path, "r")
130 except IOError, exc:
131 if exc.errno == errno.ENOENT:
132 return
133 raise
134
45e87b2 @ask Verify that the pidfile is actually written correctly. Closes #641
authored
135 try:
136 line = fh.readline()
137 if line.strip() == line: # must contain '\n'
138 raise ValueError(
139 "Partially written or invalid pidfile %r" % (self.path))
140 finally:
141 fh.close()
eeb31f3 cleaned up celery.platforms.PIDFile
Ask Solem authored
142
143 try:
45e87b2 @ask Verify that the pidfile is actually written correctly. Closes #641
authored
144 return int(line.strip())
eeb31f3 cleaned up celery.platforms.PIDFile
Ask Solem authored
145 except ValueError:
7ea3148 pyflakes
Ask Solem authored
146 raise ValueError("PID file %r contents invalid." % self.path)
eeb31f3 cleaned up celery.platforms.PIDFile
Ask Solem authored
147
148 def remove(self):
27caaad @ask Adds module docstrings
authored
149 """Removes the lock."""
eeb31f3 cleaned up celery.platforms.PIDFile
Ask Solem authored
150 try:
151 os.unlink(self.path)
152 except OSError, exc:
153 if exc.errno in (errno.ENOENT, errno.EACCES):
154 return
155 raise
156
157 def remove_if_stale(self):
27caaad @ask Adds module docstrings
authored
158 """Removes the lock if the process is not running.
159 (does not respond to signals)."""
eeb31f3 cleaned up celery.platforms.PIDFile
Ask Solem authored
160 try:
161 pid = self.read_pid()
162 except ValueError, exc:
163 sys.stderr.write("Broken pidfile found. Removing it.\n")
164 self.remove()
bc327d6 Daemonization+pidfile no longer depends on python-daemon/lockfile
Ask Solem authored
165 return True
eeb31f3 cleaned up celery.platforms.PIDFile
Ask Solem authored
166 if not pid:
167 self.remove()
168 return True
169
170 try:
171 os.kill(pid, 0)
172 except os.error, exc:
173 if exc.errno == errno.ESRCH:
174 sys.stderr.write("Stale pidfile exists. Removing it.\n")
175 self.remove()
176 return True
177 return False
bc327d6 Daemonization+pidfile no longer depends on python-daemon/lockfile
Ask Solem authored
178
27caaad @ask Adds module docstrings
authored
179 def write_pid(self):
45e87b2 @ask Verify that the pidfile is actually written correctly. Closes #641
authored
180 pid = os.getpid()
181 content = "%d\n" % (pid, )
182
c8b639b @ask Loads of new tests
authored
183 pidfile_fd = os.open(self.path, PIDFILE_FLAGS, PIDFILE_MODE)
27caaad @ask Adds module docstrings
authored
184 pidfile = os.fdopen(pidfile_fd, "w")
185 try:
45e87b2 @ask Verify that the pidfile is actually written correctly. Closes #641
authored
186 pidfile.write(content)
187 # flush and sync so that the re-read below works.
188 pidfile.flush()
189 try:
190 os.fsync(pidfile_fd)
c8b639b @ask Loads of new tests
authored
191 except AttributeError: # pragma: no cover
45e87b2 @ask Verify that the pidfile is actually written correctly. Closes #641
authored
192 pass
27caaad @ask Adds module docstrings
authored
193 finally:
194 pidfile.close()
195
c8b639b @ask Loads of new tests
authored
196 rfh = open(self.path)
197 try:
198 if rfh.read() != content:
45e87b2 @ask Verify that the pidfile is actually written correctly. Closes #641
authored
199 raise LockFailed(
200 "Inconsistency: Pidfile content doesn't match at re-read")
c8b639b @ask Loads of new tests
authored
201 finally:
202 rfh.close()
45e87b2 @ask Verify that the pidfile is actually written correctly. Closes #641
authored
203
bc327d6 Daemonization+pidfile no longer depends on python-daemon/lockfile
Ask Solem authored
204
271ca68 celeryd now supports a --pidfile argument.
Ask Solem authored
205 def create_pidlock(pidfile):
27caaad @ask Adds module docstrings
authored
206 """Create and verify pid file.
207
208 If the pid file already exists the program exits with an error message,
209 however if the process it refers to is not running anymore, the pid file
210 is deleted and the program continues.
211
212 The caller is responsible for releasing the lock before the program
213 exits.
214
215 :returns: :class:`PIDFile`.
216
217 **Example**:
271ca68 celeryd now supports a --pidfile argument.
Ask Solem authored
218
27caaad @ask Adds module docstrings
authored
219 .. code-block:: python
220
fa2d784 @ask Cosmetics and stuff
authored
221 pidlock = create_pidlock("/var/run/app.pid")
271ca68 celeryd now supports a --pidfile argument.
Ask Solem authored
222
223 """
224 pidlock = PIDFile(pidfile)
eeb31f3 cleaned up celery.platforms.PIDFile
Ask Solem authored
225 if pidlock.is_locked() and not pidlock.remove_if_stale():
fa2d784 @ask Cosmetics and stuff
authored
226 raise SystemExit(PIDLOCKED % (pidfile, pidlock.read_pid()))
227 pidlock.acquire()
228 atexit.register(pidlock.release)
271ca68 celeryd now supports a --pidfile argument.
Ask Solem authored
229 return pidlock
230
231
232 class DaemonContext(object):
233 _is_open = False
a29e9e7 @ask Daemon umask must always default to 0
authored
234 workdir = DAEMON_WORKDIR
235 umask = DAEMON_UMASK
271ca68 celeryd now supports a --pidfile argument.
Ask Solem authored
236
af4dc46 @ask Adds --fake option to celeryd_detach for debugging purposes
authored
237 def __init__(self, pidfile=None, workdir=None, umask=None,
238 fake=False, **kwargs):
a29e9e7 @ask Daemon umask must always default to 0
authored
239 self.workdir = workdir or self.workdir
240 self.umask = self.umask if umask is None else umask
af4dc46 @ask Adds --fake option to celeryd_detach for debugging purposes
authored
241 self.fake = fake
271ca68 celeryd now supports a --pidfile argument.
Ask Solem authored
242
243 def open(self):
17315f1 @ask create_daemon_context renamed -> detached and is now an actual context
authored
244 if not self._is_open:
af4dc46 @ask Adds --fake option to celeryd_detach for debugging purposes
authored
245 if not self.fake:
246 self._detach()
271ca68 celeryd now supports a --pidfile argument.
Ask Solem authored
247
17315f1 @ask create_daemon_context renamed -> detached and is now an actual context
authored
248 os.chdir(self.workdir)
249 os.umask(self.umask)
271ca68 celeryd now supports a --pidfile argument.
Ask Solem authored
250
17315f1 @ask create_daemon_context renamed -> detached and is now an actual context
authored
251 for fd in reversed(range(get_fdmax(default=2048))):
cbb791b @ask Clonedigger refactorings
authored
252 with ignore_EBADF():
17315f1 @ask create_daemon_context renamed -> detached and is now an actual context
authored
253 os.close(fd)
271ca68 celeryd now supports a --pidfile argument.
Ask Solem authored
254
17315f1 @ask create_daemon_context renamed -> detached and is now an actual context
authored
255 os.open(DAEMON_REDIRECT_TO, os.O_RDWR)
256 os.dup2(0, 1)
257 os.dup2(0, 2)
271ca68 celeryd now supports a --pidfile argument.
Ask Solem authored
258
17315f1 @ask create_daemon_context renamed -> detached and is now an actual context
authored
259 self._is_open = True
260 __enter__ = open
271ca68 celeryd now supports a --pidfile argument.
Ask Solem authored
261
17315f1 @ask create_daemon_context renamed -> detached and is now an actual context
authored
262 def close(self, *args):
271ca68 celeryd now supports a --pidfile argument.
Ask Solem authored
263 if self._is_open:
264 self._is_open = False
17315f1 @ask create_daemon_context renamed -> detached and is now an actual context
authored
265 __exit__ = close
271ca68 celeryd now supports a --pidfile argument.
Ask Solem authored
266
17315f1 @ask create_daemon_context renamed -> detached and is now an actual context
authored
267 def _detach(self):
268 if os.fork() == 0: # first child
269 os.setsid() # create new session
270 if os.fork() > 0: # second child
271 os._exit(0)
272 else:
273 os._exit(0)
274 return self
5bd6f9a PEP8ify
Ask Solem authored
275
271ca68 celeryd now supports a --pidfile argument.
Ask Solem authored
276
17315f1 @ask create_daemon_context renamed -> detached and is now an actual context
authored
277 def detached(logfile=None, pidfile=None, uid=None, gid=None, umask=0,
af4dc46 @ask Adds --fake option to celeryd_detach for debugging purposes
authored
278 workdir=None, fake=False, **opts):
27caaad @ask Adds module docstrings
authored
279 """Detach the current process in the background (daemonize).
280
281 :keyword logfile: Optional log file. The ability to write to this file
282 will be verified before the process is detached.
283 :keyword pidfile: Optional pid file. The pid file will not be created,
284 as this is the responsibility of the child. But the process will
285 exit if the pid lock exists and the pid written is still running.
286 :keyword uid: Optional user id or user name to change
287 effective privileges to.
288 :keyword gid: Optional group id or group name to change effective
289 privileges to.
290 :keyword umask: Optional umask that will be effective in the child process.
291 :keyword workdir: Optional new working directory.
af4dc46 @ask Adds --fake option to celeryd_detach for debugging purposes
authored
292 :keyword fake: Don't actually detach, intented for debugging purposes.
27caaad @ask Adds module docstrings
authored
293 :keyword \*\*opts: Ignored.
294
295 **Example**:
296
297 .. code-block:: python
298
299 import atexit
300 from celery.platforms import detached, create_pidlock
301
302 with detached(logfile="/var/log/app.log", pidfile="/var/run/app.pid",
303 uid="nobody"):
304 # Now in detached child process with effective user set to nobody,
305 # and we know that our logfile can be written to, and that
306 # the pidfile is not locked.
307 pidlock = create_pidlock("/var/run/app.pid").acquire()
308 atexit.register(pidlock.release)
309
310 # Run the program
311 program.run(logfile="/var/log/app.log")
312
313 """
314
17315f1 @ask create_daemon_context renamed -> detached and is now an actual context
authored
315 if not resource:
316 raise RuntimeError("This platform does not support detach.")
317 workdir = os.getcwd() if workdir is None else workdir
271ca68 celeryd now supports a --pidfile argument.
Ask Solem authored
318
f0962a9 @ask platforms.signals: New interface for managing process signals.
authored
319 signals.reset("SIGCLD") # Make sure SIGCLD is using the default handler.
ff9ce79 @ask setgroups() is not as easy afterall, steals some hacks from glibc to …
authored
320 if not os.geteuid():
321 # no point trying to setuid unless we're root.
322 maybe_drop_privileges(uid=uid, gid=gid)
b86bb1b celery.platforms: Do actually set effective uid/gid
Ask Solem authored
323
271ca68 celeryd now supports a --pidfile argument.
Ask Solem authored
324 # Since without stderr any errors will be silently suppressed,
325 # we need to know that we have access to the logfile.
17315f1 @ask create_daemon_context renamed -> detached and is now an actual context
authored
326 logfile and open(logfile, "a").close()
327 # Doesn't actually create the pidfile, but makes sure it's not stale.
328 pidfile and create_pidlock(pidfile)
271ca68 celeryd now supports a --pidfile argument.
Ask Solem authored
329
af4dc46 @ask Adds --fake option to celeryd_detach for debugging purposes
authored
330 return DaemonContext(umask=umask, workdir=workdir, fake=fake)
271ca68 celeryd now supports a --pidfile argument.
Ask Solem authored
331
332
333 def parse_uid(uid):
334 """Parse user id.
335
27caaad @ask Adds module docstrings
authored
336 uid can be an integer (uid) or a string (user name), if a user name
271ca68 celeryd now supports a --pidfile argument.
Ask Solem authored
337 the uid is taken from the password file.
338
339 """
340 try:
341 return int(uid)
342 except ValueError:
c8b639b @ask Loads of new tests
authored
343 try:
344 return pwd.getpwnam(uid).pw_uid
345 except (AttributeError, KeyError):
346 raise KeyError("User does not exist: %r" % (uid, ))
271ca68 celeryd now supports a --pidfile argument.
Ask Solem authored
347
348
349 def parse_gid(gid):
350 """Parse group id.
351
352 gid can be an integer (gid) or a string (group name), if a group name
353 the gid is taken from the password file.
354
355 """
356 try:
357 return int(gid)
358 except ValueError:
c8b639b @ask Loads of new tests
authored
359 try:
360 return grp.getgrnam(gid).gr_gid
361 except (AttributeError, KeyError):
362 raise KeyError("Group does not exist: %r" % (gid, ))
271ca68 celeryd now supports a --pidfile argument.
Ask Solem authored
363
364
ff9ce79 @ask setgroups() is not as easy afterall, steals some hacks from glibc to …
authored
365 def _setgroups_hack(groups):
366 """:fun:`setgroups` may have a platform-dependent limit,
367 and it is not always possible to know in advance what this limit
368 is, so we use this ugly hack stolen from glibc."""
369 groups = groups[:]
370
371 while 1:
372 try:
373 return os.setgroups(groups)
374 except ValueError: # error from Python's check.
375 if len(groups) <= 1:
376 raise
377 groups[:] = groups[:-1]
378 except OSError, exc: # error from the OS.
379 if exc.errno != errno.EINVAL or len(groups) <= 1:
380 raise
381 groups[:] = groups[:-1]
382
383
384 def setgroups(groups):
385 max_groups = None
386 try:
387 max_groups = os.sysconf("SC_NGROUPS_MAX")
c8b639b @ask Loads of new tests
authored
388 except Exception:
ff9ce79 @ask setgroups() is not as easy afterall, steals some hacks from glibc to …
authored
389 pass
390 try:
391 return _setgroups_hack(groups[:max_groups])
392 except OSError, exc:
393 if exc.errno != errno.EPERM:
394 raise
395 if any(group not in groups for group in os.getgroups()):
396 # we shouldn't be allowed to change to this group.
397 raise
398
399
400 def initgroups(uid, gid):
c8b639b @ask Loads of new tests
authored
401 if not pwd: # pragma: no cover
402 return
403 username = pwd.getpwuid(uid)[0]
404 if hasattr(os, "initgroups"): # Python 2.7+
405 return os.initgroups(username, gid)
406 groups = [gr.gr_gid for gr in grp.getgrall()
407 if username in gr.gr_mem]
408 setgroups(groups)
a777e9d @lukaszo When switching to new user set all his groups
lukaszo authored
409
410
271ca68 celeryd now supports a --pidfile argument.
Ask Solem authored
411 def setegid(gid):
412 """Set effective group id."""
413 gid = parse_gid(gid)
6f66590 @ask [Security] Use set*id() not sete*id
authored
414 if gid != os.getegid():
990c892 @harmv fix --gid option of celery_multi
harmv authored
415 os.setegid(gid)
271ca68 celeryd now supports a --pidfile argument.
Ask Solem authored
416
417
418 def seteuid(uid):
419 """Set effective user id."""
420 uid = parse_uid(uid)
6f66590 @ask [Security] Use set*id() not sete*id
authored
421 if uid != os.geteuid():
271ca68 celeryd now supports a --pidfile argument.
Ask Solem authored
422 os.seteuid(uid)
423
424
6f66590 @ask [Security] Use set*id() not sete*id
authored
425 def setgid(gid):
426 os.setgid(parse_gid(gid))
427
428
429 def setuid(uid):
430 os.setuid(parse_uid(uid))
431
432
ff9ce79 @ask setgroups() is not as easy afterall, steals some hacks from glibc to …
authored
433 def maybe_drop_privileges(uid=None, gid=None):
271ca68 celeryd now supports a --pidfile argument.
Ask Solem authored
434 """Change process privileges to new user/group.
435
ff9ce79 @ask setgroups() is not as easy afterall, steals some hacks from glibc to …
authored
436 If UID and GID is specified, the real user/group is changed.
271ca68 celeryd now supports a --pidfile argument.
Ask Solem authored
437
ff9ce79 @ask setgroups() is not as easy afterall, steals some hacks from glibc to …
authored
438 If only UID is specified, the real user is changed, and the group is
439 changed to the users primary group.
271ca68 celeryd now supports a --pidfile argument.
Ask Solem authored
440
ff9ce79 @ask setgroups() is not as easy afterall, steals some hacks from glibc to …
authored
441 If only GID is specified, only the group is changed.
271ca68 celeryd now supports a --pidfile argument.
Ask Solem authored
442
443 """
444 uid = uid and parse_uid(uid)
445 gid = gid and parse_gid(gid)
446
447 if uid:
27caaad @ask Adds module docstrings
authored
448 # If GID isn't defined, get the primary GID of the user.
864402d pwd and grp not available on Windows. Closes #210. Thanks to klibertb
Ask Solem authored
449 if not gid and pwd:
450 gid = pwd.getpwuid(uid).pw_gid
ff9ce79 @ask setgroups() is not as easy afterall, steals some hacks from glibc to …
authored
451 # Must set the GID before initgroups(), as setgid()
452 # is known to zap the group list on some platforms.
9396951 @ask Merge branch 'lukaszo/master'
authored
453 setgid(gid)
ff9ce79 @ask setgroups() is not as easy afterall, steals some hacks from glibc to …
authored
454 initgroups(uid, gid)
455
456 # at last:
6f66590 @ask [Security] Use set*id() not sete*id
authored
457 setuid(uid)
271ca68 celeryd now supports a --pidfile argument.
Ask Solem authored
458 else:
6f66590 @ask [Security] Use set*id() not sete*id
authored
459 gid and setgid(gid)
271ca68 celeryd now supports a --pidfile argument.
Ask Solem authored
460
cb5bc61 Move platform specific stuff (signal, daemon context) to celery.platform
Ask Solem authored
461
f0962a9 @ask platforms.signals: New interface for managing process signals.
authored
462 class Signals(object):
27caaad @ask Adds module docstrings
authored
463 """Convenience interface to :mod:`signals`.
464
465 If the requested signal is not supported on the current platform,
466 the operation will be ignored.
467
468 **Examples**:
469
470 .. code-block:: python
471
472 >>> from celery.platforms import signals
473
474 >>> signals["INT"] = my_handler
475
476 >>> signals["INT"]
477 my_handler
478
479 >>> signals.supported("INT")
480 True
481
482 >>> signals.signum("INT")
483 2
484
485 >>> signals.ignore("USR1")
486 >>> signals["USR1"] == signals.ignored
487 True
488
489 >>> signals.reset("USR1")
490 >>> signals["USR1"] == signals.default
491 True
492
493 >>> signals.update(INT=exit_handler,
494 ... TERM=exit_handler,
495 ... HUP=hup_handler)
496
497 """
498
f0962a9 @ask platforms.signals: New interface for managing process signals.
authored
499 ignored = _signal.SIG_IGN
500 default = _signal.SIG_DFL
3b28b85 @ask Can now terminate worker processing task remotely.
authored
501
f0962a9 @ask platforms.signals: New interface for managing process signals.
authored
502 def supported(self, signal_name):
503 """Returns true value if ``signal_name`` exists on this platform."""
504 try:
505 return self.signum(signal_name)
506 except AttributeError:
507 pass
3b28b85 @ask Can now terminate worker processing task remotely.
authored
508
f0962a9 @ask platforms.signals: New interface for managing process signals.
authored
509 def signum(self, signal_name):
510 """Get signal number from signal name."""
511 if isinstance(signal_name, int):
512 return signal_name
d16c906 @ask PEP8ify + pyflakes
authored
513 if not isinstance(signal_name, basestring) \
514 or not signal_name.isupper():
f0962a9 @ask platforms.signals: New interface for managing process signals.
authored
515 raise TypeError("signal name must be uppercase string.")
516 if not signal_name.startswith("SIG"):
517 signal_name = "SIG" + signal_name
518 return getattr(_signal, signal_name)
35e3e69 Ignore permission denied errors when removing pidfile.
Ask Solem authored
519
f0962a9 @ask platforms.signals: New interface for managing process signals.
authored
520 def reset(self, *signal_names):
521 """Reset signals to the default signal handler.
35e3e69 Ignore permission denied errors when removing pidfile.
Ask Solem authored
522
f0962a9 @ask platforms.signals: New interface for managing process signals.
authored
523 Does nothing if the platform doesn't support signals,
524 or the specified signal in particular.
c3a3fcd Hitting Ctrl+C kills the pool! Pool workers needs to ignore SIGINT.
Ask Solem authored
525
f0962a9 @ask platforms.signals: New interface for managing process signals.
authored
526 """
527 self.update((sig, self.default) for sig in signal_names)
c3a3fcd Hitting Ctrl+C kills the pool! Pool workers needs to ignore SIGINT.
Ask Solem authored
528
f0962a9 @ask platforms.signals: New interface for managing process signals.
authored
529 def ignore(self, *signal_names):
530 """Ignore signal using :const:`SIG_IGN`.
c3a3fcd Hitting Ctrl+C kills the pool! Pool workers needs to ignore SIGINT.
Ask Solem authored
531
f0962a9 @ask platforms.signals: New interface for managing process signals.
authored
532 Does nothing if the platform doesn't support signals,
533 or the specified signal in particular.
c3a3fcd Hitting Ctrl+C kills the pool! Pool workers needs to ignore SIGINT.
Ask Solem authored
534
f0962a9 @ask platforms.signals: New interface for managing process signals.
authored
535 """
536 self.update((sig, self.ignored) for sig in signal_names)
cb5bc61 Move platform specific stuff (signal, daemon context) to celery.platform
Ask Solem authored
537
f0962a9 @ask platforms.signals: New interface for managing process signals.
authored
538 def __getitem__(self, signal_name):
539 return _signal.getsignal(self.signum(signal_name))
cb5bc61 Move platform specific stuff (signal, daemon context) to celery.platform
Ask Solem authored
540
f0962a9 @ask platforms.signals: New interface for managing process signals.
authored
541 def __setitem__(self, signal_name, handler):
542 """Install signal handler.
35e3e69 Ignore permission denied errors when removing pidfile.
Ask Solem authored
543
f0962a9 @ask platforms.signals: New interface for managing process signals.
authored
544 Does nothing if the current platform doesn't support signals,
545 or the specified signal in particular.
35e3e69 Ignore permission denied errors when removing pidfile.
Ask Solem authored
546
f0962a9 @ask platforms.signals: New interface for managing process signals.
authored
547 """
ca74d92 @ask Cosmetics
authored
548 try:
f0962a9 @ask platforms.signals: New interface for managing process signals.
authored
549 _signal.signal(self.signum(signal_name), handler)
ca74d92 @ask Cosmetics
authored
550 except (AttributeError, ValueError):
551 pass
96fc5e6 setproctitle
Ask Solem authored
552
f0962a9 @ask platforms.signals: New interface for managing process signals.
authored
553 def update(self, _d_=None, **sigmap):
554 """Set signal handlers from a mapping."""
555 for signal_name, handler in dict(_d_ or {}, **sigmap).iteritems():
556 self[signal_name] = handler
557
558
559 signals = Signals()
560 get_signal = signals.signum # compat
561 install_signal_handler = signals.__setitem__ # compat
562 reset_signal = signals.reset # compat
563 ignore_signal = signals.ignore # compat
564
96fc5e6 setproctitle
Ask Solem authored
565
72d7fde celeryev: Set process title
Ask Solem authored
566 def strargv(argv):
17315f1 @ask create_daemon_context renamed -> detached and is now an actual context
authored
567 arg_start = 2 if "manage" in argv[0] else 1
72d7fde celeryev: Set process title
Ask Solem authored
568 if len(argv) > arg_start:
569 return " ".join(argv[arg_start:])
570 return ""
571
572
a658d0b set process titles if setproctitle is installed
Ask Solem authored
573 def set_process_title(progname, info=None):
44dbf5b Some cosmetic changes.
Ask Solem authored
574 """Set the ps name for the currently running process.
575
57e0217 @gvangool Corrected some ReST tags
gvangool authored
576 Only works if :mod:`setproctitle` is installed.
44dbf5b Some cosmetic changes.
Ask Solem authored
577
578 """
1e45852 93% total coverage.
Ask Solem authored
579 proctitle = "[%s]" % progname
17315f1 @ask create_daemon_context renamed -> detached and is now an actual context
authored
580 proctitle = "%s %s" % (proctitle, info) if info else proctitle
a658d0b set process titles if setproctitle is installed
Ask Solem authored
581 if _setproctitle:
17315f1 @ask create_daemon_context renamed -> detached and is now an actual context
authored
582 _setproctitle.setproctitle(proctitle)
1e45852 93% total coverage.
Ask Solem authored
583 return proctitle
a658d0b set process titles if setproctitle is installed
Ask Solem authored
584
1a7ebcc Set euid/egid ourselves. Allow using username/groupnames for the --ui…
Ask Solem authored
585
c8b639b @ask Loads of new tests
authored
586 if os.environ.get("NOSETPS"): # pragma: no cover
35e3e69 Ignore permission denied errors when removing pidfile.
Ask Solem authored
587
29ad3bd @ask Optimization: Now at 10.000 tasks/s with librabbitmq
authored
588 def set_mp_process_title(*a, **k):
589 pass
590 else:
35e3e69 Ignore permission denied errors when removing pidfile.
Ask Solem authored
591
a9d898d @ask Tests passing
authored
592 def set_mp_process_title(progname, info=None, hostname=None, # noqa
593 rate_limit=False):
29ad3bd @ask Optimization: Now at 10.000 tasks/s with librabbitmq
authored
594 """Set the ps name using the multiprocessing process name.
595
596 Only works if :mod:`setproctitle` is installed.
597
598 """
599 if not rate_limit or _setps_bucket.can_consume(1):
600 if hostname:
601 progname = "%s@%s" % (progname, hostname.split(".")[0])
3334afb @ask Now depends on billiard >= 2.7.3.3
authored
602 return set_process_title(
603 "%s:%s" % (progname, current_process().name), info=info)
9252863 @ask celeryd_multi Must use shlex.split(posix=False) on Windows.
authored
604
605
606 def shellsplit(s, posix=True):
607 # posix= option to shlex.split first available in Python 2.6+
608 lexer = shlex.shlex(s, posix=not IS_WINDOWS)
609 lexer.whitespace_split = True
610 lexer.commenters = ''
611 return list(lexer)
cbb791b @ask Clonedigger refactorings
authored
612
613
614 @contextmanager
615 def ignore_EBADF():
616 try:
617 yield
618 except OSError, exc:
619 if exc.errno != errno.EBADF:
620 raise
Something went wrong with that request. Please try again.