class GunicornServer(GunicornApplication): def init(self, **kwargs): config = { 'bind': '{0}:{1}'.format( options['host'], options['port'] ), 'workers': options['workers'], 'worker_class': 'gevent', 'accesslog': options['access_logfile'], 'max_requests': options['max_requests'], } return config def load(self): # Step needed to get around flask's import time side-effects from product_identifier.master import Master env = Master.instance() env.start() return env.flask def load_config(self): # Overriding to prevent Gunicorn from reading # the command-line arguments self.cfg = GunicornConfig(self.usage, prog=self.prog) cfg = self.init() if cfg and cfg is not None: for k, v in cfg.items(): self.cfg.set(k.lower(), v)
class DjangoApplicationCommand(Application): def __init__(self, options, admin_media_path): self.cfg = Config() self.callable = None for k, v in list(options.items()): if k.lower() in self.cfg.settings and v is not None: self.cfg.set(k.lower(), v) self.admin_media_path = admin_media_path def load(self): try: return AdminMediaHandler(WSGIHandler(), self.admin_media_path) except WSGIServerException, e: # Use helpful error messages instead of ugly tracebacks. ERRORS = { 13: "You don't have permission to access that port.", 98: "That port is already in use.", 99: "That IP address can't be assigned-to.", } try: error_text = ERRORS[e.args[0].args[0]] except (AttributeError, KeyError): error_text = str(e) sys.stderr.write(self.style.ERROR("Error: %s" % error_text) + '\n') sys.exit(1)
class Application(GunicornApp): def init(self, parser, opts, args): if len(args) < 1: parser.error("No application module specified.") self.cfg.set("default_proc_name", args[0]) self.app_uri = args[0] logging.captureWarnings(True) if opts.auto_config: # Default config_dir config_dir = os.path.join(self.cfg.chdir, 'etc', self.app_uri.split(":", 1)[0]) if os.path.exists(config_dir): self.cfg.set('config_dir', config_dir) # Define dev etc folder as default config directory # generate config_dir directly: egg or chicken problem if opts.config_dir: self.cfg.set('config_dir', opts.config_dir) if not opts.config: opts.config = os.path.join(self.cfg.config_dir, 'api_hour/gunicorn_conf.py') if not self.cfg.logconfig: self.cfg.set('logconfig', os.path.join(self.cfg.config_dir, 'api_hour/logging.ini')) else: # To avoid with Gunicorn 19 that the console it's empty when you test if not opts.errorlog: opts.errorlog = '-' if not opts.accesslog: opts.accesslog = '-' def load_default_config(self): # init configuration self.cfg = Config(self.usage, prog=self.prog) self.cfg.set('worker_class', 'api_hour.Worker') # Define api_hour.Worker as default def load_config(self): # parse console args super().load_config() if self.cfg.config_dir: self.config = get_config({'config_dir': self.cfg.config_dir}) else: self.config = None # import ipdb; ipdb.set_trace() def chdir(self): # chdir to the configured path before loading, # default is the current dir os.chdir(self.cfg.chdir) # add the path to sys.path sys.path.insert(0, self.cfg.chdir) def load(self): self.chdir() # load the app return util.import_app(self.app_uri)
class GunicornApplication(BaseApplication): def __init__(self, application, options=None): if options is None: options = {} self.application = app self.prog = None self.usage = None self.callable = None self.options = options self.do_load_config() def load_config(self): self.cfg = Config(self.usage, prog=self.prog) # optional settings from apps cfg = self.init(None, [], []) # Load up the any app specific configuration if cfg and cfg is not None: for k, v in cfg.items(): self.cfg.set(k.lower(), v) def init(self, parser, opts, args): config = dict( (key, value) for key, value in map(lambda item: (item[0].lower(), item[1]), self.options.iteritems()) if key in self.cfg.settings and value is not None ) return config def load(self): self.application.wsgi_app = ProxyFix(self.application.wsgi_app) return self.application
class PasterServerApplication(PasterBaseApplication): def __init__(self, app, gcfg=None, host="127.0.0.1", port=None, *args, **kwargs): self.cfg = Config() self.app = app self.callable = None gcfg = gcfg or {} cfgfname = gcfg.get("__file__") if cfgfname is not None: self.cfgurl = "config:%s" % cfgfname self.relpath = os.path.dirname(cfgfname) self.cfgfname = cfgfname cfg = kwargs.copy() if port and not host.startswith("unix:"): bind = "%s:%s" % (host, port) else: bind = host cfg["bind"] = bind if gcfg: for k, v in gcfg.items(): cfg[k] = v cfg["default_proc_name"] = cfg["__file__"] try: for k, v in 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)
def paste_server(app, global_conf=None, host="127.0.0.1", port=None, *args, **kwargs): """ Paster server entrypoint to add to your paster ini file: [server:main] use = egg:gunicorn#main host = 127.0.0.1 port = 5000 """ options = kwargs.copy() if port and not host.startswith("unix:"): bind = "%s:%s" % (host, port) else: bind = host options['bind'] = bind if global_conf: for key, value in list(global_conf.items()): if value and value is not None: if key == "debug": value = (value == "true") options[key] = value options['default_proc_name'] = options['__file__'] conf = Config(options) arbiter = conf.arbiter(conf.address, conf.workers, app, debug=conf["debug"], pidfile=conf["pidfile"], config=conf) if conf["daemon"] : daemonize() else: os.setpgrp() configure_logging(conf) arbiter.run()
class PasterServerApplication(Application): def __init__(self, app, gcfg=None, host="127.0.0.1", port=None, *args, **kwargs): self.cfg = Config() self.app = app self.callable = None cfg = kwargs.copy() if port and not host.startswith("unix:"): bind = "%s:%s" % (host, port) else: bind = host cfg["bind"] = bind if gcfg: for k, v in list(gcfg.items()): 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) self.configure_logging() def load(self): return self.app
class ConfigurableApplication(Application): @staticmethod def default_cfg(): return { 'worker_class': 'sync', 'workers': 2, 'secure_scheme_headers': { 'X-FORWARDED-PROTO': 'https' }, 'preload_app': True, 'user': os.getuid(), } def __init__(self, app, **config): self.app = app self._config = config super(ConfigurableApplication, self).__init__() def load(self): return self.app def init(self, parser, opts, args): self.cfg.set('default_proc_name', 'mtrpc') def load_config(self): self.cfg = Config() for k, v in chain(self.default_cfg().items(), self._config.items()): self.cfg.set(k.lower(), v)
def test_prefix_multiple_dots(): c = Config() c.set("statsd_prefix", "test...") logger = Statsd(c) logger.sock = MockSocket(False) logger.info("Blah", extra={"mtype": "gauge", "metric": "gunicorn.test", "value": 666}) t.eq(logger.sock.msgs[0], "test.gunicorn.test:666|g")
def test_prefix(): c = Config() c.set("statsd_prefix", "test.") logger = Statsd(c) logger.sock = MockSocket(False) logger.info("Blah", extra={"mtype": "gauge", "metric": "gunicorn.test", "value": 666}) assert logger.sock.msgs[0] == b"test.gunicorn.test:666|g"
def test_dogstatsd_tags(): c = Config() tags = 'yucatan,libertine:rhubarb' c.set('dogstatsd_tags', tags) logger = Statsd(c) logger.sock = MockSocket(False) logger.info("Twill", extra={"mtype": "gauge", "metric": "barb.westerly", "value": 2}) assert logger.sock.msgs[0] == b"barb.westerly:2|g|#" + tags.encode('ascii')
class PasterServerApplication(PasterBaseApplication): def __init__(self, app, gcfg=None, host="127.0.0.1", port=None, *args, **kwargs): self.cfg = Config() self.app = app self.callable = None gcfg = gcfg or {} cfgfname = gcfg.get("__file__") if cfgfname is not None: self.cfgurl = 'config:%s' % cfgfname self.relpath = os.path.dirname(cfgfname) self.cfgfname = cfgfname cfg = kwargs.copy() if port and not host.startswith("unix:"): bind = "%s:%s" % (host, port) else: bind = host cfg["bind"] = bind.split(',') if gcfg: for k, v in gcfg.items(): cfg[k] = v cfg["default_proc_name"] = cfg['__file__'] try: for k, v in cfg.items(): if k.lower() in self.cfg.settings and v is not None: self.cfg.set(k.lower(), v) except Exception as e: sys.stderr.write("\nConfig error: %s\n" % str(e)) sys.stderr.flush() sys.exit(1) def load_config(self): if not hasattr(self, "cfgfname"): return cfg = self.app_config() for k,v in cfg.items(): try: self.cfg.set(k.lower(), v) except: sys.stderr.write("Invalid value for %s: %s\n\n" % (k, v)) raise def load(self): if hasattr(self, "cfgfname"): return loadapp(self.cfgurl, relative_to=self.relpath) return self.app
class Application(object): """\ An application interface for configuring and loading the various necessities for any given web framework. """ def __init__(self, usage=None): self.log = logging.getLogger(__name__) self.cfg = Config(usage) self.callable = None parser = self.cfg.parser() opts, args = parser.parse_args() cfg = self.init(parser, opts, args) # Load up the any app specific configuration if cfg: for k, v in list(cfg.items()): self.cfg.set(k.lower(), v) # Load up the config file if its found. if opts.config and os.path.exists(opts.config): cfg = { "__builtins__": __builtins__, "__name__": "__config__", "__file__": opts.config, "__doc__": None, "__package__": None } try: execfile(opts.config, cfg, cfg) except Exception, e: print "Failed to read config file: %s" % opts.config traceback.print_exc() sys.exit(1) for k, v in list(cfg.items()): # Ignore unknown names if k not in self.cfg.settings: continue try: self.cfg.set(k.lower(), v) except: sys.stderr.write("Invalid value for %s: %s\n\n" % (k, v)) raise # Lastly, update the configuration with any command line # settings. for k, v in list(opts.__dict__.items()): if v is None: continue self.cfg.set(k.lower(), v) self.configure_logging()
class GunicornApp(VanillaGunicornApp): """Implement Gunicorn application.""" def __init__(self, usage=None, prog=None, config=None): """Initialize self.""" self._cfg = config super(GunicornApp, self).__init__(usage=usage, prog=prog) def init(self, parser, opts, args): """Initialize the application.""" if len(args) < 1: parser.error("No application module specified.") self.app_uri = args[0] self.cfg.set("default_proc_name", self.app_uri) logging.captureWarnings(True) if self.cfg.config: self.load_config_from_file(self.cfg.config) def load_default_config(self): """Prepare default configuration.""" self.cfg = VanillaGunicornConfig(self.usage, prog=self.prog) # Remove unused settings del self.cfg.settings['paste'] del self.cfg.settings['django_settings'] self.cfg.settings['worker_class'].default = 'muffin.worker.GunicornWorker' self.cfg.set('worker_class', 'muffin.worker.GunicornWorker') if self._cfg: self.cfg.set('config', self._cfg) os.environ[CONFIGURATION_ENVIRON_VARIABLE] = self._cfg def load_config(self): """Load configuration.""" parser = self.cfg.parser() args, _ = parser.parse_known_args() self.init(parser, args, args.args) def load(self): """Load a Muffin application.""" # Fix paths os.chdir(self.cfg.chdir) sys.path.insert(0, self.cfg.chdir) app = self.app_uri if not isinstance(app, Application): app = import_app(app) return app
class PasterServerApplication(PasterBaseApplication): def __init__(self, app, gcfg=None, host="127.0.0.1", port=None, *args, **kwargs): self.cfg = Config() self.gcfg = gcfg # need to hold this for app_config self.app = app self.callable = None gcfg = gcfg or {} cfgfname = gcfg.get("__file__") if cfgfname is not None: self.cfgurl = 'config:%s' % cfgfname self.relpath = os.path.dirname(cfgfname) self.cfgfname = cfgfname cfg = kwargs.copy() if port and not host.startswith("unix:"): bind = "%s:%s" % (host, port) else: bind = host cfg["bind"] = bind.split(',') if gcfg: for k, v in gcfg.items(): cfg[k] = v cfg["default_proc_name"] = cfg['__file__'] try: for k, v in cfg.items(): if k.lower() in self.cfg.settings and v is not None: self.cfg.set(k.lower(), v) except Exception as e: sys.stderr.write("\nConfig error: %s\n" % str(e)) sys.stderr.flush() sys.exit(1) if cfg.get("config"): self.load_config_from_file(cfg["config"]) else: default_config = get_default_config_file() if default_config is not None: self.load_config_from_file(default_config) def load(self): # chdir to the configured path before loading, # default is the current dir os.chdir(self.cfg.chdir) return self.app
def __init__(self, app, gcfg=None, host="127.0.0.1", port=None, *args, **kwargs): self.cfg = Config() self.app = app self.callable = None gcfg = gcfg or {} cfgfname = gcfg.get("__file__") if cfgfname is not None: self.cfgurl = 'config:%s' % cfgfname self.relpath = os.path.dirname(cfgfname) self.cfgfname = cfgfname cfg = kwargs.copy() if port and not host.startswith("unix:"): bind = "%s:%s" % (host, port) else: bind = host cfg["bind"] = bind if gcfg: for k, v in list(gcfg.items()): 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) self.configure_logging()
def load_config(self): self.cfg = Config() if self.config_file and os.path.exists(self.config_file): cfg = { "__builtins__": __builtins__, "__name__": "__config__", "__file__": self.config_file, "__doc__": None, "__package__": None } try: execfile(self.config_file, cfg, cfg) except Exception, e: print "Failed to read config file: %s" % self.config_file traceback.print_exc() sys.exit(1) for k, v in list(cfg.items()): # Ignore unknown names if k not in self.cfg.settings: continue try: self.cfg.set(k.lower(), v) except: sys.stderr.write("Invalid value for %s: %s\n\n" % (k, v)) raise
def __init__(self, options, admin_media_path): self.cfg = Config() self.callable = None # Load up the config file if its found. config_file = options.get("config") or "" if config_file and os.path.exists(config_file): cfg = { "__builtins__": __builtins__, "__name__": "__config__", "__file__": config_file, "__doc__": None, "__package__": None } try: execfile(config_file, cfg, cfg) except Exception, e: print "Failed to read config file: %s" % config_file traceback.print_exc() sys.exit(1) for k, v in list(cfg.items()): # Ignore unknown names if k not in self.cfg.settings: continue try: self.cfg.set(k.lower(), v) except: sys.stderr.write("Invalid value for %s: %s\n\n" % (k, v)) raise
def load_config(self): # init configuration self.cfg = Config(self.usage, prog=self.prog) # parse console args parser = self.cfg.parser() args = parser.parse_args() # optional settings from apps cfg = self.init(parser, args, args.args) # Load up the any app specific configuration if cfg and cfg is not None: for k, v in cfg.items(): self.cfg.set(k.lower(), v) if args.config: self.load_config_from_file(args.config) else: default_config = get_default_config_file() if default_config is not None: self.load_config_from_file(default_config) # Lastly, update the configuration with any command line # settings. for k, v in args.__dict__.items(): if v is None: continue if k == "args": continue self.cfg.set(k.lower(), v)
def load_config(self): # Overriding to prevent Gunicorn from reading # the command-line arguments self.cfg = GunicornConfig(self.usage, prog=self.prog) cfg = self.init() if cfg and cfg is not None: for k, v in cfg.items(): self.cfg.set(k.lower(), v)
def handle(self, addrport='', *args, **options): if args: raise CommandError('Usage is runserver %s' % self.args) options['bind'] = addrport or '127.0.0.1' options['default_proc_name'] =settings.SETTINGS_MODULE conf = Config(options, options.get('gconfig')) admin_media_path = options.get('admin_media_path', '') quit_command = (sys.platform == 'win32') and 'CTRL-BREAK' or 'CONTROL-C' print "Validating models..." self.validate(display_num_errors=True) print "\nDjango version %s, using settings %r" % (django.get_version(), settings.SETTINGS_MODULE) print "Development server is running at %s" % str(conf.address) print "Quit the server with %s." % quit_command # django.core.management.base forces the locale to en-us. translation.activate(settings.LANGUAGE_CODE) try: handler = AdminMediaHandler(WSGIHandler(), admin_media_path) arbiter = conf.arbiter(conf.address, conf.workers, handler, pidfile=conf['pidfile'], config=conf) if conf['daemon']: daemonize() else: os.setpgrp() configure_logging(conf) arbiter.run() except WSGIServerException, e: # Use helpful error messages instead of ugly tracebacks. ERRORS = { 13: "You don't have permission to access that port.", 98: "That port is already in use.", 99: "That IP address can't be assigned-to.", } try: error_text = ERRORS[e.args[0].args[0]] except (AttributeError, KeyError): error_text = str(e) sys.stderr.write(self.style.ERROR("Error: %s" % error_text) + '\n') sys.exit(1)
def main(usage, get_app): """ function used by different runners to setup options ans launch the arbiter. """ parser = op.OptionParser(usage=usage, option_list=options(), version="%prog " + __version__) opts, args = parser.parse_args() app = get_app(parser, opts, args) conf = Config(opts.__dict__, opts.config) arbiter = conf.arbiter(conf.address, conf.workers, app, config=conf, debug=conf['debug'], pidfile=conf['pidfile']) if conf['daemon']: daemonize() else: os.setpgrp() configure_logging(conf) arbiter.run()
def load_config(self): self.cfg = Config(self.usage, prog=self.prog) # optional settings from apps cfg = self.init(None, [], []) # Load up the any app specific configuration if cfg and cfg is not None: for k, v in cfg.items(): self.cfg.set(k.lower(), v)
def run_gunicorn(app, host, port): try: from gunicorn.app.base import Application from gunicorn.config import Config except: print "warning: couldn't import gunicorn -- running flask dev server" run_flask(app, host, port) return class Glapp(Application): def init(self, *start): pass def load(self): return app glapp = Glapp() gonfig = Config() gonfig.set('bind', '{}{}'.format(host, ':{}'.format(port) if port else '')) glapp.cfg = gonfig glapp.run()
def __init__(self, options, admin_media_path): self.cfg = Config() self.callable = None for k, v in list(options.items()): if k.lower() in self.cfg.settings and v is not None: self.cfg.set(k.lower(), v) self.admin_media_path = admin_media_path
def test_statsd_fail(): "UDP socket fails" logger = Statsd(Config()) logger.sock = MockSocket(True) logger.info("No impact on logging") logger.debug("No impact on logging") logger.critical("No impact on logging") logger.error("No impact on logging") logger.warning("No impact on logging") logger.exception("No impact on logging")
class DjangoApplicationCommand(Application): def __init__(self, options, admin_media_path): self.log = logging.getLogger(__name__) self.usage = None self.cfg = None self.config_file = options.get("config") or "" self.options = options self.admin_media_path = admin_media_path self.callable = None self.load_config() def load_config(self): self.cfg = Config() if self.config_file and os.path.exists(self.config_file): cfg = { "__builtins__": __builtins__, "__name__": "__config__", "__file__": self.config_file, "__doc__": None, "__package__": None } try: execfile(self.config_file, cfg, cfg) except Exception, e: print "Failed to read config file: %s" % self.config_file traceback.print_exc() sys.exit(1) for k, v in list(cfg.items()): # Ignore unknown names if k not in self.cfg.settings: continue try: self.cfg.set(k.lower(), v) except: sys.stderr.write("Invalid value for %s: %s\n\n" % (k, v)) raise for k, v in list(self.options.items()): if k.lower() in self.cfg.settings and v is not None: self.cfg.set(k.lower(), v)
class PasterServerApplication(PasterBaseApplication): def __init__(self, app, gcfg=None, host="127.0.0.1", port=None, *args, **kwargs): self.cfg = Config() self.app = app self.callable = None gcfg = gcfg or {} cfgfname = gcfg.get("__file__") if cfgfname is not None: self.cfgurl = 'config:%s' % cfgfname self.relpath = os.path.dirname(cfgfname) self.cfgfname = cfgfname cfg = kwargs.copy() if port and not host.startswith("unix:"): bind = "%s:%s" % (host, port) else: bind = host cfg["bind"] = bind if gcfg: for k, v in list(gcfg.items()): cfg[k] = v cfg["default_proc_name"] = cfg['__file__'] 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()
def __init__(self, app, gcfg=None, host="127.0.0.1", port=None, **kwargs): # pylint: disable=super-init-not-called self.cfg = Config() self.gcfg = gcfg # need to hold this for app_config self.app = app self.callable = None gcfg = gcfg or {} cfgfname = gcfg.get("__file__") if cfgfname is not None: self.cfgurl = 'config:%s' % cfgfname self.relpath = os.path.dirname(cfgfname) self.cfgfname = cfgfname cfg = kwargs.copy() if port and not host.startswith("unix:"): bind = "%s:%s" % (host, port) else: bind = host cfg["bind"] = bind.split(',') if gcfg: for k, v in gcfg.items(): cfg[k] = v cfg["default_proc_name"] = cfg['__file__'] try: for k, v in cfg.items(): if k.lower() in self.cfg.settings and v is not None: self.cfg.set(k.lower(), v) except Exception as e: print("\nConfig error: %s" % str(e), file=sys.stderr) sys.stderr.flush() sys.exit(1) if cfg.get("config"): self.load_config_from_file(cfg["config"]) else: default_config = get_default_config_file() if default_config is not None: self.load_config_from_file(default_config)
def load_config(self): # init configuration self.cfg = Config(self.usage, prog=self.prog) # parse console args parser = self.cfg.parser() args = parser.parse_args() # optional settings from apps cfg = self.init(parser, args, args.args) # Load up the any app specific configuration if cfg and cfg is not None: for k, v in cfg.items(): self.cfg.set(k.lower(), v) # Load up the config file if its found. if args.config: if not os.path.exists(args.config): raise RuntimeError("%r doesn't exist" % args.config) cfg = { "__builtins__": __builtins__, "__name__": "__config__", "__file__": args.config, "__doc__": None, "__package__": None } try: execfile_(args.config, cfg, cfg) except Exception: print("Failed to read config file: %s" % args.config) traceback.print_exc() sys.exit(1) for k, v in cfg.items(): # Ignore unknown names if k not in self.cfg.settings: continue try: self.cfg.set(k.lower(), v) except: sys.stderr.write("Invalid value for %s: %s\n\n" % (k, v)) raise # Lastly, update the configuration with any command line # settings. for k, v in args.__dict__.items(): if v is None: continue if k == "args": continue self.cfg.set(k.lower(), v)
def check(self): cases = self.expect[:] p = RequestParser(Config(), self.send()) try: [req for req in p] except Exception, inst: exp = cases.pop(0) if not issubclass(exp, Exception): raise TypeError("Test case is not an exception calss: %s" % exp) t.istype(inst, exp) return
def worker(iterator): # Mock socket listener mock_listener = mock.Mock() sockets = [mock_listener] # Declare worker mock_log = mock.Mock() worker = SyncIteratingWorker(None, None, sockets, None, None, Config(), mock_log) worker.wsgi = iterator worker.alive = True yield worker
def load_default_config(self): """Prepare default configuration.""" self.cfg = VanillaGunicornConfig(self.usage, prog=self.prog) # Remove unused settings del self.cfg.settings['paste'] del self.cfg.settings['django_settings'] self.cfg.settings['worker_class'].default = 'muffin.worker.GunicornWorker' self.cfg.set('worker_class', 'muffin.worker.GunicornWorker') if self._cfg: self.cfg.set('config', self._cfg) os.environ[CONFIGURATION_ENVIRON_VARIABLE] = self._cfg
def test_atoms_defaults(): response = Mock(status='200', response_length=1024, headers=(('Content-Type', 'application/json'), )) request = Mock(headers=(('Accept', 'application/json'), )) environ = {'REQUEST_METHOD': 'GET', 'RAW_URI': 'http://my.uri', 'SERVER_PROTOCOL': 'HTTP/1.1'} logger = Logger(Config()) atoms = logger.atoms(response, request, environ, datetime.timedelta(seconds=1)) t.istype(atoms, dict) t.eq(atoms['r'], 'GET http://my.uri HTTP/1.1') t.eq(atoms['{accept}i'], 'application/json') t.eq(atoms['{content-type}o'], 'application/json')
def handle(self, app, *args, **kwargs): host = kwargs['host'] port = kwargs['port'] workers = kwargs['workers'] def remove_non_gunicorn_command_line_args(): import sys args_to_remove = ['--port','-p'] def args_filter(name_or_value): keep = not args_to_remove.count(name_or_value) if keep: previous = sys.argv[sys.argv.index(name_or_value) - 1] keep = not args_to_remove.count(previous) return keep sys.argv = filter(args_filter, sys.argv) remove_non_gunicorn_command_line_args() from gunicorn import version_info if version_info < (0, 9, 0): from gunicorn.arbiter import Arbiter from gunicorn.config import Config print Config({'bind': "%s:%d" % (host, int(port)),'workers': workers}) arbiter = Arbiter(Config({'bind': "%s:%d" % (host, int(port)),'workers': workers}), app) arbiter.run() else: class FlaskApplication(Application): def init(self, parser, opts, args): return { 'bind': '{0}:{1}'.format(host, port), 'workers': workers } def load(self): return app FlaskApplication().run()
def load_default_config(self): """ Prepare default configuration. """ self.cfg = VanillaGunicornConfig(self.usage, prog=self.prog) # Remove unused settings del self.cfg.settings['paste'] del self.cfg.settings['django_settings'] self.cfg.settings[ 'worker_class'].default = 'muffin.worker.GunicornWorker' self.cfg.set('worker_class', 'muffin.worker.GunicornWorker') if self._cfg: self.cfg.set('config', self._cfg) os.environ[CONFIGURATION_ENVIRON_VARIABLE] = self._cfg
def test_instrument(): logger = Statsd(Config()) # Capture logged messages sio = io.StringIO() logger.error_log.addHandler(logging.StreamHandler(sio)) logger.sock = MockSocket(False) # Regular message logger.info("Blah", extra={ "mtype": "gauge", "metric": "gunicorn.test", "value": 666 }) assert logger.sock.msgs[0] == b"gunicorn.test:666|g" assert sio.getvalue() == "Blah\n" logger.sock.reset() # Only metrics, no logging logger.info("", extra={ "mtype": "gauge", "metric": "gunicorn.test", "value": 666 }) assert logger.sock.msgs[0] == b"gunicorn.test:666|g" assert sio.getvalue() == "Blah\n" # log is unchanged logger.sock.reset() # Debug logging also supports metrics logger.debug("", extra={ "mtype": "gauge", "metric": "gunicorn.debug", "value": 667 }) assert logger.sock.msgs[0] == b"gunicorn.debug:667|g" assert sio.getvalue() == "Blah\n" # log is unchanged logger.sock.reset() logger.critical("Boom") assert logger.sock.msgs[0] == b"gunicorn.log.critical:1|c|@1.0" logger.sock.reset() logger.access(SimpleNamespace(status="200 OK"), None, {}, timedelta(seconds=7)) assert logger.sock.msgs[0] == b"gunicorn.request.duration:7000.0|ms" assert logger.sock.msgs[1] == b"gunicorn.requests:1|c|@1.0" assert logger.sock.msgs[2] == b"gunicorn.request.status.200:1|c|@1.0"
class GunicornServer(GunicornApplication): def init(self, **kwargs): config = { 'bind': '{0}:{1}'.format(options['host'], options['port']), 'workers': options['workers'], 'worker_class': 'gevent', 'accesslog': options['access_logfile'], 'max_requests': options['max_requests'], } return config def load(self): # Step needed to get around flask's import time side-effects app = environment_manager_create() return app def load_config(self): # Overriding to prevent Gunicorn from reading # the command-line arguments self.cfg = GunicornConfig(self.usage, prog=self.prog) cfg = self.init() if cfg and cfg is not None: for k, v in cfg.items(): self.cfg.set(k.lower(), v)
def test_atoms_zero_bytes(): response = SimpleNamespace( status='200', response_length=0, headers=(('Content-Type', 'application/json'),), sent=0, ) request = SimpleNamespace(headers=(('Accept', 'application/json'),)) environ = { 'REQUEST_METHOD': 'GET', 'RAW_URI': '/my/path?foo=bar', 'PATH_INFO': '/my/path', 'QUERY_STRING': 'foo=bar', 'SERVER_PROTOCOL': 'HTTP/1.1', } logger = Logger(Config()) atoms = logger.atoms(response, request, environ, datetime.timedelta(seconds=1)) assert atoms['b'] == '0' assert atoms['B'] == 0
def test_get_username_from_basic_auth_header(): request = SimpleNamespace(headers=()) response = SimpleNamespace( status='200', response_length=1024, sent=1024, headers=(('Content-Type', 'text/plain'),), ) environ = { 'REQUEST_METHOD': 'GET', 'RAW_URI': '/my/path?foo=bar', 'PATH_INFO': '/my/path', 'QUERY_STRING': 'foo=bar', 'SERVER_PROTOCOL': 'HTTP/1.1', 'HTTP_AUTHORIZATION': 'Basic YnJrMHY6', } logger = Logger(Config()) atoms = logger.atoms(response, request, environ, datetime.timedelta(seconds=1)) assert atoms['u'] == 'brk0v'
def test_gunicorn_get_response_status(): cfg = Config() logger = gunicorn.GunicornLogger(cfg) class Response1: status_code = 200 assert logger.get_response_status(Response1()) == 200 class Response2: status = '200 OK' assert logger.get_response_status(Response2()) == 200 class Response3: status = 200 assert logger.get_response_status(Response3()) == 200
def test_gunicorn_logger_get_extra(environ): track_request_metric('sql', 1.0) track_request_metric('http', 2.0) track_request_metric('log', 3.0) response, environ, delta, expected = access_extra_args( environ, '/foo?bar=baz') expected['sql_count'] = 1 expected['sql_time_ms'] = 1.0 expected['http_count'] = 1 expected['http_time_ms'] = 2.0 expected['log_count'] = 1 expected['log_time_ms'] = 3.0 cfg = Config() logger = gunicorn.GunicornLogger(cfg) msg, extra = logger.get_extra(response, None, environ, delta, 200) assert msg == 'GET /foo?' assert extra == expected
def test_get_username_handles_malformed_basic_auth_header(): """Should catch a malformed auth header""" request = SimpleNamespace(headers=()) response = SimpleNamespace( status='200', response_length=1024, sent=1024, headers=(('Content-Type', 'text/plain'),), ) environ = { 'REQUEST_METHOD': 'GET', 'RAW_URI': '/my/path?foo=bar', 'PATH_INFO': '/my/path', 'QUERY_STRING': 'foo=bar', 'SERVER_PROTOCOL': 'HTTP/1.1', 'HTTP_AUTHORIZATION': 'Basic ixsTtkKzIpVTncfQjbBcnoRNoDfbnaXG', } logger = Logger(Config()) atoms = logger.atoms(response, request, environ, datetime.timedelta(seconds=1)) assert atoms['u'] == '-'
def load_config(self): self.cfg = Config(self.usage, prog=self.prog) self.cfg.set("default_proc_name", self.prog) self.cfg.set("proc_name", self.prog) self.cfg.set("preload_app", True) self.cfg.set("chdir", install_path) self.cfg.set("bind", pdnsnexus.app.config['SERVER_BIND']) self.cfg.set("workers", pdnsnexus.app.config['SERVER_WORKERS']) self.cfg.set("max_requests", pdnsnexus.app.config['SERVER_MAX_REQUESTS']) parser = argparse.ArgumentParser(prog=self.prog) parser.add_argument("--daemon", action='store', type=pdnsnexus.utils.powerbool, default=True, help="Run as background process (default=%(default)s)") parser.add_argument("--pid", dest='pidfile', metavar='FILE', action='store', help="If set, write PID to file FILE") args = parser.parse_args() self.cfg.set("daemon", args.daemon) if args.daemon: self.cfg.set("logger_class", NexusServerBackgroundLogger) self.cfg.set("pidfile", args.pidfile)
def test_atoms_defaults(): response = SimpleNamespace( status='200', response_length=1024, headers=(('Content-Type', 'application/json'), ), sent=1024, ) request = SimpleNamespace(headers=(('Accept', 'application/json'), )) environ = { 'REQUEST_METHOD': 'GET', 'RAW_URI': 'http://my.uri', 'SERVER_PROTOCOL': 'HTTP/1.1', } logger = Logger(Config()) atoms = logger.atoms(response, request, environ, datetime.timedelta(seconds=1)) assert isinstance(atoms, dict) assert atoms['r'] == 'GET http://my.uri HTTP/1.1' assert atoms['{accept}i'] == 'application/json' assert atoms['{content-type}o'] == 'application/json'
def gunicorn_adapter(host, port): from gunicorn import version_info if version_info < (0, 9, 0): from gunicorn.arbiter import Arbiter from gunicorn.config import Config arbiter = Arbiter(Config({'bind': "%s:%d" % (host, int(port)), 'workers': 4}), handle_request) arbiter.run() else: from gunicorn.app.base import Application class IttyApplication(Application): def init(self, parser, opts, args): return { 'bind': '{0}:{1}'.format(host, port), 'workers': 4 } def load(self): return handle_request IttyApplication().run()
def __call__(self, app, host, port, workers, timeout): from gunicorn import version_info if version_info < (0, 9, 0): from gunicorn.arbiter import Arbiter from gunicorn.config import Config arbiter = Arbiter( Config({ 'bind': '%s:%d' % (host, int(port)), 'workers': workers }), app) arbiter.run() else: from gunicorn.app.base import Application class FlaskApplication(Application): def init(self, parser, opts, args): return {'bind': '{0}:{1}'.format(host, port)} def load(self): return app FlaskApplication().run()
def test_atoms_defaults(): response = SimpleNamespace( status='200', response_length=1024, headers=(('Content-Type', 'application/json'),), sent=1024, ) request = SimpleNamespace(headers=(('Accept', 'application/json'),)) environ = { 'REQUEST_METHOD': 'GET', 'RAW_URI': '/my/path?foo=bar', 'PATH_INFO': '/my/path', 'QUERY_STRING': 'foo=bar', 'SERVER_PROTOCOL': 'HTTP/1.1', } logger = Logger(Config()) atoms = logger.atoms(response, request, environ, datetime.timedelta(seconds=1)) assert isinstance(atoms, dict) assert atoms['r'] == 'GET /my/path?foo=bar HTTP/1.1' assert atoms['m'] == 'GET' assert atoms['U'] == '/my/path' assert atoms['q'] == 'foo=bar' assert atoms['H'] == 'HTTP/1.1' assert atoms['b'] == '1024' assert atoms['B'] == 1024 assert atoms['{accept}i'] == 'application/json' assert atoms['{content-type}o'] == 'application/json'
def run(self): loop = asyncio.get_event_loop() age = None ppid = os.getpid() sockets = [] self.wsgi, app = make_stub_application(headers=self.response_headers, body=self.response_body) timeout = None cfg = Config() log = None sockname = ('127.0.0.1', '80') reader = asyncio.StreamReader() def feeder(): reader.feed_data(self.request) reader.feed_eof() worker = AsyncioWorker(age, ppid, sockets, app, timeout, cfg, log) loop.create_task(worker.connection_task(sockname, reader, self.writer)) loop.call_soon(feeder) run_worker(worker)
def test_worker_creates_servers_for_sockets(monkeypatch, mocker): loop = asyncio.get_event_loop() calls = [] age = None ppid = os.getpid() sockets = [mocker.MagicMock(), mocker.MagicMock()] app = None timeout = None cfg = Config() log = None async def start_server(*args, **kwargs): calls.append((args, kwargs)) if len(calls) == len(sockets): loop.stop() monkeypatch.setattr(asyncio, 'start_server', start_server) worker = AsyncioWorker(age, ppid, sockets, app, timeout, cfg, log) run_worker(worker) for call in calls: assert call[1]['sock'] in sockets
class Application(object): """\ An application interface for configuring and loading the various necessities for any given web framework. """ def __init__(self, usage=None): self.usage = usage self.cfg = None self.callable = None self.logger = None self.do_load_config() def do_load_config(self): try: self.load_config() except Exception as e: sys.stderr.write("\nError: %s\n" % str(e)) sys.stderr.flush() sys.exit(1) def load_config(self): # init configuration self.cfg = Config(self.usage) # parse console args parser = self.cfg.parser() opts, args = parser.parse_args() # optional settings from apps cfg = self.init(parser, opts, args) # Load up the any app specific configuration if cfg and cfg is not None: for k, v in cfg.items(): self.cfg.set(k.lower(), v) # Load up the config file if its found. if opts.config and os.path.exists(opts.config): cfg = { "__builtins__": __builtins__, "__name__": "__config__", "__file__": opts.config, "__doc__": None, "__package__": None } try: execfile_(opts.config, cfg, cfg) except Exception: print("Failed to read config file: %s" % opts.config) traceback.print_exc() sys.exit(1) for k, v in cfg.items(): # Ignore unknown names if k not in self.cfg.settings: continue try: self.cfg.set(k.lower(), v) except: sys.stderr.write("Invalid value for %s: %s\n\n" % (k, v)) raise # Lastly, update the configuration with any command line # settings. for k, v in opts.__dict__.items(): if v is None: continue self.cfg.set(k.lower(), v) def init(self, parser, opts, args): raise NotImplementedError def load(self): raise NotImplementedError def reload(self): self.do_load_config() if self.cfg.spew: debug.spew() def wsgi(self): if self.callable is None: self.callable = self.load() return self.callable def run(self): if self.cfg.check_config: try: self.load() except: sys.stderr.write("\nError while loading the application:\n\n") traceback.print_exc() sys.stderr.flush() sys.exit(1) sys.exit(0) if self.cfg.spew: debug.spew() if self.cfg.daemon: util.daemonize() # set python paths if self.cfg.pythonpath and self.cfg.pythonpath is not None: paths = self.cfg.pythonpath.split(",") for path in paths: pythonpath = os.path.abspath(self.cfg.pythonpath) if pythonpath not in sys.path: sys.path.insert(0, pythonpath) try: Arbiter(self).run() except RuntimeError as e: sys.stderr.write("\nError: %s\n\n" % e) sys.stderr.flush() sys.exit(1)
def load_default_config(self): # init configuration self.cfg = Config(self.usage, prog=self.prog) self.cfg.set('worker_class', 'api_hour.Worker') # Define api_hour.Worker as default
class PasterServerApplication(PasterBaseApplication): def __init__(self, app, gcfg=None, host="127.0.0.1", port=None, *args, **kwargs): self.cfg = Config() self.gcfg = gcfg # need to hold this for app_config self.app = app self.callable = None gcfg = gcfg or {} cfgfname = gcfg.get("__file__") if cfgfname is not None: self.cfgurl = 'config:%s' % cfgfname self.relpath = os.path.dirname(cfgfname) self.cfgfname = cfgfname cfg = kwargs.copy() if port and not host.startswith("unix:"): bind = "%s:%s" % (host, port) else: bind = host cfg["bind"] = bind.split(',') if gcfg: for k, v in gcfg.items(): cfg[k] = v cfg["default_proc_name"] = cfg['__file__'] try: for k, v in cfg.items(): if k.lower() in self.cfg.settings and v is not None: self.cfg.set(k.lower(), v) except Exception as e: sys.stderr.write("\nConfig error: %s\n" % str(e)) sys.stderr.flush() sys.exit(1) def load_config(self): if not hasattr(self, "cfgfname"): return cfg = self.app_config() for k, v in cfg.items(): try: self.cfg.set(k.lower(), v) except: sys.stderr.write("Invalid value for %s: %s\n\n" % (k, v)) raise def load(self): if hasattr(self, "cfgfname"): return loadapp(self.cfgurl, relative_to=self.relpath, global_conf=self.gcfg) return self.app
from gunicorn.config import Config from gunicorn.http.errors import InvalidHeaderName cfg = Config() request = InvalidHeaderName
def run(): fsock = FakeSocket(data_source(self.fname)) req = Request(Config(), fsock, ('127.0.0.1', 6000), ('127.0.0.1', 8000)) func(req)
def load_default_config(self): # init configuration self.cfg = Config(self.usage, prog=self.prog)
def load_py(fname): config = globals().copy() config["uri"] = uri config["cfg"] = Config() execfile_(fname, config) return config
from gunicorn.config import Config from gunicorn.http.errors import LimitRequestHeaders cfg = Config() cfg.set('limit_request_line', 0) cfg.set('limit_request_field_size', 0) request = { "method": "PUT", "uri": uri("/q=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"), "version": (1, 0), "headers": [ ("SOMEHEADER", "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") ], "body": '' }
class Application(GunicornApp): def init(self, parser, opts, args): if len(args) < 1: parser.error("No application module specified.") self.cfg.set("default_proc_name", args[0]) self.app_uri = args[0] logging.captureWarnings(True) if opts.auto_config: # Default config_dir config_dir = os.path.join(self.cfg.chdir, 'etc', self.app_uri.split(":", 1)[0]) if os.path.exists(config_dir): self.cfg.set( 'config_dir', config_dir ) # Define dev etc folder as default config directory # generate config_dir directly: egg or chicken problem if opts.config_dir: self.cfg.set('config_dir', opts.config_dir) if not opts.config: opts.config = os.path.join(self.cfg.config_dir, 'api_hour/gunicorn_conf.py') if not self.cfg.logconfig: self.cfg.set( 'logconfig', os.path.join(self.cfg.config_dir, 'api_hour/logging.ini')) else: # To avoid with Gunicorn 19 that the console it's empty when you test if not opts.errorlog: opts.errorlog = '-' if not opts.accesslog: opts.accesslog = '-' def load_default_config(self): # init configuration self.cfg = Config(self.usage, prog=self.prog) self.cfg.set('worker_class', 'api_hour.Worker') # Define api_hour.Worker as default def load_config(self): # parse console args super().load_config() if self.cfg.config_dir: self.config = get_config({'config_dir': self.cfg.config_dir}) else: self.config = None # import ipdb; ipdb.set_trace() def chdir(self): # chdir to the configured path before loading, # default is the current dir os.chdir(self.cfg.chdir) # add the path to sys.path sys.path.insert(0, self.cfg.chdir) def load(self): self.chdir() # load the app return util.import_app(self.app_uri)