Objectifs de certification

CCNA 200-301

  • 6.5 Décrire les caractéristiques des APIs de type REST (CRUD, verbes HTTP, et encodage des données)

  • 6.7 Interpréter des données encodées en JSON


APIs HTTP Restful Cisco

Si vous avez l’habitude des interfaces en ligne de commande à partir de consoles traditionnelles, les APIs HTTP Restful proposent une nouvelle manière de configurer et de gérer les périphériques et les infrastructures. Ce chapitre d’introduction a pour but de décrire les caractéristiques des APIs de type REST (CRUD, verbes HTTP, et encodage des données) et d’apprendre à interpréter des données encodées en JSON. On se penchera ici particulièrement sur l’API de Cisco IOS-XE.

En fait les APIs HTTP Restful sont des interfaces basées sur des protocoles standards qui offrent la possibilité de commander n’importe quel objet opaque à travers la simplicité et l’ubiquité d’une connexion Internet. Aussi du côté des services d’API, ce type d’architecture autorise la performance et l’évolutivité.

Si c’est l’aspect gestion d’infrastructure réseau Cisco qui nous intéresse ici, tout service accessible via Internet pourrait faire l’objet d’un interfaçage d’API HTTP Rest : consulter les horaires de cinéma et réserver une place pour la séance choisie, consulter la météo locale, déployer une infrastructure sur AWS (Amazon Web Services), mettre à jour des entrées de zone DNS hébergée chez CloudFlare ou encore gérer une infrastructure réseau Cisco Meraki …

1. Introduction aux APIs HTTP Restful

La plupart des utilisateurs de l’Internet connait le protocole HTTP et sa version sécurisée HTTPS grâce à des services populaires comme Facebook, Twitter ou Google, accessibles à travers des navigateurs Web tels que Chrome, Firefox, Safari ou Edge.

Une ressource HTTP si elle souvent un fichier HTML ou une image encodée dans un format GIF, JPEG ou PNG peut être tout élément, notament un objet abstrait tel que les propriétés d’un périphérique du réseau, un contrôleur, un point d’accès, un commutateur, un pare-feu, … qui est créé et géré par les commandes du protocole.

Le protocole HTTP propose donc un modèle plus large de gestion de ressources HTTP. Cette méthode de gestion et de configuration autorise la mise en oeuvre d’architectures inter-opérables, évolutives et performantes, programmables …

1.1. Définition du terme APIs HTTP Restful

L’expression “APIs HTTP Restful” est composée de trois éléments : (1) un type d’interface, (2) un protocole de transport et (3) une architecture logicielle :

  • API : Application Programming Interface, une interface de communication.
  • HTTP : Hyper Text Transfer Protocol, un protocole de transport largement répandu et éprouvé.
  • Restful : Une architecture logicielle qui répond à des contraintes telles qu’une architecture client-serveur, des communications sans état et avec mise en cache à des fins de performance.

1.2. API

Un API (Application Programming Interface) est un ensemble normalisé de classes, de méthodes et de fonctions pour manipuler des objets / des ressources informatiques.

1.3. API HTTP

Un API HTTP est un type d’interface qui peut comprendre des commandes HTTP, ce protocole client-serveur très populaire. Les commandes HTTP de type CRUD (Create, Read, Update, Delete) sont GET, POST, PUT, DELETE. L’interface devrait supporter la version sécurisée d’HTTPS pour rendre ce trafic de gestion confidentiel et authentifié.

Le protocole HTTP (HyperText Transfer Protocol) est un protocole de couche application client-serveur développé pour le World Wide Web. Un service HTTP écoute par défaut sur le port TCP80. Une version sécurisée HTTPS utilise une sous-couche TLS qui sécurise le trafic de couche application. Un service HTTPS écoute par défaut sur le port TCP443.

HTTP existe en version 1 et en version 2. HTTP/2 est une évolution du protocole sur des aspects d’optimisation des transferts (binaires au lieu de texte et des capacités de multiplexage), mais la sémantique des méthodes et des réponses est à 95% identique.

HTTP permet de manipuler des ressources qui peuvent être des objets totalement opaques.

1.4. Encodage XML, JSON

Les ressources à manipuler sont sollicitées sous forme d’URI/URL avec des requêtes HTTP. Les messages HTTP peuvent être précisés par un corps de message présenté dans un langage de présentation comme JSON ou XML. Les réponses attendues peuvent aussi comporter un corps de message présenté dans un format quelconque que l’on va réutiliser par exemple dans un mécanisme d’authentification ou comme identifiant d’une ressource existante à modifier ou à supprimer.

1.5. Architecture Restful

Les contraintes imposées par une architecture Restful sont les suivantes1 :

  • Client-serveur : cette architecture permet de faire évoluer et découpler facilement les services.
  • Sans état : le fait de ne pas garder l’état des sessions permet de gagner en performance, d’éviter la saturation des ressources de traitement, nécessite d’être explicite dans les informations échangées ce qui augmente la tolérance aux erreurs.
  • Mise en cache : une bonne gestion des délais de mise en cache améliore les performances des échanges client-serveur.
  • En couches : une architecture en couche permet de placer des serveurs intermédiaires pour de la répartition de charge, de l’extensibilité et de la performance.
  • Interface uniforme : Identification des ressources dans les requêtes, Manipulation des ressources par des représentations, Messages auto-descriptifs, Hypermédia comme moteur d’état de l’application (HATEOAS)

