Travailler moins pour gagner plus, en 15 minutes avec Python fabric 6


Apprendre encore un nouvel outil, c’est du temps et de l’énergie. Du coup j’ai longtemps ignoré l’outil automatique de déploiement fabric.

On vit très bien sans, mais un jour, après avoir chassé un bug des heures qui n’était dû qu’à une erreur de ma part sur un process répétitif et ennuyeux de mise en ligne, je me suis motivé. Bonne surprise, ça m’a pris 30 minutes. Et avec cet article, ça vous en prendra 15.

Avant

Fabric est un outil qui vous permet d’écrire, en Python, un script de déploiement ; c’est à dire d’automatiser la mise en ligne d’une nouvelle version de votre site.

Comme ça, ça n’a pas l’air d’être quelque chose qu’on utilise souvent, mais pourtant, quand vous corrigez un simple bug dans une requête AJAX sur un projet Django sauvegardé dans Git, voilà ce que vous devez faire:

  1. git pull remote branch (pour s’assurer que personne n’a modifié le code entre temps)
  2. git push remote branch (pour sauvegarder votre code tout frais)
  3. ssh user@host (pour aller sur le serveur distant)
  4. cd /path/to/project
  5. workon virtualenv
  6. ./manage.py collectstatic (pour que le nouveau fichier Javascript soit mis en ligne)
  7. supervisorctl -c settings/prod_supervisor.ini restart all (pour redémarrer les workers et qu’ils prennent en compte les modifications du code Python)
À un moment, vous allez vous planter dans une étape, tellement c’est ennuyeux et répétitif.

Après

Comme d’hab, on commence par un coup de pip:

pip install fabric

Et dans un fichier fabfile.py à la racine de votre projet en local:

from fabric.api import local, run, cd, env, prefix
 
REMOTE_WORKING_DIR = '/path/to/project'
 
env.hosts = ['siteweb.com']
env.user = 'username'
 
def push(branch='master', remote='origin', runlocal=True):
    if runlocal:
        # lance la commande en local
        local("git push %s %s" % (remote, branch))
    else:
        # lance la commande sur les serveurs de la liste eng.hosts
        run("git push %s %s" % (remote, branch))
 
def pull(branch='master', remote='origin', runlocal=True):
    if runlocal:
        local("git pull %s %s" % (remote, branch))
    else:
        run("git pull %s %s" % (remote, branch))
 
def sync(branch='master', remote='origin', runlocal=True):
    pull(branch, remote, runlocal)
    push(branch, remote, runlocal)
 
def deploy(branch='master', remote='origin'):
    # execute toutes les commandes dans ce dossier
    with cd(REMOTE_WORKING_DIR):
        # excute toutes les commandes avec celle-ci avant
        with prefix('workon virtualenv'):
            pull(branch, remote, False)
            run("./manage.py collectstatic --noinput")
            run("supervisorctl -c settings/prod_supervisor.ini restart all")

Et voilà du temps de sauvé, et des erreurs évitées pour un investissement vraiment minimal.

Synchroniser son code avec le reste de l’équipe: fab sync
Déployer le code en production: fab deploy
Les deux: fab sync deploy

Et ce n’est qu’une intro. On peut faire des choses biens plus avancées, notamment gérer plusieurs type de déploiements, de serveurs, etc.

Notez qu’on pourrait faire le faire en bash sans avoir à installer fabric, mais un script bash, c’est tellement laborieux à faire évoluer…

6 thoughts on “Travailler moins pour gagner plus, en 15 minutes avec Python fabric

  • Max

    Attention pour que supervisor prenne en compte les modifs faite dans le fichier ini il faut faire un reload et non pas restart, je viens d’en faire l’expérience et ça m’a prix 1 heure à comprendre pourquoi !!!

  • Sam Post author

    Ouai d’ailleurs faudra faire un article sur supervisor :-)

    En résumé:

    – restart c’est pour redémarrer les services que gère supervisor;
    – reload c’est pour recharger les paramètres de supervisor.

  • Sam Post author

    Une fusion ?

    Je vais imaginer que tu veux dire un merge. Mais il y a pas de merge à faire en prod, les merges sont toujours faits sur les machines en local. On push en prod uniquement des branches stables, sauf grosse envie de suicide pressante.

Leave a comment

Des questions Python sans rapport avec l'article ? Posez-les sur IndexError.