Este README parte de la descripción dada en el fichero del proyecto SMS, donde se explica la motivación y a lo que se dedicará el rpoyecto en general.
Como resumen, se repite que este proyecto se ha elegido por petición por parte de algunos profesores de un sistema capaz de dar apoyo en las labores del profesorado, en la etapa de enseñanza primaria, secundaria y bachillerato. Brindará soporte y agilizará las tareas de los docentes en el día a día en las aulas (pudiendose implementar gestiones de partes de incidencias de comportamiento, asistencia a clase, calificaciones, comunicación con los padres e interna entre personal del centro, etc.)
Además, proyecto se presentará al Certamen de proyectos de la UGR organizado por la Oficina de Software Libre.
Probando
Definida en dicho README que la arquitectura del proyeto serán algunas máquinas, en este proyecto en concreto se creará toda la infraestructura necesaria para la máquina estadística, incluyendo base de datos, triggers, API's de consulta de los datos, y la propia base de datos en sí. También la interfaz web necesaria para configurar estas estadísticas.
Se usará webapp2 para crear la aplicación web que servirá para consultar y configurar las estadísticas.
Se usará Ansible para manejar las máquinas en su fase de despliegue. Ansible tendrá un playbook que será ejecutado automáticamente dentro del script de despliegue automático, que levantará las dos máquinas, y les dará las primeras instrucciones (que serán descargar los scripts de aprovisionamiento para poder empezar a funcionar).
Los scripts de despliegue y de aprovisionamiento se escribirán en un fichero .sh, que podrá ser ejecutado en una máquina Linux
El testeo y pruebas se realizarán usando unittest, un framework de pruebas para Python
El alojamiento de la máquina en un principio será en Azure
Para el diseño de la aplicación web, se usará como Framework de CSS UIKit
NOTA: La aplicación, originalmente, se desarrollará en GoogleApEngine, pero realizaremos modificaciones oportunas en el código para poder hacer el despliegue en estas máquinas y sin utilizar la infraestructura de Google.
Como anotación, aunque no tenga que ver con el hito en sí, se ha renombrado tanto el repositorio como el README, además de cambiar el enfoque del proyecto. Ahora el proyecto tratará de crear una base de datos de estadísticas, que cogerá los datos de la base de datos del compañero, para elaborar una serie de funciones que establezcan relaciones entre los datos, y pueda ser usadas en el proyecto principal (quien es el profesor con más porcentaje de suspensos, cuál es la clase con más porcentaje de faltas o partes de incidencias, etc.)
Se ha optado por hacer un archivo Makefile que se encarga tanto de testear el proyecto, como de instalarlo. Las órdenes respectivamente son make test y make install.
Para el testeo de la prueba, se utiliza sure, un paquete destinado al testeo de aplicaciones Python. Se podría haber hecho el desarrollo de la aplicación en otro lenguaje, pero como el proyecto principal y el otro subproyectoestarán hechos con Python, creí conveniente seguir usando el mismo lenguaje (además, en los ejercicios utilicé Python, así que no tenía más que replicar los pasos de los ejercicios, pero en el proyecto). También, tengo pensado crear un apartado web de configuración de las estadísticas (de ahí la carpeta plantilla, y que use el archivo pasarelatest para que el test principal pueda usar las funciones de webapp2).
Este paquete es de funcionamiento simple: busca todas las funciones que comiencen por test_ definidas en la clase del archivo .py que se pasa como parámetro, y las ejecuta. Dentro de dichas funciones, hacemos llamdas a otras funciones de la aplicación, y se comprueba si la salida de las mismas son como deberían de ser.
El test se lanza mediante nose, otro paquete que complementa a las funciones de unittest. En realidad, tan solo con unittest es necesario para poder ejecutar el test, pero sure aporta facilidad al testeo(no necesitamos llamar explícitamente a las funciones de testeo, él lo hace solo), estando un poco a más alto nivel.
Para definir todas las dependencias de instalación, se usa el archivo requirements.txt, el cuál usará el makefile para intentar resolver.
Se ha usado Travis para agilizar la integración continua en el proyecto (de hecho, el estado de erróneo o de éxito del proyecto en un momento determinado, aparece en la primera imagen de éste Readme).
Al darme de alta en Travis mediante GitHub, y enlazar este repositorio a Travis, éste se quedará "esperando" nuevos push para ponerse a testear el proyecto, y comprobar si las actualizaciones conducen a un estado exitoso. Para que Travis pueda hacer esto, se necesita configurar en el repositorio el archivo .travis.yml, donde básicamente se esepcifica que instale las dependencias y ejecute el script de testeo.
Debido a la naturaleza del proyecto, necesito conectar a la base de datos del compañero para poder realizar funciones realmente útiles. Por ahora, el archivo RecolectorDatos.py devuelve listas inventadas, aunque ese mismo archivo será sobreescrito para que pueda conectar a la base de datos del compañero y traer datos reales.
El archivo Estadisticas.py se encarga de la logística de las operaciones de estadística, llamando a RecolectorDatos para servirse de la información necesaria para funcionar. Por ahora, todas las funciones devuelven datos de prueba para que pase los tests, aunque la función que se encarga de calcular el porcentaje de suspensos de cada profesor si está implementada y funciona correctamente.
Llegados a este punto de desarrollo del proyecto, hay que remarcar que en realidad, este proyecto al ser parte de un proyecto mayor, no tiene interfaz de usuario como tal. Dicho de otra forma: este proyecto es un micro-servicio de otro mayor. Y aunque en el segundo hito se comentara que se iba a hacer un apartado de configuración de las Estadísticas (quizás la única parte con interfaz de usuario), al final se decidió no hacerlo. En su lugar, se dotará a la API de funciones que leerán datos pasados desde la página web, y configurará las estadísticas en función de esos parámetros (aunque las opciones de configuración no serán complicadas, ya que por la naturaleza del proyecto, quizás lo más interesante a configurar sea la frecuencia en tiempo con la que se "refrescan" las estadísticas, y poco más).
Por todo esto, se ha creado una "interfaz de usuario" mínima, donde hay un formulario con 3 elementos: campo de entrada, botón, y área de texto. En el campo de entrada, se pone el nombre de la función estadística que se desea ejecutar, y tras enviarla con el botón, aparecerá a la derecha la salida de la función. Esa salida será la que reciba bien otro micro servicio "parseador" que trate esos datos, o bien la propia interfaz web, y ya se encargará de leer y colocar en la vista de la página para el usuario (aún está por ver).
Definida la interfaz web mínima necesaria para el proyecto, se ha decidido desplegarla en Heroku. La razón de por qué se ha escogido este PaaS, es la de poder incluir la configuración necesaria en un fichero Procfile, por que es compatible con el lenguaje de desarrollo del proyecto (en este caso, Python), también por que viendo la documentación de Heroku sobre despliegues de aplicaciones Python, hay bastantes ejemplos y ayuda que nos facilita el proceso, y por último, por que permite la conexión con GitHub para el auto-despliegue de la aplicación después de hacer "push" del código.
Se ha configurado Heroku de la siguiente forma:
Para usar la aplicación, simplemente seguimos el enlace de Heroku del principio del documento, y escribimos algunas de las órdenes que hay como ejemplo debajo del formulario.
Nota: He tenido que usar Gunicorn como servidor WSGI de Python, ya que según la documentación de Heroku, parece que es el único compatible. Buscando información por Internet, nos topamos con que no somos los únicos con este problema, y la solución pasa por Gunicorn (al menos la más fácil), tal y como se comenta en esta pregunta de StackOverflow
En este punto de desarrollo del proyecto, se trabajará con Docker, para crear un contenedor que contendrá la aplicación en sí.
Primero, se han elaborado los correspondientes archivos Dockerfile y docker_run.sh respectivamente.
El primero, incluye todas las órdenes que se ejecutarán dentro del contenedor una vez creado (es una especie de script de "despliegue" en el contenedor).
El segundo script es otro script de despliegue secundario, que también es necesario. En él se han introducido las instalaciones de todas las dependencias (requirements de pip para Python, aparte de la instalación de éste).
Antes de todo esto, hemos tenido que tocar el archivo de servidor (main.py) para que sirva en la dirección 0.0.0.0, el puerto lo seguimos manteniendo (8080).
Una vez tenemos todo creado en local, con docker:
sudo docker build -t jagonz/sms_estadisticas .
La direción DockerHub del repo con docker es esta, y para llegar a tenerla ahí, hemos hecho lo siguiente:
Primero, asignar el tag. Una vez tenemos el contenedor con docker puesto,asignamos su ID con el tag que nos da DockerHub una vez creado el repositorio. En nuestro caso:
sudo docker tag c1aa0c0c874d /jagonz/sms_estadisticas
Después, configuramos docker login:
sudo docker login --name=JAGonz --email=XXXX@XXXX.com
Una vez docker "sabe quienes somos", podemos hacer el push:
sudo docker push jagonz/sms_estadisticas
Se subirá al repo la imagen creada, y tardará bastante.
Una vez acabe, podemos descargarla en nuestra máquina de Azure:
$ sudo apt-get update
$ sudo apt-get install -y docker.io
$ sudo docker pull jagonz/sms_estadisticas
$ sudo docker run -t -i jagonz/sms_estadisticas
Como tenemos el dockerfile y el docker_run configurado, todo se lanza automáticamente.
Podemos ver el resultado en la máquina Azure en este enlace
usaremos Vagrant para poder levantar las máquinas necesarias, con de garantizar una infraestructura para el proyecto.
Primero debemos de instalar Vagrant. La version instalada desde repositorios por apt-get contiene un bug que impide la ejecución de Vagrant con el fichero Vagrantfile proporcionado, testeando en una máquina con Ubuntu 15.10. El fallo ya ha sido reportado en este enlace, y se ha llegado a esta conclusión a raíz de esta respuesta al mismo problema que se tenía en las ejecuciones en local.
La solución pues, ha sido desinstalar la versión de Vagrant instalada desde los repositorios, así como todos los plugins que han sido necesarios, y descargar Vagrant desde aquí. Los plugins instalados previamente (si hemos seguido la instalación de repositorios y hemos intentado arreglar las dependencias), es con la orden:
rm -r ~/.vagrant.d/plugins.json ~/.vagrant.d/gems
Instalamos el paquete descargado.
Instalamos plugins de Azure:
vagrant plugin install vagrant-azure
Rellenamos el fichero Vagrantfile, que se explica aqui
Rellenamos el fichero configuracion_ansible.ym, que se explica aqui
Una vez está listo todo, lanzamos el despliegue de la máquina (y su provisionamiento):
vagrant up --provider=azure
Fabric es una herramienta para poder administrar la máquina remota, una vez que ha sido creada y aprovisionada con todo lo necesario. Dicha herramienta tiene el siguinete uso:
fab -p CONTRASEÑA -H usuario@host ORDEN
Dicho comando buscará en la ubicación actual (en el equipo local, no el remoto) un fichero fabfile que contrendrá el nombre de órdenes posibles que podremos ejecutar en la máquina remota, y las acciones que dicha máquina debe cumplir para llevar a cabo las órdenes.
En este proyecto se incluyen las siguientes órenes:
En este estado, el proyecto cuenta con una base de datos NDB, que usa el servidor de Google. Dicho servidor emula el servidor appengine, si se subiera el proyecto a los endpoints de Google, como un microservicio de apoyo al sistema. Dicho microservicio realizará peticiones a otro con los datos necesarios, los procesará, y guardará dicho procesamiento de datos usando esta nueva tecnología de almacenamiento (NDB), que permite una recuperación de datos mucho más rápida que las bases de datos convencionales.
En el código fuente del proyecto, se ha incluido un fichero Estructuras.py, en el cuál se incluirán todas las estructuras de datos necesarias a guardar en la base de datos. Utiliza como import el recurso ndb de google.
Se ha usado como servidor el propio de Google, que emula precisamente el servidor appengine, haciendo que la aplicación se comporte en nuestra máquina igual que se comportaría en los servidores de Google si finalmente se realiza el despliegue en esa infreaestructura.
Dicho servidor se ejecuta con python, sobre el fichero dev_server, en la carpeta oportuna del proyecto. En esta carpeta se encuentra un fichero app.yaml, donde realizamos una configuración global de la aplicación que va a ejecutar el servidor. Principalmente, cabe destacar las librerías (en nuestro caso, sólo usamos jinja2 para generar las plantillas de las páginas web, y webapp2 como servidor WSGI). El número de librerías soportadas por el servidor de google es bastante reducido, aunque siempre se pueden descargar los fuentes de librerías de terceros e incluirlas en el proyecto. Aunque no es tan trivial, sigue siendo posible, como se indica en esta pregunta de stackoverflow..