diff --git a/examples/test.py b/examples/test.py index c9fc4c97..9e5e1274 100644 --- a/examples/test.py +++ b/examples/test.py @@ -5,6 +5,7 @@ # # Example code from Eventlet sources +import os from wsgiref.validate import validator import sys @@ -12,9 +13,12 @@ from gunicorn import __version__ #@validator def app(environ, start_response): """Simplest possible application object""" + data = b'Hello, World!\n' status = '200 OK' + print("foo=%s" % (os.environ['FOO'])) + response_headers = [ ('Content-type','text/plain'), ('Content-Length', str(len(data))), diff --git a/gunicorn/arbiter.py b/gunicorn/arbiter.py index bf2a3bc6..693b5f3d 100644 --- a/gunicorn/arbiter.py +++ b/gunicorn/arbiter.py @@ -122,6 +122,12 @@ class Arbiter(object): self.pidfile = Pidfile(self.cfg.pidfile) self.pidfile.create(self.pid) self.cfg.on_starting(self) + + # set enviroment' variables + if self.cfg.env: + for k, v in self.cfg.env.items(): + os.environ[k] = v + self.init_signals() if not self.LISTENERS: self.LISTENERS = create_sockets(self.cfg, self.log) @@ -346,17 +352,32 @@ class Arbiter(object): self.master_name = "Old Master" return + environ = self.cfg.env_orig.copy() fds = [l.fileno() for l in self.LISTENERS] - os.environ['GUNICORN_FD'] = ",".join([str(fd) for fd in fds]) + environ['GUNICORN_FD'] = ",".join([str(fd) for fd in fds]) os.chdir(self.START_CTX['cwd']) self.cfg.pre_exec(self) - os.execvpe(self.START_CTX[0], self.START_CTX['args'], os.environ) + # exec the process using the original environnement + os.execvpe(self.START_CTX[0], self.START_CTX['args'], environ) def reload(self): old_address = self.cfg.address + # reset old environement + for k in self.cfg.env: + if k in self.cfg.env_orig: + # reset the key to the value it had before + # we launched gunicorn + os.environ[k] = self.cfg.env_orig[k] + else: + # delete the value set by gunicorn + try: + del os.environ[k] + except KeyError: + pass + # reload conf self.app.reload() self.setup(self.app) diff --git a/gunicorn/config.py b/gunicorn/config.py index b48151ef..b5bca173 100644 --- a/gunicorn/config.py +++ b/gunicorn/config.py @@ -48,8 +48,12 @@ class Config(object): self.settings = make_settings() self.usage = usage self.prog = prog or os.path.basename(sys.argv[0]) + self.env_orig = os.environ.copy() def __getattr__(self, name): + if name == "env_orig": + return self.env_orig + if name not in self.settings: raise AttributeError("No configuration setting for: %s" % name) return self.settings[name].get() @@ -144,6 +148,23 @@ class Config(object): return opts + @property + def env(self): + env = {} + if not self.settings['raw_env']: + return env + + for e in self.settings['raw_env'].get(): + s = six.bytes_to_str(e) + try: + k, v = s.split('=') + except ValueError: + raise RuntimeError("environement setting %r invalid" % s) + + env[k] = v + + return env + class SettingMeta(type): def __new__(cls, name, bases, attrs): @@ -699,6 +720,23 @@ class Daemon(Setting): background. """ +class Env(Setting): + name = "raw_env" + action = "append" + section = "Server Mechanic" + cli = ["-e", "--env"] + meta = "ENV" + validator = validate_list_string + + desc = """\ + Set environment variable (key=value). + + Pass variables to the execution environment. Ex.:: + + $ gunicorn -b 127.0.0.1:8000 --env FOO=1 test:app + + and test for the foo variable environement in your application. + """ class Pidfile(Setting): name = "pidfile" diff --git a/gunicorn/workers/base.py b/gunicorn/workers/base.py index 945ef024..5566dd18 100644 --- a/gunicorn/workers/base.py +++ b/gunicorn/workers/base.py @@ -78,6 +78,12 @@ class Worker(object): super(MyWorkerClass, self).init_process() so that the ``run()`` loop is initiated. """ + + # set enviroment' variables + if self.cfg.env: + for k, v in self.cfg.env.items(): + os.environ[k] = v + util.set_owner_process(self.cfg.uid, self.cfg.gid) # Reseed the random number generator