阿帕奇SETENV不工作与预期的mod_wsgi [英] Apache SetEnv not working as expected with mod_wsgi

查看:222
本文介绍了阿帕奇SETENV不工作与预期的mod_wsgi的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在烧瓶中的应用我写的,我充分利用可使用环境变量来配置一个外部库。注:我写这个外部库自己。所以,我的可能的如果有必要进行更改。当从命令行运行的运行与瓶服务器:

In a flask application I wrote, I make use of an external library which can be configured using environment variables. Note: I wrote this external library myself. So I could make changes if necessary. When running from the command line an running the flask server with:

# env = python virtual environment
ENV_VAR=foo ./env/bin/python myapp/webui.py

它预期的所有炒菜锅。但它部署到Apache和使用后的 SETENV 它的的工作了。事实上,打印出 os.environ 标准错误(所以它显示了在Apache日志显示,该 WSGI 过程似乎是在一个非常不同的环境(一, os.environ ['PWD'] 似乎是的办法的关闭。事实上,它指向我的开发文件夹。

it all woks as expected. But after deploying it to apache, and using SetEnv it does not work anymore. In fact, printing out os.environ to stderr (so it shows up in the apache logs reveals, that the wsgi process seems to be in a very different environment (for one, os.environ['PWD'] seems to be way off. In fact, it points to my development folder.

要帮助确定问题,以下是应用作为一个独立的hello-world应用程序的相关部分。错误输出和观测在文章的末尾。

To help identifying the problem, following are the relevant parts of the application as a standalone hello-world app. The error output, and observations are at the very end of the post.

Python应用程序:

Python app:

.
├── myapp.ini
├── setup.py
└── testenv
    ├── __init__.py
    ├── model
    │   └── __init__.py
    └── webui.py

Apache的文件夹( /无功/网络/米歇尔/ testenv

.
├── env
│   ├── [...]
├── logs
│   ├── access.log
│   └── error.log
└── wsgi
└── app.wsgi

MYAPP.INI

[app]
somevar=somevalue

setup.py

from setuptools import setup, find_packages

setup(
    name="testenv",
    version='1.0dev1',
    description="A test app",
    long_description="Hello World!",
    author="Some Author",
    author_email="author@example.com",
    license="BSD",
    include_package_data=True,
    install_requires = [
      'flask',
      ],
    packages=find_packages(exclude=["tests.*", "tests"]),
    zip_safe=False,
)

testenv / 的init 的.py

# empty

testenv /模型/ 的init 的.py

from os.path import expanduser, join, exists
from os import getcwd, getenv, pathsep
import logging
import sys

__version__ = '1.0dev1'

LOG = logging.getLogger(__name__)

def find_config():
    """
    Searches for an appropriate config file. If found, return the filename, and
    the parsed search path
    """

    path = [getcwd(), expanduser('~/.mycompany/myapp'), '/etc/mycompany/myapp']
    env_path = getenv("MYAPP_PATH")
    config_filename = getenv("MYAPP_CONFIG", "myapp.ini")
    if env_path:
        path = env_path.split(pathsep)

    detected_conf = None
    for dir in path:
        conf_name = join(dir, config_filename)
        if exists(conf_name):
            detected_conf = conf_name
            break
    return detected_conf, path

def load_config():
    """
    Load the config file.
    Raises an OSError if no file was found.
    """
    from ConfigParser import SafeConfigParser

    conf, path = find_config()
    if not conf:
        raise OSError("No config file found! Search path was %r" % path)

    parser = SafeConfigParser()
    parser.read(conf)
    LOG.info("Loaded settings from %r" % conf)
    return parser

try:
    CONF = load_config()
except OSError, ex:
    # Give a helpful message instead of a scary stack-trace
    print >>sys.stderr, str(ex)
    sys.exit(1)

testenv / webui.py

from testenv.model import CONF

from flask import Flask

app = Flask(__name__)

@app.route('/')
def index():
    return "Hello World %s!" % CONF.get('app', 'somevar')

if __name__ == '__main__':
    app.debue = True
    app.run()

Apache的配置

<VirtualHost *:80>
    ServerName testenv-test.my.fq.dn
    ServerAlias testenv-test

    WSGIDaemonProcess testenv user=michel threads=5
    WSGIScriptAlias / /var/www/michel/testenv/wsgi/app.wsgi
    SetEnv MYAPP_PATH /var/www/michel/testenv/config

    <Directory /var/www/michel/testenv/wsgi>
        WSGIProcessGroup testenv
        WSGIApplicationGroup %{GLOBAL}
        Order deny,allow
        Allow from all
    </Directory>

    ErrorLog /var/www/michel/testenv/logs/error.log
    LogLevel warn

    CustomLog /var/www/michel/testenv/logs/access.log combined

</VirtualHost>

app.wsgi

activate_this = '/var/www/michel/testenv/env/bin/activate_this.py'
execfile(activate_this, dict(__file__=activate_this))

from os import getcwd
import logging, sys

from testenv.webui import app as application

# You may want to change this if you are using another logging setup
logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)

LOG = logging.getLogger(__name__)
LOG.debug('Current path: {0}'.format(getcwd()))

# Application config
application.debug = False

# vim: set ft=python :

错误和意见

这是Apache的错误日志的输出。

Error and observations

This is the output of the apache error log.

[Thu Jan 26 10:48:15 2012] [error] No config file found! Search path was ['/home/users/michel', '/home/users/michel/.mycompany/myapp', '/etc/mycompany/myapp']
[Thu Jan 26 10:48:15 2012] [error] [client 10.115.192.101] mod_wsgi (pid=17946): Target WSGI script '/var/www/michel/testenv/wsgi/app.wsgi' cannot be loaded as Python module.
[Thu Jan 26 10:48:15 2012] [error] [client 10.115.192.101] mod_wsgi (pid=17946): SystemExit exception raised by WSGI script '/var/www/michel/testenv/wsgi/app.wsgi' ignored.
[Thu Jan 26 10:48:15 2012] [error] [client 10.115.192.101] Traceback (most recent call last):
[Thu Jan 26 10:48:15 2012] [error] [client 10.115.192.101]   File "/var/www/michel/testenv/wsgi/app.wsgi", line 10, in <module>
[Thu Jan 26 10:48:15 2012] [error] [client 10.115.192.101]     from testenv.webui import app as application
[Thu Jan 26 10:48:15 2012] [error] [client 10.115.192.101]   File "/var/www/michel/testenv/env/lib/python2.6/site-packages/testenv-1.0dev1-py2.6.egg/testenv/webui.py", line 1, in <module>
[Thu Jan 26 10:48:15 2012] [error] [client 10.115.192.101]     from testenv.model import CONF
[Thu Jan 26 10:48:15 2012] [error] [client 10.115.192.101]   File "/var/www/michel/testenv/env/lib/python2.6/site-packages/testenv-1.0dev1-py2.6.egg/testenv/model/__init__.py", line 51, in <module>
[Thu Jan 26 10:48:15 2012] [error] [client 10.115.192.101]     sys.exit(1)
[Thu Jan 26 10:48:15 2012] [error] [client 10.115.192.101] SystemExit: 1

我的第一个观察是,环境变量 MYAPP_PATH 未出现在 os.environ (这是不可见在这个输出,但我测试了它,它不存在!)。因此,配置解析回落到默认路径。

My first observation is that the environment variable MYAPP_PATH does not appear in os.environ (this is not visible in this output, but I tested it, and it's not there!). As such, the config "resolver" falls back to the default path.

和我的第二个观察是为配置文件列出的搜索路径 /家庭/用户/米歇尔的返回值os.getcwd() 。我其实里面期待着什么 /无功/网络/米歇尔/ testenv

And my second observation is the search path for the config file lists /home/users/michel as return value of os.getcwd(). I was actually expecting something inside /var/www/michel/testenv.

我的直觉告诉我,那我做配置分辨率的方式是不对的。这主要是因为code在进口时执行。这使我的想法,也许是执行的配置分辨率code的的WSGI的环境中正确设置。我是到什么呢?

My instinct tells me, that the way I am doing config resolution is not right. Mainly because code is executed at import-time. This leads me to the idea, that maybe the config-resolution code is executed before the WSGI environment is properly set up. Am I onto something there?

会有怎样的的做在这种情况下,配置分辨率?鉴于模式子文件夹是在现实的一种外部模块,也应在非WSGI应用程序的工作,并应提供配置数据库连接的方法。

How would you do the config resolution in this case? Given that the "model" sub-folder is in reality an external module, which should also work in non-wsgi applications, and should provide a method to configure a database connection.

就个人而言,我喜欢我搜索的配置文件,同时仍然能够覆盖它的方式。只是,那个code在进口时执行的事实使我的蜘蛛感官刺痛像疯了似的。这样做的理由:配置的处理是完全隐藏(抽象垒)由家伙开发商使用此模块,它只是工程。他们只需要导入模块(当然,现有的配置文件),并可以直接在跳不知道任何细节DB。这也给了他们一个轻松的方式与不同的数据库(开发/测试/部署)和开关它们之间轻松的工作。

Personally, I like the way I search for config files while still being able to override it. Only, the fact that code is executed at import-time is making my spider-senses tingling like crazy. The rationale behind this: Configuration handling is completely hidden (abstraction-barrier) by fellow developers using this module, and it "just works". They just need to import the module (with an existing config-file of course) and can jump right in without knowing any DB details. This also gives them an easy way to work with different databases (dev/test/deployment) and switch between them easily.

现在,里面的mod_wsgi它没有了:(

Now, inside mod_wsgi it does not anymore :(

刚才测试我上面的想法,我改变了 webui.py 为以下内容:

Just now, to test my above idea, I changed the webui.py to the following:

import os

from flask import Flask, jsonify

app = Flask(__name__)

@app.route('/')
def index():
    return jsonify(os.environ)

if __name__ == '__main__':
    app.debue = True
    app.run()

网页上的输出如下:

The output on the webpage is the following:

{
    LANG: "C",
    APACHE_RUN_USER: "www-data",
    APACHE_PID_FILE: "/var/run/apache2.pid",
    PWD: "/home/users/michel/tmp/testenv",
    APACHE_RUN_GROUP: "www-data",
    PATH: "/usr/local/bin:/usr/bin:/bin",
    HOME: "/home/users/michel/"
}

此示出了相同的环境中 - 一个通过其他调试方法看到。所以,我最初虽然是错误的。但现在我意识到陌生人的东西还没有。 os.environment ['PWD'] 设置为在那里我有我发展的文件的文件夹。这不是在的所有的应用程序正在运行的地方。陌生人的是, os.getcwd()收益 /家庭/用户/米歇尔?这是我在见os.environ 不一致。如果它不一样的 os.environ ['PWD']

This shows the same environment as the one seen by other debugging methods. So my initial though was wrong. But now I realised something stranger yet. os.environment['PWD'] is set to the folder where I have my development files. This is not at all where the application is running. Stranger yet, os.getcwd() returns /home/users/michel? This is inconsistent with what I see in os.environ. Should it not be the same as os.environ['PWD']?

最重要的问题依然存在,但:为什么是由Apache的设定值 SETENV MYAPP_PATH 在这种情况下)在 os.environ

The most important problem remains though: Why is the value set by apache's SetEnv (MYAPP_PATH in this case) not found in os.environ?

推荐答案

请注意,该WSGI环境是建立在每个请求到应用程序的 ENVIRON 参数应用程序传递目的。这个环境是完全无关的是保存在 os.environ 进程环境。在 SETENV 指令对 os.environ 没有影响,也没有办法通过Apache配置指令影响是什么过程环境。

Note that the WSGI environment is passed upon each request to the application in the environ argument of the application object. This environment is totally unrelated to the process environment which is kept in os.environ. The SetEnv directive has no effect on os.environ and there is no way through Apache configuration directives to affect what is in the process environment.

所以,你必须做其他别的东西比 getenviron os.environ ['PWD'] 来获得在 my_path的来自Apache。

So you have to do something else other than getenviron or os.environ['PWD'] to get the MY_PATH from apache.

瓶添加WSGI ENVIRON的请求,而不是 app.environ ,它是由垫层完成 WERKZEUG 。因此,对每个请求到应用程序,Apache会添加 MYAPP_CONF 键,你会进入它的地方,您可以访问请求时,它似乎, request.environ。得到('MYAPP_CONFIG')为例。

Flask adds the wsgi environ to the request, not app.environ, it is done by the underlaying werkzeug. So on each request to the application, apache will add the MYAPP_CONF key and youll access it wherever you can access request it seems as, request.environ.get('MYAPP_CONFIG') for example.

这篇关于阿帕奇SETENV不工作与预期的mod_wsgi的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