1.6. Avantages d’une interface Restful

Les avantages d’une interface Restful sont les suivants :

  • performance dans les interactions des composants, qui peuvent être le facteur dominant dans la performance perçue par l’utilisateur et l’efficacité du réseau ;
  • extensibilité permettant de supporter un grand nombre de composants et leurs interactions.
  • simplicité d’une interface uniforme ;
  • évolutivité des composants pour répondre aux besoins (même lorsque l’application est en cours de fonctionnement) ;
  • visibilité des communications entre les composants par des agents de service ;
  • portabilité des composants en déplaçant le code avec les données ;
  • fiabilité dans la résistance aux pannes du système en cas de pannes des composants, des connecteurs ou des données.

Plus précisément, la disponiblité des APIs HTTP Rest contribue aux architectures programmables et à l’automation des réseaux. Il est la base des architetcure en micro-services.

2. Fonctionnement des APIs REST basées sur HTTP

Les APIs REST basés sur HTTP sont définis par :

  • un URI de base, comme http://api.example.com/collection/ ;
  • des méthodes HTTP standards (par ex. : GET, POST, PUT, PATCH et DELETE) ;
  • un type de médias pour les données permettant une transition d’état (par ex. : Atom, microformats, application/vnd.collection+json, etc.). La nature hypermédia de l’application permet d’accéder aux états suivants de l’application par inspection de la représentation courante. Cela peut être aussi simple qu’un URI ou aussi complexe qu’un applet Java.

2.1. Désignation de la ressource HTTP : URI

