Apache SetEnv não está funcionando conforme o esperado com mod_wsgi

Em um aplicativo de balão que escrevi, utilizo uma biblioteca externa que pode ser configurada usando variáveis de ambiente. Nota: Eu escrevi essa biblioteca externa. Então eupoderi faça alterações, se necessário. Ao executar a partir da linha de comando, execute o servidor do balão com:

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

com todos os woks conforme o esperado. Mas depois de implantá-lo no apache, e usandoSetEnv faznã trabalho mais. De fato, imprimiros.environ parastderr (assim aparece nos logs do apache revela que owsgi processo @ parece estar em um ambiente muito diferente (por um lado,os.environ['PWD'] parece sercaminh fora. Na verdade, ele aponta para a minha pasta de desenvolviment

Para ajudar a identificar o problema, a seguir estão as partes relevantes do aplicativo como um aplicativo olá mundo independente. A saída do erro e as observações estão no final da postagem.

Layout da pasta App:

Python app:

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

asta @Apache /var/www/michel/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="[email protected]",
    license="BSD",
    include_package_data=True,
    install_requires = [
      'flask',
      ],
    packages=find_packages(exclude=["tests.*", "tests"]),
    zip_safe=False,
)
testenv /inicia .py
# empty
testenv / model /inicia .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 config
<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 :
Erro e observações

Esta é a saída do log de erros do apach

[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

Minha primeira observação é que a variável de ambienteMYAPP_PATH não aparece emos.environ (isso não é visível nesta saída, mas eu testei e não está lá!). Como tal, o "resolvedor" de configuração volta ao caminho padrã

E minha segunda observação é o caminho de pesquisa para as listas de arquivos de configuração/home/users/michel como valor de retorno deos.getcwd(). Na verdade, eu estava esperando algo dentro de/var/www/michel/testenv.

Meu instinto me diz que a maneira como estou fazendo a resolução da configuração não está correta. Principalmente porque o código é executado no momento da importação. Isso me leva à idéia de que talvez o código de resolução de configuração seja executadoante o ambiente WSGI está configurado corretamente. Estou em algo lá?

Discussão curta / pergunta tangencial

Como seriavoc fazer a resolução de configuração neste caso? Dado que a subpasta "model" é, na realidade, um módulo externo, que também deve funcionar em aplicativos não-wsgi e deve fornecer um método para configurar uma conexão com o banco de dado

Pessoalmente, gosto da maneira como pesquiso os arquivos de configuração enquanto ainda sou capaz de substituí-los. Só que o fato de o código ser executado no momento da importação está fazendo meus sentidos de aranha formigarem como loucos. A lógica por trás disso: o tratamento da configuração é completamente oculto (barreira de abstração) pelos colegas desenvolvedores que usam este módulo e "simplesmente funciona". Eles só precisam importar o módulo (com um arquivo de configuração existente, é claro) e podem entrar diretamente sem conhecer detalhes do banco de dados. Isso também oferece a eles uma maneira fácil de trabalhar com diferentes bancos de dados (dev / test / deployment) e alternar entre eles facilment

Agora, dentro do mod_wsgi não existe mais:

Atualizar

gora, para testar minha idéia acima, mudei owebui.py para o seguinte:

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()

A saída na página da web é a seguinte:

{
    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/"
}

Isso mostra o mesmo ambiente que o visto por outros métodos de depuração. Então, meu pensamento inicial estava errado. Mas agora eu percebi algo mais estranho ainda.os.environment['PWD'] está definido para a pasta onde eu tenho meus arquivos de desenvolvimento. Isso não é àstodo onde o aplicativo está sendo executado. Mais estranho ainda,os.getcwd() retorna/home/users/michel? Isso é inconsistente com o que vejo emos.environ. Não deve ser o mesmo queos.environ['PWD']?

O problema mais importante permanece: por que o valor definido pelo @ do apacSetEnv (MYAPP_PATH neste caso) não encontrado emos.environ?

questionAnswers(4)

yourAnswerToTheQuestion