Introduction
Fabric [1] est un outil de permettant d'automatiser l'exécution de taches, sa particularité vient du fait qu'il est capable aussi bien d'exécuter des taches localement que d'exécuter sur une ou plusieurs machines distantes.
Si cet outil vient plutôt du monde des serveurs, il reste un compagnon de choix pour le développement sur cartes embarquées puisqu'il requiert uniquement la présence d'un serveur SSH sur la machine cible pour fonctionner.
Commandes locales et distantes
Les scripts Fabric sont écrits en python (2.5+), chaque tache étant définie par une fonction python
#fabfile.py from fabric.api import task, local @task def hello(): local("uname -a")
Le fichier contenant notre code doit s'appeler fabfile.py. Pour déclarer une tache auprès de Fabric, nous utilisons le décorateur @task, la fonction local permet d'exécuter des commandes sur la machine hôte.
Pour exécuter notre tache, il suffit de se placer dans le dossier contenant notre fichier fabfile.py et de lancer la commande fab hello
nibbler% fab hello [localhost] local: uname -a Linux nibbler 3.2.0-4-amd64 #1 SMP Debian 3.2.51-1 x86_64 GNU/Linux Done.
Exécuter des taches localement est d'un intérêt assez limité... Pour exécuter une tache sur une machine distante, Fabric apporte la commande run qui indique que la commande doit être exécutée sur une machine cible. La plupart des commandes de Fabric possèdent une version locale (ici local) et une version distante (ici run) permettant de différencier le travaille sur la machine hôte ou cible.
from fabric.api import task, run @task def hello_dist(): run("uname -a")
Lors de l'appel à notre script nous allons fournir les paramètres décrivant la machine cible
nibbler% fab hello_dist -H 10.5.16.180 -u root [10.5.16.180] Executing task 'hello_dist' [10.5.16.180] run: uname -a [10.5.16.180] Login password for 'root': [10.5.16.180] out: Linux testhost 2.6.35.3-11.09.01+yocto+ged51f22 #1 PREEMPT Tue Oct 8 14:39:20 CEST 2013 armv7l GNU/Linux [10.5.16.180] out: Done. Disconnecting from 10.5.16.180... done.
Si l'on travaille toujours sur la ou les mêmes machines, il est possible de les enregistrer en dur dans le script. Pour cela Fabric fournit un environnement env permettant d'enregistrer des valeurs par défaut :
from fabric.api import task, local, run, env env.hosts = "10.5.16.180" env.user = "root" @task def hello_dist(): run("uname -a")
Fabric peut aussi adresser plusieurs machines, il suffit d'en fournir la liste :
env.user = "root" env.hosts = ["10.5.16.180", "10.5.16.181", "user@10.5.16.182"]
Enfin, Fabric permet aussi de aussi demander l'élévation de privilèges pour l'exécution d'une action, avec la commande python sudo
@task def runassudo(): sudo("whoami")
Transferts de fichiers
Puisqu'un des objectifs est de permettre de déployer des solutions, il est nécessaire de pouvoir transférer des fichiers depuis notre machine hôte vers notre cible. Pour cela Fabric fournit 2 commandes permettant de transférer vers (put) et depuis (get) la machine cible.
Par exemple:
@task def install(): """cette commande va uploader un programme et l'installer""" put("myprogramm.deb", "/tmp/") run("dpkg -i /tmp/myprogramm.deb") @task def getlog(): """cette commande va télécharger les dossier /var/log""" logdir = datetime.datetime.now().strftime("./log-%Y%m%dT%H%M%S/") get("/var/log/", logdir)
Contextes
Il est possible de définir des contextes d'exécution qui seront appliqués pour toutes les commandes affectées : par exemple pour définir une variable d'environnement ou exécuter des commandes en se plaçant dans un dossier particulier. Les contextes sont définis grâce au mot clé d'utilisation de contextes python with
@task def runmycommande(): with shell_env(PATH='/home/user/bin:$PATH'): with cd("/home/user/mydir"): run("mycommande")
À noter que la commande de contexte cd possède un équivalent pour les opérations locales nommé lcd
Pas de SFTP?
Par défaut Fabric utilise SFTP pour ses transferts de fichiers (commandes put et get). Or, certaines distributions minimales peuvent proposer un accès SSH sans pour autant offrir un service SFTP, c'est notamment le cas des distributions utilisant Dropbear [2]
Nous allons étendre fabric pour lui permettre l'utilisation de SCP à la place de SFTP
Fabric est basé sur l'implémentation SSH fournie par la bibliothèque paramiko [3] : Fabric ouvre une connexion SSH lors du premier accès au serveur et la garde jusqu'à la fin de ses taches. Il est possible de récupérer cette connexion pour l'utiliser directement.
Il existe des implémentations libre du protocole SCP basé sur paramiko, nous allons donc fonder notre extension sur une librairie minimaliste [4] disponible sous licence LGPL
#! /usr/bin/env python # -*- coding: utf-8 -*- # fabextra.py import os from scp import SCPClient from fabric.state import output, connections, env HOME = "~" def scpput(local_path = None, remote_path=None): local_path = local_path or os.getcwd() recursive = True if os.path.isdir(local_path) else False remote_path = remote_path or HOME #on récupère la connexion pour l'hote courrant transport = connections[env.host_string].get_transport() scp = SCPClient(transport) scp.put(local_path, remote_path, recursive)
il nous est alors possible d'utiliser notre nouvelle commande dans nos taches
from fabric.api import task from fabextra import scpput @task def uploadfile(): scpput("myfile")
Conclusion
Nous avons ainsi vu les opérations de base permettant de définir les taches les plus courantes, que ce soit pour des opérations locales, distantes ou des transferts de fichiers.
Fabric possède une communauté assez active et de nombreuses extensions existent pour des besoins plus particuliers (gestion des paquets de distribution, opérations d'administration courantes, intégration de git …)
Il ne vous reste plus qu'à vous lancer et écrire vos propres scripts !
Je vous invite à explorer la documentation [1] de ce projet afin d'en découvrir toutes ses capacités.
[1] | (1, 2) https://docs.fabfile.org/ |
[2] | https://matt.ucc.asn.au/dropbear/dropbear.html |
[3] | https://github.com/paramiko/paramiko/ |
[4] | https://github.com/jbardin/scp.py |