Como instalar tu propio Sentry en debian 8


Hace poco instalé Sentry en un VPS con debian y como los pasos son unos cuantos, decidí escribir este post para mantenerlo en algún lugar público (que mejor que el blog!).

Sentry es un sistema que reporta en tiempo real los crashes o excepciones que ocurren en nuestras aplicaciones web, apps mobiles o juegos. No solo reporta y notifica por email, sino que podés discutir con colegas sobre errores, darle un seguimiento, etc. Permite definir multiples proyectos, y permisos específicos por usuarios y proyectos.

Sentry trabaja con la mayoría de los lenguajes y frameworks:

../images/sentry-lang.png

También permite integraciones con aplicaciones y servicios:

../images/sentry-inte.png

Bueno, basta de chachara, vamos con los pasos.

Añadimos un usuario para manejar la aplicación y lo agregamos al grupo sudo

adduser sentry  (sentrymava)
gpasswd -a sentry sudo

Iniciamos sesión con el nuevo usuario e instalamos dependencias:

su - sentry
sudo apt-get install build-essential python-dev
sudo apt-get python-pip
sudo apt-get install libxml2-dev libxslt-dev libz-dev libssl-dev

# sentry instalaré dependiencia para postgres
sudo apt-get install postgresql postgresql-contrib libpq-dev

# si no tiene virtuelenv
sudo apt-get install python-virtualenv

# sentry necesita redis
sudo apt-get install redis-server

Comprobamos que está todo ok con redis:

redis-cli ping
PONG  # son unos genios LOL

Creamos virtualenv para sentry y lo instalamos:

cd ~
virtualenv env
source env/bin/activate
pip install sentry

Si da error

c/_cffi_backend.c:15:17: fatal error: ffi.h: No such file or directory #include <ffi.h>

compilation terminated

# probá instalando

sudo apt-get install libffi-dev

y reintentar con

pip install sentry --upgrade --force-reinstall

Una vez instalado, iniciamos la configuración:

sentry init  # dentro del virtuelenv

Configuramos la base de datos postgres

sudo -u postgres psql
psql (9.4.5)
Digite «help» para obtener ayuda.

postgres=# create extension adminpack;
CREATE EXTENSION
postgres=# \q

Si da error

ERROR: no se pudo abrir el archivo de control de extensión «/usr/share/postgresql/9.4/extension/admipack.control»: No existe el fichero o el directorio

ls /usr/share/postgresql/9.4/extension/ | grep adminpack

y vemos contenido, hacemos

sudo apt-get install locale
sudo updatedb

reintentar!

Continuamos configurando la base de datos:

sudo passwd postgres
sudo su - postgres
psql -d template1 -c "ALTER USER postgres WITH PASSWORD 'unaclaverealmentefuerte';"
createdb sentry_db
createuser sentry_user --pwprompt
psql -d template1 -U postgres
GRANT ALL PRIVILEGES ON DATABASE sentry_db TO sentry_user;
\q
exit # salir del usuario postgres

Proseguimos editando el archivo de configuración de sentry:

vim .sentry/sentry.conf.py

y establecemos los valores para la conexión a la base de datos

DATABASES = {
    'default': {
        'ENGINE': 'sentry.db.postgres',
        'NAME': 'sentry_db',
        'USER': 'sentry_user',
        'PASSWORD': 'unaclaverealmentefuerte',
        'HOST': 'localhost',
        'PORT': '',
    }
}

y actualizamos la instalación

sentry upgrade  # dentro del virtualenv

Podemos probar si funciona ok la instalación:

sentry start

Configuración NGINX

Añadimos en la configuración

server {
    listen 80;
    server_name  sentry.tudominio.com;
    access_log  /home/sentry/logs/nginx.access.log;

    location / {
      proxy_pass         http://localhost:9000;
      proxy_redirect     off;

      proxy_set_header   Host              $host;
      proxy_set_header   X-Real-IP         $remote_addr;
      proxy_set_header   X-Forwarded-For   $proxy_add_x_forwarded_for;
      proxy_set_header   X-Forwarded-Proto $scheme;
    }
}

