Arnaud/Développement d'un outil CLI en Python

Created Thu, 09 Dec 2021 18:35:12 +0200

Développement d’un outil CLI en Python

Je ne suis pas un developpeur Python. À part un Hello World!, je n’ai jamais développé en Python.

Non pas que j’ai des reproches à faire à ce langage. C’est juste une question de temps et d’opportunités. Je n’en ai jamais vraiment eu besoin.

Pour mes petits scripts, j’utilise soit du bash, soit du NodeJS pour mes développements personnels.

Et la semaine dernière … une opportunité s’est présentée.

Dans cet article, je vais vous expliquer quel était le besoin, pourquoi je n’ai pas utilisé NodeJS ou bash pour le faire, et je présenterai également le résultat partiel de mon développement (et je vous expliquerai pourquoi seulement partiel…)

Le besoin

Dans la société pour laquelle je travaille, nous utilisons Google Apigee comme plateforme d’API Management (pas pour toutes les API, mais ça, c’est un autre débat…).

Nous avons des tâches de maintenance à effectuer sur la plateforme, comme du nettoyage des attributs personnalisés sur les clients (développeurs) ou le renouvellement des certificats TLS afin de pouvoir exposer nos services sur des noms de domaines plus “marketing” mais également sécurisés.

Pour préparer ces tâches, j’aurais pu parcourir la console, de pages en pages, récupérer les infos, changer de page, etc.. Mais c’est une longue tâche, un peu ingrate, source d’erreurs et, avoue-le … ennuyeuse.

C’est pour cela que j’ai décidé de faire un petit script pour parcourir tout cela de manière plus fiable et plus rapide (hors temps de dev 😄).

L’objectif de ce script est donc :

  • parcourir certains objets APIGEE (proxies ou apps ou virtualhosts)
  • filtrer certains de ces éléments selon certains critères (la présence de tel ou tel attribut spécifique…)
  • pour chacun des objets sélectionnés, récupérer des informations complémentaires
  • encore filtrer,
  • etc.

Chaque verbe que j’ai employé (parcourir, récupérer, etc..) est une action équivalente à un appel d’API du jeu des API d’Administration APIGEE.

Choix du langage

Oui, c’est sûr, j’aurais pu utiliser NodeJS pour ce projet. Habituellement, cela aurait été mon premier choix.

Cependant … J’ai considéré une des forces de NodeJS comme une faiblesse pour ce projet : l’asynchrone qui apporte son lot de complexité et de noeuds au cerveau.

Mon besoin est d’appeler une API, de parser son résultat puis d’en appeler d’autres à partir d’informations issues du premier appel, etc. Même si je dois effectuer 30 appels d’API, ils seront séquentiels.

Vous pourriez très justement dire “hey, idiot, tu peux utiliser les promesses pour ça !”.

Oui, mais …

J’ai juste eu envie de saisir une opportuniteé de regarder d’un peu plus prêt Python !

Laissez moi être curieux et vouloir essayer de nouvelles choses ! (et ne m’appelez pas idiot, s’il-vous-plait, on n’a pas gardé les vaches ensemble…)😄

La logique VENV

Je suis assez attentif à la gestion des dépendance. J’ai accompagné des équipes sur ce domaine.

Dans une de mes précédentes missions, j’ai eu beaucoup à me plaindre d’un éditeur de logiciel qui livrait son application sans gestion des dépendances, ni même une liste claires des dépendances… Et nous avons dû découvrir les dépendances nécessaires… Plus jamais ça, c’est vraiment trop pénible (pour être poli).

Sur ma machine, j’avais déjà un nombre certain (pour ne pas dire un certain nombre) de librairies Python installées globalement:

$ pip freeze | wc -l
119
$

Et je suis certain que ce n’ai pas besoin de tout cela pour utiliser les request ou print()! 😄

Alors, j’ai utilisé Virtual Environment 🔗, pour créer un espace de travail propre.

$ python3 -m venv ./venv

$ source venv/bin/activate

(venv) $

Puis, j’ai installé classiquement les librairies dont j’avais vraiment besoin.

… et mon requirements.txt a fondu comme neige au soleil!

(venv) $ pip freeze | wc -l
6
(venv) $

C’est une première victoire !

image

Gestion des identifiants

Pour me connecter aux API de Google, j’ai besoin d’un nom d’utilisateur et d’un mot de passe (pour une BasicAuth). Évidemment, mon code ne DOIT PAS avoir ces informations écrites quelques part, que ce soit dans le code principal, dans un fichier de config ou annexe, etc… Pour résumer : nulle part

ATTENTION: Remarque INDÉCENTE à venir

Mes oreilles saignent encore d’une discussion avec un collègue qui m’a dit, très sérieusement :

“Je ne me souviens jamais de mes mots de passe, même ceux admin, alors, je les ai tous écrits dans le fichier password.txt qui se trouve sur mon bureau Windows…”

images

… J’aurai vraiment préféré que ce soit une blague … mais malheureusement, c’est une histoire vraie…

Alors, pour faire simple, j’ai décidé que je prendrai ces informations dans les variables d’environnement de mon OS, à définir alors avant d’appeler le script


(venv) $ export APEX_USERNAME="admin@arnaduga.dev"
(venv) $ export APEX_PASSWORD="Password1234"

# OU
(venv) $ APEX_USERNAME="admin@arnaduga.dev" APEX_PASSWORD="Password1234" python3 myscript.py

Note

Vous pouvez contrôler ce qui est stocké dans votre history en vous appuyant sur la bonne option, puis en ajoutant un espace en début de commande !

  • bash 🔗 avec la variable $HISTCONTROL
  • ZSH :link avec le paramétrage setopt HIST_IGNORE_SPACE

Alors, j’ai pu ensuite récupérer les valeurs très classiquement dans mon code :

import sys
import os

try:
    username = os.environ['APEX_USERNAME']
    password = os.environ['APEX_PASSWORD']
except Exception as e:
    print("ERROR: APEX_USERNAME and APEX_PASSWORD must be set")
    sys.exit(1)

L’approche CLI : la superbe librairie Click !

Il y avait aussi deux arguments que je voualsi absolument garder hors de mon code, pour le rendre un tant soit peu générique : organisation et environment.

Donc, idéallement, je voulais pouvoir appeler mon script de la manière suivante :

$ python3 myscript.py --env prd --organisation myorg

Et comme je suis feignant (d’une certaine manière) et que je n’aime pas ré-inventer la roue (qui serait, de toutes façons, moins ronde que ce qui pourrait déjà exister), j’ai regardé quelques librairies, et principalement Click 🔗.

Elle m’est rapidement apparue comme très efficace et simple d’utilisation. Alors, je lui ai donné sa chance ! 😉

Bonus

Cette librairie possède également des utilities, comme par exemple la barre de progression 🔗, qui permet d’avoir un effet visuel intéressant, sans coût (de dev).

image

Résultats partiels

Comme j’ai développé ces scripts sur l’ordinateur de la société pour laquelle je travaille, sur mon temps de travail, le code appartient à la société. Je ne peux donc pas le partager, même s’il ne contient aucun secret et qu’il est sans lien avec l’activité principale de la boite.

Alors, j’ai recréé un ersatz de script, avec mon matériel et sur mon temps. C’est simplifié à l’extrême, mais cela illustre tout de même mes recherches et tests.

Le code est doc disponible sur un dépôt Gitlab.

D’un point de vue de l’utilisation, ça donne ça :

image

C’est tout pour ce soir !

image