Cisco France Blog

J’ai testé… Ansible + NETCONF avec IOS-XE

8 min read



Introduction


Dans le précédent article “Manager vos équipements Cisco avec Ansible“, nous avons vu comment utiliser Ansible pour configurer des équipements Cisco. L’Ansible Management Node se connecte aux équipements cibles via SSH, puis il insère les commandes spécifiées dans la Command Line Interface (CLI) via la collection Ansible correspondante (dans le cas de Cisco il s’agit de la collection cisco.ios.ios_config).

Simple et efficace. Nous utilisons la syntaxe bien connue du CLI, et nous automatisons nos opérations.

Mais alors, pourquoi un autre article sur le sujet ?

Pour répondre à cette question, nous devons revenir à notre besoin. En effet, dans un contexte d’interaction humain-machine, l’utilisateur a besoin d’une interface lisible et intuitive : le CLI. Cela fait des décennies que les administrateurs réseaux utilisent cette interface, qui permet facilement de configurer un équipement.

Mais de nos jours, il ne s’agit plus que d’un seul équipement. L’infrastructure réseau est devenue vaste, complexe et plus stratégique que jamais. Copier-coller une configuration d’un équipement/CLI à l’autre devient laborieux, instable, et sujet aux erreurs. Jérôme DURAND, dans son article JRES2019 – Automatiser son infrastructure réseau, a clairement mis en lumière les challenges rendant le CLI obsolète dans un contexte d’automatisation :

  • Absence d’un réel modèle de données standard (un humain doit lire les guides de configuration)
  • Pas de réels codes d’erreurs. Il est compliqué de détecter quand une configuration est acceptée ou non et surtout la raison d’un problème
  • Les lignes de CLI sont exécutées souvent séquentiellement, et un échec sur une ligne de CLI n’interrompt pas toujours l’action globale de configuration, engendrant potentiellement des incohérences finales
  • Risque d’avoir plusieurs configurations simultanées et antagonistes sur le même équipement

Ce sont ces challenges qui m’ont amené à rédiger un nouvel article, me permettant de vous présenter une solution complémentaire à Ansible : NETCONF/YANG.

Dans les sections suivantes nous allons voir pourquoi NETCONF/YANG complète Ansible en résolvant les challenges identifiés ci-dessus, puis nous verrons comment le mettre en place dans un environnement Ansible existant.

Notons qu’Ansible n’est pas requis pour l’utilisation de NETCONF/YANG. Ce sont deux solutions distinctes, qui peuvent s’intégrer ensemble.

 

Pourquoi NETCONF/YANG complète Ansible ?


Avant de comprendre en quoi NETCONF/YANG complète Ansible, nous devons d’abord comprendre le rôle de ces deux éléments : NETCONF et YANG. Et bien que NETCONF et YANG soient eux-mêmes complémentaires, il est important de bien les différencier. Comment ?

Pour faire court, YANG permet de modéliser les données, tandis que NETCONF assure le transport de ces données sur le réseau. Voyons cela un peu plus en détail :

 

Yet Another Next Generation (YANG)

En premier lieu, il faut modéliser les données. Mais de quelles données parlons-nous ? Il s’agit à la fois :

  • Des données de configuration, accessibles en lecture et écriture : par exemple l’adresse IP statique d’une interface.
  • Des données de fonctionnement, accessibles en lecture seule : par exemple l’état d’une interface (UP ou DOWN).

L’organisation de ces données est contenue dans un module. En voici un de l’IETF sur les interfaces, qui décrit l’arborescence suivante :

Organisation des données du module ietf-interfaces

Organisation des données du module ietf-interfaces

La syntaxe YANG peut paraître lourde, notamment lorsqu’on compare un module YANG avec l’arborescence qu’il décrit. Néanmoins, il existe des plugins facilitant la lecture de cette nouvelle syntaxe, comme pyang pour Python.

On distingue deux types de modules :

  • Module du vendeur : Native
  • Modules communs : IETF, OpenConfig, IEEE on YANG, …

