Desplegar Django bajo Apache con WSGI en un virtualenv, *y que funcione*

El despliegue de Django es una de las pocas cosas claramente mejorables de este estupendo framework. Suele dar más de un dolor de cabeza porque es un poco lío establecer correctamente las variables de entorno. Un caso concreto que me ha dado bastantes problemas es desplegarlo con mod_wsgi de Apache, pero estando el Django dentro de un python con virtualenv.

En la documentación de Django explican el caso general de usar Django con Apache y mod_wsgi, incluyendo enlaces a otros documentos más extensos. Pero no explican el caso del virtualenv. Buscando en la web he encontrado muchos tutoriales pero ninguno me terminaba de aclarar. El problema es cómo decirle a mod_wsgi que coja el python del virtualenv en vez del global del sistema. Este tutorial es el que parecía más prometedor. Básicamente dice que hay que añadir el path del site-packages de nuestro virtualenv con una llamada site.addsitedir() y definir el path de python añadiendo WSGIPythonHome al fichero de configuración de Apache.

Sin embargo, la parte del site.addsitedir() sí funciona, pero el WSGPythonHome no. Después de mucho probar, descubrí que mod_wsgi necesita que el python del virtualenv esté en el path del sistema, si no, no lo encuentra aunque pongamos el WSGIPythonHome apuntando a él. Así que la solución es añadir /mi/path/virtualenv/bin al path, por ejemplo en el script  que lanza apache (normalmente será /etc/init.d/apache o /etc/init.d/httpd). Ojo con esto, que puede afectar a otros proyectos que usen python en el mismo apache.

Y observar una cosa importante: WSGI usa el mismo python para todos los virtual hosts, con lo cual se pierde una de las razones principales para usar virtualenv. Ahora esto sólo servirá si queremos aislar nuestro django de otros proyectos python que haya en el sistema, pero que no usen mod_wsgi.

Y otra cosa más: el mod_wsgi lanza el servidor en un directorio cualquiera, que no tiene por qué ser la raíz de Django. Para que encuentre las cosas, hay dos opciones: una es poner todos los paths absolutos en el settings.py, y la otra es añadir al principio del script django.wsgi las siguientes líneas:

import os
os.chdir(‘/mi/path/virtualenv/mi_proyecto/src’)

En este otro documento explica con bastante más detalle el comportamiento del wsgi script con Django.

Aplicación en Grails que se reinicia sin parar

Hace un rato me ha ocurrido algo muy curioso con grails. He parado el servidor y al volver a ejecutar grails run-app una vez que terminaba de arrancar se ponía a recompilar unas clases y volvía a arrancar en un bucle infinito.

Server running. Browse to http://localhost:8080/
  [groovyc] Compiling 1 source file to /home/ivan/workspace-sts/myApp/target/classes
  [groovyc] Compiling 1 source file to /home/ivan/workspace-sts/myApp/target/classes
   [delete] Deleting directory /home/ivan/.grails/1.3.7/projects/myApp/tomcat
Running Grails application..
2011-10-17 16:42:19,231 [main] INFO  spring.BeanBuilder  - [RuntimeConfiguration] Configuring data source for environment: DEVELOPMENT

He ejecutado varias veces grails-clean por si se había quedado algo raro pero seguía sin funcionar. Al final, la solución es arrancar con grails run-app –verboseCompile (cuidado que son dos guiones) para obtener información adicional. Así, una vez arrancado muestra las clases que intenta recompilar (en negrita):

Server running. Browse to http://localhost:8080/
  [groovyc] Compiling 1 source file to /home/ivan/workspace-sts/myApp/target/classes
  [groovyc] /home/ivan/workspace-sts/myApp/src/groovy/com/auth/MySuccessHandler.groovy
  [groovyc] Compiling 1 source file to /home/ivan/workspace-sts/myApp/target/classes
  [groovyc] /home/ivan/workspace-sts/myApp/src/groovy/com/auth/MySuccessHandler.groovy
   [delete] Deleting directory /home/ivan/.grails/1.3.7/projects/myApp/tomcat
Running Grails application..

Era una clase de una prueba anterior, así que la he borrado y todo se ha solucionado :-)

Activar Auditoría en Alfresco 3.3

