From b62055d529e06461849f2dea1a7fab2a99bfccaa Mon Sep 17 00:00:00 2001 From: benoitc Date: Sun, 12 Dec 2010 12:38:47 +0100 Subject: [PATCH] fail sooner on user and group error. Fix issue #75. Note: the process could be extended to other variable that need specific parsing. --- gunicorn/app/base.py | 12 ++++++++-- gunicorn/app/djangoapp.py | 4 ++-- gunicorn/app/pasterapp.py | 11 +++++++--- gunicorn/arbiter.py | 3 ++- gunicorn/config.py | 46 ++++++++++++++++++++++++--------------- gunicorn/errors.py | 8 +++++++ 6 files changed, 59 insertions(+), 25 deletions(-) diff --git a/gunicorn/app/base.py b/gunicorn/app/base.py index ed92196d..f0aa34c2 100644 --- a/gunicorn/app/base.py +++ b/gunicorn/app/base.py @@ -33,7 +33,15 @@ class Application(object): self.cfg = None self.callable = None self.logger = None - self.load_config() + self.do_load_config() + + def do_load_config(self): + try: + self.load_config() + except Exception, e: + sys.stderr.write("\nError: %s\n" % str(e)) + sys.stderr.flush() + sys.exit(1) def load_config(self): # init configuration @@ -91,7 +99,7 @@ class Application(object): raise NotImplementedError def reload(self): - self.load_config() + self.do_load_config() if self.cfg.spew: debug.spew() loglevel = self.LOG_LEVELS.get(self.cfg.loglevel.lower(), logging.INFO) diff --git a/gunicorn/app/djangoapp.py b/gunicorn/app/djangoapp.py index 18ff24bc..34d511e2 100644 --- a/gunicorn/app/djangoapp.py +++ b/gunicorn/app/djangoapp.py @@ -97,7 +97,7 @@ class DjangoApplicationCommand(Application): self.options = options self.admin_media_path = admin_media_path self.callable = None - self.load_config() + self.do_load_config() def load_config(self): self.cfg = Config() @@ -124,7 +124,7 @@ class DjangoApplicationCommand(Application): try: self.cfg.set(k.lower(), v) except: - sys.stderr.write("Invalid value for %s: %s\n\n" % (k, v)) + sys.stderr.write("Invalid value for %s: %s [%s]\n\n" % (k, v)) raise for k, v in list(self.options.items()): diff --git a/gunicorn/app/pasterapp.py b/gunicorn/app/pasterapp.py index cd58b839..51961ed6 100644 --- a/gunicorn/app/pasterapp.py +++ b/gunicorn/app/pasterapp.py @@ -114,9 +114,14 @@ class PasterServerApplication(PasterBaseApplication): cfg[k] = v cfg["default_proc_name"] = cfg['__file__'] - for k, v in list(cfg.items()): - if k.lower() in self.cfg.settings and v is not None: - self.cfg.set(k.lower(), v) + try: + for k, v in list(cfg.items()): + if k.lower() in self.cfg.settings and v is not None: + self.cfg.set(k.lower(), v) + except Exception, e: + sys.stderr.write("\nConfig error: %s\n" % str(e)) + sys.stderr.flush() + sys.exit(1) self.configure_logging() diff --git a/gunicorn/arbiter.py b/gunicorn/arbiter.py index a9f27383..4b1a2950 100644 --- a/gunicorn/arbiter.py +++ b/gunicorn/arbiter.py @@ -14,7 +14,7 @@ import sys import time import traceback -from gunicorn.errors import HaltServer +from gunicorn.errors import ConfigError, HaltServer from gunicorn.pidfile import Pidfile from gunicorn.sock import create_socket from gunicorn import util @@ -146,6 +146,7 @@ class Arbiter(object): "Main master loop." self.start() util._setproctitle("master [%s]" % self.proc_name) + self.manage_workers() while True: try: diff --git a/gunicorn/config.py b/gunicorn/config.py index 6872b794..642b32dc 100644 --- a/gunicorn/config.py +++ b/gunicorn/config.py @@ -9,10 +9,12 @@ import inspect import optparse import os import pwd +import sys import textwrap import types from gunicorn import __version__ +from gunicorn.errors import ConfigError from gunicorn import util KNOWN_SETTINGS = [] @@ -87,23 +89,11 @@ class Config(object): @property def uid(self): - user = self.settings['user'].get() - if not user: - return os.geteuid() - elif user.isdigit() or isinstance(user, int): - return int(user) - else: - return pwd.getpwnam(user).pw_uid - + return self.settings['user'].get() + @property def gid(self): - group = self.settings['group'].get() - if not group: - return os.getegid() - elif group.isdigit() or isinstance(group, int): - return int(group) - else: - return grp.getgrnam(group).gr_gid + return self.settings['group'].get() @property def proc_name(self): @@ -217,6 +207,28 @@ def validate_callable(arity): return _validate_callable +def validate_user(val): + if val is None: + return os.geteuid() + elif val.isdigit() or isinstance(val, int): + return int(val) + else: + try: + return pwd.getpwnam(val).pw_uid + except KeyError: + raise ConfigError("No such user: '%s'" % val) + +def validate_group(val): + if val is None: + return os.getegid() + elif val.isdigit() or isinstance(val, int): + return int(val) + else: + try: + return grp.getgrnam(val).gr_gid + except KeyError: + raise ConfigError("No such group: '%s'" % val) + class ConfigFile(Setting): name = "config" section = "Config File" @@ -446,7 +458,7 @@ class User(Setting): section = "Server Mechanics" cli = ["-u", "--user"] meta = "USER" - validator = validate_string + validator = validate_user default = None desc = """\ Switch worker processes to run as this user. @@ -461,7 +473,7 @@ class Group(Setting): section = "Server Mechanics" cli = ["-g", "--group"] meta = "GROUP" - validator = validate_string + validator = validate_group default = None desc = """\ Switch worker process to run as this group. diff --git a/gunicorn/errors.py b/gunicorn/errors.py index 482b8293..5270393c 100644 --- a/gunicorn/errors.py +++ b/gunicorn/errors.py @@ -1,3 +1,8 @@ +# -*- coding: utf-8 - +# +# This file is part of gunicorn released under the MIT license. +# See the NOTICE for more information. + class HaltServer(Exception): def __init__(self, reason, exit_status=1): @@ -6,3 +11,6 @@ class HaltServer(Exception): def __str__(self): return "" % (self.reason, self.exit_status) + +class ConfigError(Exception): + """ Exception raised on config error """