Le sujet YANG est très vaste, nous pourrions encore aborder les différentes structures d’un module (container, list, leaf-list, leaf), l’inclusion d’un module dans un autre (augment), les types de données (string, float, integer, boolean, typedef, …), et tant d’autres sujets. Néanmoins nous avons déjà abordé les éléments clés nous permettant de comprendre la suite.

 

NETwork CONFiguration (NETCONF)

Maintenant que les données sont modélisées, il faut les transporter sur le réseau. C’est là que le protocole NETwork CONFiguration (NETCONF) intervient.

Le contrôleur réseau va communiquer avec les équipements réseaux via NETCONF (en charge de la bonne transmission des données, ainsi que de l’interfaçage avec les modules YANG).

NETCONF se base sur SSH pour le transport et XML pour l’encodage. On remarque ainsi la parfaite intégration avec Ansible, qui utilise lui aussi des sessions SSH pour piloter les équipements.

NETCONF opère sur un datastore donné (startup, candidate, running, …) via les opérations suivantes :

  • get : récupère les données de configuration et les données de fonctionnement de l’équipement cible
  • get-config : récupère les données de configuration de l’équipement cible
  • edit-config : envoie les données de configuration spécifiées à l’équipement cible
  • copy-config : crée ou remplace une configuration complète
  • delete-config : Supprime les données de configuration de l’équipement cible.
  • lock : bloque l’accès aux données de configuration pour éviter un conflit avec d’autres clients NETCONF, SNMP, CLI ou autres
  • unlock : inverse de lock
  • close-session : demande l’arrêt de la session en cours et attend une confirmation
  • kill-session : force l’arrêt de la session en cours

Notons que pour get et get-config, il est possible d’utiliser des filtres spécifiant les éléments du module YANG que nous souhaitons récupérer. C’est ce que nous ferons dans la partie pratique.

 

YANG avec NETCONF

Il est maintenant temps de comprendre comment NETCONF et YANG s’intègre l’un et l’autre :

Intégration de NETCONF avec YANG

Intégration de NETCONF avec YANG

On remarque qu’il existe des alternatives à NETCONF : RESTCONF et gNMI. Nous n’aborderons pas ces sujets dans cet article, néanmoins notons la flexibilité que l’on peut avoir sur les protocoles de transports.

Pour résumer, un équipement réseau va donc organiser ses données de configuration/fonctionnement via des modules YANG. Ces données sont ensuite sérialisées avec des langages tels que XML, pour être enfin transportées sur le réseau par des protocoles tels que NETCONF (le protocole activé durant le lab du précédent article “Manager vos équipements Cisco avec Ansible“).

Trêve de théorie, voyons tout cela en pratique !

 

Comment mettre en place NETCONF/YANG avec Ansible ?


Prenons un cas d’usage très générique : la récupération de la configuration des interfaces d’un routeur.

Afin de répondre à ce cas d’usage, nous aborderons les parties suivantes :

  • l’architecture du lab
  • le choix du modèle YANG
  • le playbook Ansible avec NETCONF
  • le résultat

 

Architecture du lab

Nous commençons par définir l’architecture du lab sur lequel nous allons travailler. Il s’agit d’une infrastructure très simple, avec un Ansible Management Node (un serveur Ubuntu), un routeur/switch pour la connectivité, et Catalyst 8000V Edge (anciennement CSR1000V) :

Architecture du lab

Architecture du lab

Sur ce même lab, nous souhaitons :

  • Récupérer la configuration des interfaces du Catalyst 8000v Edge en XML via la méthode GET de NETCONF
  • Sauvegarder la configuration des interfaces du Catalyst 8000v Edge dans un fichier XML

Avec ce découpage fonctionnel, on obtient les deux tâches que notre playbook Ansible va devoir réaliser.

Mais avant, nous devons choisir un modèle sur lequel nous allons nous baser.