[Actualizado el 7/10/2010 a las 15:30]

La documentación sobre auditoría en Alfresco 3.3 es bastante pobre porque llegó en un momento de transición de la 3.2 al nuevo sistema con servicios y de todo en la 3.4.

Para activar la auditoría se añadirán las siguientes opciones en

alfresco-global.properties

# Auditing
# Audit configuration
# from: alfresco/repository.properties
audit.enabled=true
audit.tagging.enabled=true
audit.repository.enabled=true
audit.cmischangelog.enabled=true
# Setting this flag to true will cause alfresco/auditConfig.xml to be ignored
# when audit is enabled. When false both alfresco/auditConfig.xml and
# alfresco/audit/*.xml will be used.
audit.useNewConfig=false
# Setting this flag to true will force startup failure when invalid audit configurations are detected
audit.config.strict=false

y activar también la auditoría en el siguiente fichero:

auditConfig.xml

<Audit xmlns="http://www.alfresco.org/model/audit/1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" enabled="true" auditInternal="false" mode="all">

 

Esto activa la auditoría antigua, pues la nueva no he conseguido que funcione.

La información de auditoría en Alfresco 3.3 se almacena en base de datos.

Para ver estos datos se pueden usar estas consultas de ejemplo:

(Queries para Informix, sí Informix, qué se le va a hacer)

Encontrar usuarios que nunca han entrado o hecho nada para ser auditado:

select *
 from alf_audit_fact fact
 right outer join alf_node_properties prop on fact.user_id = prop.string_value
 where prop.qname_id = 44
 and fact.user_id is null ;

Encontrar todo el contenido que ha sido “visto por un usuario en los últimos 7 días:

select *
 from alf_audit_fact fact
 join alf_audit_source source
 on fact.audit_source_id = source.id
 and (
 (source.service = 'ContentService' and source.method = 'getReader')
 or (source.service = 'FileFolderService' and source.method = 'getReader')
)
 where
 fact.user_id = 'admin'
 and fact.timestamp > DATE(DATE(CURRENT)-7)
 order by fact.id asc ;

Para el metodo crearNodo sería:

or (source.service = 'NodeService' and source.method = 'createNode')

Lista de metodos disponibles desde la tabla alf_audit_source

id application service methd
15 SystemMethodInterceptor NodeService createNode
 17 SystemMethodInterceptor RuleService disableRules
 28 SystemMethodInterceptor RuleService enableRules
 47 SystemMethodInterceptor ContentService getWriter
 64 SystemMethodInterceptor PermissionService setPermission
 66 SystemMethodInterceptor NodeService addAspect
 98 SystemMethodInterceptor PermissionService setInheritParentPermissions
 244 SystemMethodInterceptor NodeService setProperty
 2468 SystemMethodInterceptor NodeService addChild
 2698 SystemMethodInterceptor WorkflowService deployDefinition
 2998 SystemMethodInterceptor NodeService setProperties
 3220 SystemMethodInterceptor AuthenticationService authenticate
 3222 SystemMethodInterceptor AuthenticationService invalidateTicket
 3251 SystemMethodInterceptor AuthorityService createAuthority
 3282 SystemMethodInterceptor PersonService createPerson
 3286 SystemMethodInterceptor AuthenticationService createAuthentication
 3288 SystemMethodInterceptor AuthenticationService setAuthenticationEnabled
 3293 SystemMethodInterceptor AuthorityService addAuthority
 3370 SystemMethodInterceptor AuthenticationService validate
 24934 SystemMethodInterceptor AuthenticationService authenticateAsGuest
 25156 SystemMethodInterceptor FileFolderService getReader
 25174 SystemMethodInterceptor NodeService deleteNode
 25780 SystemMethodInterceptor TemplateService buildDefaultModel
 25782 SystemMethodInterceptor ContentService getReader
 25784 SystemMethodInterceptor TemplateService processTemplate

Más información de Auditoría para Alfresco 3.3
http://wiki.alfresco.com/wiki/Auditing_%28from_V3.2r%29

Espero que haya servido de ayuda.

Establecer el idioma para el cliente de test de Django

Si necesitas especificar un idioma para el cliente de test de Django (django.test.client.Client), puedes hacerlo especificandolo en el settings, mediante la variable:

