lunes, marzo 21, 2016

Usando Docker para crear máquinas virtuales ubuntu debian para testing - Crear una imagen a medida

En la anterior entrada sobre docker ya me llevé una grata sorpresa de cómo descargar y usar una imagen limpia de Ubuntu 14.04 en unos segundos con que la poder testear un script para la compilación de las últimas versiones de libgphoto2.

El principal problema era que en cada ocasión tenía que instalar git en el contenedor descargado y posteriormente clonar el proyecto git con su rama correspondiente y lanzar manualmente el script. Dado que además quería probar el script en Debian 7 y 8 resultaba en que tenía que hacer muchas acciones manuales.

He  tenido tiempo de sentarme a mirarlo con más detenimiento y resulta muy fácil crear una imagen personalizada partiendo de una base oficial como ubuntu o debian a la que posteriormente puedo añadir una serie de comandos personalizados para que agilice la ejecución.

El objetivo es que finalmente se me quede un único script en el que yo pueda ejecutar  "probar-en [SO deseado] [direccion de la rama git que quiero probar]". En cada ocasión el contenedor será una imagen limpia de ubuntu/debian/raspbian que sólo tendrá instalado git.

Empezamos creando la imagen personalizada de Ubuntu 14.04 con los añadidos para ejecutar los tests. Lo hacemos en dos pasos:
  • Crearmos un dockerfile, que especifica las características de la imagen que queremos crear y generándola
  • Añadimos la funcionalidad para que descargue la rama y la ejecute
Creando el container básico
Creamos una carpeta específica para el proyecto y dentro de ella un archivo llamado "Dockerfile" con el siguiente contenido indicando cual es la imagen base que vamos a tomar y el añadido que le queremos ahcer


   FROM ubuntu:14.04
   RUN apt-get -y update && apt-get install -y git

Guardamos y generamos la imagen con 

   docker build -t ubuntu-14.04-git .

El nombre ubuntu-14.04-git será el nombre de la imagen que figurará en nuestros respositorio local. Una vez finaliza la ejecución podemos comprobar que se ha generado correctamente con:

   $ docker images
   REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
   ubuntu-14.04-git    latest              d9adeb8df631        21 minutes ago      247.5 MB

Si accedemos a la imagen con "docker run -ti ubuntu-14.04-git /bin/bash" accederemos a la línea de comandos y podremos comprobar que es una imagen limpia con el git recien instalado.

Añadiendo el script de descarga y compilación
En mi caso quiero que el container este listo para que con un sólo comando se descargue un repositorio git y ejecute el script correspondiente. Así pues voy a crear un script de shell que haga todo eso para copiarlo dentro del container y que se ejecute al lanzarlo. 

En la misma carpeta donde tenemos el Dockerfile añadimos un fichero llamado test-script.sh con el siguiente contenido:

   #!/usr/bin/env bash
   git clone $1
   cd gphoto2-updater
   ./gphoto2-updater.sh

Como puedes ver es bastante obvio lo que hacer: recibe por parámetro una URL de un repositorio git, lo descarga, accede a la carpeta y lanza el comando.

Modificamos el Dockerfile con el siguiente contenido:

   FROM ubuntu:14.04
   RUN apt-get -y update && apt-get install -y git
   COPY ./test-script.sh /

... y generamos de nuevo la imagen para que añada el fichero al sistema de archivos...

   docker build -t ubuntu-14.04-git .

tardará sólo un momento y la imagen estará lista para trabajar. Cada vez que quiera probar una nueva rama de mi script basta con que lance:

   docker run -rm -ti ubuntu-14.04-git /test-script.sh [URL de la rama GIT para probar]

...y tendré un container limpio de ubuntu 14.04 con el git instalado que directamente descargará la rama git indicada y lanzará el script de compilación. Una vez finalice saldrá y el flag rm borrará el container que se acababa de generar sin que queden rastros de la ejecución. 

En mi caso he creado una alias para el comando anterior en el que reduzco el comando a 

   $test-ubuntu.sh [url proyecto git]

Partiendo de esta base es muy sencillo crear imágenes similares para debian 7 y 8 e incluso un script genérico para que lance los test sobre todos los SO que quiera.