Un URI se désigne par un protocole (https://), d’un serveur à joindre et éventuellement d’un port explicite (api.example.com:55443) et d’un emplacement (/api/v1/interfaces/GigabitEthernet1/statistics) :

https://example.com:55443/api/v1/interfaces/GigabitEthernet1/statistics

Un URI permet d’identifier un ressource Internet comme cet objet opaque /api/v1/interfaces/GigabitEthernet1/statistics, un téléphone IP, une page Web, une adresse de contact de messagerie instantannée, …

2.2. Anatomie d’une méthode HTTP

On trouve deux types de messages HTTP (RFC7231) :

  1. Des requêtes contenant une méthode émanant du client.
  2. Des réponses accompagnées d’un code de retour émant d’un serveur.

Chacunes peuvent transporter des données dans un corps de message.

Une méthode HTTP, comme une réponse HTTP, dispose d’une ligne de départ, de ligne(s) d’en-tête, d’une ligne vide et éventuellement d’un corps de message.

  • Une ligne de départ contient le nom de la méthode (GET), une cibe sur le serveur (/api/v1/interfaces) et la version d’HTTP (HTTP/1.1).

    > GET /api/v1/interfaces HTTP/1.1
    
  • Des lignes d’en-tête (headers) permettent au client HTTP d’envoyer plus de détails au serveur, précisant la méthode, notamment en matière d’authentification ou d’encodage, mais il y en a bien d’autres.

    > GET /api/v1/interfaces HTTP/1.1
    > Host: 192.168.122.38:55443
    > Authorization: Basic cm9vdDp0ZXN0dGVzdA==
    > User-Agent: curl/7.64.1
    > Accept: */*
    > X-auth-token: 8UFn0IMULvifwYfDHbhwgNGH73pse8u926LgDn91YNA=
    

    On apprend ici la nature du client (User-Agent: curl/7.64.1) et on voit un en-tête d’authentification (X-auth-token).

  • Un corps de message brut rend ici les informations dans un format JSON compris du serveur et du client, et qui est annoncé dans l’en-tête HTTP (champ Content-Type: application/json). Ici on trouve la réponse subséquente 200 OK au GET qui précède avec un corps de message ["thing"] :

    < HTTP/1.1 200 OK
    < Server: nginx/1.4.2
    < Date: Fri, 15 Nov 2019 14:29:15 GMT
    < Content-Type: application/json
    < Content-Length: 2539
    < Connection: keep-alive
    <
    * Connection #0 to host 192.168.122.38 left intact
    ["thing"]
    

    Notez que la ligne de départ d’une réponse HTTP est construite différement de celle d’une méthode :

    HTTP/1.1 200 OK
    

2.3. Commandes CRUD

En programmation informatique, l’acronyme “CRUD”, “créer” (create), “lire” (read), “mettre-à-jour” (update) et “supprimer” (delete), représente les quatre fonctions du stockage persistent. Il fait référence aux fonctions principales rencontrées dans les applications des bases de données relationnelles. Chaque initiale de l’acronyme CRUD peut correspondre à une fonction Structured Query Language (SQL), à une méthode HTTP ou à une opération Data Distribution Service (DDS) :

OperationSQLHTTPRESTful WSDDS
CreateINSERT PUT / POSTPOSTwrite
Read (Retrieve)SELECTGETGET read / take
Update (Modify)UPDATE PUT / POST / PATCHPUTwrite
Delete (Destroy)DELETEDELETEDELETEdispose

2.4. Sureté et idempotence

Certaines commandes sont dites “sûres”, c’est-à-dire qu’elles fonctionnent en lecture-seule (read-only, RO) : elles ne modifient pas les ressources sur le serveur. La commande GET est une commande sûre par exemple.

Les commandes HTTP PUT et POST peuvent créer des ressources mais seul PUT est idempotent contrairement à POST. L’idempotence signifie qu’une opération a le même effet qu’on l’applique seulement une fois ou plusieurs fois.

Avec un PUT, la ressource sur le serveur est remplacée (PUT est donc idempotente), alors qu’avec POST elle est modifiée pour intégrer les données envoyées dans le corps du POST.

Attention, le respect de ce comportement dépend de la qualité de conception des APIs que l’on manipule.

Toute méthode sûre est idempotente (puisqu’elle ne change pas la ressource) mais l’inverse n’est pas vrai.

Enfin, il y a des méthodes que l’on peut mettre en cache à des fins de performance.

  • GET est sûre et donc idempotente et cachable.
  • HEAD est sûre et donc idempotente et cachable.
  • POST n’est pas sûre, n’est pas idempotente et n’est pas cachable.
  • PUT n’est pas sûre, mais est idempotente.
  • DELETE n’est pas sûre.

2.5. Codes de réponses HTTP

Les réponses 100 sont des messages provisionnels (d’attente) rarement rencontrés en HTTP.

Les réponses 200 signifient une réponse positive, les plus connues sont 200 OK en réponse de la méthode GET ou encore 201 Created qui viendraient logiquement en suite d’une méthode PUT ou encore 202 Accepted à la suite de la méthode DELETE.

Les réponses 300 indiquent des emplacements de redirection. Les méthodes HTTP de redirection plus connues sont 301 Moved Permanently, 302 Found ou encore 307 Temporary Redirect.

Les réponses d’erreurs sont codées 400 (Client Error) et 500 (Internal Server Error). La plupart des erreurs pourraient venir du client, parmi les plus probables :

  • 400 Bad Request : problème de syntaxe.
  • 403 Forbidden : problème de droits.
  • 404 Not Found : mauvaise ressource sollicitée (chemin dans l’URL).
  • 405 Method Not Allowed : la ressource ne supporte pas la méthode utilisée (voir la documentation de l’API).
  • 408 Request Timeout : indique un délai dans le traitement des requêtes.

Disposer de la documentation de l’API que l’on manipule aidera à la résolution d’éventuels problèmes.

2.6. Formats de présentation des données

HTTP transporte tout type de format d’encodage indiqué dans le document de l’IANA Media Types. Cette charge est annoncée dans une ligne d’en-tête HTTP Content-Type. On présentera brièvement dans cette section trois formats de présentation de données :

  • XML, le standard
  • JSON, le standard en version lisible
  • YAML, pour présenter des données utilisateur

Le format JSON sera plus amplement étudié dans une section suivante.

XML

L’Extensible Markup Language, généralement appelé XML est un métalangage informatique de balisage générique qui est un sous-ensemble du Standard Generalized Markup Language (SGML). Sa syntaxe est dite “extensible” car elle permet de définir différents langages avec chacun leur vocabulaire et leur grammaire, comme XHTML, XSLT, RSS, SVG… Elle est reconnaissable par son usage des chevrons (<, >) encadrant les noms des balises. L’objectif initial de XML est de faciliter l’échange automatisé de contenus complexes (arbres, texte enrichi, etc.) entre systèmes d’informations hétérogènes (interopérabilité). Avec ses outils et langages associés, une application XML respecte généralement certains principes :

  • la structure d’un document XML est définie et validable par un schéma ;
  • un document XML est entièrement transformable dans un autre document XML.

Exemple :

<menu id="file" value="File">
  <popup>
    <menuitem value="New" onclick="CreateNewDoc()"/>
    <menuitem value="Open" onclick="OpenDoc()"/>
    <menuitem value="Close" onclick="CloseDoc()"/>
  </popup>
</menu>

JSON

JavaScript Object Notation (JSON) est un format de données textuelles dérivé de la notation des objets du langage JavaScript. Il permet de représenter de l’information structurée comme le permet XML par exemple.

{
    "menu": {
        "id": "file",
        "value": "File",
        "popup": {
            "menuitem": [
                { "value": "New", "onclick": "CreateNewDoc()" },
                { "value": "Open", "onclick": "OpenDoc()" },
                { "value": "Close", "onclick": "CloseDoc()" }
            ]
        }
    }
}

Remarque : JSON ne supporte pas les commentaires au contraire de YAML ou de XML.

YAML

YAML, acronyme de “Yet Another Markup Language” dans sa version 1.0, il devient l’acronyme récursif de “YAML Ain’t Markup Language” (“YAML n’est pas un langage de balisage”) dans sa version 1.1, est un format de représentation de données par sérialisation Unicode. Il reprend des concepts d’autres langages comme XML.

YAML est facilement à lire et à encoder pour un humain.

menu:
    id: file
    value: File
    popup:
        menuitem:
           - value: New
             onclick: CreateNewDoc()
           - value: Open
             onclick: OpenDoc()
           - value: Close
             onclick: CloseDoc()

Valider, convertir et travailler avec les formats de données

Code Beautify

2.7. Spécification OpenAPI

Spécification OpenAPI

3. Format de présentation JavaScript Object Notation (JSON)

JavaScript Object Notation (JSON) est donc un format de données textuelles dérivé de la notation des objets du langage JavaScript. Il permet de représenter de l’information structurée. On en trouvera une description dans le RFC 8259. On trouvera une explication “officielle” de la syntaxe sur la page https://www.json.org/json-fr.html.

3.1. Types de données JSON

Les types de données de base de JSON sont les suivantes :

  1. Objet : une collection non ordonnée de paires nom-valeur dont les noms (aussi appelés clés) sont des chaînes de caractères.2 Les objets sont délimités par des accolades (“{” et “}”) et séparés par des virgules, tandis que dans chaque paire, le caractère deux-points “:” sépare la clé ou le nom de sa valeur. La valeur peut être un tableau, un nombre, une chaîne de caractère, ou une valeur boléenne, ou nulle.
  2. Tableau (array) : une liste ordonnée de zéro ou plus de valeurs, dont chacune peut être de n’importe quel type. Les tableaux utilisent la notation par crochets (“[” et “]”) et les éléments sont séparés par des virgules (“,”).
  3. Nombre : est déclaré sans protection des guillemets.
  4. Chaîne de caractères (string) : une séquence de zéro ou plus de caractères Unicode. Les chaînes de caractères sont délimitées par des guillemets (“"” et “"”) et supportent une barre oblique inversée comme caractère d’échappement (“\”).
  5. Booléen : valeur binaire, l’une ou l’autre des valeurs “true” ou “false”, sans guillemets.
  6. Nulle : Une valeur vide, en utilisant le mot “null”, sans guillemets.

Les espaces limités sont autorisés et ignorés autour ou entre les éléments syntaxiques (valeurs et ponctuation, mais pas à l’intérieur d’une valeur de chaîne). Seuls quatre caractères spécifiques sont considérés comme des espaces : espace, tabulation horizontale, saut de ligne et retour chariot.

JSON ne fournit pas de syntaxe pour les commentaires.

Dans le cadre de la manipulation d’APIs HTTP Rest, on trouvera souvent le format JSON dans le corps de messages HTTP.

3.2. Objet JSON

Voici deux objets JSON constitués d’une liste non-ordonnée de clé/valeur :

{
  "id": 0,
  "name":"GigabitEthernet1",
  "description":null,
  "isEnabled":true
},
{
  "id": 1,
  "name":"GigabitEthernet2",
  "description":null,
  "isEnabled":false
}

Différents objets sont séparés par des virgules ,. Les objets sont délimités par des accolades { et }.

3.3. Tableau (Array) JSON

Un tableau (array) JSON est une liste ordonnée de zéro ou plus valeurs, séparées par des virgules ,, par exemple, si les valeurs sont des chaînes de caractère :

[
  "Loopback0","Loopback1","Loopback2","Loopback3"
]

Un tableau est encadré par des crochets [ et ].

On peut désigner chaque valeur de la liste ordonnée, du tableau, avec un index.

3.4. Un tableau d’objets imbriqués dans un objet

On trouvera plus bas, un seul objet comportant deux clés items et kind. La valeur de la clé items est un tableau constitué de deux entrées, chaque entrée est un objet consitué de quatre clés : “kind” (chaîne de caractère), “name” (chaîne de caractère), “description” (nulle) et “isEnabled” (boléen).

{
  "items": [
    {
      "kind": "object#interface",
      "name":"GigabitEthernet1",
      "description":null,
      "isEnabled":true
    },
    {
      "kind": "object#interface",
      "name":"GigabitEthernet2",
      "description":null,
      "isEnabled":false
    }
  ],
  "kind": "collections#interface"
}

4. Manipulation d’APIs

4.1. Différentes APIs pour différents usages

Beaucoup de produits Cisco Systems, y compris le support, sont disponibles via des APIs HTTP Rest.

Mais on peut aussi en trouver d’autres avec la liste “A collective list of free APIs for use in software and web development”. Chaque prestataire de service Web fournit un API comme celui d’AWS par exemple.

Il est indispensable d’aller consulter la documentation des APIs que l’on va manipuler.

4.2. Outils de manipulation d’APIs

On manipule ces APIs via différents outils :

  • Un outil graphique comme Postman.
  • Directement en Python.
  • En Bash ou Powershell avec cURL et ./jq.
  • A travers des outils de gestion de configuration comme Ansible, Chef ou Puppet.
  • A travers l’interface Web du Service.

4.3. Outil Postman

Postman est un outil graphique de test, de documentation et de manipulation d’APIs.

Capture d'écran d'une fenêtre Postman

Cisco DevNet Postman Collections offre un grand nombre de collections Postman pour des APIs Cisco.

4.4. Outil cURL

Normalement, l’outil cURL est installé par défaut sur tout OS moderne. Abréviation de client URL request library, il fournit une librairie (libcurl) et un outil en ligne de commande pour transférer des données avec différents protocoles.

On a notamment l’habitude de l’utiliser comme client HTTP/HTTPS Restful.

Voici une nomenclature d’usage de la commande curl :

curl -v -s -k -X POST \
  https://${server}/api/v1/interfaces \
  -H "X-auth-token: ${token_id}" \
  -H 'Content-Type: application/json' \
  -d '{
      "type": "loopback",
      "description": "test api 3",
      "if-name": "Loopback3",
      "ip-address": "3.3.3.3",
      "subnet-mask": "255.255.255.255"
    }'
Option cURLSignification
-vmode verbeux
-sdésactive la barre de progression
-Lsuit les redirections
-kne vérifie pas les certificats TLS
-X <méthode HTTP> <URI>commande HTTP GET, PUT, POST, DELETE, …
-Hdéfinit une ligne d’en-tête (Header)
-ddéfinit le corps de message (data)
-o <fichier>enregistre la sortie dans un fichier
-G <URI>commande HTTP GET
-I <URI>commande HTTP HEAD

4.5. Traitement de sorties JSON avec Jq

./jq est comme sed pour les données JSON - vous pouvez l’utiliser pour découper, filtrer, mapper et transformer des données structurées avec la même facilité que sed, awk, grep et autres du même type permettent de jouer avec le texte.

choco install jq
brew install jq
yum install jq
apt-get install jq

./jq permet de traiter les sorties JSON sur la ligne de commande grâce à un grand nombre de filtres. En voici quelques uns.

FiltreSignification
.filtre d’identité
.foo ou .[“foo”]identifie la clé “foo” dans l’objet
.[2]retourne le troisième élément d’un tableau

4.6. HTTPie

HTTPie (“aitch-tee-tee-pie”) est un client HTTP en ligne de commande avec une interface utilisateur intuitive, le support de JSON, la coloration syntaxique, les téléchargements de type wget, des plugins, et plus encore.

HTTPie

5. Exercice pratique de manipulation d’API HTTP Rest Cisco

5.1. Enoncé

Pour cet exercice on utilisera un routeur CSR1000v avec une image csr1000v-universalk9.16.5.1b-serial.qcow2 pour laquelle on aura activé l’API Rest HTTP de l’IOS-XE qui est livré avec la plateforme.

Les objectifs de cet exercice :

  • activer l’API d’un routeur Cisco.
  • s’authentifier auprès d’un API avec un jeton (token).
  • manipuler les méthodes HTTP : GET, PUT, POST, DELETE, notamment avec curl.
  • interpréter les codes de retour HTTP.
  • interpréter des sorties formatée en JSON notamment avec ./jq.
  • encoder des données en format JSON

5.2. Topologie

La topologie est connectée à un commutateur par défaut de GNS3 et à l’Internet par un nuage NAT GNS3.

Une station de travail et routeur Cisco CSR1000v ios-xe0 sur son interface GigabitEthernet1 se partagent le réseau de gestion 192.168.122.0/24.

Topologie API HTTP Restful avec un seul routeur Cisco CSR1000v

5.3. Configuration du routeur CSR1000v

La procédure suivante est directement inspirée de la documentation officielle : Cisco CSR 1000v and Cisco ISRv Software Configuration Guide, Enabling Management by REST API.

Il est nécessaire de nommer le périphérique, de configurer un utilisateur priviliégé et de configurer une interface de gestion GigabitEthernet1 avec l’adresse IPv4 192.168.122.10 255.255.255.0 ou attribuée par un service DHCP.

hostname ios-xe0
ip domain name lab
username root privilege 15 secret testtest
!
interface GigabitEthernet1
 ! ip address 192.168.122.10 255.255.255.0
 ip address dhcp
 no shutdown
! ip route 0.0.0.0 0.0.0.0 192.168.122.1

Ensuite on configure une interface de gestion partagée (“Shared Management Interface”) GigabitEthernet1 pour prendre en charge l’API REST :

virtual-service csr_mgmt
 ip shared host-interface GigabitEthernet1
 activate
!
ip http server
ip http secure-server
!
end

Un message %VIRT_SERVICE-5-ACTIVATION_STATE: Successfully activated virtual service csr_mgmt devrait nous avertir du lancement du service d’API. Ensuite, on active le support de l’API :

remote-management
 restful-api
end

La commande show virtual-service detail permet de visualiser le statut du service.

show virtual-service detail

On y apprend l’adresse IP et le port du serveur HTTP (TCP 55443) du service d’API.

<sortie omise>
Package information
  Name                : iosxe-remote-mgmt.16.05.01b.ova
  Path                : bootflash:/iosxe-remote-mgmt.16.05.01b.ova
<sortie omise>
  ----------------------------------------------------------------------
  Feature         Status                 Configuration
  ----------------------------------------------------------------------
  Restful API   Enabled, UP             port: 55443
                                        auto-save-timer: 30 seconds
                                        socket: unix:/usr/local/nginx/csrapi-fcgi.sock;
                                        single-session: Disabled
<sortie omise>

5.4. Documentation de l’API d’un Cisco IOS XE

Cisco IOS XE REST API Management Reference Guide

A partir de maintenant il s’agit de travailler à partir de l’interface de gestion.

6. Authentification HTTP et jeton

Un “token”, un jeton, est un élément d’identification aléatoire et limité dans le temps associé à un compte et ses privilèges pour accéder à une interface de gestion comme un API HTTP Restful.

Avec IOS-XE, pour obtenir un jeton ou un “token-id”, on s’authentifie en méthode “HTTP Basic Auth” sur un ressource précise /api/v1/auth/token-services. Le “jeton” donnera accès aux autres ressources de l’API pour une durée déterminée sans qu’il soit nécessaire d’utiliser un login et un mot de passe.

Une authentification “HTTP Basic Auth” utilise un “challenge” en MD5 pour l’échange du mot de passe.

Avec cURL, on peut s’authentifier en “HTTP Basic Auth” en désignant la ressource :

https://${username}:${password}@${server}/ressource

6.1. Mise en variable de paramètres

Il sera plus facile de manipuler des variables BASH à partir de la station de gestion.

server="192.168.122.10:55443"
username="root"
password="testtest"

6.2. Authentification et récupération du jeton

La documentation de l’API intitulée Authentication nous indique des détails sur la manipulation de la ressource /api/v1/auth/token-services :

  • Les clients effectuent l’authentification avec ce service en invoquant un POST sur cette ressource avec “HTTP Basic Auth” comme mécanisme d’authentification. La réponse à cette demande comprend un id de jeton (“token”). Les Token-ids sont des objets opaques de courte durée qui représentent l’authentification réussie du client avec le service token.
  • Les clients accèdent ensuite à d’autres API en incluant l’identifiant du jeton comme en-tête HTTP personnalisé “X-auth-token”. Si ce jeton n’est pas présent ou est expiré, l’accès API renvoie un code d’état HTTP “401 Unauthorized”.
  • Les clients peuvent également invalider explicitement un jeton en effectuant une opération DELETE sur la ressource du jeton.
  • Le nom d’utilisateur/mot de passe de la session HTTPS doit être configuré avec le privilège 15.
curl -s -k -X POST \
  https://${username}:${password}@${server}/api/v1/auth/token-services \
  | jq '.'

Le filtre Jq '.' représente la racine de la sortie en format interprété.

{
  "kind": "object#auth-token",
  "expiry-time": "Thu Nov 21 09:33:46 2019",
  "token-id": "2vVr1FG25jQOQWfZLEkjAKFyIEc6qL+63AGq7tmsel8=",
  "link": "https://192.168.122.10:55443/api/v1/auth/token-services/1402599582"
}

On obtient un objet “object#auth-token” qui contient quatre clés dont la clé “token-id” qui devra être réutilisée comme valeur d’un en-tête HTTP “X-auth-token”.

On peut demander à Jq de sortir uniquement la valeur de la clé “token-id” avec le filtre '.["token-id"]'. L’option -r sort le résultat en brut, sans guillemets.

curl -s -k -X POST \
  https://${username}:${password}@${server}/api/v1/auth/token-services \
  | jq -r '.["token-id"]'

Et on obtient la valeur “token-id”, comme par exemple :

2vVr1FG25jQOQWfZLEkjAKFyIEc6qL+63AGq7tmsel8=

On peut alors stocker la valeur du jeton dans une variable $token_id :

token_id=$(curl -s -k -X POST \
  https://${username}:${password}@${server}/api/v1/auth/token-services \
  | jq -r '.["token-id"]')
  echo ${token_id}

Dans la suite des opérations de prise d’information et de gestion, on réutilisera le jeton dans une option cURL sous la forme -H "X-auth-token: ${token_id}".

Aussi il peut être utile de garder un oeil sur l’URI du jeton :

link=$(curl -s -k -X POST \
  https://${username}:${password}@${server}/api/v1/auth/token-services \
  | jq -r '.["link"]')
  echo ${link}

6.3. Information sur le jeton

curl -s -k -X GET \
  ${link} -H "X-auth-token: ${token_id}"

6.4. Suppression d’un jeton

Pour supprimer un jeton, on agira sur la ressource renseignée dans la réponse d’authentification précédente :

curl -s -k -v -X DELETE \
  ${link} -H "X-auth-token: ${token_id}"

on obtient une réponse HTTP HTTP/1.1 204 NO CONTENT.

7. Collecte d’informations

L’API IOS-XE organise les ressources de gestion du routeur en une hiérarchie :

  • global
    • cpu
    • memory
      • processes
    • banner
    • host-name
    • domain-name
    • local-users
      • ${username}
    • logging
    • tacacs
    • snmp
    • reload
    • save-config
    • ipv6
      • routing
  • interfaces
    • {if-id}
      • statistics
      • state
  • routing-svc
    • ospf
    • eigrp
    • bgp
  • nat-svc
  • zbfw-svc

On pourra agir sur ces ressources d’une manière ou d’une autre selon ce que la documentation indique.

7.1. Ressources CPU et RAM

Memory and CPU Usage Report

Par exemple, pour obtenir les informations concernant l’usage CPU on sollicite la ressource /api/v1/global/cpu avec la commande HTTP GET :

curl -s -k -X GET \
  https://${server}/api/v1/global/cpu \
  -H "X-auth-token: ${token_id}" | jq '.'
{
  "last-1-mn-utilization": "1%",
  "last-5-secs-utilization": "0%",
  "kind": "object#cpu",
  "last-5-mns-utilization": "1%"
}

De la même manière pour l’utilisation de la mémoire vive du routeur en interrogeant /api/v1/global/memory/processes :

curl -s -k -X GET \
  https://${server}/api/v1/global/memory/processes \
  -H "X-auth-token: ${token_id}" | jq '.'

Cette sortie est particulièrement longue. Il devient utile de la filtrer avec l’outil ./jq.

7.2. Traitement avec Jq

Il sera plus aisé de placer le résultat de la requête dans une variable de façon à ne pas solliciter l’API à chaque traitement d’une même sortie :

memory=$(curl -s -k -X GET \
  https://${server}/api/v1/global/memory/processes \
  -H "X-auth-token: ${token_id}" | jq '.')

On peut afficher le nombre de clés de premier niveau :

echo ${memory} | jq '. | length'

On apprend qu’il y a quatre clés dans un tableau. Quelles sont-elles ?

echo ${memory} | jq '. | keys'
[
  "kind",
  "processes",
  "total-free",
  "total-used"
]

On peut afficher la valeur d’une clé par son nom, ici la clé “total-free” :

echo ${memory} | jq '.["total-free"]'
1777015696

Si vous connaissez la valeur que vous cherchez vous pouvez utiliser le filtre Jq select. Par exemple, pour identifier le service “NTP” :

echo ${memory} | jq '.processes[] | select(.["process-name"] == "NTP")'

7.3. Collecte d’informations sur les interfaces

IP Interface Configuration Requirements

Pour obtenir l’équivalent de la sortie de la commande IOS show ip interface brief, on peut solliciter la ressource /api/v1/interfaces

curl -s -k -X GET \
  https://${server}/api/v1/interfaces \
-H "X-auth-token: ${token_id}" | jq '.'

On obtient donc un objet “interfaces” de deux clés, dont l’une items a pour valeur un dictionnaire de quatre objets (quatre interfaces) contenant chacun une liste non-ordonnée de clés (les propriétés de chacune des interfaces).

{
  "items": [
    {
      "kind": "object#interface",
      "description": "",
      "if-name": "GigabitEthernet4",
      "proxy-arp": true,
      "subnet-mask": "",
      "icmp-unreachable": true,
      "ipv6-enable": false,
      "nat-direction": "",
      "icmp-redirects": true,
      "ip-address": "",
      "verify-unicast-source": false,
      "type": "ethernet",
      "mac-address": "0c87.8583.3503"
    },
    {
      "kind": "object#interface",
      "description": "",
      "if-name": "GigabitEthernet1",
      "proxy-arp": true,
      "subnet-mask": "255.255.255.0",
      "icmp-unreachable": true,
      "ipv6-enable": false,
      "nat-direction": "",
      "icmp-redirects": true,
      "ip-address": "192.168.122.38",
      "verify-unicast-source": false,
      "type": "ethernet",
      "mac-address": "0c87.8583.3500"
    },
    {
      "kind": "object#interface",
      "description": "",
      "if-name": "GigabitEthernet2",
      "proxy-arp": true,
      "subnet-mask": "",
      "icmp-unreachable": true,
      "ipv6-enable": false,
      "nat-direction": "",
      "icmp-redirects": true,
      "ip-address": "",
      "verify-unicast-source": false,
      "type": "ethernet",
      "mac-address": "0c87.8583.3501"
    },
    {
      "kind": "object#interface",
      "description": "",
      "if-name": "GigabitEthernet3",
      "proxy-arp": true,
      "subnet-mask": "",
      "icmp-unreachable": true,
      "ipv6-enable": false,
      "nat-direction": "",
      "icmp-redirects": true,
      "ip-address": "",
      "verify-unicast-source": false,
      "type": "ethernet",
      "mac-address": "0c87.8583.3502"
    }
  ],
  "kind": "collections#interface"
}

Enregistrons le résulat dans un fichier interfaces.json :

curl -s -k -X GET \
  https://${server}/api/v1/interfaces \
-H "X-auth-token: ${token_id}" -o interfaces.json

7.4. Exercice de traitement avec jq

Combien y a-t-il de valeurs dans la clé items qui corresspond aux interfaces ? En effet, on obtient bien le chiffre 4 quand on utilise le filtre length :

cat interfaces.json | jq '.items | length'

Quelles sont les éléments de la clé items ?

cat interfaces.json | jq '.items | keys'
[
  0,
  1,
  2,
  3
]

Comment obtenir le premier élément de la clé items ?

cat interfaces.json | jq '.items[0]'
{
  "kind": "object#interface",
  "description": "",
  "if-name": "GigabitEthernet4",
  "proxy-arp": true,
  "subnet-mask": "",
  "icmp-unreachable": true,
  "ipv6-enable": false,
  "nat-direction": "",
  "icmp-redirects": true,
  "ip-address": "",
  "verify-unicast-source": false,
  "type": "ethernet",
  "mac-address": "0c87.8583.3503"
}

Le filtre keys offre uniquement le nom des clés, comme ci-dessous :

cat interfaces.json | jq '.items[0] | keys'
[
  "description",
  "icmp-redirects",
  "icmp-unreachable",
  "if-name",
  "ip-address",
  "ipv6-enable",
  "kind",
  "mac-address",
  "nat-direction",
  "proxy-arp",
  "subnet-mask",
  "type",
  "verify-unicast-source"
]

Comment obtenir la clé mac-address du second élément de la clé items ?

cat interfaces.json | jq '.items[1]["mac-address"]'
"0c87.8583.3500"

Comment obtenir la clé if-name de chacune des quatre clé de l’objet items ?

cat interfaces.json | jq '.items[]["if-name"]'
"GigabitEthernet4"
"GigabitEthernet1"
"GigabitEthernet2"
"GigabitEthernet3"
curl -s -k -X GET \
  https://${server}/api/v1/interfaces \
  -H "X-auth-token: ${token_id}" \
  | jq -s '.[].items[]["if-name"]'

8. Configuration et vérification d’une interface

C’est la commande HTTP POST qui permet de configurer une interface.

8.1. Création d’une interface de Loopback

La documentation de l’API nous apprend aussi comment configurer une interface. Par exemple, pour créer une interface Loopback0 disposant d’une adresse IPv4 11.11.11.11/32 avec une description :

curl -v -s -k -X POST \
  https://${server}/api/v1/interfaces \
  -H "X-auth-token: ${token_id}" \
  -H 'Content-Type: application/json' \
  -d '{
      "type": "loopback",
      "description": "test api 0",
      "if-name": "Loopback0",
      "ip-address": "11.11.11.11",
      "subnet-mask": "255.255.255.255"
    }'

On obtien une réponse HTTP/1.1 201 CREATED.

8.2. Vérification de l’interface créée

curl -s -k -X GET \
  https://${server}/api/v1/interfaces \
  -H "X-auth-token: ${token_id}" \
  | jq -s '.[].items[] | select(.["if-name"] == "Loopback0")'
{
  "kind": "object#interface",
  "description": "test api 0",
  "if-name": "Loopback0",
  "proxy-arp": true,
  "subnet-mask": "255.255.255.255",
  "icmp-unreachable": true,
  "ipv6-enable": false,
  "nat-direction": "",
  "icmp-redirects": true,
  "ip-address": "11.11.11.11",
  "verify-unicast-source": false,
  "type": "loopback"
}

Ou alors un appel directement à la ressource /api/v1/interfaces/Loopback0 :

curl -s -k -X GET \
  https://${server}/api/v1/interfaces/Loopback0 \
  -H "X-auth-token: ${token_id}" | jq '.'

9. Gestion de la configuration

9.1. Sauvegarde de la configuration

Pour sauvegarder la configuration, on utilise la commande PUT sur la ressource /api/v1/global/save-config, ici avec un en-tête HTTP Content-Type: application/json :

curl -v -s -k -X PUT \
  https://${server}/api/v1/global/save-config \
  -H "X-auth-token: ${token_id}" \
  -H 'Content-Type: application/json'

Le code d’état attendu dans la réponse est 204 NO CONTENT.

9.2. Rapatrier la configuration

Pour l’équivalent d’une commande IOS CLI show running-config on sollicite la ressource /api/v1/global/running-config avec la commande GET, ici la sortie est enregistrée dans le fichier running-config.txt :

curl -s -k -X GET \
  https://${server}/api/v1/global/running-config \
  -H "X-auth-token: ${token_id}" -o running-config.txt

9.3. Exécution de commande IOS CLI avec l’API

curl -s -k -X PUT \
  https://${server}/api/v1/global/cli \
  -H "X-auth-token: ${token_id}" \
  -H 'Content-Type: application/json' \
-d '{
  "show": "ip interface brief"
}'
curl -s -k -X PUT \
  https://${server}/api/v1/global/cli \
  -H "X-auth-token: ${token_id}" \
  -H 'Content-Type: application/json' \
-d '{
  "show": "ip interface brief"
}' | jq  '.results | split("\n")'

10. Conclusion

Imaginons une infrastructure entière, voire un système d’information entier, sous la gestion d’un ensemble de micro-services inter-opérables et programmables.

Modularity+Abstraction+Automation = Microservices

En conclusion, un API définit comment une application est utilisée par une autre application.

  • Un API expose les fonctions internes au monde extérieur, ce qui permet à d’autres applications externes d’utiliser les fonctionnalités de l’application.
  • Le protocole de communication le plus souvent utilisée : HTTP
  • Un API est la base de l’architecture Microservice

Un microservice est :

  • Un petit service qui fait très bien une seule chose
  • Indépendant des autres
  • Propriétaire de ses propres données

JSON est un format d’encodage et d’échange de données inter-opérable, facile à traiter aussi bien pour les humains que pour les machines.

Source de l’image : Cisco Live! June 25-29, 2017 - Las Vegas, NV

  1. Representational state transfer 

  2. Puisque les objets sont destinés à représenter des tableaux associatifs, il est recommandé, bien que non requis, que chaque clé soit unique dans un objet.