Si vous ne souhaitez pas mettre en place votre propre lab, sachez que Cisco mets à disposition des bacs à sable, ce qui vous évite de déployer un équipement Cisco IOS-XE si vous n’en avez pas encore. Avec cette alternative, il vous suffit d’installer Ansible sur une machine, avec un accès à Internet pour communiquer avec le bac à sable.

 

Choix du module YANG

Vous souvenez-vous des modules YANG dont nous avons parlé dans la première partie ? C’est ici qu’ils vont nous servir.

Nous souhaitons récupérer la configuration des interfaces du Catalyst 8000v Edge, certes, mais via quel module ? IETF, Natif, OpenConfig, …

Pour faire le bon choix, une bonne compréhension de chacun des modules est nécessaire. Un très bon article à ce sujet est disponible ici.

En voici un extrait répondant à notre question :

“When just starting out the IETF models can be great options to learn the protocols, features, and tooling for model driven programmability.”

Les modules IETF sont en effet une bonne option pour une initiation au Model Driven Programmability. Comme nous l’avons vu précédemment, il s’agit de modules communs à tous les constructeurs, offrant donc de la flexibilité en dépit de fonctionnalités avancées.

Nous devons maintenant choisir le module au sein des modules de l’IETF. Dans notre cas d’usage, nous avons besoin du module de configuration de l’interface d’un routeur. Comme nous l’avons vu dans la partie sur YANG, ce module s’appelle ietf-interfaces, et les données de configuration sont les suivantes (seulement les données rw) :

Nous n’avons plus qu’à indiquer à NETCONF :

  • Le module choisi, c’est à dire ietf-interfaces
  • Le type de donnée choisi, c’est à dire les données de configuration.

Nous faisons cela avec des filtres (la syntaxe est ici en XML) :

<filter>
  <interfaces
    xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
  </interfaces>
</filter>

Si vous souhaitez obtenir les données de fonctionnement et non les données de configuration, vous devez remplacer la balise XML <interfaces> par <interfaces-state>.

Ce filtre sera utilisé dans la tâche NETCONF du playbook, qui est décrite dans le paragraphe suivante.

Le module étant à présent défini, nous pouvons passer au playbook.

 

Playbook Ansible avec NETCONF

Nous pouvons maintenant réaliser le playbook qui doit effectuer les tâches précédemment identifiées, qui sont pour rappel :

  • Récupérer la configuration des interfaces en XML du Catalyst 8000v Edge via la méthode GET de NETCONF
  • Sauvegarder la configuration des interfaces dans un fichier XML
---
- name: Récupération et sauvegarde de la config des interfaces de routeurs
  hosts: cat8kv1
  gather_facts: false

  tasks:
  - name: Récupérer la config en XML des interfaces via la méthode GET de NETCONF
    netconf_get:
      source: running
      filter: |
               <interfaces
                 xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
               </interfaces>
    register: config

  - name: Sauvegarder la configuration des interfaces dans un fichier XML
    copy:
      content: "{{config.stdout}}"
      dest: "~/Projects/devnet/ansible/cfg/{{inventory_hostname}}_NC.xml"
...

 

Résultat

Exécutons maintenant le playbook Ansible avec NETCONF :

devnet@devnet:~/Projects/devnet/ansible/playbooks$ ansible-playbook getIntNetconf.yml

PLAY [Récupération et sauvegarde des interfaces de routeurs] 

TASK [Récupérer la configuration en XML du routeur via la méthode GET de NETCONF] 
ok: [cat8kv1]

TASK [Sauvegarder la configuration des interfaces dans un fichier XML] 
ok: [cat8kv1]

PLAY RECAP 
cat8kv1 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

Le playbook fonctionne, mais que s’est-il exactement passé durant son exécution ?

Pour mieux comprendre, il est nécessaire de connaître les APIs Remote Procedure Call (RPC). L’Ansible Management Node envoie une requête <rpc> (contenant la méthode NETCONF <get>) au Catalyst 8000v, qui répond par un <rpc-reply> (contenant les données <data> au format XML) :