LANGUAGE_CODE=”en-us”

Redireccionar después del login con spring-security-core

En un proyecto personal estoy utilizando Grails junto con spring security core para la autenticación de los usuarios.
Cuando intentamos acceder a una url que hemos configurado para permitir el acceso sólo a usuarios autenticados, el plugin nos redirige a la vista de login. Una vez autenticados nos redirecciona a la url a la que queríamos acceder inicialmente. Pero ¿qué ocurre si queremos redireccionar siempre a una url concreta?.

La solución pasa por añadir en la vista auth.gsp lo que marco en negrita:

<form action='${postUrl}?spring-security-redirect=/url-a-redireccionar'
method='POST' id='loginForm' class='cssform' autocomplete='off'>

Y eso es todo. Después de autenticarse, el usuario es redireccionado a la url elegida.

Explicación de la arquitectura de Alfresco

Recientemente en un cliente hemos necesitado explicar cómo es la arquitectura de sistemas de Alfresco.

La estructura de espacios en Alfresco no es la estructura “física” con la que los documentos se graban en disco. No replica exactamente la distribución que hagamos por carpetas en el sistema de ficheros. (Ver presentación más abajo)

La estructura de carpetas es “lógica” por tanto, pero de cara al usuario es así como los documentos se distribuyen por el repositorio y así los mostrará en un posible acceso por unidad de red de windows, o webdav, o un arbol de directorios.

Otras vistas que podemos realizar a partir de otros elementos de clasificación como las categorías, nubes de tags, o búsquedas prediseñadas en función de tipos de documento o un valor de un metadato, son visibles para el usuario, pero a través de otros sistemas.
Estas vistas podrían ser la la propia interfaz web de Alfresco Share o vistas diseñadas por nosotros a partir de los servicios que ofrece.

En todo caso no habría nunca ningún perjuicio en el rendimiento de Alfresco por clasificar los documentos en carpetas o por nube de tags, todo es transparente para las búsquedas, que únicamente se basan en los índices que se generan automáticamente.

La única recomendación de rendimiento a este nivel que nos da Alfresco es respetar en la estructura de carpetas el número máximo de 1000 nodos por nivel. Es importante en accesos que muestren el árbol de directorios como acceder con Alfresco Share, Alfresco Explorer, CIFS, Webdav, FTP, etc.

 

Adjunto una pequeña presentación que espero aclare estos conceptos.

Cortes de Spotify en Ubuntu (instalado por Wine)

A mí también se me bloqueaba Spotify después de un cierto tiempo funcionando con normalidad, hasta que cambié un ajuste sencillo de audio en Wine…

Desde Ubuntu aceder a la configuración de wine y cambiar lo que sigue:

Menu/Aplicaciones/Wine/Configurar Wine:

  • Pestaña “Audio”:  Controlador Alsa (Desactivado) y Conrolador EsounD (Activado.
  • Pestaña “Aplicaciones”: Versión a Imitar:  “Windows XP”
“Aplicar” y listo.

Espero que os sirva, hasta que Spotify se digne a sacar una versión para Linux, y usuarios “No premium”.

Referencias:

http://crashbit.homelinux.com/node/1756

http://www.ubuntu-es.org/node/124169

Error en Eclipse “Specified VM install not found” solucionado (solved)

Desde que añadí el java de Sun desde el repositorio de paquetes de Ubuntu, en vez de tenerlo en mi directorio /opt, creo voy a tener este problema de manera periódica, pero por lo menos ya se arreglarlo.

Hoy me encuentro con este error al ejecutar el build de mi tarea ant:

Specified VM install not found: type Standard VM, name java-6-sun-1.6.0.22

Y por más que miraba y remiraba en Preferences>Java>Installed JREs, allí no había más que una JDK, la java-6-sun-1.6.0.24.

Al final encontré la solución en este post

http://www.artima.com/forums/flat.jsp?forum=1&thread=85315

Try deleting these files:

…/.metadata/.plugins/org.eclipse.debug.core/.launches/*.launch

Roger

Con el eclipse cerrado añadiría yo.

Y funcionó…

Si es que al final era una tontería. :-)

Actualización 11/03/2011

A través de los comentarios Julio nos deja este consejo:

“Creo que hay otra forma…

Al instalar la JDK vía repos de Ubuntu, si no me equivoco, las JVM se instalan en /usr/lib/jvm/java-x.y-z; cada vez que se actualiza, el “x.y.z” cambia. Para evitar los problemas que esto conlleva, se crea un enlace en “/usr/lib/jvm/java-x” a la última versión, por lo que si la JRE en Eclipse la configuras contra el enlace te ahorras este problema.”

¿Qué pasa con el botón de submit si envío un form HTML con la tecla Intro?

Nos enfrentamos a un bug ciertamente extraño. Tenemos dos forms en los que hacemos lo mismo: hay un <input type=”submit” name=”button_send” value=”Aceptar”>, y en el script que recibe el form estamos preguntando en los datos de GET o POST si viene un campo llamado “button_send”.

En Firefox y otros no hay ningún problema… pero al llegar a Explorer comienzan (qué raro) los comportamientos extraños. En uno de los forms, al pulsar Intro mientras el foco está en uno de los campos que no es el botón, el formulario se envía pero el “button_send” NO APARECE en los datos recibidos. Lo impresionante del asunto es que en el otro form sí que aparece incluso pulsando Intro, y ambos forms tienen la misma estructura, sólo se diferencian en los campos de datos que contienen.

Tras un buen rato de comernos el coco y flipar bastante, llegamos a la solución leyendo este texto (hay que ir a archive.org porque el original se borró):

http://web.archive.org/web/20060518010241/ppewww.ph.gla.ac.uk/~flavell/www/formquestion.html

There seems to be some confusion/disagreement among browser developers as to whether a Submit control is a “successful control” (in the terms of e.g the HTML4 specification) when a form is submitted by means of Enter.

MSIE4′s behaviour seemed odd. If there was only a single text-input field, then hitting Enter with the focus on the text-input field would submit the form without sending the name/value pair associated with a submit control. Surprisingly, however, if there were two text-input fields, then hitting Enter when the focus was on either of those fields would result in the form being submitted together with the name/value pair of the submit control (or of the first submit control if there were more than one). This seemed illogical and inconsistent.

Básicamente, el comportamiento de Explorer (comenzando por IE4 pero se ha mantenido en los siguientes, al menos hasta el 8 ) es que si el form tiene exactamente 1 <input type=”text”>, entonces el botón de submit no se envía; pero si tiene más de uno, sí.

El resto de navegadores se comportan de maneras variadas ante este hecho, aunque ninguna tan barroca como esta. La causa es que el comportamiento de enviar un form con Intro no está modelado en la especificación del W3C.

¿Solución?

Si nuestro form tiene varios botones, el script debe contemplar un caso por defecto para cuando no se reciba ninguno.

Si el form es modo GET y estábamos leyendo el botón para distinguir si el usuario ha enviado el formulario o sólo leído la página que lo contiene, hay que cambiar de método, es mejor usar un <input type=”hidden”> y leer éste en lugar del botón.

Configurar Redmine en una sub-URL

Redmine por defecto está preparado para ser servido desde http://redmine.midominio.com (o similar). Puede que nos interese instalarlo en http://www.midominio.com/redmine. Después de mirar varios tutoriales, foros y probar mil opciones, logré dar con la solución:

  • Instalar mod_passenger para apache
    # apt-get install libapache2-mod-passenger
  • Habilitar el módulo
    # aenmod passenger
  • Añadir al virtual host las dos últimas líneas
    <VirtualHost *:80>
         ServerName subdominio.midominio.com
         DocumentRoot /home/user/application/
    
         ErrorLog /var/log/apache2/application.log
         LogLevel warn
         CustomLog /var/log/apache2/application-access.log combined
         DirectoryIndex index.php
    
         # Para servir el redmine
         RailsBaseURI /redmine
         RailsEnv production
    </VirtualHost>
    
  • Crear un enlace simbólico desde DocumentRoot/redmine a la ruta de instalación de redmine
    # ln -s /home/user/redmine-1.1.1/public /home/user/application/redmine
  • Reiniciar apache y listo, ya podemos acceder a redmine desde http://www.midominio.com/redmine
  • Seguir

    Get every new post delivered to your Inbox.