Creando un dockerfile para cada SO
Muy sencillo, podemos crearlos todos en la misma carpeta añadiendo un sufijo al Dockerfile (como por ejemplo Dockerfile-debian-7) y luego personalizamos la llamada al docker build como sigue:

   docker build -t debian-7-git -f Dockerfile-debian-7 .

Generará una imagen con la etiqueta debian-7-git. Ahora sí, revisando los alias puedo lanzar el testing de un rama GIT sobre un SO limpio con algo tan simple como:

   $ ./test-os.sh debian-7-git https://github.com/gonzalo/gphoto2-updater.git
   $ ./test-os.sh debian-8-git https://github.com/gonzalo/gphoto2-updater.git
   $ ./test-os.sh ubuntu-14.04-git https://github.com/gonzalo/gphoto2-updater.git
   $ ./test-os.sh raspbian-8-git https://github.com/gonzalo/gphoto2-updater.git





lunes, marzo 07, 2016

Cómo importar contactos con télefono a Google Contacts con excel o csv

El otro día tuve que crear una cuenta de Google Contacts a la que necesitaba importar unos 400 contactos con teléfono que me habían pasado en una excel. El tema era más delicado de lo que parecía y no conseguía que identificara correctamente los teléfonos como tales.

Resulta que el importador de contactos de Google no es demasiado avanzado y exige que uses una plantilla muy concreta para poder recoger los contactos correctamente, aunque es sencillo adaptar tu documento para poder hacerlo.

Basta con crear una hoja de cálculo que has de guardar en formato csv. Te sugiero al guardar el csv indiques que los campos te los encierre con "" y como separador de campos uses la coma (,). Los nombres de las columnas deben ser obligatoriamente los siguientes y tienen que estar en inglés:

  • name
  • notes (opcional, por si quieres poner notas)
  • Phone 1 – Type
  • Phone 1 – Value
El valor de la columna "Phone 1 – Type" tiene que ser algo como "Mobile" aunque también puedes cambiarlo por "Work" o "Home"... cualquiera de los valores que acepte la ficha de Google Contatcs.
En el campo "Phone 1 – Value" pones el número de teléfono preferentemente precedido del código de país (+34 en España) para que pueda gestionarlo mejor.


Si necesitas añadir más campos aquí tienes una guía de todas las etiquetas que reconoce Google Contacts. Aunque dicha lista parece ser que varía con cierta frecuencia.

Ahora para importar te vas a la página principal de los contactos. Pinchas en "Más"->Importar->desde csv y le pasas el archivo que has generado.




miércoles, febrero 24, 2016

Docker para crear una máquina virtual Ubuntu 14.04 de testing en cuestión de segundos

Ya he estado jugando hace tiempo con Docker y sus contenedores para hacer pruebas sin tener que meterle mano a mis máquinas de desarrollo y la verdad es que cada vez me impresiona más lo útil y fácil que es usarlas.


En este caso necesitaba una especie de "máquina virtual" con ubuntu 14.04 para hacer pruebas de un proyecto que mantengo en GitHub: un proyecto para descargar y compilar la última versión de gphoto2. Hasta ahora los nuevos pulls que me iban llegando los probaba sobre mi máquina personal y eso me generaba algunos problemas colaterales en mi sistema de paquetes y librerías. Además tenía el inconveniente de que las pruebas no terminaban de ser reales por no estar utilizando una versión "limpia" de Ubuntu.

Una de las soluciones pasaba por tener una máquina virtual con VirtualBox o VMware, pero suelen ser máquinas pesadas y no quería pasar por el proceso de instalación. La solución final ha venido de la mano de Docker y sus contenedores, una solución que en pocos minutos (casi segundos) me ha permitido tener una instalación limpia de ubuntu sin ejecutar más que un par comandos.

Tan sencillo como:

