Proyecto para la asignatura de Infraestructura Virtual 2016-2017
This project is maintained by adalsa91
Proyecto para la asignatura de Infraestructura Virtual 2016-2017
La aplicación consiste en un gestor de ficheros que junto a un editor de texto permitirá al usuario la creación y edición de scripts de python, quedando estos almacenados permanentemente entre sesiones, posibilitando la opción de ejecutar estos scripts en un entorno virtual y seguro que devolverá los resultados del programa en pantalla.
Para la descripción de las dependencias de la aplciación se ha creado un archivo requeriments.txt que suele ser el nombre usado por convención en Python.
click==6.6
Flask==0.11.1
gunicorn==19.6.0
itsdangerous==0.24
Jinja2==2.8
MarkupSafe==0.23
Werkzeug==0.11.11
psycopg2==2.6.2
SQLAlchemy==1.1.2
Flask-SQLAlchemy==2.1
Flask-Migrate==2.0.0
Flask-Testing==0.6.1
Flask-Login==0.4.0
Flask-WTF==0.13.1
WTForms==2.1
Para asegurar el correcto funcionamiento de la aplicación antes de ser desplegada se han escrito los siguientes tests. Para la automatización de los test se ha usado el framework de test unittest de Python, que además de orquestar la ejecución de los test proporciona una clase base llamada TestCase que podemos usar para crear nuevos casos de prueba, esta clase incluye métodos como *setUp o tearDown que permiten configurar un entorno funcional para la realización de los test y limpiarlo todo tras las pruebas.
import unittest
import os
import shutil
from app import app, db
from models import User
from flask_login import current_user
class ApyeTestCase(unittest.TestCase):
"""A base test case for flask-tracking."""
def create_app(self):
app.config.from_object('config.TestConfiguration')
return app
def setUp(self):
db.session.close()
db.drop_all()
db.create_all()
self.app = app.test_client()
if not os.path.exists('users/'):
os.makedirs('users/')
def tearDown(self):
db.session.remove()
db.drop_all()
shutil.rmtree('users')
def test_adduser(self):
usuario = User('adrian', 'adalsa@correo.ugr.es',
'password', 'Adrian', True)
db.session.add(usuario)
db.session.commit()
usuarios = User.query.all()
assert usuario in usuarios
print("[OK] Usuario creado satisfactoriamente\n")
def test_home_user(self):
if not os.path.exists('users/' + 'adrian'):
os.makedirs('users/' + 'adrian')
f = open('users/adrian/Welcome', 'w+')
f.write('Welcome!')
f.seek(0)
assert f.read() == 'Welcome!'
f.close()
print("[OK] Entorno de usuario creado correctamente\n")
def test_login_logout(self):
usuario = User('jorge', 'jorge@correo.ugr.es',
'password', 'Jorge Nitales', True)
db.session.add(usuario)
db.session.commit()
with self.app:
# Login
response = self.app.post(
'/login', data={'username': 'jorge', 'password': 'password'},
follow_redirects=True)
assert current_user.username == 'jorge'
assert b'Success' in response.data
# Logout
response = self.app.post(
'/logout', follow_redirects=True)
assert current_user.is_anonymous
print("[OK] Usuarios registrados pueden identificarse correctamente")
if __name__ == '__main__':
unittest.main()
Para ejecutar los tests utilizamos la función discover de unittest:
python -m unittest discover
Este comando busca recursivamente tests desde el directorio en el que lo lanzamos.
Para simplificar el lanzamiento de tests y otras tareas creamos un Makefile:
install:
pip install -r requirements.txt
test:
python -m unittest discover
run:
python manage.py runserver
Para este paso usamos el sistema de integración continua Travis, el mótivo de la elección es debido a su popularidad y documentación.
El primer paso es sincronizar Travis con nuestro GitHub, para ello iniciamos sesión en Travis con nuestra cuenta de GitHub y activamos el repositorio que queremos conectar en la página de nuestro perfil de Travis.
A continuación creamos el archivo .travis.yml
en el que especificaremosel lenguaje y versión usados, además de otros datos necesarios para construir el entorno de ejecución y el comando para ejecutar los tests.
language: python
python:
- "3.4"
install: "pip install -r requirements.txt"
services:
postgresql
before_script:
- psql -c "create user apye with password 'iDDLpkP1uv' " -U postgres
- psql -c "create database apye_users;" -U postgres
- psql -c "grant all privileges on database apye_users to apye;" -U postgres
- python manage.py db upgrade
script: python test_base.py
También necesitaremos definir las variables de entorno necsarias para la aplicación, podemos hacerlo en el fichero anterior o en la interfaz web.
Una vez todo esté configurado hacemos un add --> commit --> push y Travis detectará los cambios en nuestro repositorio de GitHub y lanzará los tests. Podemos comprobar el resultado en la página web de Travis.
Además Travis nos ofrece un incrustable que demuestra el estado actual del repositorio.
En primer lugar instalamos Heroku CLI con el siguiente comando:
$ wget -O- https://toolbelt.heroku.com/install-ubuntu.sh | sh
Una vez instalado iniciamos sesión.
Ahora creamos la aplicación, en mi caso he creado una para producción y otra para pruebas.
$ heroku create apye-pro
$ heroku create apye-stage
Y los añadimos a los remotos.
$ git remote add pro git@heroku.com:apye-pro.git
$ git remote add stage git@heroku.com:apye-stage.git
Creamos un fichero Procfile en la raíz de la aplciación para declarar que comandos deben ser ejecutados al iniciar la aplicación.
web: gunicorn app:app
También tenemos que especificar la versión de Python que necesita nuestra aplicación, para ello creamos el fichero runtime.txt
con el siguiente contenido.
python-3.4.2
El resto de dependencias de la aplicación están en el fichero requeriments.txt
en la raíz del proyecto y Heroku lo detectará automáticamente.
Debemos definir las variables de entorno, para ello usaremos las herramientas de la CLI.
$ heroku config:set APP_SETTINGS=config.ProductionConfig --remote pro
$ heroku config:set SECRET_KEY=SuperSecretKey --remote pro
$ heroku config:set APP_SETTINGS=config.ProductionConfig --remote stage
$ heroku config:set SECRET_KEY=SuperSecretKey --remote stage
Ya podemos hacer un push a heroku.
Ahora podemos iniciar la aplicación en local con heroku local
.
heroku local web
Antes de poder lanzar la aplicación en remoto tendremos que configurar PostgreSQL en Heroku, para ello añadimos un addon tanto al servidor de stage como al pro.
$ heroku addons:create heroku-postgresql:hobby-dev --app apye-stage
$ heroku addons:create heroku-postgresql:hobby-dev --app apye-pro
Con el comando config
del CLI de Heroku podemos comprobar que efectivamente se ha creado la base de datos y la correspondiente variable de entorno.
Actualizamos la base de datos con las migraciones.
$ heroku run python manage.py db upgrade --app apye-pro
$ heroku run python manage.py db upgrade --app apye-stage
Podemos comprobar que todo está funcionando correctamente lanzando los tests.
Conectamos la aplicación de Heroku con el respositorio de GitHub para activar el despliegue automático, activando la opción de comprobocación de tests para que el despliegue no se realice hasta que Travis CI ejecute los tests con éxito.
Por último añadimos un botón para poder desplegar el repositorio de GitHub automáticamente a Heroku, para ello creamos una fichero app.json
en la raíz del proyecto con la descripción de la aplicación, enlace al repositorio, addons de Heroku y variables de entorno necesarios.
{
"name": "APYE",
"description": "Editor online de Python",
"image": "heroku/python",
"repository": "https://github.com/adalsa91/APYE",
"logo": "https://www.herokucdn.com/deploy/button.svg",
"keywords": ["python", "flask" ],
"addons": [ "heroku-postgresql" ],
"env": {
"SECRET_KEY": {
"description": "A secret key for verifying the integrity of signed cookies.",
"generator": "secret"
},
"APP_SETTINGS": {
"description": "Determine environment.",
"value": "config.ProductionConfig"
}
}
}
Con el siguiente fragmento en Markdown insertamos el botón.
[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy)
Adrián Álvarez Sáez