La gestion atomique des configurations en IOS-XE est un sujet plus complexe qu’il n’y parait. Des avancées ont été présentées dernièrement lors de la conférence CiscoLive et je vous propose de faire le point sur ce thème qui impacte directement la manière de configurer les équipements. Je remercie Xavier Valette et Antoine Orsoni pour leur relecture et leurs conseils avisés.
Atomique ? C’est dangereux ?
Commençons déjà par rappeler ce qui est derrière l’atomicité des changements de configuration. Il est question ici d’appliquer un bloc complet de configuration en une fois et de ne l’appliquer que s’il est complètement valide. L’objectif est d’éviter d’avoir une configuration partiellement appliquée s’il y a la moindre erreur. “Tout à la fois” et “tout ou rien”, c’est ainsi que l’on pourrait résumer le changement atomique des configurations.
Etat des lieux sur IOS-XE
La CLI de l’IOS-XE conserve des principes très anciens d’application des lignes de configuration une à une. En gros quand vous tapez une ligne de configuration elle est directement appliquée sur l’équipement. Si vous cherchez à appliquer plusieurs lignes successivement, ces dernières seront appliquées l’une après l’autre sans logique globale. Si vous vous trompez quelque part, c’est tant pis pour vous, il vous faudra détecter et corriger les lignes en erreur. Et pendant ce temps une partie de la configuration est appliquée. L’équipement se retrouve dans un état intermédiaire pas forcément idéal. Dans un monde de configuration manuel des équipements, cela n’est pas très gênant. Mais quand il s’agit d’automatiser à grande échelle des changements complexes alors cela devient une propriété intéressante.
De nombreux outils vont apporter cette atomicité au-dessus d’IOS-XE. On peut citer par exemple Cisco Crosswork Network Service Orchestrator (NSO), Ansible, Network to code mais aussi nos dashboards Meraki et Catalyst Center… Ces derniers vont permettre de garantir des changements de configuration atomiques en implémentant la logique localement avant d’appliquer les lignes de configuration IOS-XE ad-hoc. Inutile de s’alarmer donc… Cependant cela crée des dépendances techniques avec d’autres outils. Il convient d’apporter une solution directement sur IOS-XE et simplifier ainsi le stack d’automatisation.
Modifier le mode de configuration standard de l’IOS-XE est impossible. Des centaines de milliers de clients utilisent le fameux “conf t” et de nombreux outils/scripts l’exploitent. Changer ce mode de configuration pour introduire une validation en bloc déclenche une véritable révolte.
NETCONF à la rescousse
Dans un précédent article, j’expliquais tout l’intérêt d’utiliser NETCONF et une configuration modélisée. Cela permet de valider des payloads de configuration entiers et de les appliquer globalement via commit. Mais voilà pas tout le monde n’a envie de passer aux payloads de configuration XML malgré les outils existants pour aider, notamment YangSuite.
Aussi depuis la release IOS-XE 17.9, nous avons la possibilité d’avoir cette transactionnalité tout en conservant nos configurations CLI grâce au modèle Cisco-IOS-XE-CLI-RPC.YANG et la directive config-ios-cli-trans. L’idée ici est d’utiliser un payload NETCONF pour vos configurations (au lieu d’une connexion SSH directe) mais de conserver le format de configuration CLI. Si ce n’est pas encore clair, les exemples suivants devraient vous aider à y voir clair.
Pour tous ces exemples j’utilise YangSuite pour envoyer des payloads NETCONF simplement (à nouveau c’est votre meilleur ami pour appréhender les interfaces programmatiques des équipements réseau). Evidemment vous utiliserez d’autres outils ensuite quand vous voudrez mettre tout cela en production. Par exemple Xavier Valette rappelle dans cet article récent comment utiliser NETCONF avec Ansible.
Exemple 1 – Gestion des erreurs
Imaginons que j’applique le bloc de configuration suivant qui contient une erreur sur la troisième ligne (shutnow au lieu de shutdown).
int lo 666 description TEST RESEAUXBLOG shutdnow
En utilisant un mode de configuration classique (conf t), les lignes sont appliquées une à une indépendamment de la validité de l’ensemble.
C9300#conf t Enter configuration commands, one per line. End with CNTL/Z. C9300(config)#int lo 666 C9300(config-if)#description TEST RESEAUXBLOG C9300(config-if)#shutdnow ^ % Invalid input detected at '^' marker. C9300(config-if)# 045023: Sep 2 21:24:04.346: %LINEPROTO-5-UPDOWN: Line protocol on Interface Loopback666, changed state to up
Je vois que mon interface Loopback 666 est créée malgré l’erreur.
C9300#sh run int lo 666 ! interface Loopback666 description TEST RESEAUXBLOG no ip address end
On n’a pas ici d’atomicité des configurations dans ce mode de configuration. Les lignes valides sont bien appliquées et uniquement les celles en erreur ne sont pas prises en compte. Evidemment ici l’impact est faible mais on peut imaginer qu’une erreur sur un changement plus complexe soit plus problématique si un objet est mal créé et doit être appelé par la suite (par exemple un serveur radius, un protocole de routage…)
Si je pousse maintenant les mêmes configurations dans un payload NETCONF (utilisation du modèle Cisco-IOS-XE-cli-rpc.yang)
Un message d’erreur clair apparaît quand j’essaye d’appliquer ce payload.
<error-message xml:lang="en">inconsistent value: Failed to load commands via transaction: external error, syntax error: unknown command Error: on line 2: int lo 666 </error-message>
De retour sur mon équipement, je constate qu’aucune ligne n’a été appliquée.
C9300#sh run int lo 666 ^ % Invalid input detected at '^' marker.
On répond bien à notre besoin. Sous le capot, le CLI est ensuite modélisé par l’équipement et atteint directement la base de données de configuration. Vu que pratiquement 100% de la configuration CLI est modélisée vous ne devriez pas avoir de problèmes ici.
Exemple 2 – Syntaxe correcte mais une configuration non valide
Prenons l’exemple suivant dans lequel je vais pousser un serveur NTP invalide (une adresse multicast) en plus d’une interface de loopback.
ntp server 239.1.1.1 interface Loopback 666 description TEST RESEAUXBLOG
D’un point de vue syntaxe tout est bon. Je respecte le modèle de données sous-jacent.
Si j’utilise le CLI pur, les lignes sont appliquées une à une, aucune transactionnalité.
C9300(config)#ntp server 239.1.1.1 % Invalid address C9300(config)#interface Loopback 666 C9300(config-if)#description TEST RESEAUXBLOG 045942: Sep 3 06:56:21.508: %LINEPROTO-5-UPDOWN: Line protocol on Interface Loopback666, changed state to up
Pas de surprise ici, la loopback est donc créée malgré l’invalidité du serveur NTP. Maintenant j’applique la commande via NETCONF en utilisant YangSuite.
J’ai une erreur remontée dans NETCONF avec la mise en évidence de la ligne concernée.
<bad-cli>
<bad-command>ntp server 239.1.1.1</bad-command>
<error-location>20</error-location>
<parser-response>
% Invalid address</parser-response>
<parser-context>ntp server 239.1.1.1</parser-context>
</bad-cli>
Et bonne nouvelle ici aussi, aucune configuration n’est appliquée, on a bien une atomicité des configurations.
Exemple 3 – Mauvais ordre d’application des configurations
Ici je vais appliquer des configurations dans le mauvais ordre, en appelant un objet non encore créé. Dans cet exemple je déclare une interface source pour le protocole NTP qui est créée dans un second temps.
ntp source Loopback 666
interface Loopback 666
description TEST RESEAUXBLOG
Ici pas de surprises non plus, si j’applique en CLI la première ligne va être refusée mais l’interface va quand même être créée.
C9300(config)#ntp source Loopback 666 ^ % Invalid input detected at '^' marker. C9300(config)#interface Loopback 666 C9300(config-if)# description TEST RESEAUXBLOG 047219: Sep 3 19:12:55.180: %LINEPROTO-5-UPDOWN: Line protocol on Interface Loopback666, changed state to up
La configuration est à nouveau à moitié appliquée. La loopback est créée mais n’est pas utilisée comme source pour le protocole NTP. Petit test via NETCONF maintenant avec YangSuite, je pousse exactement la même configuration.
Dans le cas présent NETCONF m’indique que tout s’est bien passé:
<result xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-cli-rpc">Configuration applied successfully</result>
Et en effet je peux voir que ma Loopback est bien créée et est utilisée comme source pour le protocole NTP.
C9300#sh run int lo666 interface Loopback666 description TEST RESEAUXBLOG no ip address end ! C9300#sh run | i ntp sour ntp source Loopback666
Là aussi l’utilisation d’un mode de configuration transactionnel a permis de simplifier les opérations en apportant l’atomicité désirée.
Un peu plus loin : atomicité complète avec 2-stage commit
L’atomicité présentée dans le précédent exemple est avant tout syntaxique et ne relève pas forcément de logique d’ensemble. Elle peut dans certains cas de révéler insuffisante et c’est aussi l’objet des dernières innovations présentées à CiscoLive. On va complètement tester le payload de configuration sur un 2nd IOS de test pour vérifier que la modification tient la route avant de l’appliquer. Aujourd’hui cette fonctionnalité est en “pre-release feature pour tests” depuis IOS-XE 17.15.3 sur Catalyst 9300, 9500 et WLC 9800 et devrait se généraliser sur d’autres plateformes ensuite. Il est un peu tôt donc pour utiliser cette fonctionnalité en production mais c’est intéressant de commencer à appréhender un peu ces concepts.
Tout d’abord il faut activer le two-stage commit. Sur IOS-XE 17.18 les commandes complètes sont:
netconf-yang netconf-yang feature candidate-datastore yang-interfaces feature atomic-config yang-interfaces feature deprecated disable
Si vous faites vos tests en 17.15 (pre-release feature) la troisième ligne était légèrement différente: “yang-interfaces feature ios-two-stage” au lieu de “yang-interfaces feature atomic-config”.
Le two-stage commit va nous permettre d’adresser des configurations encore plus complexes et globales en s’assurant que l’intégralité est accepté par IOS-XE. On a ici une atomicité complète. Cela va être très pratique pour faire des remplacements complets de configuration, ou l’application d’un bloc intégral. Cela sera bien plus efficace qu’un “configuration replace”.
Configuration de secours
Là c’est une innovation de la toute récente release IOS-XE 17.18.1. Avec le modèle Cisco-IOS-XE-rescue-config-rpc.yang vous pouvez créer sur l’équipement une configuration de secours que vous savez fonctionnelle, et vous avez la possibilité de demander à l’appliquer immédiatement en cas de coup dur. Imaginez par exemple une maintenance un peu complexe qui nécessite de très nombreux changements et qui n’offre pas le résultat attendu, vous voudrez alors tout annuler et revenir rapidement dans l’état initial. Ce rescue config devrait se révéler plus efficace que le “configuration replace” actuel. YangSuite permet là aussi de commencer à tester cette fonctionnalité en sauvegardant une nouvelle configuration de secours, et en l’appliquant depuis n’importe quel état.
Et pour la suite ?
Beaucoup d’innovations sont encore prévues, armez-vous d’un peu de patience mais la suite devrait vous plaire. Je vous recommande pour le moment de vous familiariser avec les concepts d’atomicité et de voir si vous pouvez déjà en tirer profit actuellement (attention je rappelle que certaines fonctions comme le 2-stage commit sont encore en LA – Limited Availability). Touchez-en un mot à vos équipes DevOps elles verront tout de suite quel avantage en tirer. Je vous recommande de regarder les présentations CiscoLive référencées ci-dessous pour voir d’autres cas d’utilisation et parfaire votre socle de connaissance en programmabilité IOS-XE. Prenez un peu de temps pour regarder les articles connexes sur ce blog également.
Références:
- Présentation Cisco Live Atomic Configuration Replace (BRKENS-2604)
- Présentation Cisco Live – Modern approaches for IOS-XE network device management on Cat9K (DEVNET-11110)
- Article Blog- YangSuite, l’attente est finie
- Article Blog – J’ai testé: automatiser une fabric BGP EVPN VXLAN avec NETCONF
- Article Blog – J’ai testé: dial-in telemetry avec NETCONF
- Article Blog – J’ai testé… Ansible + NETCONF avec IOS-XE