$docker pull ubuntu:14.04
.... (30")
Digest: sha256:a3799e46440cabaa5414d42972b1693980b30bd2772b969fe11d08d99a8b753c
Status: Image is up to date for ubuntu:14.04
$docker run -i -t ubuntu:14.04 /bin/bash

root@453796e98d8c:/#

¡y ya está! ¡Una máquina ubuntu limpia para poder empezar a hacer pruebas! A partir de ahí bastaba con instalar git para empezar a hacer el testing. Por cierto, una imagen ligera que compila a toda velocidad.

Lo más curioso es que basta con hacer exit para que todos los cambios que he realizado desaparezcan. Es decir, si he instalado git, bajado archivos, compilado código... todo eso desaparece en el momento que salgo del entorno. Una nueva ejecución de "docker run -i -t ubuntu:14.04 /bin/bash" me lleva de nuevo a la imagen limpia.

Por supuesto los cambios pueden ser persistentes pero eso no es lo que estoy buscando ahora mismo. En resumen, una opción estupenda para probar código sobre un SO limpio.

jueves, octubre 15, 2015

Sincronizando archivos por FTP usando OSX y LFTP

Hace poco necesité establecer un sistema de copias de seguridad mediante un MacBook Air hacia un servidor FTP. Para la sincronización de archivos no encontré ningún cliente gratuito que fuera del estilo de SyncBack para Windows (el más cómodo que he probado) y acabé encontrando que lo podía hacer mediante lftp, un cliente libre de ftp que puedes instalar en tu mac mediante homebrew.

Lo primero sería instalar el gestor de paquetes Homebrew (una herramienta al estilo de apt-get) en tu mac.

ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

Instalas lftp con

brew install lftp

Lftp funciona como el comando ftp pero añade unas cuantas funciones especiales, lo que implica que si lo quieres hacer todo en un click-y-listo tendrás que crear un script. Este es el que uso yo:

#!/bin/bash

##esta es la parte que tienes que parametrizar
login="nombre_usuario"
pass="password"
host="servidor_ftp"
remote_dir="/carpeta_en_el_servidor/"
local_dir="$HOME/carpeta_en_tu_ordenador/"
## fin de los parámetros

base_name="$(basename "$0")"
lock_file="/tmp/$base_name.lock"
trap "rm -f $lock_file" SIGINT SIGTERM
if [ -e "$lock_file" ]
then
    echo "$base_name is running already."
    exit
else
    touch "$lock_file"
    lftp -u $login,$pass $host << EOF
    set ftp:ssl-allow no
    set mirror:use-pget-n 5
    mirror -R -e -c -P5 --log="/tmp/$base_name.log" "$local_dir" "$remote_dir"
    quit
EOF
    rm -f "$lock_file"
    trap - SIGINT SIGTERM
    exit

fi

Guarda el script en tu máquina con la extensión .command y hazlo ejecutable con:

chmod +x nombre_archivo.command

La extensión .command permite que luego puedas lanzar el script directamente desde el Finder.

La clave del script está en el comando

mirror -R -e -c -P5 --log="/tmp/$base_name.log" "$local_dir" "$remote_dir"

-R indica que la copia es "reversa", es decir, que se copian los contenidos de tu directorio local al remoto. Si quisieras invertir el proceso puedes hacerlo eliminando este parámetro.
-e es una opción importante. Elimina en el servidor remoto los archivos que no existan en el directorio local. Es la opción que garantiza realmente que el directorio de destino sea un espejo del original.
-c continúa el proceso de sincronización en caso de que se haya interrumpido
-P5 trocea los archivos en 5 para hacer 5 conexiones concurrentes. Puedes variar este valor dependiendo de tu conexión.
--log guarda un archivo de log para que puedas analizar si hay algún problema.

¡y ya está! Puedes mover el script a tu escritorio y probarlo lanzando un doble click. Te sugiero hacer primero unas pruebas con un directorio y contenidos de prueba antes de poner tu base de datos de producción en manos de este script :-D.



viernes, julio 03, 2015

GoAccess para el análisis de logs Apache desde la terminal

Recientemente estaba peleando con los archivos de log de uno de mis servidores web teniendo que explorarlos a mano ya que no tenía muchas ganas de instalar ningún analizador tipo AWstats o similar. 

Buscando alguna solución de terminal me he encontrado con GoAccess. Una herramienta que permite explorar los logs de apache o Nginx en tiempo real y desde la terminal. Es especialmente útil si lo que queremos es dar un vistazo rápido al estado de nuestro servidor conectando por ssh y ver las principales estadísticas de páginas servidas, visitantes, errores, ancho de banda, etc.

 

Tan sencillo como instalarlo mediante apt-get...

$sudo apt-get install goaccess

...y cargando el fichero que queremos analizar...

$goaccess -f /var/log/apache2/access.log -a

Ten en cuenta que, dependiendo de tu configuración, es posible que necesites tener permisos de root para poder acceder al archivo de log. 

Puedes usar directamente el ratón o las flechas para recorrer el informe. Con el tabulador vas pasando por lo distintos paneles y con ENTER/Q vas ampliando o reduciendo la información que muestra cada panel. Con S puedes desplegar las opciones de cada panel. Tienes un listado completo de las instrucciones en la página del manual o directamente en la web.

Otro aspecto interesante es que puede cargar múltiples archivos de log al mismo tiempo:

$zcat -f /var/log/apache2/*log | goaccess

¡Incluso los gz si queremos!

$zcat -f /var/log/apache2/*log* | goaccess

O todos a la vez...

Y lo que me parece más alucinante, no necesitas ni tenerlo instalado en tu servidor, puedes rescatar tus logs por ssh y analizarlos en tu propia máquina

ssh root@server 'cat /var/log/apache2/access.log' | goaccess -a

Goaccess permite incuso generar informes en html, json o csv si es lo que prefieres. En la misma página del manual lo tienes. 

En definitiva es una herramienta sencilla y rápida con un bajo consumo de recursos que permite hacer análisis de logs sin tener que instalar ni configurar ningún software web. 


martes, febrero 17, 2015

Postfix - Configurando un servidor de correo en debian / raspberry pi

La mayor parte de las instrucciones de este artículo están extraídas del magnífico artículo de Sam Hobbs y que forma parte de una serie más completa de instalar un servidor de correo completo con servidor web etc.

Requerimientos

En mi caso sólo pretendo configurar mi Rasberry Pi para que sea capaz de enviar correos electrónicos y recibir algunos correos electrónicos en las cuentas de usuario o reenviarlos a cuentas exteriores. ¿no me explico bien? A ver si así:
  • Quiero poder enviar correos electrónicos desde las cuentas de usuario (como "pi") y desde algunas programas como el fail2ban o el php.
  • Los correos que se reciban para ciertos usuarios (como "pi") estarán disponibles al loguearse por ssh.
  • Quiero que existan ciertas direcciones virtuales (como gonzalo@zoogon.net) que cuando reciban correo lo reenvíen directamente a mi cuenta de gmail.
  • Las cuentas de correo NO serán accesibles por pop3 ni imap, para eso hace falta más software. Accederé directamente desde la línea de comandos.
  • Quiero que la instalación esté protegida para que nadie pueda hacer envíos de correo desde este servidor.

Prerrequisitos

Debes disponer de un dominio propio. En mi caso lo he contratado con NameCheap y las pantallas de configuración que mostraré serán las de ellos. Otros servicios de dominio deberían servirte igual mientras te permitan crear subdominios y especificar si los registros son tipo A, txt y registros MX (date una vuelta por este artículo si no sabes de lo que estoy hablando)

Lo normal sería que tu Raspberry Pi esté configurada con una ip fija detrás de un router. Asegúrate de que tienes redirigido el puerto 25 del router a la RPi. Si además tu ip externa es dinámica (lo que sería normal) puedes utilizar el cliente ddclient para mantener tus registros DNS actualizados (ejemplo con namecheap y raspberry pi)

Con sudo hostname nombre-maquina.dominio.com establece el nombre de tu máquina. (debe ser completo o fqn) Deberías verlo actualizado en /etc/hostname

$ cat /etc/hostname 
rpi.midominio.net

Preparando los dominios

En tu registrador de DNS tiene que ofrecerte la posibilidad de configurar a qué servidores mail tiene que vincular los correo midominio.net. En mi configuración puedes ver que tengo definidos dos subdominios rpi y mail del tipo A (que corresponden con una dirección). En realidad, para mi caso ambos dominios están vinculados a la misma máquina pero lo he preparado por si quisiera instalar un segundo servidor de correo para backup.

El registro de subdominio @ con los valores de v=spf1 mx a ~all del tipo TXT Record es importante porque muchos servidores de correo no reconocerán el nuestro como válido si no lo incluimos.

En la parte de definir los servidores de correo lo que estoy indicando con la @ es que para cualquier correo que llegue a mis direcciones debe redirigir el mensaje a mail.midominio.net y en caso de no encontrarlo lo debe hacer  rpi.midominio.net. El valor MX PREF indica la prioridad a la hora de seleccionarlos.

En el artículo de Sam sobre configurar correctamente un DNS tienes unas buenas explicaciones de qué significa cada cosa.

Instalando y configurando postfix

Voy a ir rápido en muchas de las instrucciones.  Te recomiendo que le des un vistazo al artículo que menciono al principio del post si quieres profundizar. La única diferencia es que yo no he llegado a instalar dovecot para acceder por pop3 e imap.

Comienza instalando postfix y las herramientas de mail

$sudo apt-get update && sudo apt-get install postfix mailutils

Te preguntará que tipo de servicio deseas instalar, le decimos que "sitio en internet". Si hemos configurado el hostname correctamente lo cogerá. Tendrás algunos warnings referentes a ipv6, no te preocupes enseguida lo solucionaremos.

Editar /etc/postfix/main.cf y añade lo siguiente al final del archivo

#usar sólo el protoclo ipv4, evitamos mensajes de warning
inet_protocols = ipv4

#establecemos restricciones para que no cualquiera se pueda 
#conectar a nuestra máquina y hacer envíos a direcciones 
#de correo externas
smtpd_recipient_restrictions =
permit_sasl_authenticated,
permit_mynetworks,
reject_unauth_destination

#establecemos unas restricciones en el saludo a la máquina
smtpd_helo_required = yes
smtpd_helo_restrictions =
        permit_mynetworks,
        permit_sasl_authenticated,
        reject_invalid_helo_hostname,
        reject_non_fqdn_helo_hostname,
        reject_unknown_helo_hostname
        check_helo_access hash:/etc/postfix/helo_access

virtual_alias_maps = hash:/etc/postfix/virtual

Puedes ver referencias a dos archivos que vamos a crear. El primero /etc/postfix/helo_access sirve para spammers que pretendan hacerse pasar por nuestras máquinas.  Debería contener los dominios que tenemos registrados para el correo, en mi caso:

midominio.net          REJECT          Get lost - you're lying about who you are
mail.midominio.net     REJECT          Get lost - you're lying about who you are
rpi.midominio.net      REJECT          Get lost - you're lying about who you are

El segundo contendrá los mapeos de direcciones virtuales que queremos introducir

webadmin@midominio.net mi-correo-en@gmail.com
rpi@midominio.net       pi

Esto significa que cualquier correo que llegue a webadmin@midominio.net saldrá rebotado a mi cuenta de gmail. Cualquier correo que llegue a nombre de rpi@midominio.net se dirigirá a la bandeja de entrada del usuario "pi". Cualquier otro correo entrante será rechazado.

Ha llegado el momento de arrancar definitivamente postfix. Mapeamos ambos archivo virtuales y reiniciamos el servicio.

$sudo postmap /etc/postfix/virtual
$sudo postmap /etc/postfix/helo_access
$sudo service postfix restart

No deberías ver ningún mensaje de error.

Probando el servicio de envío

Antes de nada saber dónde debemos buscar los mensajes de error y log. Prepárate para lanzar los siguientes comandos 

$cat /var/log/mail.log
$cat /var/log/mail.err

En esos logs encontramos la información de los problemas así como los eventos que suceden en postfix: intentos de conexión, correos enviados y recibidos, etc. Estos archivos rotan frecuentemente y podemos verlos ampliados con mail.log.1, mail.log.2...

Empezamos por lo básico e intentamos enviar directamente un mensaje a nuestra cuenta de gmail. Cada línea se introduce por separado:

$ mail mi-cuenta@gmail.com
Cc: 
Subject: mensaje de prueba de postfix
estas son las líneas de contenido del mensaje para acabarlo y enviar pulsa Ctrl+D
$

El comando acaba sin que aparentemente pase nada pero internamente mail se configura con postfix que inserta el mensaje en su cola de salida e inicia el proceso de comunicación con los servidores de gmail para enviar el mensaje. Poco segundos después deberías ver el mensaje en tu bandeja de entrada aunque es muy probable que haya ido a parar a tu bandeja de spam, si es así ábrelo e indica que no es spam para que acepte futuros mensajes.

Puedes comprobar el proceso de comunicación en el mail.log y las últimas líneas deberían ser algo así.

Feb 17 18:27:21 rpi postfix/pickup[7381]: C64EB42481: uid=1000 from=
Feb 17 18:27:21 rpi postfix/cleanup[7395]: C64EB42481: message-id=<20150217172721 .c64eb42481="" rpi.midominio.net="">
Feb 17 18:27:21 rpi postfix/qmgr[7382]: C64EB42481: from=, size=432, nrcpt=1 (queue active)
Feb 17 18:27:22 rpi postfix/smtp[7397]: C64EB42481: to=, relay=gmail-smtp-in.l.google.com[74.125.140.27]:25, delay=0.89, delays=0.18/0.06/0.42/0.22, dsn=2.0.0, status=sent (250 2.0.0 OK 1424194042 ca16si30265556wib.105 - gsmtp)
Feb 17 18:27:22 rpi postfix/qmgr[7382]: C64EB42481: removed
   
Si el mensaje parece que se ha enviado correctamente pero no llega deberías comprobar el mail.log. A mi me ha llegado a pasar que algún servidor de correo tenía mi IP (dinámica) marcada como generadora de spam. Bastón con acceder al mail.log, comprobar por qué me habían rechazado el correo y acceder a un formulario web para solicitar que la volvieran a habilitar como aceptable.

Probando la recepción de correo
Ahora tocaría recorrer el camino inverso. Hay una dirección de correo que corresponde a un usuario de mi sistema pi@rpi.midominio.net. Desde gmail escribo un mensaje a la misma y uno segundos después acceso por ssh de nuevo a la rpi para comprobar que ha llegado y...

$ ssh pi@rpi.midominio.net
Linux rpi.midominio.net 3.18.7+ #755 PREEMPT Thu Feb 12 17:14:31 GMT 2015 armv6l
[...]
You have new mail.
pi@rpi ~ $

Lo puedes leer usando el mismo comando mail y pulsando 1

$ mail
"/var/mail/pi": 1 mensaje 1 nuevo
>N   1 Gonzalo Cao Cabeza mar feb 17 18:41  44/1923  mensaje de vuelta
? 1
Return-Path:
X-Original-To: pi@rpi.midominio.net
Delivered-To: pi@rpi.midominio.net
Received: from mail-wg0-f51.google.com (mail-wg0-f51.google.com [74.125.82.51])
by rpi.midominio.net (Postfix) with ESMTPS id ABA6342480
for ; Tue, 17 Feb 2015 18:41:02 +0100 (CET)
Received: by mail-wg0-f51.google.com with SMTP id y19so37464344wgg.10
        for ; Tue, 17 Feb 
[...]

Si examinas el mail.log encontraras unas líneas similares a cuando enviaste el correo.

Nos quedan probar las direcciones que hemos virtualizado. Sólo sirven para recibir correo: en el caso de pi@midominio.net la deberíamos recibir en la misma cuenta del caso anterior y para la cuenta webadmin@midominio.net debería recibirla directamente en mi cuenta de correo de gmail.

Asegurando nuestro servidor

Como ya tengo instalado fail2ban lo único que he tenido que hacer es ampliar los jail activados. Edito el /etc/fail2ban/jail.conf y realizo el siguiente cambio

[postfix]
enabled  = true
port     = smtp,ssmtp
filter   = postfix
logpath  = /var/log/mail.log

Con un simple comando podemos observar si fail2ban ha detectado algún comportamiento extraño.

$ sudo fail2ban-client status postfix
Status for the jail: postfix
|- filter
|  |- File list: /var/log/mail.log 
|  |- Currently failed: 0
|  `- Total failed: 0
`- action
   |- Currently banned: 0
   |  `- IP list:
   `- Total banned: 0