y creamos el archivo de log

mkdir logs
touch logs/nginx.access.log
sudo service nginx reload

Arrancamos sentry y verificamos que podemos acceder en sentry.tudominio.com

sentry start

Gestión de la aplicación con supervisor

Si no lo tenemos instalado

sudo apt-get install supervisor

Debemos crear dos archivos de configuración, una para la app web, y otro para las tareas que ejecuta celery

Archivo en /etc/supervisor/conf.d/sentry.conf

[program:sentry-web]
directory=/home/sentry/
command=/home/sentry/env/bin/sentry start http
user = sentry
stdout_logfile = /home/sentry/logs/sentry.log
redirect_strerr = true
autostart=true
autorestart=true

Archivo en /etc/supervisor/conf.d/sentry-worker.conf

[program:sentry-worker]
directory=/home/sentry/
command=/home/sentry/env/bin/sentry celery worker -B
stdout_logfile = /home/sentry/logs/sentry-worker.log
user = sentry
autostart=true
autorestart=true
redirect_stderr=true
killasgroup=true

Creamos los archivos de logs de ambos procesos

touch logs/sentry-worker.log
touch logs/sentry.log

Y por último, recargamos e reiniciamos supervisor

sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl reload

Eso es todo. Realmente Sentry es una app indispensable si querés estar al tanto de todo lo que suceda en tus sistemas web o mobile.

Los pasos que siguen tienen que ver con crear un usuario en sentry, crear un proyecto y realizar la integración en tu proyecto. Todo esto es explicado por el mismo sentry cuando dseleccionas el lenguaje o framework que estás usando en tu proyecto.

Espero les sirva.

Bye!

Fabric en Python3 usando fades


El título es un poco engañoso, por lo que paso a ampliar un poco el contexto.

Hace algunos meses que vengo trabajando felizmente con django 1.8 + python3. Y aunque todo fluye mejor de lo que esperaba, hay una dependencia con la que no puedo contar en python3, fabric. No es un dependencia en sí, pero la utilizo para automatizar el proceso de despliegue (deploy), el cuál hacerlo manualmente es muy tedioso (y hasta te diría equivocado).

Dada esta limitación, lo primero que se me ocurrió fue hacer un virtualenv con python2, e instalar en él fabric. Luego, cuando quería utilizarlo para realizar alguna tarea en el proyecto, desactivaba el virtualenv del proyecto, activaba el de fabric y lo útilizaba. Era molesto, pero funcionaba.

Hasta que se me ocurrió probar fades y ahí surgió la magia.

Pero, ¿qué es *fades*? Fades es un sistema que administra virtualenvs buscando automaticamente aquel que cumple con los requerimientos del script o programa, o creandolos, y luego ejecutando la tarea (el script o el programa) dentro de él. Es una app desarrollada principalmente por @gilgamezh y @facubatista dentro de la comunidad de pyar.

https://raw.githubusercontent.com/PyAr/fades/master/resources/logo256.png

Resulta pues, que usando fades no es necesario desactivar el virtualenv con el que estás trabajando, y podes correr fabric con python 2, ¿que tul?

fades -p python2 -d fabric -x fab [task]

donde [task] es la tarea que querés ejecutar. La primera vez, tarda un poquito, ya que fades orquesta todo lo necesario (creación de virtualenv, activación, instalación de requerimientos), pero luego es instántaneo.

Les recomiendo pegarle una mirada a estos otros ejemplos de usos.

Espero les sirva.

Django + Postgresql dockerizada!


WOW! "Dockerizada", que palabrita!

Luego del comentario de gilgamezh sobre docker y como utilizarlo como alternativa a instalar un motor en la maquina host, y la charla de Ricardo en la PyCon, decidí sentarme y aprender a utilizar docker como herramienta de desarrollo.

Así es que preparé una pequeña charla para el primer meetup que se realizó acá en San Rafael, sobre Docker y Docker-Compose. Me sirvió como excusa para comenzar a utilizarlo. La presentación que armé para esa charla la podés encontrar acá.