Communication NETCONF pour la méthode GET

Communication NETCONF pour la méthode GET

Ci-dessous un extrait du fichier de configuration obtenu pour une interface (qui correspond à la payload de la réponse <rpc-reply>) :

<?xml version="1.0" encoding="UTF-8"?>

<rpc-reply 
  xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" 
  xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" 
  message-id="urn:uuid:127ffa4a-90f6-46cf-a2e8-527a10cfd1b5">

  <data 
    xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" 
    xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
    <interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
      <interface>
        <name>GigabitEthernet1</name>
        <type xmlns:ianaift="urn:ietf:params:xml:ns:yang:iana-if-type">
          ianaift:ethernetCsmacd
        </type>
        <enabled>false</enabled>
        <ipv4 xmlns="urn:ietf:params:xml:ns:yang:ietf-ip">
          <address>
            <ip>192.168.1.125</ip>
            <netmask>255.255.255.0</netmask>
          </address>
        </ipv4>
        <ipv6 xmlns="urn:ietf:params:xml:ns:yang:ietf-ip" />
      </interface>
      [...]
    </interfaces>
  </data>

</rpc-reply>

Le tag <rpc-reply> n’apparaitra pas dans le fichier de configuration sauvegardé par le playbook. Vous ne verrez que la partie <data>. Néanmoins, le tag <rpc-reply> permet de comprendre le rôle des APIs RPC avec les méthodes de NETCONF.

Vous avez peut-être remarqué que certains objets n’apparaissent pas, comme description et link-up-down-trap-enable. Ces objets sont optionnels, c’est pourquoi on retrouve un “?” à la fin de leur nom dans la description du modèle. Dans notre cas, aucune de ces données n’a été configurée dans le routeur, elles sont donc vides.

Nous retrouvons la même structure que celle décrite dans le modèle ietf-interfaces, à l’exception de deux objets :

  • ipv4
  • ipv6

Que sont ces valeurs ? Ce sont des conteneurs provenant d’un autre module YANG. On retrouve le module correspondant dans le namespace de ces objets : ietf-ip. Cela est possible grâce à la fonction augment de YANG, qui permet à un module d’étendre un autre module, complétant ainsi le module :

Félicitations ! Vous êtes maintenant capable de superviser et configurer tout équipement réseau supportant NETCONF avec Ansible. Il ne reste plus qu’à mettre à jour l’inventaire en fonction de votre parc, et définir vos propres cas d’usages avec les modules YANG correspondant !

 

Conclusion


A travers cet article, nous avons vu comment pallier les limites du CLI dans un contexte d’automatisation, et ce grâce à :

  • NETCONF, un protocole encodé en XML, transporté via SSH, et permettant d’interagir avec les modèles de données standardisés par YANG sur les équipements réseaux.
  • Deux modules Ansible, ansible.netcommon.netconf_get pour la supervision, et ansible.netcommon.netconf_config pour la configuration.

Malgré les simplifications qu’apporte NETCONF avec Ansible pour la gestion d’une infrastructure réseau, il est important de prendre de la hauteur et de se questionner sur le type de solution souhaitée (clé en main ou à faire soi-même).

Et si après cette réflexion, vous réalisez que la solution à faire soi-même (tel que NETCONF/YANG et Ansible) ne répond pas à vos besoins, je vous invite à regarder les solutions de gestion du réseau clés en main qu’offre Cisco.

Par exemple, pour un réseau entreprise, Cisco propose le DNA Center :

Image de DNA Center

Cisco DNA Center

DNA Center et Ansible ne sont pas incompatibles, au contraire ! Florian GIRGARD dans son article Accélérer vos opérations avec Ansible et Cisco DNA Center nous présente les cas d’usages de l’intégration de DNA Center avec Ansible.

Authors

Xavier VALETTE

Solutions Engineer

Laisser un commentaire


1 commentaires

  1. Un tres bon article, merci