Linux Embedded

Le blog des technologies libres et embarquées

Prise en main de Fabric

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

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée.