Adrianistán

El blog de Adrián Arroyo


Fabric, automatiza tareas en remoto

- Adrián Arroyo Calle

En la medida de lo posible tenemos que automatizar todo lo posible. No solo reducimos tiempo sino que reducimos errores, y a la vez, estamos documentando un proceso. Muchas de estas ideas ya las dejé claras en ¡Haz scripts! Sin embargo, hay situaciones donde es más complicada esta situación, como por ejemplo, trabajar con máquinas remotas. Aquí entra Fabric en acción, una librería para Python que permite automatizar procesos en remoto a través de SSH.

Originalmente Fabric, compatible únicamente con Python 2, funcionaba a través de unos archivos llamados Fabfile que se ejecutaban con el comando fab. Este mecanismo ha sido transformado por completo en Fabric 2, que ha salido hace nada. Yo ya he hecho la transición y puedo decir que el nuevo sistema, más enfocado a ser una librería sin más, es mucho más práctico y útil que el anterior.


Instalando Fabric


Voy a usar Pipenv, que es la manera recomendada de gestionar proyectos en Python actualmente.
pipenv install fabric==2.0.1

Y accedemos al virtualenv con:
pipenv shell

Conexiones


El elemento fundamental de Fabric a partir de la versión 2 son las conexiones. Estos objetos representan la conexión con otra máquina y podemos:

  • ejecutar comandos en el shell de la otra máquina, run, sudo.

  • descargar archivos desde la máquina remota a local, get

  • subir archivos de local a remoto, put

  • hacer forwarding, forward_local, forward_remote.


Para iniciar una conexión necesitamos la dirección de la máquina y alguna manera de identificarnos. En todo el tema de la autenticación Fabric delega el trabajo en Paramiko, que soporta gran variedad de opciones, incluida la opción de usar gateways.

Vamos a mostrar un ejemplo, en este caso, de autenticación con contraseña:
from fabric import Connection
from getpass import getpass

password = getpass(prompt="Password for Numancia: ")
numancia = Connection(host="192.168.0.158",user="roma",connect_kwargs={"password" : password})

El objeto creado con Connection ya lo podemos usar. Habitualmente no es necesario cerrar la conexión aunque en casos extremos puede ser necesario, una manera es llamando a close, otra es con un bloque with.

Tareas


Una vez que ya tenemos la conexión podemos pasárselo a diferentes funciones, cada una con una tarea distinta. Veamos algunos ejemplos.

Actualizar con apt


def update(cxn):
cxn.run("sudo apt update")
cxn.sudo("apt upgrade -y")

Los comandos que necesiten sudo pueden necesitar una pseudo-terminal para preguntar la contraseña (si es que la piden, no todos los servidores SSH piden contraseña al hacer sudo). En ese caso añadimos, pty=True.
def update(cxn):
cxn.run("sudo apt update",pty=True)
cxn.run("sudo apt upgrade -y",pty=True)

 

Backup de Mysql/Mariadb y cifrado con gpg


def backup_sql(cxn):
date = time.strftime("%Y%m%d%H%M%S")
filename = "/tmp/blog-backup-"+date+".sql.gz"

cxn.run("sudo mysqldump blog | gzip > "+filename)
local_filename = "backups/"+os.path.basename(filename)
cxn.get(filename,local_filename)
cxn.run("sudo rm "+filename)
os.system("gpg --cipher-algo AES256 -c "+local_filename)
os.remove(local_filename)

Requiere que MySQL/MariaDB esté configurado con la opción de autenticación POSIX (modo por defecto en el último Ubuntu)

Como véis, usar Fabric es muy sencillo, ya que apenas se diferencia de un script local.



Si queremos obtener el resultado del comando, podemos simplemente asignar a una variable la evaluación de los comandos run/sudo.
def isLinux(cxn):
result = cxn.run("uname -s")
return result.stdout.strip() == "Linux"

Grupos


Fabric es muy potente, pero en cuanto tengamos muchas máquinas vamos a hacer muchas veces las mismas tareas. Podemos usar un simple bucle for, pero Fabric nos trae una abstracción llamada Group. Básicamente podemos juntar conexiones en un único grupo y este ejecutas las acciones que pidamos. Existen dos tipos de grupo, SerialGroup, que ejecuta las operaciones secuencialmente y ThreadGroup que las ejecuta en paralelo.
from fabric import ThreadingGroup

def update(cxn):
cxn.run("sudo apt update")


pool = ThreadingGroup("roma@192.168.0.158","madrid@192.168.0.155")
update(pool)

O si tienes ya objetos de conexión creados:
from fabric import ThreadingGroup

def update(cxn):
cxn.run("sudo apt update")

pool = ThreadingGroup.from_connections([roma,madrid])
update(pool)

Con esto ya deberías saber lo básico para manejar Fabric, una fantástica librería para la automatización en remoto. Yo la uso para este blog y otras webs. Existen alternativas como Ansible, aunque a mí nunca me ha terminado de gustar su manera de hacer las cosas, que requiere mucho más aprendizaje.

Comentarios

Añadir comentario

Todos los comentarios están sujetos a moderación