Pregunta Acceda a la variable SetEnv de Apache desde el archivo Django wsgi.py


Estoy tratando de separar la clave secreta de Django y el pase de DB en variables ambientales, como se ha sugerido ampliamente, así que puedo usar bases de código idénticas entre los servidores locales / de producción.

El problema al que me estoy enfrentando es configurar correctamente y luego leer los vars ambientales en el servidor de producción que ejecuta Apache + mod_wsgi.

Los Vars configurados en mi perfil de usuario no están disponibles porque Apache no se ejecuta como ese usuario. Vars establecido en el archivo de Hosts Virtuales con SetEnv no están disponibles porque el alcance es de alguna manera diferente.

He leído un par 1,2 de respuestas SO, lo que conduce a este blog con una solución

No puedo encontrar la manera de aplicar la solución a las versiones actuales de Django que usan un wsgi.py archivo, que se ve así:

import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.settings")

from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()

¿Cómo puedo aplicar esa solución de blog al archivo wsgi.py, o hay un mejor lugar para almacenar env-vars donde Django puede acceder?


15
2017-11-03 15:55


origen


Respuestas:


Si alguien está frustrado por la respuesta de Graham, aquí hay una solución que realmente funciona para la pregunta original. Personalmente encuentro que establecer variables de entorno de Apache es extremadamente útil y práctico, especialmente porque configuro mi propio entorno de alojamiento y puedo hacer lo que quiera.

wsgi.py (probado en Django 1.5.4)

from django.core.handlers.wsgi import WSGIHandler

class WSGIEnvironment(WSGIHandler):

    def __call__(self, environ, start_response):

        os.environ['SETTINGS_CONFIG'] = environ['SETTINGS_CONFIG']
        return super(WSGIEnvironment, self).__call__(environ, start_response)

application = WSGIEnvironment()

De menor importancia, pierdes el método de prueba de futuro django.core.wsgi.get_wsgi_application, que actualmente solo regresa WSGIHandler(). Si el WSGIHandler.__call__ método siempre se actualiza y actualiza Django también, puede que tenga que actualizar el WSGIEnvironment clase si los argumentos cambian Considero que esto es una multa muy pequeña para pagar por la conveniencia.


22
2018-01-14 21:12



FWIW. En general, no es una buena idea basarse en variables de entorno para la configuración de granularidad fina. Esto se debe a que no todos los entornos de alojamiento de WSGI ni las ofertas comerciales de PaaS respaldan el concepto. El uso de variables de entorno para ajustes detallados también puede encerrarlo efectivamente en una oferta PaaS específica donde ha incorporado directamente una búsqueda de una variable de entorno específicamente nombrada directamente en su código, donde la convención de nomenclatura de esa variable de entorno es específica para ese servicio de alojamiento. Entonces, aunque el uso de variables de entorno es impulsado por ciertos servicios, siempre tenga cuidado de depender de variables de entorno, ya que reducirá la portabilidad de su aplicación WSGI y dificultará el cambio entre los mecanismos de implementación.

Dicho todo esto, la publicación del blog que mencionas no suele ser útil. Esto se debe a que está utilizando el desagradable truco de establecer las variables de entorno de proceso en cada solicitud en función de la configuración de entorno de WSGI por solicitud establecida mediante SetEnv en Apache. Esto puede causar varios problemas en una configuración de subprocesamiento múltiple si los valores de las variables de entorno pueden diferir según el contexto de URL. Para el caso de Django, no es útil porque el módulo de configuración de Django normalmente se importaría antes de que se hubiera manejado cualquier solicitud, lo que significa que las variables de entorno no estarían disponibles en el momento requerido.

Toda esta área de configuración de implementación necesita urgentemente una mejor manera de hacer las cosas, pero, francamente, es principalmente una causa perdida porque los servicios de alojamiento no cambiarán las cosas para adaptarse a una mejor estrategia de despliegue de WSGI. Han hecho su trabajo, tienen a sus clientes encerrados en la forma en que lo han hecho y no están por crear un trabajo para ellos mismos y cambiar las cosas, incluso si existiera una mejor manera.