Pero bueno, vayamos al objetivo de este post. Utilizar docker y docker compose para administrar contenedores que nos permitan utilizar un motor PostgreSQL sin necesidad de instalarlo en la máquina.

Voy a suponer que sabés que es Docker y que conocés de la herramienta de su staff Docker Compose.

Basándome en este script, creé mi propia imagen y la subí a Docker Hub (matuu/postgresql). Podés usar esa o cualquier otra con postgres instalado.

Dentro de la carpeta del proyecto Django creamos un archivo docker-compose.yml con el siguiente contenido:

data:
  restart: always
  image: matuu/postgresql:latest
  volumes:
    - /var/lib/postgresql
  command: "true"

postgres:
  restart: always
  image: matuu/postgresql:latest
  volumes_from:
    - data
  ports:
    - "5432:5432"

Básicamente, lo que hacemos con este archivo es indicarle a Docker Compose cómo tiene que orquestar todo el entorno de desarrollo del proyecto. Indicamos que cree un contenedor para el storage, y un contenedor con el motor postgresql exponiendo el puerto 5432.

Para arrancar el entorno completo (todo lo que indicamos con el archivo docker-compose.yml), hacemos:

sudo docker-compose up -d

Esto creará y ejecutará los contenedores. Con -d indicamos que se ejecute en background.

sudo docker-compose ps
Name                     Command               State           Ports
-----------------------------------------------------------------------------------
web_data_1       true                             Up
web_postgres_1   /usr/lib/postgresql/9.3/bi ...   Up      0.0.0.0:5432->5432/tcp

Genial! Están ambos ejecutandose.

Probemos entonces si podemos acceder al motor.

$ psql -Udocker -h localhost -W docker
Contraseña para usuario docker:
psql (9.4.5, servidor 9.3.10)
conexión SSL (protocolo: TLSv1.2, cifrado: DHE-RSA-AES256-GCM-SHA384, bits: 256, compresión: desactivado)
Digite «help» para obtener ayuda.

docker=#

¡¡Éxito!!

La imagen tiene configurada un usuario docker (con password docker) y una base de datos docker, por lo que tendrémos que reflejar esos datos en los settings del proyecto.

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'docker',
        'USER': 'docker',
        'PASSWORD': 'docker',
        'HOST': 'localhost',
        'PORT': '5432',
    }
}

Acá ya podemos hacer syncdb o migrate

Importando la base de datos desde un dump

Viendo que nos podemos conectar directamente al motor del contenedor, podemos restaurar la base de datos normalmente con:

cat dump.sql | psql -Udocker -h localhost -W docker

Tené en cuenta que quizás tengas, o bien, que modificar tu dump cambiando el nombre de la base de datos y/o usuario a docker, o bien, añadiendo la base de datos y usuario correspondiente.

Cualquier cosa, dejame un comentario.

Abrazo!

Django + Postgresql - Configuración inicial del entorno


Trabajando con Postgresql

/images/dj+postgresql+python.png

En reiteradas ocaciones tuve que instalar y configurar un entorno de desarrollo para django con postgres, por lo que me hice esta pequeña guia.

Instalamos:

sudo aptitude install postgresql pgadmin3

Una vez finalizada la instalación, continuamos con la configuración. Tengan especial atención al usuario que ejecuta el comando. user@equipo es tu usuario, root@equipo es el root del sistema. postgres@equipo es el usuario postgres del sistema (se creará una vez finalizada la instalación del motor).

Nos pasamos al usuario root

user@equipo:$ sudo -i

Establecemos una clave al usuario postgres (recordala!)

root@equipo:# passwd postgres
root@equipo:# exit

Como usuario normal nos pasamos al usuario postgres, nos pedirá el pass

user@equipo:$ su - postgres
postgres@equipo:$

Creamos usuario y base de datos

postgres@equipo:$ createuser user
postgres@equipo:$ createdb db1

Establecemos la clave del usuario y los permisos de este sobre la base de datos

