on irc jbergstroem noticed that gunicorn behavior is different than

nginx one in the way it manages processes uid/gid. Only nginx workers
get uid/gid and master if launch as root stay root. This patch give ti
gunicorn the same behavior.
This commit is contained in:
benoitc 2010-02-22 14:20:06 +01:00
parent 0a2585fdc0
commit 6c12f313e3
6 changed files with 55 additions and 31 deletions

View File

@ -356,7 +356,7 @@ class Arbiter(object):
continue
worker = Worker(i, self.pid, self.LISTENER, self.modname,
self.timeout/2.0, self.debug)
self.timeout/2.0, self.conf)
self.conf.before_fork(self, worker)
pid = os.fork()
if pid != 0:

View File

@ -3,7 +3,9 @@
# This file is part of gunicorn released under the MIT license.
# See the NOTICE for more information.
import grp
import os
import pwd
import sys
from gunicorn import util
@ -104,13 +106,37 @@ class Config(object):
@property
def umask(self):
if not self.conf['umask']:
if not self.conf.get('umask'):
return 0
umask = self.conf['umask']
if isinstance(umask, basestring):
return int(umask, 0)
return umask
@property
def uid(self):
if not self.conf.get('user'):
return os.geteuid()
user = self.conf.get('user')
if user.isdigit() or isinstance(user, int):
uid = int(user)
else:
uid = pwd.getpwnam(user).pw_uid
return uid
@property
def gid(self):
if not self.conf.get('group'):
return os.getegid()
group = self.conf.get('group')
if group.isdigit() or isinstance(group, int):
gid = int(group)
else:
gid = grp.getgrnam(group).gr_gid
return gid
def _hook(self, hookname, *args):
hook = self.conf.get(hookname)

View File

@ -3,12 +3,9 @@
# This file is part of gunicorn released under the MIT license.
# See the NOTICE for more information.
import ctypes
import grp
import logging
import optparse as op
import os
import pwd
import pkg_resources
import sys
@ -99,26 +96,7 @@ def daemonize(umask):
os.dup2(0, 1)
os.dup2(0, 2)
def set_owner_process(user,group):
""" set user and group of workers processes """
if group:
if group.isdigit() or isinstance(group, int):
gid = int(group)
else:
gid = grp.getgrnam(group).gr_gid
try:
os.setgid(gid)
except OverflowError:
# versions of python < 2.6.2 don't manage unsigned int for
# groups like on osx or fedora
os.setgid(-ctypes.c_int(-gid).value)
if user:
if user.isdigit() or isinstance(user, int):
uid = int(user)
else:
uid = pwd.getpwnam(user).pw_uid
os.setuid(uid)
def main(usage, get_app):
""" function used by different runners to setup options
@ -137,7 +115,6 @@ def main(usage, get_app):
else:
os.umask(conf['umask'])
os.setpgrp()
set_owner_process(conf['user'], conf['group'])
configure_logging(conf)
arbiter.run()
@ -173,7 +150,6 @@ def paste_server(app, global_conf=None, host="127.0.0.1", port=None,
else:
os.umask(conf['umask'])
os.setpgrp()
set_owner_process(conf["user"], conf["group"])
configure_logging(conf)
arbiter.run()

View File

@ -71,7 +71,6 @@ class Command(BaseCommand):
else:
os.umask(conf['umask'])
os.setpgrp()
set_owner_process(conf["user"], conf["group"])
configure_logging(conf)
arbiter.run()
except WSGIServerException, e:

View File

@ -3,6 +3,7 @@
# This file is part of gunicorn released under the MIT license.
# See the NOTICE for more information.
import ctypes
import errno
import fcntl
import os
@ -29,7 +30,25 @@ monthname = [None,
'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
def set_owner_process(uid,gid):
""" set user and group of workers processes """
if gid:
try:
os.setgid(gid)
except OverflowError:
# versions of python < 2.6.2 don't manage unsigned int for
# groups like on osx or fedora
os.setgid(-ctypes.c_int(-gid).value)
if uid:
os.setuid(uid)
def chown(path, uid, gid):
try:
os.chown(path, uid, gid)
except OverflowError:
os.chown(path, uid, -ctypes.c_int(-gid).value)
def parse_address(host, port=None, default_port=8000):
if host.startswith("unix:"):
return host.split("unix:")[1]

View File

@ -27,14 +27,16 @@ class Worker(object):
PIPE = []
def __init__(self, workerid, ppid, socket, app, timeout, debug=False):
def __init__(self, workerid, ppid, socket, app, timeout, conf):
self.nr = 0
self.id = workerid
self.ppid = ppid
self.debug = debug
self.debug = conf['debug']
self.conf = conf
self.socket = socket
self.timeout = timeout
self.fd, self.tmpname = tempfile.mkstemp(prefix="wgunicorn-")
util.chown(self.tmpname, conf.uid, conf.gid)
self.tmp = os.fdopen(self.fd, "r+b")
self.app = app
self.alive = True
@ -81,6 +83,8 @@ class Worker(object):
os.chmod(self.tmpname, self.spinner)
def init_process(self):
util.set_owner_process(self.conf.uid, self.conf.gid)
# init pipe
self.PIPE = os.pipe()
map(util.set_non_blocking, self.PIPE)