De todos modos, "todos los problemas en la informática se pueden resolver con otro nivel de indirección". (http://en.wikipedia.org/wiki/Indirection) y eso es lo que puedes hacer aquí.

No tiene sus variables de entorno de búsqueda de aplicaciones. Haga que importe un módulo de configuración de Python específico de la implementación que contenga un medio para usar una API para obtener las configuraciones. Este módulo de configuración implementaría diferentes formas de obtener la configuración real en función del mecanismo de implementación. En algunos casos, podría tomar los valores de las variables de entorno. Para otros, como Apache / mod_wsgi, los valores podrían estar en ese módulo de configuración, o leer desde un archivo de configuración separado que podría ser un formato ini, json o yaml. Al proporcionar una API, también puede asignar nombres de ajustes de configuración a diferentes nombres utilizados por diferentes ofertas de PaaS.

Este módulo de configuración no necesita ser parte de su código de aplicación, pero podría colocarlo manualmente en un subdirectorio de '/ etc /' en el sistema de destino. Solo necesita configurar la ruta de búsqueda del módulo de Python para que su aplicación pueda verla. Todo el sistema podría hacerse bastante elegante como parte de un estándar mejor y más amplio para la implementación de WSGI, pero como dije, poco incentivo para hacer el arduo trabajo de crear tal cosa cuando es muy poco probable que cambien las ofertas existentes de PaaS para usar dicho estándar .


10
2017-11-04 00:19



Aquí hay una solución alternativa tan a prueba de futuro como get_wsgi_application. Incluso le permite establecer variables de entorno para usar en su inicialización de Django.

# in wsgi.py

KEYS_TO_LOAD = [
    # A list of the keys you'd like to load from the WSGI environ
    # into os.environ
]

def loading_app(wsgi_environ, start_response):
    global real_app
    import os
    for key in KEYS_TO_LOAD:
        try:
            os.environ[key] = wsgi_environ[key]
        except KeyError:
            # The WSGI environment doesn't have the key
            pass
    from django.core.wsgi import get_wsgi_application
    real_app = get_wsgi_application()
    return real_app(wsgi_environ, start_response)

real_app = loading_app

application = lambda env, start: real_app(env, start)

No estoy 100% claro cómo mod_wsgi gestiona sus procesos, pero supongo que no vuelve a cargar la aplicación WSGI con mucha frecuencia. De ser así, la penalización de rendimiento al inicializar Django solo ocurrirá una vez, dentro de la primera solicitud.

Alternativamente, si no necesita establecer las variables de entorno antes de inicializar Django, puede usar lo siguiente:

# in wsgi.py

KEYS_TO_LOAD = [
    # A list of the keys you'd like to load from the WSGI environ
    # into os.environ
]

from django.core.wsgi import get_wsgi_application
django_app = get_wsgi_application()

def loading_app(wsgi_environ, start_response):
    global real_app
    import os
    for key in KEYS_TO_LOAD:
        try:
            os.environ[key] = wsgi_environ[key]
        except KeyError:
            # The WSGI environment doesn't have the key
            pass
    real_app = django_app
    return real_app(wsgi_environ, start_response)

real_app = loading_app

application = lambda env, start: real_app(env, start)

4
2017-09-05 18:53



Para Django 1.11:

Configuración de Apache:

<VirtualHost *:80 >
    ...
    SetEnv VAR_NAME VAR_VALUE
</VirtualHost>

wsgi.py:

import os
import django
from django.core.handlers.wsgi import WSGIHandler

class WSGIEnvironment(WSGIHandler):
    def __call__(self, environ, start_response):
        os.environ["VAR_NAME"] = environ.get("VAR_NAME", "")
        return super(WSGIEnvironment, self).__call__(environ, start_response)

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.settings")
django.setup(set_prefix=False)
application = WSGIEnvironment()

0
2018-04-30 22:06



Me encontré con el mismo problema de separar el código de producción y desarrollo mientras los controlé a ambos en el control de la versión. Resolví el problema usando diferentes scripts wsgi, uno para servidor de producción y otro para servidor de desarrollo. Crea dos archivos de configuración diferentes como se menciona aquí.  Y hacer referencia a ellos en scripts wsgi. Por ejemplo, el siguiente es el archivo wsgi_production.py

...
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.settings.production")
...

y en el archivo wsgi_development.py

...
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.settings.development")
...

0
2018-05-16 10:58