postgres@equipo:$ psql template1
template1=# \password user
template1=# GRANT ALL PRIVILEGES ON DATABASE db1 to user

Habilitar el acceso a usuarios locales mediante password

sudo vim /etc/postgresql/9.4/main/pg_hba.conf  # puede cambiar el numero de versión en tu sistema

Buscar las lineas:

# "local" is for Unix domain socket connections only
local   all            all                      peer

Cambiar por:

local   all            all                      md5

Reiniciar el servicio

sudo services postgresql restart

Probamos la conexión a la nueva base de datos con el nuevo usuario

psql -U user -W db1

Password for user user:
psql (9.4.4)
Type "help" for help.

user=>

Éxito!

Importar base de datos

Es común importar a la base de datos vacia un dump de otra base. Esto es sencillo. Suponiendo que el dump de la base de datos se llama dump.sql y te encuentras en la misma carpeta, ejecutá:

psql -U user -W db1 < dump.sql

Te solicitará la contraseña y comentará a importar cada instrucción del archivo.

Suerte! y cualquier cosa dejá un comentario.

Bye!

python + vim - Entorno de trabajo


Esta es una simple guía de los pasos que suelo seguir para configurar un entorno de trabajo con python, usando vim como editor+IDE.

/images/dj+vim+python.png

VIM

Uso la config de fisa fisa-vim-config

Instalo vim, git y dependencias

sudo apt-get install vim exuberant-ctags git

Verifico que vim tiene soporte para python

vim --version | grep +python

Otras dependencias para python

sudo pip install dbgp vim-debug pep8 flake8 pyflakes isort

Abro vim para instalar los plguins

vim

PYTHON

Verifico versión de python y versión de pip

python --version
pip --version

Instalo virtualenv

sudo apt-get install virtualenv

Creo carpeta de para virtualenv

mkdir ~/.virtualenvs

Instalo virtualenv-wrapper

sudo pip install virtualenvwrapper

Configuro virtualenv-wrapper

echo "export WORKON_HOME=~/.virtualenvs" >> ~/.bashrc
echo ". /usr/local/bin/virtualenvwrapper.sh" >> ~/.bashrc

Recargo bashrc

. ~/.bashrc

Compruebo el funcionamiento

workon  # esto debe mostrar tus entornos virtuales, vacio si lo acabamos de instalar

Creo un entorno

mkvirtualenv new_env

Verás que el prompt cambia y ahora empieza con (new_env). Eso indica que estás en un entorno virtual.

Especifico la carpeta del proyecto - útil para moverse a la carpeta una vez ingresado en el entorno virtual:

cd [project_root]  # reemplaza [project_root] por la carpeta del proyecto
pwd > ~/.virtualenvs/new_env/.project

Chequeo que funcione OK con

cdproject

Hasta acá llega la guía. La iré actualizando según vaya añadiendo pasos en la configuración del entorno.

¿Tenés pasos extra en tu configuración? ¿O tenés algún consejo para dar?

Por favor, deja un comentario!! :-)

Abrazo

Django + mysql - Cambio de COLLATION y CHARSET


En un proyecto django en el que vengo trabajando estaba teniendo problemas con el tipo de caracter usado en la base de datos MySql. Los datos se obtienen a través de una api (cuyo encoding es UTF-8) y al guardar los datos recibidos solía obtener un:

_mysql_exceptions.Warning: Incorrect string value: 'xECx9AxB4 xECx9D...' for column 'name' at row 1

Esto sucedia aleatoreamente en distintas tablas y campos, por lo que decidí modificar todas las tablas de la aplicación django en cuestión.

El problema es que eran muuuchas tablas y se debe establecer el charset y collation individualmente (por tabla).

Usando esta respuesta como base hice lo siguiente:

  1. Ejecuté este script para obtener el script (valga la redundancia) que me convertiría cada tabla (app_django en el nombre de la aplicación django cuya base de datos quiero actualizar):
SELECT CONCAT('ALTER TABLE `', t.`TABLE_SCHEMA`, '`.`', t.`TABLE_NAME`,
    '` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;') as spt
