<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Articles | Florian Lacommare - Network Engineer</title><link>https://ipnull0.netlify.app/post/</link><atom:link href="https://ipnull0.netlify.app/post/index.xml" rel="self" type="application/rss+xml"/><description>Articles</description><generator>Wowchemy (https://wowchemy.com)</generator><language>en-us</language><image><url>https://ipnull0.netlify.app/images/icon_hu0b7a4cb9992c9ac0e91bd28ffd38dd00_9727_512x512_fill_lanczos_center_2.png</url><title>Articles</title><link>https://ipnull0.netlify.app/post/</link></image><item><title>Débuter avec YANG</title><link>https://ipnull0.netlify.app/post/debuter-avec-yang/</link><pubDate>Thu, 09 May 2019 00:00:00 +0000</pubDate><guid>https://ipnull0.netlify.app/post/debuter-avec-yang/</guid><description>&lt;p>Suite à mon &lt;a href="https://ipnull0.netlify.app/post/l-automatisation-reseau-multi-vendeurs-pari-tenu/" target="_blank">précédent article&lt;/a>
sur l&amp;rsquo;introduction de l&amp;rsquo;automatisation multi-vendeurs et à l&amp;rsquo;annonce de Jason Edelman la &lt;a href="https://www.networktocode.com/blog/post/open-source-model-driven-network-programmability/" target="_blank">semaine dernière&lt;/a> sur un nouveau projet &lt;a href="https://github.com/networktocode/yangify" target="_blank">Yangify&lt;/a>, il est intéressant de faire une introduction au langage YANG. Celui-ci est inspiré de l&amp;rsquo;article de &lt;a href="https://napalm-automation.net/yang-for-dummies/" target="_blank">David Barroso&lt;/a>.&lt;/p>
&lt;p> &lt;/p>
&lt;h2 id="yang-cest-quoi-">YANG, c&amp;rsquo;est quoi ?&lt;/h2>
&lt;p>YANG (Yet Another Next Generation) est un langage de modélisation de données qui permet de manipuler des états et configurations réseau. YANG est défini par de multiples RFC, &lt;a href="https://tools.ietf.org/html/rfc6020" target="_blank">RFC 6020&lt;/a> et la &lt;a href="https://tools.ietf.org/html/rfc7950" target="_blank">RFC 7950&lt;/a> pour la version 1.1.&lt;br>
Il ne faut pas confondre YANG, un langage, avec JSON ou XML, qui sont des formats de données. Et par ailleurs, comme on le verra dans l&amp;rsquo;article, YANG utilise nativement XML comme format et le support du JSON est ajouté par la &lt;a href="https://tools.ietf.org/html/rfc7951" target="_blank">RFC 7951&lt;/a>.&lt;/p>
&lt;p> &lt;/p>
&lt;h2 id="terminologie">Terminologie&lt;/h2>
&lt;p>Je vais tenter d&amp;rsquo;expliquer simplement les termes YANG que je vais utiliser dans cet article, cependant sachez qu&amp;rsquo;il en existe d&amp;rsquo;autres, que vous trouverez dans la &lt;a href="https://tools.ietf.org/html/rfc6020#section-3" target="_blank">RFC 6020 section 3&lt;/a> :&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>module&lt;/strong> : Un module YANG défini une hiérarchie de noeuds, ou autrement dit, un ensemble hiérarchisé de données, qui peuvent être utilisés par NETCONF (protocole de communication avec les équipements réseaux).&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>leaf&lt;/strong> : C&amp;rsquo;est un noeud qui contiendra une valeur lorsque le module sera instancié.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>list&lt;/strong> : C&amp;rsquo;est un noeud qui comporte un ensemble de noeuds enfants et qui peut être instancié plusieurs fois. Plus simplement, c&amp;rsquo;est une liste comme dans tout type de langage. Chaque entrée de la liste doit avoir un identifiant unique.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>grouping&lt;/strong> : Cela défini un ensemble de noeuds qui peut être utilisé dans un module (qu&amp;rsquo;il soit local, ou dans un des modules qui l&amp;rsquo;inclu ou l&amp;rsquo;importe).&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>identity&lt;/strong> : Permet de définir un type abstrait et unique.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>container&lt;/strong> : Ne contient pas de valeur mais un ensemble de noeuds.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>augment&lt;/strong> : Ajoute un nouveau schéma, une hiérachie, à un module déjà existant.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p> &lt;/p>
&lt;h2 id="cas-dusage">Cas d&amp;rsquo;usage&lt;/h2>
&lt;h3 id="création-dun-modèle">Création d&amp;rsquo;un modèle&lt;/h3>
&lt;p>Afin de comprendre le fonctionnement de YANG, prenons l&amp;rsquo;exemple d&amp;rsquo;un inventaire de voiture à vendre.&lt;br>
Pour commencer, nous allons créer notre structure permettant d&amp;rsquo;ajouter des voitures sous forme de liste.&lt;/p>
&lt;p>Les différentes informations dont nous avons besoins sont :&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>name&lt;/strong>, qui sera le nom du vendeur. Son type est une chaîne de caractères&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>inService&lt;/strong>, l&amp;rsquo;année de mise en service, que l&amp;rsquo;on souhaite démarrer à 2009, année de mise en place du nouveau système d&amp;rsquo;immatriculation, ainsi, voici le type de valeur attendu :&lt;/p>
&lt;/li>
&lt;/ul>
&lt;pre>&lt;code class="language-plaintext">typedef yearInService {
type uint16 {
range 2009..2999;
}
}
&lt;/code>&lt;/pre>
&lt;ul>
&lt;li>&lt;strong>numberplate&lt;/strong>, la plaque d&amp;rsquo;immatriculation utilisant le système SIV (ex: AB-120-CD) :&lt;/li>
&lt;/ul>
&lt;pre>&lt;code class="language-plaintext">typedef numberplate {
type string {
pattern '[a-zA-Z]{2}-[0-9]{3}-[a-zA-Z]{2}';
}
}
&lt;/code>&lt;/pre>
&lt;ul>
&lt;li>&lt;strong>brand&lt;/strong>, qui répresente la marque du véhicule. Pour la représenter, nous allons créer une &lt;code>identity&lt;/code> pour identifier chaque possibilité :&lt;/li>
&lt;/ul>
&lt;pre>&lt;code class="language-plaintext">identity BRAND {
description &amp;quot;Describe the brand of the vehicule&amp;quot;;
}
identity RENAULT {
base BRAND;
description &amp;quot;Vehicule manufactured by Renault&amp;quot;;
}
identity PEUGEOT {
base BRAND;
description &amp;quot;Vehicule manufactured by Peugeot&amp;quot;;
}
&lt;/code>&lt;/pre>
&lt;p>Maintenant que le principal est fait, il ne reste plus qu&amp;rsquo;à créer le module :&lt;/p>
&lt;pre>&lt;code class="language-plaintext">// module name
module sell-vehicule {
yang-version &amp;quot;1&amp;quot;;
namespace &amp;quot;http://flolaco.ovh/post/debuter-avec-yang/&amp;quot;;
prefix &amp;quot;sell-vehicule&amp;quot;;
// identity to identify the brand of the vehicule
identity BRAND {
description &amp;quot;Describe the brand of the vehicule&amp;quot;;
}
identity RENAULT {
base BRAND;
description &amp;quot;Vehicule manufactured by Renault&amp;quot;;
}
identity PEUGEOT {
base BRAND;
description &amp;quot;Vehicule manufactured by Peugeot&amp;quot;;
}
// new type to enforce the date
typedef yearInService {
type uint16 {
range 2009..2999;
}
}
// new type to enforce the numberplate
typedef numberplate {
type string {
pattern '[a-zA-Z]{2}-[0-9]{3}-[a-zA-Z]{2}';
}
}
// this grouping gather all data assigned to vehicules
grouping vehicule-data {
leaf name {
type string;
}
leaf inService {
type yearInService;
}
leaf numberplate {
type numberplate;
}
leaf brand {
type identityref {
base sell-vehicule:BRAND;
}
}
}
// this is the root object defined by the model
container stock {
list vehicule {
// identify each vehicule by using it's numberplate
key &amp;quot;numberplate&amp;quot;;
// each vehicule have the elements defined in the grouping
uses vehicule-data;
}
}
}
&lt;/code>&lt;/pre>
&lt;p>Dans le module, nous avons créé un &lt;code>grouping&lt;/code> qui permet de regrouper toutes les données de chaque véhicule puis en enfin un &lt;code>container&lt;/code> afin de contenir notre &lt;code>list&lt;/code> de véhicules. Notez que la &lt;code>key&lt;/code> de chaque élément de la liste (les véhicules) est la plaque d&amp;rsquo;immatriculation.&lt;/p>
&lt;p> &lt;/p>
&lt;h3 id="utilisation-du-modèle">Utilisation du modèle&lt;/h3>
&lt;p>Pour la suite de l&amp;rsquo;article, nous allons utiliser l&amp;rsquo;outil &lt;code>pyang&lt;/code> qui nous permet de représenter les modèles YANG sous une forme d&amp;rsquo;arbre. Nous allons également utiliser &lt;code>pyangbind&lt;/code> qui est un plugin de &lt;code>pyang&lt;/code> permettant de générer un code Python capable de fonctionner avec un modèle YANG particulier.&lt;/p>
&lt;p>L&amp;rsquo;installation de cet outil est très simple :
&lt;code>pip install pyang pyangbind&lt;/code>&lt;/p>
&lt;p>Pour représenter notre modèle sous la forme d&amp;rsquo;un arbre :&lt;/p>
&lt;pre>&lt;code class="language-shell">$ pyang -f tree sell-vehicule.yang
module: sell-vehicule
+--rw stock
+--rw vehicule* [numberplate]
+--rw name? string
+--rw inService? yearInService
+--rw numberplate numberplate
+--rw brand? identityref
&lt;/code>&lt;/pre>
&lt;p>Notez que &lt;code>numberplate&lt;/code> ne contient pas de &lt;code>?&lt;/code> car il représente la clé de la liste.&lt;br>
Il est temps de générer notre code Python pour tester notre modèle YANG grâce au plugin &lt;code>pyangbind&lt;/code> :&lt;/p>
&lt;pre>&lt;code class="language-shell">$ export PYBINDPLUGIN=`/usr/bin/env python -c \
'import pyangbind; \
import os; print &amp;quot;%s/plugin&amp;quot; % os.path.dirname(pyangbind.__file__)'`
$ pyang --plugindir $PYBINDPLUGIN -f pybind sell-vehicule.yang &amp;gt; sell_vehicule.py
&lt;/code>&lt;/pre>
&lt;p>Maintenant que notre code Python a été généré on peut le tester :&lt;/p>
&lt;pre>&lt;code class="language-python">&amp;gt;&amp;gt;&amp;gt; import sell_vehicule
&amp;gt;&amp;gt;&amp;gt;
&amp;gt;&amp;gt;&amp;gt; v = sell_vehicule.sell_vehicule()
&amp;gt;&amp;gt;&amp;gt;
&amp;gt;&amp;gt;&amp;gt; flo = v.stock.vehicule.add(&amp;quot;AA-101-ZZ&amp;quot;)
&amp;gt;&amp;gt;&amp;gt; flo.inService = 2009
&amp;gt;&amp;gt;&amp;gt; flo.name = &amp;quot;Flo&amp;quot;
&amp;gt;&amp;gt;&amp;gt; flo.brand = &amp;quot;RENAULT&amp;quot;
&amp;gt;&amp;gt;&amp;gt;
&amp;gt;&amp;gt;&amp;gt; laco = v.stock.vehicule.add(&amp;quot;AB-987-CD&amp;quot;)
&amp;gt;&amp;gt;&amp;gt; laco.inService = 2011
&amp;gt;&amp;gt;&amp;gt; laco.name = &amp;quot;Lacommare&amp;quot;
&amp;gt;&amp;gt;&amp;gt; laco.brand = &amp;quot;PEUGEOT&amp;quot;
&amp;gt;&amp;gt;&amp;gt;
&amp;gt;&amp;gt;&amp;gt; jeff = v.stock.vehicule.add(&amp;quot;FL-999-LF&amp;quot;)
&amp;gt;&amp;gt;&amp;gt; jeff.inService = 2031
&amp;gt;&amp;gt;&amp;gt; jeff.name = &amp;quot;Jeff&amp;quot;
&amp;gt;&amp;gt;&amp;gt; jeff.brand = &amp;quot;RENAULT&amp;quot;
&amp;gt;&amp;gt;&amp;gt;
&amp;gt;&amp;gt;&amp;gt;
&amp;gt;&amp;gt;&amp;gt; import json
&amp;gt;&amp;gt;&amp;gt; print(json.dumps(v.get(), indent=4))
{
&amp;quot;stock&amp;quot;: {
&amp;quot;vehicule&amp;quot;: {
&amp;quot;AA-101-ZZ&amp;quot;: {
&amp;quot;brand&amp;quot;: &amp;quot;RENAULT&amp;quot;,
&amp;quot;name&amp;quot;: &amp;quot;Flo&amp;quot;,
&amp;quot;numberplate&amp;quot;: &amp;quot;AA-101-ZZ&amp;quot;,
&amp;quot;inService&amp;quot;: 2009
},
&amp;quot;AB-987-CD&amp;quot;: {
&amp;quot;brand&amp;quot;: &amp;quot;PEUGEOT&amp;quot;,
&amp;quot;name&amp;quot;: &amp;quot;Lacommare&amp;quot;,
&amp;quot;numberplate&amp;quot;: &amp;quot;AB-987-CD&amp;quot;,
&amp;quot;inService&amp;quot;: 2011
},
&amp;quot;FL-999-LF&amp;quot;: {
&amp;quot;brand&amp;quot;: &amp;quot;RENAULT&amp;quot;,
&amp;quot;name&amp;quot;: &amp;quot;Jeff&amp;quot;,
&amp;quot;numberplate&amp;quot;: &amp;quot;FL-999-LF&amp;quot;,
&amp;quot;inService&amp;quot;: 2031
}
}
}
}
&lt;/code>&lt;/pre>
&lt;p>Testons maintenant la création d&amp;rsquo;une entrée avec le format d&amp;rsquo;une plaque d&amp;rsquo;immatriculation incorrect :&lt;/p>
&lt;pre>&lt;code class="language-python">&amp;gt;&amp;gt;&amp;gt; willfail = v.stock.vehicule.add(&amp;quot;KAFE-9-KAFE&amp;quot;)
Traceback (most recent call last):
File &amp;quot;&amp;lt;stdin&amp;gt;&amp;quot;, line 1, in &amp;lt;module&amp;gt;
File &amp;quot;/usr/local/lib/python2.7/site-packages/pyangbind/lib/yangtypes.py&amp;quot;, line 760, in add
self.__set(_k=k)
File &amp;quot;/usr/local/lib/python2.7/site-packages/pyangbind/lib/yangtypes.py&amp;quot;, line 679, in __set
raise KeyError(&amp;quot;key value must be valid, %s&amp;quot; % m)
KeyError: u'key value must be valid, {\'error-string\': \'numberplate must be of a type compatible with numberplate\', \'generated-type\': \'YANGDynClass(base=RestrictedClassType(base_type=six.text_type, restriction_dict={u\\\'pattern\\\': u\\\'[a-zA-Z]{2}-[0-9]{3}-[a-zA-Z]{2}\\\'}), is_leaf=True, yang_name=&amp;quot;numberplate&amp;quot;, parent=self, path_helper=self._path_helper, extmethods=self._extmethods, register_paths=True, is_keyval=True, namespace=\\\'http://flolaco.ovh/post/debuter-avec-yang/\\\', defining_module=\\\'sell-vehicule\\\', yang_type=\\\'numberplate\\\', is_config=True)\', \'defined-type\': \'sell-vehicule:numberplate\'}'
&lt;/code>&lt;/pre>
&lt;p>Nous avons une erreur, normal car le format est incorrect.&lt;br>
Et maintenant imaginons qu&amp;rsquo;on souhaite ajouter une voiture Dacia :&lt;/p>
&lt;pre>&lt;code class="language-python">&amp;gt;&amp;gt;&amp;gt; dacia = v.stock.vehicule.add(&amp;quot;DA-030-IA&amp;quot;)
&amp;gt;&amp;gt;&amp;gt; dacia.inService = 2019
&amp;gt;&amp;gt;&amp;gt; dacia.name = &amp;quot;John Doe&amp;quot;
&amp;gt;&amp;gt;&amp;gt; dacia.brand = &amp;quot;DACIA&amp;quot;
Traceback (most recent call last):
File &amp;quot;&amp;lt;stdin&amp;gt;&amp;quot;, line 1, in &amp;lt;module&amp;gt;
File &amp;quot;sell_vehicule.py&amp;quot;, line 199, in _set_brand
'generated-type': &amp;quot;&amp;quot;&amp;quot;YANGDynClass(base=RestrictedClassType(base_type=six.text_type, restriction_type=&amp;quot;dict_key&amp;quot;, restriction_arg={u'sell-vehicule:RENAULT': {u'@namespace': u'http://flolaco.ovh/post/debuter-avec-yang/', u'@module': u'sell-vehicule'}, u'sell-vehicule:PEUGEOT': {u'@namespace': u'http://flolaco.ovh/post/debuter-avec-yang/', u'@module': u'sell-vehicule'}, u'PEUGEOT': {u'@namespace': u'http://flolaco.ovh/post/debuter-avec-yang/', u'@module': u'sell-vehicule'}, u'RENAULT': {u'@namespace': u'http://flolaco.ovh/post/debuter-avec-yang/', u'@module': u'sell-vehicule'}},), is_leaf=True, yang_name=&amp;quot;brand&amp;quot;, parent=self, path_helper=self._path_helper, extmethods=self._extmethods, register_paths=True, namespace='http://flolaco.ovh/post/debuter-avec-yang/', defining_module='sell-vehicule', yang_type='identityref', is_config=True)&amp;quot;&amp;quot;&amp;quot;,
ValueError: {'error-string': 'brand must be of a type compatible with identityref', 'generated-type': 'YANGDynClass(base=RestrictedClassType(base_type=six.text_type, restriction_type=&amp;quot;dict_key&amp;quot;, restriction_arg={u\'sell-vehicule:RENAULT\': {u\'@namespace\': u\'http://flolaco.ovh/post/debuter-avec-yang/\', u\'@module\': u\'sell-vehicule\'}, u\'sell-vehicule:PEUGEOT\': {u\'@namespace\': u\'http://flolaco.ovh/post/debuter-avec-yang/\', u\'@module\': u\'sell-vehicule\'}, u\'PEUGEOT\': {u\'@namespace\': u\'http://flolaco.ovh/post/debuter-avec-yang/\', u\'@module\': u\'sell-vehicule\'}, u\'RENAULT\': {u\'@namespace\': u\'http://flolaco.ovh/post/debuter-avec-yang/\', u\'@module\': u\'sell-vehicule\'}},), is_leaf=True, yang_name=&amp;quot;brand&amp;quot;, parent=self, path_helper=self._path_helper, extmethods=self._extmethods, register_paths=True, namespace=\'http://flolaco.ovh/post/debuter-avec-yang/\', defining_module=\'sell-vehicule\', yang_type=\'identityref\', is_config=True)', 'defined-type': 'sell-vehicule:identityref'}
&lt;/code>&lt;/pre>
&lt;p> &lt;/p>
&lt;h2 id="étendre-le-modèle">Étendre le modèle&lt;/h2>
&lt;p>Comme nous venons de le voir, il est impossible d&amp;rsquo;ajouter une voiture d&amp;rsquo;une nouvelle marque si notre modèle YANG ne le supporte pas. Et si on voulait ajouter une information supplémentaire : Neuve ou d&amp;rsquo;occassion ?&lt;/p>
&lt;p>C&amp;rsquo;est tout à fait possible, YANG est puissant pour rajouter des compléments dans un modèle existant. En effet, nous ne sommes pas obligé de modifier le modèle original, ni de faire un fork de celui-ci.&lt;br>
Nous pouvons simplement importer l&amp;rsquo;ancien et ajouter nos nouveautés comme suit :&lt;/p>
&lt;pre>&lt;code class="language-plaintext">module sell-vehicule-ext {
yang-version &amp;quot;1&amp;quot;;
namespace &amp;quot;http://flolaco.ovh/post/debuter-avec-yang/ext&amp;quot;;
prefix &amp;quot;sell-vehicule-ext&amp;quot;;
// We import the old model
import sell-vehicule { prefix sv; }
// New manufacture based on the old BRAND
identity DACIA {
base sv:BRAND;
description &amp;quot;Vehicule manufactured by Renault-Dacia&amp;quot;;
}
// We are adding more information to the vehicule
// data of the old model
grouping ext-vehicule-data {
leaf category {
type enumeration {
enum NEW {
description &amp;quot;New vehicule, never used&amp;quot;;
}
enum USED {
description &amp;quot;Vehicule already used&amp;quot;;
}
}
default NEW;
}
}
// We are actually adding new stuff in the old model
augment &amp;quot;/sv:stock/sv:vehicule&amp;quot; {
uses ext-vehicule-data;
}
}
&lt;/code>&lt;/pre>
&lt;p>La force d&amp;rsquo;utiliser ce système d&amp;rsquo;extension est que si le modèle original subit des changements, notre modèle va également en bénéficier.&lt;br>
Maintenant, affichons notre modèle sous forme d&amp;rsquo;arbre et essayons de créer nos données :&lt;/p>
&lt;pre>&lt;code class="language-shell">$ pyang -f tree sell-vehicule-ext.yang sell-vehicule.yang
module: sell-vehicule
+--rw stock
+--rw vehicule* [numberplate]
+--rw name? string
+--rw inService? yearInService
+--rw numberplate numberplate
+--rw brand? identityref
+--rw sell-vehicule-ext:category? enumeration
$ pyang --plugindir $PYBINDPLUGIN -f pybind sell-vehicule-ext.yang sell-vehicule.yang &amp;gt; sell_vehicule_ext.py
&lt;/code>&lt;/pre>
&lt;pre>&lt;code class="language-python">&amp;gt;&amp;gt;&amp;gt; import sell_vehicule_ext
&amp;gt;&amp;gt;&amp;gt;
&amp;gt;&amp;gt;&amp;gt; v = sell_vehicule_ext.sell_vehicule()
&amp;gt;&amp;gt;&amp;gt;
&amp;gt;&amp;gt;&amp;gt; flo = v.stock.vehicule.add(&amp;quot;AA-101-ZZ&amp;quot;)
&amp;gt;&amp;gt;&amp;gt; flo.inService = 2009
&amp;gt;&amp;gt;&amp;gt; flo.name = &amp;quot;Flo&amp;quot;
&amp;gt;&amp;gt;&amp;gt; flo.brand = &amp;quot;RENAULT&amp;quot;
&amp;gt;&amp;gt;&amp;gt;
&amp;gt;&amp;gt;&amp;gt; laco = v.stock.vehicule.add(&amp;quot;AB-987-CD&amp;quot;)
&amp;gt;&amp;gt;&amp;gt; laco.inService = 2011
&amp;gt;&amp;gt;&amp;gt; laco.name = &amp;quot;Lacommare&amp;quot;
&amp;gt;&amp;gt;&amp;gt; laco.brand = &amp;quot;PEUGEOT&amp;quot;
&amp;gt;&amp;gt;&amp;gt;
&amp;gt;&amp;gt;&amp;gt; jeff = v.stock.vehicule.add(&amp;quot;FL-999-LF&amp;quot;)
&amp;gt;&amp;gt;&amp;gt; jeff.inService = 2031
&amp;gt;&amp;gt;&amp;gt; jeff.name = &amp;quot;Jeff&amp;quot;
&amp;gt;&amp;gt;&amp;gt; jeff.brand = &amp;quot;RENAULT&amp;quot;
&amp;gt;&amp;gt;&amp;gt;
&amp;gt;&amp;gt;&amp;gt; dacia = v.stock.vehicule.add(&amp;quot;DA-030-IA&amp;quot;)
&amp;gt;&amp;gt;&amp;gt; dacia.inService = 2019
&amp;gt;&amp;gt;&amp;gt; dacia.name = &amp;quot;John Doe&amp;quot;
&amp;gt;&amp;gt;&amp;gt; dacia.brand = &amp;quot;DACIA&amp;quot;
&amp;gt;&amp;gt;&amp;gt; dacia.category = &amp;quot;USED&amp;quot;
&amp;gt;&amp;gt;&amp;gt;
&amp;gt;&amp;gt;&amp;gt; import json
&amp;gt;&amp;gt;&amp;gt; print(json.dumps(v.get(), indent=4))
{
&amp;quot;stock&amp;quot;: {
&amp;quot;vehicule&amp;quot;: {
&amp;quot;AA-101-ZZ&amp;quot;: {
&amp;quot;category&amp;quot;: &amp;quot;NEW&amp;quot;,
&amp;quot;brand&amp;quot;: &amp;quot;RENAULT&amp;quot;,
&amp;quot;name&amp;quot;: &amp;quot;Flo&amp;quot;,
&amp;quot;numberplate&amp;quot;: &amp;quot;AA-101-ZZ&amp;quot;,
&amp;quot;inService&amp;quot;: 2009
},
&amp;quot;AB-987-CD&amp;quot;: {
&amp;quot;category&amp;quot;: &amp;quot;NEW&amp;quot;,
&amp;quot;brand&amp;quot;: &amp;quot;PEUGEOT&amp;quot;,
&amp;quot;name&amp;quot;: &amp;quot;Lacommare&amp;quot;,
&amp;quot;numberplate&amp;quot;: &amp;quot;AB-987-CD&amp;quot;,
&amp;quot;inService&amp;quot;: 2011
},
&amp;quot;FL-999-LF&amp;quot;: {
&amp;quot;category&amp;quot;: &amp;quot;NEW&amp;quot;,
&amp;quot;brand&amp;quot;: &amp;quot;RENAULT&amp;quot;,
&amp;quot;name&amp;quot;: &amp;quot;Jeff&amp;quot;,
&amp;quot;numberplate&amp;quot;: &amp;quot;FL-999-LF&amp;quot;,
&amp;quot;inService&amp;quot;: 2031
},
&amp;quot;DA-030-IA&amp;quot;: {
&amp;quot;category&amp;quot;: &amp;quot;USED&amp;quot;,
&amp;quot;brand&amp;quot;: &amp;quot;DACIA&amp;quot;,
&amp;quot;name&amp;quot;: &amp;quot;John Doe&amp;quot;,
&amp;quot;numberplate&amp;quot;: &amp;quot;DA-030-IA&amp;quot;,
&amp;quot;inService&amp;quot;: 2019
}
}
}
}
&lt;/code>&lt;/pre>
&lt;p> &lt;/p>
&lt;h2 id="exemple-appliqué-au-réseau">Exemple appliqué au réseau&lt;/h2>
&lt;p>Maintenant que l&amp;rsquo;on a fait une brève introduction du langage YANG, il est intéressant de voir l&amp;rsquo;usage qui en est fait par &lt;code>napalm-yang&lt;/code>. OpenConfig, qui est un groupe de travail pour la création de modèle YANG multi-vendeur, a créé (entre autre) un modèle pour définir les interfaces réseaux des équipements.&lt;/p>
&lt;p>Cependant, ils n&amp;rsquo;ont pas pris en compte le support des IP &lt;code>secondary&lt;/code> de certains constructeurs. &lt;code>napalm-yang&lt;/code> a donc créé un modèle qui étend celui d'&lt;a href="https://github.com/openconfig/public/blob/master/release/models/interfaces/openconfig-if-ip.yang" target="_blank">openconfig-if-ip&lt;/a> :&lt;/p>
&lt;pre>&lt;code class="language-plaintext">module napalm-if-ip {
yang-version &amp;quot;1&amp;quot;;
namespace &amp;quot;https://github.com/napalm-automation/napalm-yang/yang_napalm/interfaces&amp;quot;;
prefix &amp;quot;napalm-ip&amp;quot;;
import openconfig-interfaces { prefix oc-if; }
import openconfig-vlan { prefix oc-vlan; }
import openconfig-if-ip { prefix oc-ip; }
organization &amp;quot;NAPALM Automation&amp;quot;;
contact &amp;quot;napalm-automation@googlegroups.com&amp;quot;;
description &amp;quot;This module defines some augmentations to the interface's IP model of OC&amp;quot;;
revision &amp;quot;2017-03-17&amp;quot; {
description
&amp;quot;First release&amp;quot;;
reference &amp;quot;1.0.0&amp;quot;;
}
grouping secondary-top {
description &amp;quot;Add secondary statement&amp;quot;;
leaf secondary {
type boolean;
default &amp;quot;false&amp;quot;;
description
&amp;quot;Most platforms need a secondary statement on when configuring multiple IPv4
addresses on the same interfaces&amp;quot;;
reference &amp;quot;https://www.cisco.com/c/en/us/td/docs/ios/12_2/ip/configuration/guide/fipr_c/1cfipadr.html#wp1001012&amp;quot;;
}
}
augment &amp;quot;/oc-if:interfaces/oc-if:interface/&amp;quot; +
&amp;quot;oc-if:subinterfaces/oc-if:subinterface/&amp;quot; +
&amp;quot;oc-ip:ipv4/oc-ip:addresses/oc-ip:address/&amp;quot; +
&amp;quot;oc-ip:config&amp;quot; {
description &amp;quot;Add secondary statement to subinterfaces' IPs&amp;quot;;
uses secondary-top;
}
augment &amp;quot;/oc-if:interfaces/oc-if:interface/&amp;quot; +
&amp;quot;oc-vlan:routed-vlan/&amp;quot; +
&amp;quot;oc-ip:ipv4/oc-ip:addresses/oc-ip:address/&amp;quot; +
&amp;quot;oc-ip:config&amp;quot; {
description &amp;quot;Add secondary statement to routed VLANs' IPs&amp;quot;;
uses secondary-top;
}
}
&lt;/code>&lt;/pre>
&lt;p> &lt;/p>
&lt;p>Maintenant que YANG n&amp;rsquo;a plus de secret pour vous, je vous conseil d&amp;rsquo;aller jeter un oeil au nouveau projet &lt;a href="https://github.com/networktocode/yangify" target="_blank">Yangify&lt;/a> qui s&amp;rsquo;appuie justement sur des modèles YANG pour générer des configurations et vice-versa et qui fera sans doute l&amp;rsquo;objet d&amp;rsquo;un prochain article.&lt;/p></description></item><item><title>L'automatisation réseau multi-vendeurs, pari tenu ?</title><link>https://ipnull0.netlify.app/post/l-automatisation-reseau-multi-vendeurs-pari-tenu/</link><pubDate>Tue, 02 Oct 2018 00:00:00 +0000</pubDate><guid>https://ipnull0.netlify.app/post/l-automatisation-reseau-multi-vendeurs-pari-tenu/</guid><description>&lt;h3 id="lautomatisation-au-service-des-entreprises">L’automatisation au service des entreprises&lt;/h3>
&lt;p>Cela fait maintenant plusieurs années que les entreprises cherchent à gagner en agilité, en rapidité de déploiement pour un « Time To Market » de plus en plus court ou pour minimiser les risques opérationnels. Une des solutions pour répondre à ces enjeux est l’automatisation de son SI.&lt;/p>
&lt;p>L’automatisation a démarré il y a maintenant plusieurs années sur le domaine du système et de la virtualisation. Là où une équipe mettait plusieurs semaines pour provisionner un serveur, elle arrive à déployer une VM en quelques secondes. Peut-on en dire autant pour le réseau ?&lt;/p>
&lt;p> &lt;/p>
&lt;h3 id="lautomatisation-système-est-mature-et-maintenant-place-à-lautomatisation-réseau">L’automatisation système est mature. Et maintenant, place à l’automatisation réseau&lt;/h3>
&lt;p>Peut-on automatiser son réseau ? La réponse est bien évidemment oui, mais la vraie question à se poser est comment le faire ?&lt;/p>
&lt;p>La première réponse possible est d’intégrer un système d’automatisation adapté au fournisseur déjà en place dans la production. Une des principales difficultés avec cette approche apparaît lorsqu’on souhaite faire rentrer un nouveau fournisseur dans le parc déjà existant ou tout simplement quand on ajoute des équipements de gammes différentes. Dans ces cas-là, il faut soit multiplier les solutions d’automatisation (une par fournisseur, et rarement compatible), soit tout reconstruire pour l’adapter aux nouveaux équipements.&lt;/p>
&lt;p>La deuxième possibilité est d’intégrer dès le début une solution d’automatisation multi-vendeurs permettant de minimiser les adaptations / développements à réaliser en fonction des nouveaux fournisseurs. Pour répondre à cette problématique, il est possible soit de retenir une solution SDN multi-vendeurs, soit de bâtir une solution sur un framework comme NAPALM.&lt;/p>
&lt;p> &lt;/p>
&lt;h3 id="napalm-framework-dautomatisation-multi-vendeurs">NAPALM, framework d’automatisation multi-vendeurs&lt;/h3>
&lt;p>NAPALM est un framework open source agnostique, écrit en Python, qui utilise de façon unifiée les API des différents fournisseurs. Actuellement, ce framework supporte IOS, IOS-XR, NX-OS de Cisco, EOS d’Arista et JunOS de Juniper.&lt;/p>
&lt;figure id="figure-matrice-de-compatibilité-napalm-source--httpsnapalmreadthedocsioenlatestsupportindexhtml">&lt;img src="https://ipnull0.netlify.app/post/2019-05-06-l-automatisation-r%c3%a9seau-multi-vendeurs-pari-tenu_files/compatibility-matrix.png" alt="Matrice de compatibilité NAPALM (source : https://napalm.readthedocs.io/en/latest/support/index.html)" loading="lazy" data-zoomable
/>
&lt;figcaption>
Matrice de compatibilité NAPALM (source : &lt;a href="https://napalm.readthedocs.io/en/latest/support/index.html">https://napalm.readthedocs.io/en/latest/support/index.html&lt;/a>)
&lt;/figcaption>
&lt;/figure>
&lt;p> &lt;/p>
&lt;h3 id="un-framework-aux-multiples-interactions">Un framework aux multiples interactions&lt;/h3>
&lt;p>Ce framework regroupe plusieurs projets, dont un qui nous intéresse plus particulièrement : la bibliothèque NAPALM, du même nom que le framework. Cette bibliothèque permet de se connecter aux équipements réseaux et d’interagir avec eux par le biais de « getters » et de fonctions permettant la configuration, le tout via le développement de scripts en Python.&lt;/p>
&lt;pre>&lt;code class="language-python"># NAPALM code in Python
from napalm import get_network_driver
driver = get_network_driver(&amp;quot;nxos&amp;quot;)
device = driver(&amp;quot;IP&amp;quot;, &amp;quot;my_login&amp;quot;, &amp;quot;my_passwd&amp;quot;)
device.open()
mac_table = device.get_mac_address_table()
device.close()
&lt;/code>&lt;/pre>
&lt;p>Le projet « napalm-ansible » permet d’utiliser ce framework d’une autre façon, directement au sein de l’outil Ansible, très répandu dans le domaine de l’automatisation système. Ce modèle, malgré l’utilisation d’Ansible, utilisera toujours le back-end de NAPALM, ainsi, l’installation de la bibliothèque Python reste nécessaire.&lt;/p>
&lt;pre>&lt;code class="language-yaml">---
# Utilisation de NAPALM dans un playbook Ansible
- hosts: cisco
connection: no
gather_facts: no
tasks:
- name: Gather Facts
napalm_get_facts:
hostname: &amp;quot;{{ ansible_host }}&amp;quot;
username: &amp;quot;{{ ansible_user }}&amp;quot;
password: &amp;quot;{{ ansible_password }}&amp;quot;
dev_os: &amp;quot;nxos&amp;quot;
register: result
- name: Print Facts
debug: msg=&amp;quot;{{ result }}&amp;quot;
&lt;/code>&lt;/pre>
&lt;p> &lt;/p>
&lt;h3 id="des-uses-cases-qui-fonctionnent-">Des uses cases qui fonctionnent ….&lt;/h3>
&lt;p>Maintenant que l’utilisation du framework NAPALM n’a plus de secrets pour automatiser nos équipements, nous allons nous intéresser à différents use case. Si par exemple nous souhaitons connaitre les serveurs NTP de nos équipements, il est très facile de trouver cette information grâce à la méthode « get_ntp_servers() ».&lt;/p>
&lt;p>Si maintenant nous désirons en savoir plus sur les voisins BGP qui sont en peering avec nos équipements ainsi que leur statut, nous pouvons récupérer ces éléments grâce à la méthode « get_bgp_neighbors ».&lt;/p>
&lt;p> &lt;/p>
&lt;h3 id="-et-dautres-qui-ne-fonctionnent-pas">… et d’autres qui ne fonctionnent pas&lt;/h3>
&lt;p>En revanche, si nous souhaitons disposer de ces mêmes informations pour le protocole OSPF, alors nous constatons qu’il n’est pas possible de le faire car aujourd’hui il n’existe aucune implémentation d’une telle méthode dans le framework. De même, si nos équipements font partie d’une fabrique VXLAN, il n’existe aujourd’hui aucun support pour récupérer les informations des VNI, les informations MP-BGP EVPN ou autres.&lt;/p>
&lt;p>Pour répondre à ces problématiques, il existe différentes alternatives. La première est de développer par soi-même ces méthodes. Par exemple, vous pouvez trouver sur mon propre repository GitHub (&lt;a href="https://github.com/FloLaco/napalm">https://github.com/FloLaco/napalm&lt;/a>) l’ajout de plusieurs fonctionnalités (OSPF et VXLAN). Une autre possibilité, si nous utilisons Ansible et NAPALM, est de tirer profit des modules Ansible des différents équipementiers. Malheureusement, il y a plusieurs inconvénients à cela. Le premier est la perte du bénéfice initial de l’approche multi-vendeurs, et le deuxième est que, même avec ces modules, tout n’est pas disponible. Une autre alternative serait alors de changer d’approche et d’utiliser des modèles YANG comme par exemple OpenConfig.&lt;/p>
&lt;p> &lt;/p>
&lt;h3 id="napalm-oui--mais-pas-que-">NAPALM, oui ! mais pas que …&lt;/h3>
&lt;p>Au final, l’automatisation multi-vendeurs par le biais du framework NAPALM est possible et recommandée sous certaines conditions. Il est donc impératif de bien étudier les besoins d’automatisation initiaux pour s’assurer que tous les besoins sont bien couverts, et évaluer le cas échéant les développements complémentaires à réaliser. Cependant, il existe d’autres alternatives comme OpenConfig, qui fera certainement l’objet d’un autre article au regard de sa popularité grandissante.&lt;/p></description></item></channel></rss>