FROM `information_schema`.`TABLES` t
WHERE 1 AND t.`TABLE_SCHEMA` = 'app_django' and t.`table_name` like "app_django_%"
ORDER BY 1

Esto genera una salida por tabla a actualizar:

ALTER TABLE `app_db`.`app_django_country` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;
ALTER TABLE `app_db`.`app_django_customeraddress` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;
ALTER TABLE `app_db`.`app_django_customer` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;
  1. Ejecutamos la salida anterior para modificar todas las tablas de la app django.

Anduvo de maravillas.

Saludos

PyCamp 2015 en La Serranita - Córdoba


Entre los días 14 y 17 de agosto se realizó, en La Serranita, Córdoba, el pycamp 2015.

/images/pycamp2015/pano_pycamp.jpg

Este evento, organizado anualmente por la comunidad de python argentina (pyAr), tiene como principal objetivo reunir a sus integrantes en un lugar alejado de las grandes ciudades, y trabajar durantes estos días conjuntamente en distintos proyectos relacionados con python.

Éste fue el primer pycamp al que asisto, y seguramente no sea el último. Para mi fue genial conocer a todas esas personas que leo hace años. pyAr está compuesto por un gran grupo humano, además de técnico, y eso lo pude sentir personalmente en este, mi primer contacto con el grupo. Con respecto al lugar, para mi estuvo muy bien elegido. La Serranita es muy lindo, seguramente vuelva dentro de poco con la flia, la verdad es que me encantó.

/images/pycamp2015/collageSerranita.jpg

Es cierto que el SUM no fue todo lo espacioso que quizás necesitamos, pero el lugar contaba con otros espacios al aire libre, y los días acompañaron.

Si hablamos de la comida, SARPADO!! Comimos abundantemente, y el asado del domingo fue exquisito!

¿Se nota que la pase bien?

Si hablamos de proyectos, yo estuve partcipando de algunos. El viernes estuvimos trabajando en una herramienta web para eventos tipo hackaton. Esta herramienta se llama htools (Hackaton TOOLS), y podríamos decir que nació de HTV (HashTag Viewer), la sencilla aplicación que construí para el Hackaton San Rafael.

/images/pycamp2015/planproject.jpg /images/pycamp2015/slots.jpg

Htools tiene el objetivo de brindar las funcionalidades útiles para un hackaton, que entendemos son: un visualizador de Twitter con determinado #hashtag, un tablero con los distintos proyectos (tomado de hackdash.org) y un timer del tipo countdown para marcar el tiempo restando del evento.

El sábado en la mañana estuve en modo read only en el grupo que estaban con el tema de arduido, raspberry py y esas yerbas, y en la tarde me puse a trabajar en un issue de fades (FAst DEpendencies for Scripts).

Fades es un sistema que automatiza el manejo de virtualenvs encontrando los requerimientos en el código, en un requirements.txt, o si son pasados por parámetros, creando o cargando un virtualenv adecuado y ejecutando el script dentro de él. Mi aporte fue la funcionalidad de poder especificar los requerimientos en el docstrings del script. Seguramente, en estos días se integrará esa funcionalidad.

/images/pycamp2015/sum1.jpg /images/pycamp2015/sum2.jpg

El mismo sábado, pero después de cenar, comencé a mirar TOTA, ya que me intrigaba cómo era el juego y cómo competían esos bot. Me enganché tanto que mi domingo se dividió en terminar lo de fades, y dotar de habilidades a mi bot. En el torneo me fue muy mal, pero me gustó muchísimo esa actividad.

Realmente, me gustó mucho el pycamp, conocí muchas excelentes personas, hice amigos, me acerqué a pyAr. Es un evento muy recomendable!!

Django + mysql - Error en mysql_config


Si estás configurando un entorno para trabajar con django y mysql, puede ocurrir un error al instalar MySQL-python (el conector python para el motor MySQL).

La solución es simple (ubuntu / debian):

sudo apt-get install libmysqlclient-dev

Haciendo esto pude instalar correctamente MySQL-python.