<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="https://www.w3.org/2005/Atom">
  <channel>
    <title>Michael Wadman</title>
    <description>My thoughts and experiences with all things IT</description>
    <link>https://mwadman.github.io/</link>
    <atom:link href="https://mwadman.github.io/feed.xml" rel="self" type="application/rss+xml" />
    <pubDate>Sun, 27 Aug 2023 05:03:23 +0000</pubDate>
    <lastBuildDate>Sun, 27 Aug 2023 05:03:23 +0000</lastBuildDate>
    <generator>Jekyll v3.9.3</generator>
    
      <item>
        <title>Viewing LibreNMS data in Grafana</title>
        <description>&lt;h1 id=&quot;overview&quot;&gt;Overview&lt;/h1&gt;

&lt;p&gt;LibreNMS is a great network device monitoring system, and Grafana is a wonderful tool for visualising and alerting on data from multiple sources.&lt;br /&gt;
Both are great examples of open-source software that you should be considering for your environment.&lt;/p&gt;

&lt;p&gt;However, while LibreNMS does provide &lt;a href=&quot;https://docs.librenms.org/Extensions/Metric-Storage/&quot;&gt;official integration&lt;/a&gt; with many external databases that you can then use as a data source in Grafana, if you don’t already have one of these in your environment it requires you to deploy these as well.&lt;br /&gt;
I’ve also personally run into performance issues with the &lt;a href=&quot;https://docs.librenms.org/Extensions/metrics/Prometheus/&quot;&gt;Prometheus Pushgateway integration&lt;/a&gt; when pushing a large number of metrics, probably because &lt;a href=&quot;https://prometheus.io/docs/practices/pushing/&quot;&gt;Pushgateway isn’t designed for that use case&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Recently I stumbled upon a &lt;a href=&quot;https://www.reddit.com/r/LibreNMS/comments/ojc8cc/how_to_almost_natively_integrate_librenms_and/&quot;&gt;Reddit post by user /u/wjhinz&lt;/a&gt; which described a method for “(almost) natively” using LibreNMS as a data source in Grafana by using &lt;a href=&quot;https://github.com/tbotnz/RRDReST&quot;&gt;RRDReST&lt;/a&gt; as an API endpoint to access the RRD files that LibreNMS creates.&lt;br /&gt;
After testing this and confirming it works very well, I wanted to add to the Reddit post by documenting what a containerised deployment of this solution looks like.&lt;/p&gt;

&lt;p&gt;Major kudos to both &lt;a href=&quot;https://www.reddit.com/user/tbotnz&quot;&gt;/u/tbotnz&lt;/a&gt; (for their work on RRDReST) and &lt;a href=&quot;https://www.reddit.com/user/wjhinz&quot;&gt;/u/wjhinz&lt;/a&gt; (for documenting this solution).&lt;/p&gt;

&lt;h1 id=&quot;containerised-deployment&quot;&gt;Containerised Deployment&lt;/h1&gt;

&lt;h2 id=&quot;librenms&quot;&gt;LibreNMS&lt;/h2&gt;

&lt;p&gt;I’ll be using Docker Compose for this deployment, and starting with the &lt;a href=&quot;https://github.com/librenms/docker/blob/master/examples/compose/docker-compose.yml&quot;&gt;LibreNMS docker example compose file&lt;/a&gt; as the base.&lt;br /&gt;
I’ve trimmed some services that aren’t needed (mstpd, syslog and SNMP traps), and included my compose file in an appendix section.&lt;/p&gt;

&lt;h2 id=&quot;rrdrest&quot;&gt;RRDReST&lt;/h2&gt;

&lt;p&gt;Next, we want to add an RRDReST container. As a container image doesn’t currently exist, we will need to create one.&lt;br /&gt;
Thanks to tbotnz, who has provided &lt;a href=&quot;https://github.com/tbotnz/RRDReST#getting-started&quot;&gt;instructions on how to get RRDReST running in his Github repository&lt;/a&gt;, creating a container image is relatively easy.&lt;br /&gt;
Here’s the &lt;a href=&quot;https://github.com/mwadman/RRDReST/blob/main/Dockerfile&quot;&gt;Dockerfile I’ve written&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-Dockerfile highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; python:3.10-alpine&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;RUN &lt;/span&gt;apk add g++ make rrdtool
&lt;span class=&quot;k&quot;&gt;COPY&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; requirements.txt /opt/RRDReST/requirements.txt&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;WORKDIR&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; /opt/RRDReST&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;RUN &lt;/span&gt;pip3 &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-r&lt;/span&gt; requirements.txt
&lt;span class=&quot;k&quot;&gt;COPY&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; . /opt/RRDReST&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ENTRYPOINT&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; [&quot;uvicorn&quot;, &quot;rrdrest:rrd_rest&quot;]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;CMD&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; [&quot;--host&quot;, &quot;0.0.0.0&quot;, &quot;--port&quot;, &quot;9000&quot;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I’ve built the container using this and pushed it to be &lt;a href=&quot;https://hub.docker.com/r/michaelwadman/rrdrest&quot;&gt;pulled from Docker Hub&lt;/a&gt; as well.&lt;/p&gt;

&lt;p&gt;To add this to our deployment, we simply need to add another service to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker-compose.yml&lt;/code&gt; file and give the container access to the LibreNMS volume (so it can read the RRD files).&lt;br /&gt;
I’m using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/opt/librenms&lt;/code&gt; as the mount point for the volume, as it mimics where data would be located in a non-containerised deployment.&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;...&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;rrdrest&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;michaelwadman/rrdrest:latest&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;container_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;rrdrest&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;./librenms:/opt/librenms&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As /u/wjhinz notes in their post, RRDReST needs read access to the RRD files, which should be fine with a docker-compose set up like this, but could be a good place to start investigations if it isn’t working for you.&lt;/p&gt;

&lt;h2 id=&quot;grafana&quot;&gt;Grafana&lt;/h2&gt;

&lt;p&gt;Finally, we want to add a Grafana container.&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;...&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;grafana&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;grafana/grafana-oss:latest&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;container_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;grafana&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;ports&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;3000&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;published&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;3000&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;protocol&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;tcp&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;GF_INSTALL_PLUGINS=marcusolsson-json-datasource&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note that I’m adding an environment variable for the installation of the &lt;a href=&quot;https://grafana.com/grafana/plugins/marcusolsson-json-datasource/&quot;&gt;JSON API plugin&lt;/a&gt;, as this is needed to interact with both the LibreNMS API as well as the RRDReST API.&lt;/p&gt;

&lt;h2 id=&quot;docker-compose-up&quot;&gt;docker-compose up&lt;/h2&gt;

&lt;p&gt;With a complete compose file, we can spin up the environment:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;docker-compose up &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt;
Creating network &lt;span class=&quot;s2&quot;&gt;&quot;librenms_grafana_default&quot;&lt;/span&gt; with the default driver
Creating librenms            ... &lt;span class=&quot;k&quot;&gt;done
&lt;/span&gt;Creating grafana             ... &lt;span class=&quot;k&quot;&gt;done
&lt;/span&gt;Creating librenms_db         ... &lt;span class=&quot;k&quot;&gt;done
&lt;/span&gt;Creating librenms_dispatcher ... &lt;span class=&quot;k&quot;&gt;done
&lt;/span&gt;Creating librenms_redis      ... &lt;span class=&quot;k&quot;&gt;done
&lt;/span&gt;Creating librenms_memcached  ... &lt;span class=&quot;k&quot;&gt;done
&lt;/span&gt;Creating rrdrest             ... &lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;adding-data-sources-in-grafana&quot;&gt;Adding data sources in Grafana&lt;/h1&gt;

&lt;h2 id=&quot;creating-librenms-user&quot;&gt;Creating LibreNMS user&lt;/h2&gt;

&lt;p&gt;To add LibreNMS as a data source in Grafana, we first need to create an API token in LibreNMS.&lt;br /&gt;
Visit the LibreNMS web interface and log in (in my case, “http://127.0.0.1:8000”, with the default credentials of librenms/librenms).&lt;/p&gt;

&lt;p&gt;Because Grafana will only require read access, we’re going to create a new user with read-only access and then associate the token we create with that user.&lt;br /&gt;
Under ‘Settings -&amp;gt; Manage Users’, I created a user named “grafana”, changed the access level to “Global Read” and set a random password as we will only be using the API access.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/librenms-create-user.png&quot; alt=&quot;Creating LibreNMS User&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/librenms-user-configuration.png&quot; alt=&quot;LibreNMS User Configuration&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Then, under ‘Settings -&amp;gt; API -&amp;gt; API Settings’, I created an API token for the grafana user:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/librenms-create-api-token.png&quot; alt=&quot;Creating LibreNMS API Token&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/librenms-api-token.png&quot; alt=&quot;LibreNMS API Configuration&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Make sure to copy the token when creating it, as we’ll need that later when adding the data source into LibreNMS.&lt;/p&gt;

&lt;h2 id=&quot;adding-librenms-data-source-in-grafana&quot;&gt;Adding LibreNMS data source in Grafana&lt;/h2&gt;

&lt;p&gt;After logging into the Grafana web interface (in my case, “http://127.0.0.1:3000”, with the default credentials of admin/admin), navigate to ‘Configuration -&amp;gt; Data Sources’ from the left pane.&lt;br /&gt;
Add a new data source and select the JSON API type from the list.&lt;/p&gt;

&lt;p&gt;In the settings for the LibreNMS API data source, we need to change the URL and add the token authentication header.&lt;br /&gt;
The URL should be set to your LibreNMS host and port, with the API endpoint of “/api/v0” appended.&lt;br /&gt;
Then, under “Custom HTTP Headers”, select “Add Header”. The header name will be “X-Auth-Token” and the value will be the token string that you created above.&lt;br /&gt;
Save and test that the API endpoint is working for you, and you should get a green “Success” pop-up if everything is working.&lt;/p&gt;

&lt;p&gt;My data source looked like the following when finished:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/grafana-librenms-datasource.png&quot; alt=&quot;Grafana LibreNMS data source&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;adding-rrdrest-data-source-in-grafana&quot;&gt;Adding RRDReST data source in Grafana&lt;/h2&gt;

&lt;p&gt;Like the above, we’re going to also add the RRDReST API as a new data source in Grafana too.&lt;br /&gt;
This will also be a JSON API, so select this from the data source type when creating it.&lt;/p&gt;

&lt;p&gt;In the settings for the RRDReST API data source, we only need to change the URL.&lt;br /&gt;
Again, point this towards your RRDReST container host and port, and leave the endpoint blank.&lt;br /&gt;
Save and test that the API endpoint is working for you, and you should get a red “Unprocessable Entity” pop-up if everything is working. This error means the API is reachable, but the plugin can’t process the data returned (which is expected, because there isn’t any data returned, as we haven’t pointed it to an RRD file yet).&lt;/p&gt;

&lt;p&gt;My data source looked like the following when finished:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/grafana-rrdrest-datasource.png&quot; alt=&quot;Grafana RRDReST data source&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;creating-a-dashboard&quot;&gt;Creating a dashboard&lt;/h2&gt;

&lt;p&gt;The last thing to do is to create a dashboard for the LibreNMS data to be visualised.&lt;br /&gt;
From the left pane in Grafana, select ‘Create -&amp;gt; Import’ and then upload the &lt;a href=&quot;https://pastebin.com/Bt2n0QgL&quot;&gt;JSON file created by /u/wjhinz on Pastebin&lt;/a&gt;. I’ve also included it in an appendix section below in the case that the Pastebin link goes away for some reason.&lt;/p&gt;

&lt;p&gt;After import, you’ll be prompted to name the dashboard, place it into a folder and select the data sources you created before. Here’s what mine looked like before import:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/grafana-rrdrest-dashboard-import.png&quot; alt=&quot;Grafana RRDReST Dashboard Import&quot; /&gt;&lt;/p&gt;

&lt;p&gt;There was one last item that I needed to change to get data displayed on the graph panels, which was to set the timezone to UTC. I believe this is needed because LibreNMS stores (or RRDReST represents) data in UTC format, but Grafana queries it with the local browser timezone by default.&lt;br /&gt;
To do so, drop-down the time picker from the top right of the dashboard screen, select “Change Time Settings” and choose UTC.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/grafana-dashboard-timezone.png&quot; alt=&quot;Grafana Dashboard Timezone&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If you’ve got devices in LibreNMS, they should appear up the top left of the page in a drop down menu along with a list of interfaces. After selecting a device and an interface, both the “Bandwidth In/Out” and “Errors In/Out” graphs will populate with information:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/grafana-rrdrest-dashboard-graphs.png&quot; alt=&quot;Grafana RRDReST Graphs&quot; /&gt;&lt;/p&gt;

&lt;p&gt;While the panels in the dashboard provided only show port throughput and errors, it’s pretty easy to pick up the other RRD files in a device directory and display those statistics as well.&lt;br /&gt;
For example, LibreNMS has created 64 other RRD files full of stats for my test device:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;docker &lt;span class=&quot;nb&quot;&gt;exec&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-it&lt;/span&gt; rrdrest &lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt; /opt/librenms/rrd/
Test_Device
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;docker &lt;span class=&quot;nb&quot;&gt;exec&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-it&lt;/span&gt; rrdrest &lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt; /opt/librenms/rrd/Test_Device/ | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; port | &lt;span class=&quot;nb&quot;&gt;wc&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-l&lt;/span&gt;
64
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;Providing RRDReST access to the RRD files that LibreNMS creates is not only easy, but it performs well too.&lt;br /&gt;
If you are already using Grafana in your environment to visualise, analyse and/or alert on data in a centralised fashion, then pulling SNMP metrics in through LibreNMS (and its’ device discovery feature) from devices that are otherwise unmonitored and using RRDReST as a data source is a great “quick win”.&lt;/p&gt;

&lt;h1 id=&quot;appendices&quot;&gt;Appendices&lt;/h1&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://www.reddit.com/r/LibreNMS/comments/ojc8cc/how_to_almost_natively_integrate_librenms_and/&quot;&gt;wjhinz’s Reddit Post&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://github.com/tbotnz/RRDReST&quot;&gt;RRDReST Repository&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://hub.docker.com/r/michaelwadman/rrdrest&quot;&gt;RRDReST Container Image&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://grafana.com/grafana/plugins/marcusolsson-json-datasource/&quot;&gt;Grafana JSON API Data source Plugin&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;versions-used&quot;&gt;Versions used&lt;/h2&gt;

&lt;p&gt;Desktop Machine: &lt;em&gt;Ubuntu 20.04&lt;/em&gt;&lt;br /&gt;
Docker: &lt;em&gt;20.10.12&lt;/em&gt;&lt;br /&gt;
Docker Compose: &lt;em&gt;1.26.2&lt;/em&gt;&lt;br /&gt;
LibreNMS: &lt;em&gt;21.11.0&lt;/em&gt;&lt;br /&gt;
Grafana: &lt;em&gt;8.3.3&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;full-code&quot;&gt;Full Code&lt;/h2&gt;

&lt;h3 id=&quot;docker-compose-file&quot;&gt;Docker Compose file&lt;/h3&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;3.5&quot;&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;mariadb:10.5&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;container_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;librenms_db&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;mysqld&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;--innodb-file-per-table=1&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;--lower-case-table-names=0&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;--character-set-server=utf8mb4&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;--collation-server=utf8mb4_unicode_ci&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;./db:/var/lib/mysql&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;TZ=Pacific/Auckland&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;MYSQL_ALLOW_EMPTY_PASSWORD=yes&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;MYSQL_DATABASE=librenms&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;MYSQL_USER=librenms&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;MYSQL_PASSWORD=asupersecretpassword&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;restart&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;always&lt;/span&gt;

  &lt;span class=&quot;na&quot;&gt;memcached&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;memcached:alpine&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;container_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;librenms_memcached&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;TZ=Pacific/Auckland&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;restart&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;always&lt;/span&gt;

  &lt;span class=&quot;na&quot;&gt;redis&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;redis:5.0-alpine&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;container_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;librenms_redis&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;TZ=Pacific/Auckland&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;restart&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;always&lt;/span&gt;

  &lt;span class=&quot;na&quot;&gt;librenms&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;librenms/librenms:latest&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;container_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;librenms&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;hostname&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;librenms&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;cap_add&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;NET_ADMIN&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;NET_RAW&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;ports&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;8000&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;published&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;8000&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;protocol&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;tcp&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;./librenms:/data&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;TZ=Pacific/Auckland&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;PUID=1000&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;PGID=1000&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;DB_HOST=db&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;DB_NAME=librenms&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;DB_USER=librenms&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;DB_PASSWORD=asupersecretpassword&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;DB_TIMEOUT=60&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;REDIS_HOST=redis&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;REDIS_PORT=6379&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;REDIS_DB=0&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;MEMORY_LIMIT=256M&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;UPLOAD_MAX_SIZE=16M&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;OPCACHE_MEM_SIZE=128&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;REAL_IP_FROM=0.0.0.0/32&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;REAL_IP_HEADER=X-Forwarded-For&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;LOG_IP_VAR=remote_addr&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;MEMCACHED_HOST=memcached&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;MEMCACHED_PORT=11211&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;LIBRENMS_WEATHERMAP=false&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;restart&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;always&lt;/span&gt;

  &lt;span class=&quot;na&quot;&gt;dispatcher&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;librenms/librenms:latest&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;container_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;librenms_dispatcher&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;hostname&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;librenms-dispatcher&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;cap_add&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;NET_ADMIN&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;NET_RAW&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;./librenms:/data&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;TZ=Pacific/Auckland&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;PUID=1000&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;PGID=1000&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;DB_HOST=db&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;DB_NAME=librenms&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;DB_USER=librenms&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;DB_PASSWORD=asupersecretpassword&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;DB_TIMEOUT=60&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;DISPATCHER_NODE_ID=dispatcher1&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;REDIS_HOST=redis&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;REDIS_PORT=6379&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;REDIS_DB=0&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;SIDECAR_DISPATCHER=1&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;MEMORY_LIMIT=256M&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;UPLOAD_MAX_SIZE=16M&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;OPCACHE_MEM_SIZE=128&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;REAL_IP_FROM=0.0.0.0/32&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;REAL_IP_HEADER=X-Forwarded-For&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;LOG_IP_VAR=remote_addr&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;MEMCACHED_HOST=memcached&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;MEMCACHED_PORT=11211&quot;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;LIBRENMS_WEATHERMAP=false&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;restart&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;always&lt;/span&gt;

  &lt;span class=&quot;na&quot;&gt;rrdrest&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;michaelwadman/rrdrest:latest&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;container_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;rrdrest&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;./librenms:/opt/librenms&quot;&lt;/span&gt;

  &lt;span class=&quot;na&quot;&gt;grafana&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;grafana/grafana-oss:latest&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;container_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;grafana&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;ports&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;3000&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;published&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;3000&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;protocol&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;tcp&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;GF_INSTALL_PLUGINS=marcusolsson-json-datasource&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;grafana-dashboard-json&quot;&gt;Grafana Dashboard JSON&lt;/h3&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;__inputs&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;DS_RRDREST_API&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;RRDRest API&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;datasource&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;pluginId&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;marcusolsson-json-datasource&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;pluginName&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;JSON API&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;DS_LIBRENMS_API&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;LibreNMS API&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;datasource&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;pluginId&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;marcusolsson-json-datasource&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;pluginName&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;JSON API&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;__requires&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;grafana&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;grafana&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Grafana&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;panel&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;graph&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Graph&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;datasource&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;marcusolsson-json-datasource&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;JSON API&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;1.2.1&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;annotations&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;list&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;builtIn&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;datasource&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;-- Grafana --&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;enable&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;hide&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;iconColor&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;rgba(0, 211, 255, 1)&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Annotations &amp;amp; Alerts&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;dashboard&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;editable&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;gnetId&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;graphTooltip&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;iteration&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1626152089476&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;links&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;panels&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;aliasColors&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;bars&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;dashLength&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;dashes&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;datasource&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;${DS_RRDREST_API}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;fieldConfig&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;defaults&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;custom&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;unit&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;bps&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;overrides&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;fill&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;fillGradient&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;gridPos&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;h&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;w&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;24&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;y&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;hiddenSeries&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;legend&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;avg&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;current&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;max&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;min&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;show&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;total&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;values&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;lines&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;linewidth&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;nullPointMode&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;null&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;options&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;alertThreshold&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;percentage&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;pluginVersion&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;7.3.5&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;pointradius&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;points&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;renderer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;flot&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;seriesOverrides&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;spaceLength&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;stack&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;steppedLine&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;targets&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;body&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;cacheDurationSeconds&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;fields&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;jsonPath&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;$.data[*].time&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;time&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;time&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;jsonPath&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;$.data[*].inoctets&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;inoctets&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;number&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;jsonPath&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;$.data[*].outoctets&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;outoctets&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;number&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;hide&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;method&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;GET&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;params&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;queryParams&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;refId&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;A&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;urlPath&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;?rrd_path=/opt/librenms/rrd/$device/port-id$portid.rrd&amp;amp;epoch_start_time=${__from:date:seconds}&amp;amp;epoch_end_time=${__to:date:seconds}&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;thresholds&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;timeFrom&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;timeRegions&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;timeShift&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;title&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Bandwidth In/Out&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tooltip&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;shared&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;sort&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;value_type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;individual&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;transformations&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;calculateField&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;options&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;alias&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;inMbps&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;binary&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;left&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;inoctets&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;operator&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;reducer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;sum&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;right&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;8&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;binary&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;reduce&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;include&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;inoctets&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;reducer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;lastNotNull&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;replaceFields&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;calculateField&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;options&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;alias&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;outMbps&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;binary&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;left&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;outoctets&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;operator&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;reducer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;sum&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;right&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;8&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;binary&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;reduce&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;reducer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;sum&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;replaceFields&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;filterFieldsByName&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;options&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;include&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;names&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;time&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;inMbps&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;outMbps&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;graph&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;xaxis&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;buckets&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;time&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;show&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;values&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;yaxes&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;$$hashKey&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;object:1546&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;format&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;bps&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;logBase&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;max&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;min&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;show&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;$$hashKey&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;object:1547&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;format&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;short&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;logBase&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;max&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;min&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;show&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;yaxis&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;align&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;alignLevel&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;aliasColors&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;bars&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;dashLength&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;dashes&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;datasource&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;${DS_RRDREST_API}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;fieldConfig&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;defaults&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;custom&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;unit&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;bps&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;overrides&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;fill&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;fillGradient&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;gridPos&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;h&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;w&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;24&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;y&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;hiddenSeries&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;legend&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;avg&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;current&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;max&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;min&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;show&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;total&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;values&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;lines&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;linewidth&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;nullPointMode&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;null&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;options&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;alertThreshold&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;percentage&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;pluginVersion&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;7.3.5&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;pointradius&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;points&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;renderer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;flot&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;seriesOverrides&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;spaceLength&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;stack&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;steppedLine&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;targets&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;body&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;cacheDurationSeconds&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;fields&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;jsonPath&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;$.data[*].time&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;time&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;time&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;jsonPath&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;$.data[*].inerrors&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;inerrors&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;number&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;jsonPath&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;$.data[*].outerrors&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;outerrors&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;number&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;hide&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;method&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;GET&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;params&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;queryParams&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;refId&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;A&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;urlPath&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;?rrd_path=/opt/librenms/rrd/$device/port-id$portid.rrd&amp;amp;epoch_start_time=${__from:date:seconds}&amp;amp;epoch_end_time=${__to:date:seconds}&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;thresholds&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;timeFrom&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;timeRegions&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;timeShift&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;title&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Errors In/Out&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tooltip&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;shared&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;sort&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;value_type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;individual&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;transformations&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;graph&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;xaxis&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;buckets&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;time&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;show&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;values&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;yaxes&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;$$hashKey&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;object:1546&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;format&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;bps&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;logBase&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;max&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;min&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;show&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;$$hashKey&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;object:1547&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;format&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;short&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;logBase&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;max&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;min&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;show&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;yaxis&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;align&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;alignLevel&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;refresh&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;30s&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;schemaVersion&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;26&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;style&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;dark&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tags&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;templating&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;list&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;allValue&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;current&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;datasource&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;${DS_LIBRENMS_API}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;definition&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;$.devices[*].hostname&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;error&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;hide&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;includeAll&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;multi&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;device&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;options&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;query&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;cacheDurationSeconds&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;fields&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;jsonPath&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;$.devices[*].hostname&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;method&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;GET&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;queryParams&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;urlPath&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/devices&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;refresh&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;regex&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;skipUrlSync&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;sort&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tagValuesQuery&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tags&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tagsQuery&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;query&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;useTags&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;allValue&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;current&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;datasource&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;${DS_LIBRENMS_API}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;definition&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;$.ports[*].port_id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;error&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;hide&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;includeAll&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Interface&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;multi&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;portid&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;options&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;query&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;cacheDurationSeconds&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;experimentalVariableTextField&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;ifName&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;experimentalVariableValueField&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;fields&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;jsonPath&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;$.ports[*].port_id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;jsonPath&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;$.ports[*].ifName&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;method&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;GET&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;queryParams&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;urlPath&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/devices/$device/ports?columns=ifName%2Cport_id&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;refresh&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;regex&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;skipUrlSync&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;sort&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tagValuesQuery&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tags&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tagsQuery&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;query&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;useTags&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;time&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;from&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;now-12h&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;to&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;now&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;timepicker&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;timezone&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;utc&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;title&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;LibreNMS RRDReST&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;uid&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;mFveL2mm1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;28&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</description>
        <pubDate>Sun, 02 Jan 2022 00:00:00 +0000</pubDate>
        <link>https://mwadman.github.io/2022/01/02/Viewing-LibreNMS-data-in-Grafana/</link>
        <guid isPermaLink="true">https://mwadman.github.io/2022/01/02/Viewing-LibreNMS-data-in-Grafana/</guid>
        
        <category>Monitoring</category>
        
        <category>Grafana</category>
        
        <category>LibreNMS</category>
        
        
      </item>
    
      <item>
        <title>Resolving my DNS issues - Disabling systemd-resolved on Ubuntu 18.04</title>
        <description>&lt;h1 id=&quot;overview&quot;&gt;Overview&lt;/h1&gt;

&lt;p&gt;The below snippet from my ~/.bash_aliases should illustrate my feelings towards systemd-resolved:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;grep &lt;/span&gt;resolved ~/.bash_aliases
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;fuck-resolved&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'sudo systemctl restart systemd-resolved'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For the longest time, I’ve put up with the pain-in-my-ass that is systemd-resolved and the constant issues that it has given me (not to mention the time spent troubleshooting various issues).
Today, I intend to resolve my issues once and for all.&lt;/p&gt;

&lt;p&gt;There are a ton of “guides” already on the internet (a google search for “disable systemd-resolved” has 179,000 results at the time of writing this).&lt;br /&gt;
The blog post &lt;a href=&quot;https://ohthehugemanatee.org/blog/2018/01/25/my-war-on-systemd-resolved/&quot;&gt;My War on Systemd-resolved&lt;/a&gt; is a good, quick read and gives some ideas on why the google search results differ ever-so-slightly from each other (but please don’t follow his proposed solution).&lt;br /&gt;
Like the above post, I intend to shut down systemd-resolved permanently, and document how (for Ubuntu 18.04 at least).&lt;/p&gt;

&lt;h1 id=&quot;disabling-systemd-resolved&quot;&gt;Disabling systemd-resolved&lt;/h1&gt;

&lt;p&gt;First up is disabling the systemd-resolved service.&lt;br /&gt;
Easy enough using systemctl:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;systemctl disable systemd-resolved
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;systemctl stop systemd-resolved
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Next, we’ll remove the existing “/etc/resolv.conf” file, which is currently a symbolic link to “/run/systemd/resolve/stub-resolv.conf”:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt; /etc/resolv.conf &lt;span class=&quot;nt&quot;&gt;-al&lt;/span&gt;
lrwxrwxrwx 1 root root 39 Jun 16  2018 /etc/resolv.conf -&amp;gt; ../run/systemd/resolve/stub-resolv.conf
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo rm&lt;/span&gt; /etc/resolv.conf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;reconfiguring-dns&quot;&gt;Reconfiguring DNS&lt;/h1&gt;

&lt;p&gt;There are now two paths you can take to configure your DNS, depending on whether you receive your DNS configuration via DHCP or not.&lt;br /&gt;
If you do, then we’ll configure NetworkManager to look after the “/etc/resolv.conf” file.&lt;br /&gt;
If you don’t, then simply configure this file statically yourself and you’re good to go.&lt;/p&gt;

&lt;h2 id=&quot;using-networkmanager&quot;&gt;Using NetworkManager&lt;/h2&gt;

&lt;p&gt;If you want to use the settings given out via DHCP, we need to reconfigure NetworkManager so that it starts to set this for us.&lt;br /&gt;
This is as simple as editing the file “/etc/NetworkManager/NetworkManager.conf” and setting (or adding, if not already present) the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dns&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rc-manager&lt;/code&gt; keys under the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[main]&lt;/code&gt; section, as below:&lt;/p&gt;

&lt;div class=&quot;language-ini highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;[main]&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;dns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;default&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;rc-manager&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;resolvconf&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then we’ll restart NetworkManager so that it’ll create us a new “/etc/resolv.conf” file:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;systemctl restart network-manager
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We can now verify that the new configuration has been picked up by checking the contents of “/etc/resolv.conf”:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cat&lt;/span&gt; /etc/resolv.conf
&lt;span class=&quot;c&quot;&gt;# Generated by NetworkManager&lt;/span&gt;
search example.com
nameserver 192.168.0.1
nameserver 192.168.0.2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;manual-configuration&quot;&gt;Manual configuration&lt;/h2&gt;

&lt;p&gt;If you’re not receiving DNS settings over DHCP, or you want to have manual control over this, then you can skip the NetworkManager configuration and simply start manually configuring the “/etc/resolv.conf” file yourself.&lt;/p&gt;

&lt;h1 id=&quot;appendices&quot;&gt;Appendices&lt;/h1&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://ohthehugemanatee.org/blog/2018/01/25/my-war-on-systemd-resolved/&quot;&gt;My War on Systemd-resolved&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://www.unixgr.com/disabling-systemd-resolvd-service-on-ubuntu-systems/&quot;&gt;Disabling systemd-resolvd service on Ubuntu systems&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://askubuntu.com/questions/1081832/how-do-i-disable-systemd-resolved-and-replace-with-something-sane-on-ubuntu-18/1081835&quot;&gt;AskUbuntu - How do I disable systemd-resolved and replace with something sane on Ubuntu 18?&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://blog.mesouug.com/2018/09/22/how-to-correctly-disable-systemd-resolved-on-ubuntu-18-04/&quot;&gt;How to correctly disable systemd-resolved on Ubuntu 18.04&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;versions-used&quot;&gt;Versions used&lt;/h2&gt;

&lt;p&gt;Desktop Machine: &lt;em&gt;kubuntu-18.04.3&lt;/em&gt;&lt;/p&gt;
</description>
        <pubDate>Sun, 22 Sep 2019 00:00:00 +0000</pubDate>
        <link>https://mwadman.github.io/2019/09/22/Disabling-resolved/</link>
        <guid isPermaLink="true">https://mwadman.github.io/2019/09/22/Disabling-resolved/</guid>
        
        <category>Ubuntu</category>
        
        
      </item>
    
      <item>
        <title>OpenStack Lab Network - Deployment Preparation</title>
        <description>&lt;h1 id=&quot;overview&quot;&gt;Overview&lt;/h1&gt;

&lt;p&gt;This post is the tenth in a series that plans to document my progress through installing and configuring a small OpenStack Lab.&lt;/p&gt;

&lt;p&gt;For other posts in this series, see the overview section of the &lt;a href=&quot;https://www.wadman.co.nz/2018/02/08/OpenStack-Lab-Network-Introduction/#overview&quot;&gt;introduction post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the &lt;a href=&quot;https://wadman.co.nz/2019/02/03/OpenStack-Lab-Host-Routing/&quot;&gt;last post&lt;/a&gt;, we installed and configured the FRR suite on our OpenStack hosts.
In this post, we’ll start making the final touches before we run OpenStack-Ansible.&lt;/p&gt;

&lt;h1 id=&quot;configuration&quot;&gt;Configuration&lt;/h1&gt;

&lt;p&gt;This post will be a quick one, with the goal of preparating our OpenStack hosts for the OpenStack services to be deployed to them.&lt;/p&gt;

&lt;p&gt;The steps that I’m going to cover will be a direct translation of what is listed in OpenStack-Ansible’s deployment guide. Specifically, the following pages:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.openstack.org/project-deploy-guide/openstack-ansible/latest/deploymenthost.html&quot;&gt;OpenStack-Ansible: Prepare the deployment host&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.openstack.org/project-deploy-guide/openstack-ansible/latest/targethosts.html&quot;&gt;OpenStack-Ansible: Prepare the target hosts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s start with the deployment host preparation.&lt;/p&gt;

&lt;h2 id=&quot;deployment-host&quot;&gt;Deployment Host&lt;/h2&gt;

&lt;p&gt;The deployment guide recommends that (in a testing environment) one of the control nodes act as the deployment host as well.&lt;br /&gt;
In production this role would instead be handed to a host that won’t be participating in the OpenStack services, to avoid potential conflicts occurring during initial deployment or upgrades (as the deployment host will act as the source of any future updates to OpenStack services).&lt;/p&gt;

&lt;h3 id=&quot;ansible-playbook-and-role&quot;&gt;Ansible Playbook and Role&lt;/h3&gt;

&lt;p&gt;With that in mind, let’s create a new role and add this to our existing playbook.&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Configuring OpenStack hosts&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;hosts&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;openstack_hosts&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;become&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;gather_facts&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;roles&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;role&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;openstack-interfaces&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;openstack-interfaces&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;role&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;openstack-routing&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;openstack-routing&lt;/span&gt;

&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Prepare deployment host&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;hosts&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;openstack-control&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;become&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;gather_facts&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;roles&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;role&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;openstack-deployment&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;openstack-deployment&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note that instead of adding this role onto the existing “Configuring OpenStack hosts” entry, I’ve defined another entry.&lt;br /&gt;
By doing this, I can specify that the role is only to be run on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hosts: openstack-control&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We’ll create the skeleton of our new role too.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; /etc/ansible/roles/openstack-deployment/tasks/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;packages&quot;&gt;Packages&lt;/h3&gt;

&lt;p&gt;As always, our first step is to ensure the required packages are installed on our host.&lt;br /&gt;
The deployment guide gives us a list of &lt;a href=&quot;https://docs.openstack.org/project-deploy-guide/openstack-ansible/latest/deploymenthost.html#configure-ubuntu&quot;&gt;required packages&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here’s what the first task in our file “/etc/ansible/roles/openstack-interfaces/tasks/main.yml” looks like:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Install prerequisite packages&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;apt&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;aptitude&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;build-essential&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;git&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ntp&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ntpdate&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;openssh-server&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;python-dev&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;sudo&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;latest&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;cache_valid_time&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;3600&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;clone-repository&quot;&gt;Clone Repository&lt;/h3&gt;

&lt;p&gt;Next, the guide says to clone their repository into the local directory “/opt/openstack-ansible”.&lt;br /&gt;
For this, we’ll use Ansible’s &lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/git_module.html&quot;&gt;“git” module&lt;/a&gt;.&lt;/p&gt;

&lt;!--  --&gt;
&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Clone openstack-ansible repository&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;git&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;repo&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;https://github.com/openstack/openstack-ansible&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;openstack_ansible_exec_dir&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;}}&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;stable/stein&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;!--  --&gt;

&lt;p&gt;This module has a ton of parameters that are able to be passed in, but we’re going to stay simple and use just the following:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;repo&lt;/code&gt; - The address to clone the repository from. I’ll use the projects Github mirror as I’ve had issues with the official repository link in the past.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dest&lt;/code&gt; - The directory to clone the repository into.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;version&lt;/code&gt; - The version of the repository to clone. In our case, we’re going to reference the branch named “stable/stein”, as we’ll be installing the OpenStack version named “Stein” using OpenStack-Ansible.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’ve also referenced the variable “openstack_ansible_exec_dir”, which isn’t yet defined.&lt;br /&gt;
I’m going to define this variable (as “/opt/openstack-ansible”), along with another variable we’ll use later, in the defaults file (“defaults/main.yml”) for this role:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;openstack_ansible_exec_dir&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;/opt/openstack-ansible&quot;&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;openstack_ansible_config_dir&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;/etc/openstack_deploy&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;ssh-authentication&quot;&gt;SSH Authentication&lt;/h3&gt;

&lt;p&gt;During the running of the OpenStack-Ansible playbooks, Ansible on the deployment host will attempt to connect as the root user to other remote nodes.&lt;br /&gt;
In order for this to work, we’ll need to create and then set the root users’ public key on the deployment (control) host as an authorised key on our compute host.&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Create a SSH key for the root user&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ssh-keygen -q -t rsa -b 4096 -f /root/.ssh/id_rsa -C &quot;&quot; -N &quot;&quot;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;creates&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/root/.ssh/id_rsa.pub&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The above command will create the ssh-key if it doesn’t already exist.&lt;br /&gt;
In the future, we should be able to use the new &lt;a href=&quot;https://docs.ansible.com/ansible/devel/modules/openssh_keypair_module.html&quot;&gt;“openssh_keypair”&lt;/a&gt; module, but this is currently only available in the development release.&lt;/p&gt;

&lt;p&gt;To store the contents of the public key file as a variable, we’ll use Ansible’s &lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/slurp_module.html&quot;&gt;“slurp”&lt;/a&gt; and &lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/set_fact_module.html&quot;&gt;“set_fact”&lt;/a&gt; modules.&lt;/p&gt;

&lt;!--  --&gt;
&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Get root user public key&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;slurp&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/root/.ssh/id_rsa.pub&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;register&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;root_pub_key&lt;/span&gt;

&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;set_fact&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;openstack_deploy_pub_key&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;root_pub_key['content']&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;b64decode&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;}}&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;!--  --&gt;

&lt;p&gt;“slurp” will gather the contents of a file on a remote host. Together with the &lt;a href=&quot;https://docs.ansible.com/ansible/latest/user_guide/playbooks_conditionals.html#register-variables&quot;&gt;“register”&lt;/a&gt; keyword, we can save this as a (base-64 encoded) variable.&lt;/p&gt;

&lt;p&gt;We then use “set_fact” to decode and save the result as another variable.&lt;br /&gt;
We need to save this off again, as the “register” action only saves the variable on the host the playbook is running on at the time, in our case the OpenStack control host, and we want this available across all of our hosts.&lt;/p&gt;

&lt;h3 id=&quot;bootstrap-openstack-ansible&quot;&gt;Bootstrap OpenStack-Ansible&lt;/h3&gt;

&lt;p&gt;The last step for the deployment host is to run the bootstrap script that was cloned in the step before.&lt;/p&gt;

&lt;!--  --&gt;
&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Run bootstrap-ansible.sh script&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;./scripts/bootstrap-ansible.sh&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;chdir&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;openstack_ansible_exec_dir&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;}}&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;creates&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;/usr/local/bin/openstack-ansible&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;!--  --&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;creates&lt;/code&gt; argument is a way of telling the task whether it needs to be run or not, by saying what file is created if it has been run successfully.&lt;br /&gt;
I’ve used the file “/usr/local/bin/openstack-ansible” as this is the last (we want the creation of the file to be as near to the end of the script as possible) file that is always created when the script is run.&lt;/p&gt;

&lt;h2 id=&quot;target-hosts&quot;&gt;Target Hosts&lt;/h2&gt;

&lt;p&gt;Onto the target hosts. The &lt;a href=&quot;https://docs.openstack.org/project-deploy-guide/openstack-ansible/latest/targethosts.html&quot;&gt;guide for which&lt;/a&gt; is the next page on from the deployment host guide.&lt;/p&gt;

&lt;h3 id=&quot;ansible-playbook-and-role-1&quot;&gt;Ansible Playbook and Role&lt;/h3&gt;

&lt;p&gt;We’ll add our new role to the playbook first:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Configuring OpenStack hosts&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;hosts&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;openstack_hosts&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;become&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;gather_facts&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;roles&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;role&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;openstack-interfaces&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;openstack-interfaces&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;role&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;openstack-routing&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;openstack-routing&lt;/span&gt;

&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Prepare deployment host&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;hosts&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;openstack-control&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;become&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;gather_facts&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;roles&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;role&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;openstack-deployment&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;openstack-deployment&lt;/span&gt;

&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Configuring OpenStack hosts&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;hosts&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;openstack_hosts&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;become&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;gather_facts&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;roles&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;role&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;openstack-preparation&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;openstack-preparation&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And our role creation.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; /etc/ansible/roles/openstack-preparation/tasks/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;packages-1&quot;&gt;Packages&lt;/h3&gt;

&lt;p&gt;You know the drill by now. &lt;a href=&quot;https://docs.openstack.org/project-deploy-guide/openstack-ansible/stein/targethosts.html#configure-ubuntu&quot;&gt;Pre-requisitie packages&lt;/a&gt; first.&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Install prerequisite packages&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;apt&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;bridge-utils&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;debootstrap&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ifenslave&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ifenslave-2.6&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;lsof&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;lvm2&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;openssh-server&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;python&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;sudo&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;tcpdump&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;vlan&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;latest&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;cache_valid_time&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;3600&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;kernel-modules&quot;&gt;Kernel Modules&lt;/h3&gt;

&lt;p&gt;After installing packages, the guide then says to complete the following:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Install the “linux-image-extra” package. For our case, this would be “linux-image-extra-virtual-hwe-18.04”, which doesn’t install anything other than a copyright text file in “/usr/share/doc”, at least at the time of writing this.&lt;/li&gt;
  &lt;li&gt;Configure the chrony service. The astute of you will notice that I have omitted the chrony package from the list in the previous step. This is because we really don’t need to worry about time drift in an ephemeral lab deployment like ours. Even in a production environment, I would consider just configuring ntpd correctly instead.&lt;/li&gt;
  &lt;li&gt;Load the kernel modules “8021q” and “bonding”. Since we aren’t bonding interfaces in our topology, we’ll just enable the 8021q module below.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Enable required kernel modules&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;modprobe&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;8021q&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Yes, that simple.&lt;/p&gt;

&lt;h3 id=&quot;ssh-authentication-1&quot;&gt;SSH Authentication&lt;/h3&gt;

&lt;p&gt;Carrying on from where we left off in the SSH Authentication section for the deployment host, we now have a variable which stores the public key of the root user.&lt;br /&gt;
All we need to do now is set this as an authorised key on all other hosts. Luckily there is an &lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/authorized_key_module.html&quot;&gt;Ansible module&lt;/a&gt; for doing just that.&lt;/p&gt;

&lt;!--  --&gt;
&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Set root user authorised ssh key&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;authorized_key&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;root&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;hostvars['openstack-control']['openstack_deploy_pub_key']&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;}}&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;!--  --&gt;

&lt;h3 id=&quot;storage&quot;&gt;Storage&lt;/h3&gt;

&lt;p&gt;Because we’ve already set up the networking, the last step is to &lt;a href=&quot;https://docs.openstack.org/project-deploy-guide/openstack-ansible/stein/targethosts.html#configuring-the-storage&quot;&gt;set up LVM storage&lt;/a&gt; for the Cinder (block storage) service and lxc.&lt;br /&gt;
We’ll be utilising the second hard disk that we set up on both of our OpenStack hosts in the &lt;a href=&quot;https://wadman.co.nz/2018/04/08/OpenStack-Lab-Network-Vagrant/#storage&quot;&gt;Vagrant configuration&lt;/a&gt;.&lt;/p&gt;

&lt;!--  --&gt;
&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Create required partitions&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;parted&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;item.name&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;}}&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;present&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;device&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/dev/sdb&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;item.number&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;}}&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;part_start&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;item.part_start&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;}}&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;part_end&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;item.part_end&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;}}&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;gpt&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;flags&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;lvm&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;loop&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;cinder-volumes&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;part_start&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;0%'&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;part_end&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;50%'&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;lxc&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;part_start&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;50%'&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;part_end&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;100%'&lt;/span&gt;

&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Create required LVM volume groups&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;lvg&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;vg&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;item.vg&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;}}&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;pvs&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;item.pvs&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;}}&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;vg_options&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;--metadatasize &lt;/span&gt;&lt;span class=&quot;m&quot;&gt;2048&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;loop&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;vg&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;cinder-volumes&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;pvs&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/dev/sdb1&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;vg&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;lxc&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;pvs&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/dev/sdb2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;!--  --&gt;

&lt;p&gt;First up we use the &lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/parted.html&quot;&gt;“parted”&lt;/a&gt; module to split our disk into two equal sized partitions. The naming of these is important, as the OpenStack-Ansible playbooks look for these specific names when running.&lt;br /&gt;
Next, we create LVM volume groups using the &lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/lvg.html&quot;&gt;“lvg”&lt;/a&gt; module. Note that we don’t need to create the physical volumes separately, as these are created automatically by the module if they don’t exist.&lt;/p&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;In this post, we’ve completed the final preparation steps (a bit of an oxymoron, I know) required on our OpenStack hosts.&lt;/p&gt;

&lt;h1 id=&quot;appendices&quot;&gt;Appendices&lt;/h1&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/apt_module.html&quot;&gt;Ansible - “apt” module&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/git_module.html&quot;&gt;Ansible - “git” module&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/command_module.html&quot;&gt;Ansible - “command” module&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/slurp_module.html&quot;&gt;Ansible - “slurp” module&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/set_fact_module.html&quot;&gt;Ansible - “set_fact” module&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://docs.ansible.com/ansible/devel/modules/authorized_key_module.html&quot;&gt;Ansible - “authorized_key” module&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/parted.html&quot;&gt;Ansible - “parted” module&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/lvg.html&quot;&gt;Ansible - “lvg” module&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://docs.openstack.org/project-deploy-guide/openstack-ansible/latest/deploymenthost.html&quot;&gt;OpenStack-Ansible - Prepare the deployment host&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://docs.openstack.org/project-deploy-guide/openstack-ansible/latest/targethosts.html&quot;&gt;OpenStack-Ansible - Prepare the target hosts&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;versions-used&quot;&gt;Versions used&lt;/h2&gt;

&lt;p&gt;Desktop Machine: &lt;em&gt;kubuntu-18.04&lt;/em&gt;&lt;br /&gt;
VirtualBox: &lt;em&gt;virtualbox-5.2.18&lt;/em&gt;&lt;br /&gt;
Vagrant: &lt;em&gt;2.2.4&lt;/em&gt;&lt;br /&gt;
Cumulus VX Vagrant Box: &lt;em&gt;CumulusCommunity/cumulus-vx (virtualbox, 3.7.5)&lt;/em&gt;&lt;br /&gt;
Ubuntu Server Vagrant Box: &lt;em&gt;geerlingguy/ubuntu1804 (virtualbox, 1.0.7)&lt;/em&gt;&lt;br /&gt;
Ansible: &lt;em&gt;2.7.10&lt;/em&gt;&lt;/p&gt;
</description>
        <pubDate>Sun, 14 Apr 2019 00:00:00 +0000</pubDate>
        <link>https://mwadman.github.io/2019/04/14/OpenStack-Lab-Deployment-Preparation/</link>
        <guid isPermaLink="true">https://mwadman.github.io/2019/04/14/OpenStack-Lab-Deployment-Preparation/</guid>
        
        <category>OpenStack</category>
        
        <category>Ansible</category>
        
        <category>Vagrant</category>
        
        <category>VirtualBox</category>
        
        <category>Ubuntu</category>
        
        
      </item>
    
      <item>
        <title>OpenStack Lab Network - Host Routing</title>
        <description>&lt;h1 id=&quot;overview&quot;&gt;Overview&lt;/h1&gt;

&lt;p&gt;This post is the ninth in a series that plans to document my progress through installing and configuring a small OpenStack Lab.&lt;/p&gt;

&lt;p&gt;For other posts in this series, see the overview section of the &lt;a href=&quot;https://www.wadman.co.nz/2018/02/08/OpenStack-Lab-Network-Introduction/#overview&quot;&gt;introduction post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the &lt;a href=&quot;https://wadman.co.nz/2019/01/26/OpenStack-Lab-Host-Interfaces/&quot;&gt;last post&lt;/a&gt;, we configured the network interfaces on our OpenStack hosts.
In this post, we’ll cover the installation and configuration of our routing protocol suite, Free Range Routing (FRR), on our OpenStack hosts.&lt;/p&gt;

&lt;h1 id=&quot;configuration&quot;&gt;Configuration&lt;/h1&gt;

&lt;p&gt;As I’ve &lt;a href=&quot;https://wadman.co.nz/2018/12/09/OpenStack-Lab-Network-Switch-Routing/#free-range-routing&quot;&gt;already gone over&lt;/a&gt; what FRR is and how it is configured, I’m not going to cover that in too much detail in this post.&lt;br /&gt;
What I will cover is the differences between FRR on our switches and our OpenStack hosts, mainly the installation of FRR as this is not already present on our hosts.&lt;/p&gt;

&lt;p&gt;At the end of this post, we’ll have:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;OSPF neighborships from the hosts to their connected leaf switches.&lt;/li&gt;
  &lt;li&gt;BGP peerings from the hosts to the spine switches/route reflectors, with the EVPN family/capability negotiated.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;ansible-playbook-and-role&quot;&gt;Ansible Playbook and Role&lt;/h2&gt;

&lt;p&gt;Let’s start with our playbook.&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Configuring OpenStack hosts&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;hosts&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;openstack_hosts&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;become&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;gather_facts&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;roles&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;role&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;openstack-interfaces&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;openstack-interfaces&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;role&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;openstack-routing&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;openstack-routing&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And our role creation.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; /etc/ansible/roles/openstack-routing/tasks/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;frr-prerequisites&quot;&gt;FRR Prerequisites&lt;/h2&gt;

&lt;h3 id=&quot;frr-packages&quot;&gt;FRR Packages&lt;/h3&gt;

&lt;p&gt;Because FRR does not come preinstalled on our hosts, our first tasks will cover the installation of the required packages.&lt;br /&gt;
This step is made a little trickier for us because the latest versions of FRR are not present in any public repository (not even their own one).&lt;br /&gt;
Instead, the installation (and any upgrade) of FRR will need to be done by manually downloading the packages from their &lt;a href=&quot;https://github.com/FRRouting/frr/releases&quot;&gt;releases page on Github&lt;/a&gt; (or directly from the &lt;a href=&quot;https://ci1.netdef.org/browse/FRR&quot;&gt;projects CI site&lt;/a&gt;, by navigating to the “artifacts” page for the version you want to install - &lt;a href=&quot;https://ci1.netdef.org/browse/FRR-FRRV601-2/artifact/shared/Ubuntu-18.04-x86_64-Packages/&quot;&gt;Ubuntu 18.04 x86_64, as an example&lt;/a&gt;).&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Side note: If you’re not looking for the features from the newest release, then Cumulus do provide a public repository for version 4.0. My recommendation would be to avoid this if at all possible, as this doesn’t seem to be updated frequently.&lt;br /&gt;
Instructions on how to use their repository can be found on their website &lt;a href=&quot;https://docs.cumulusnetworks.com/display/HOSTPACK/Installing+FRRouting+on+the+Host&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Luckily for us, some people have already created a role that includes tasks for the installation of FRR (and supports Ubuntu 18.04 hosts like ours) - &lt;a href=&quot;https://github.com/mrlesmithjr/ansible-frr&quot;&gt;ansible-frr&lt;/a&gt;.&lt;br /&gt;
However, the role they’ve written also includes tasks for steps that we either want to complete ourselves (&lt;a href=&quot;https://github.com/mrlesmithjr/ansible-frr/blob/master/tasks/config.yml&quot;&gt;configuration of FRR&lt;/a&gt;) or don’t want to include at all (&lt;a href=&quot;https://github.com/mrlesmithjr/ansible-frr/blob/master/tasks/monitor.yml&quot;&gt;Installation of their custom scripts for monitoring&lt;/a&gt;), so instead of calling the entire role in our playbook we’re going to “include” this role in our tasks file and ask that only the installation tasks are completed.&lt;/p&gt;

&lt;p&gt;The first thing we need to do is install the ansible-frr role as a git submodule so that we can reference it:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/etc/ansible&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git submodule add https://github.com/mrlesmithjr/ansible-frr.git roles/ansible-frr
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After which, we can use Ansible’s &lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/include_role_module.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;include_role&lt;/code&gt;&lt;/a&gt; module with the argument &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tasks_from&lt;/code&gt; to specify that we only want to run the tasks in the “&lt;a href=&quot;https://github.com/mrlesmithjr/ansible-frr/blob/master/tasks/debian.yml&quot;&gt;debian.yml&lt;/a&gt;” tasks file (the ones needed to install FRR on Ubuntu).&lt;br /&gt;
This is what our “tasks/main.yml” looks like:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Install FRR&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;include_role&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ansible-frr&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;tasks_from&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;debian&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;By default, the above tasks file will download and install the latest stable version of FRR on our hosts.&lt;br /&gt;
Thanks, ansible-frr!&lt;/p&gt;

&lt;h3 id=&quot;kernel-version&quot;&gt;Kernel Version&lt;/h3&gt;

&lt;p&gt;Before we move on to the configuration of FRR, there’s one other prerequisite that the above role doesn’t consider - the kernel version of the host.&lt;br /&gt;
The version being used on our OpenStack hosts becomes important when we take a look at the minimum kernel required for specific features of FRR, as outlined on either on FRR’s &lt;a href=&quot;https://github.com/FRRouting/frr/wiki/Features-and-Kernel-Support&quot;&gt;Github Wiki&lt;/a&gt; or on their &lt;a href=&quot;http://docs.frrouting.org/en/latest/overview.html#supported-protocols-vs-platform&quot;&gt;official documentation site&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;According to these pages, to be able to run EVPN (with full feature support/at full performance) on our Linux based Ubuntu hosts we need to be running a minimum kernel version of 4.18.&lt;br /&gt;
Unfortunately, if we look at our Ubuntu hosts we see that these are installed with kernel 4.15:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;uname&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-r&lt;/span&gt;
4.15.0-29-generic
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Luckily, Ubuntu 18.04 has what is called a “hardware enablement kernel”, that we can install via a package from the default repositories, which will bring us up to the desired 4.18 kernel version.&lt;/p&gt;

&lt;p&gt;To install this using Ansible, I am first going to write a task that will check our hosts to see if they need to be upgraded, and place this before our “Install FRR” task:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Check if minimum linux kernel version is met&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;include_tasks&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;kernel-upgrade.yml&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;when&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ansible_kernel is version (openstack_routing_kernel_minimum, '&amp;lt;')&lt;/span&gt;

&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Install FRR&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;include_role&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ansible-frr&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;tasks_from&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;debian&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Similar to the above use of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;include_role&lt;/code&gt; module, we’re going to use the module &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;include_tasks&lt;/code&gt; to run the tasks inside of another file (“kernel-upgrade.yml”) that we’ll create next.&lt;/p&gt;

&lt;p&gt;Also note the use of the ansible fact “ansible_kernel”, which is really helpful with this task.
The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;when&lt;/code&gt; clause of the action takes that fact and checks whether it is less than the variable “openstack_routing_kernel_minimum” to see if the included tasks need to be run.&lt;br /&gt;
We haven’t yet defined the variable “openstack_routing_kernel_minimum” though, so let’s do that before we move on:&lt;/p&gt;

&lt;p&gt;In defaults/main.yml:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;openstack_routing_kernel_minimum&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;4.18&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Finally, this is what the “tasks/kernel-upgrade.yml” file ends up looking like:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Upgrade to required linux kernel version&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;apt&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;linux-generic-hwe-18.04&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;present&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;cache_valid_time&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;3600&lt;/span&gt;

&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Reboot host after kernel upgrade&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;reboot&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is also pretty simple. Install the hardware enablement kernel package and then use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reboot&lt;/code&gt; module afterwards so that the new kernel is used (installing the package enables the kernel on the next boot).&lt;/p&gt;

&lt;p&gt;We’re done with our prerequisites. Onto configuration.&lt;/p&gt;

&lt;h2 id=&quot;frr-configuration&quot;&gt;FRR Configuration&lt;/h2&gt;

&lt;p&gt;Because I’ve covered the major points of FRR, OSPF and BGP in a previous post from the switch point of view, I’ll try and make the next sections brief and again only cover the differences.&lt;/p&gt;

&lt;h3 id=&quot;kernel-parameters&quot;&gt;Kernel Parameters&lt;/h3&gt;

&lt;p&gt;One of those differences is that our Ubuntu hosts are not readily built to act as “routers”, due to the default settings of the kernel in Ubuntu 18.04 server.&lt;/p&gt;

&lt;p&gt;One good example of this is the switch “net.ipv4.ip_forward”, which by default is set to “0” (or “false” in boolean terms).&lt;br /&gt;
With this setting left as is, the host will never forward packets that it receives either from other external devices (switches) or from internal virtual devices (virtual machines). This is pretty bad if we want virtual machines on our two hosts to be able to talk to each other.&lt;/p&gt;

&lt;p&gt;Not to worry, these settings are quite easy to change.&lt;br /&gt;
We’ll use the trusty &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;template&lt;/code&gt; module, along with a handler to load any changes made.&lt;/p&gt;

&lt;p&gt;First, our task:&lt;/p&gt;

&lt;!--  --&gt;
&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Create sysctl file for routing tweaks&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;sysctl.j2&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;openstack_routing_sysctl_file&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;}}&quot;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;notify&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Load sysctl changes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;!--  --&gt;

&lt;p&gt;Then we need to define the variable “openstack_routing_sysctl_file”.&lt;br /&gt;
I’ll do so in “defaults/main.yml”:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;openstack_routing_sysctl_file&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;/etc/sysctl.d/99free_range_routing.conf&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Our template file (I won’t cover every setting. If you’re interested, have a google!):&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# &lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# /etc/sysctl.d/99free_range_routing.conf&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Enables Routing&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;net.ipv4.ip_forward=1&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Routing Options&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;net.ipv4.conf.all.ignore_routes_with_linkdown=1&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Enables Unnumbered BGP/OSPF&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;net.ipv4.conf.all.rp_filter=0&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;net.ipv4.conf.default.rp_filter=0&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;net.ipv4.conf.lo.rp_filter=0&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;net.ipv4.conf.all.forwarding=1&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;net.ipv4.conf.default.forwarding=1&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;net.ipv4.conf.default.arp_announce=2&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;net.ipv4.conf.default.arp_notify=1&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;net.ipv4.conf.default.arp_ignore=1&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;net.ipv4.conf.all.arp_announce=2&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;net.ipv4.conf.all.arp_notify=1&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;net.ipv4.conf.all.arp_ignore=1&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;net.ipv4.icmp_errors_use_inbound_ifaddr=1&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# ARP/NDP Garbage Collection&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;net.ipv4.neigh.default.gc_thresh2=7168&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;net.ipv4.neigh.default.gc_thresh3=8192&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;net.ipv4.neigh.default.base_reachable_time_ms=14400000&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Use neighborship info on selection of nexthop address for multipath hops&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;net.ipv4.fib_multipath_use_neigh=1&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Allows applications to work with VRF&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;net.ipv4.tcp_l3mdev_accept=1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Last, our “handlers/main.yml” file:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Load sysctl changes&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;sysctl&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-p&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;base-configuration&quot;&gt;Base Configuration&lt;/h3&gt;

&lt;p&gt;Just like our switches, we need to tell FRR which of its’ daemons to load for the host to be active in our topology.&lt;br /&gt;
A template will do the trick here too:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Set FRR daemons file&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;daemons.j2&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;/etc/frr/daemons&quot;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;notify&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Restart FRR&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;With our template looking like the below:&lt;/p&gt;

&lt;!--  --&gt;
&lt;div class=&quot;language-jinja highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ansible_managed&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
# This file tells the frr package which daemons to start.
#
# Sample configurations for these daemons can be found in
# /usr/share/doc/frr/examples/.
#
# ATTENTION:
#
# When activation a daemon at the first time, a config file, even if it is
# empty, has to be present *and* be owned by the user and group &quot;frr&quot;, else
# the daemon will not be started by /etc/init.d/frr. The permissions should
# be u=rw,g=r,o=.
# When using &quot;vtysh&quot; such a config file is also needed. It should be owned by
# group &quot;frrvty&quot; and set to ug=rw,o= thendough. Check /etc/pam.d/frr, too.
#
# The watchfrr and zebra daemons are always started.
#
bgpd=&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt;   &lt;span class=&quot;s2&quot;&gt;&quot;yes&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;openstack_hosts_routing_bgp_enabled&lt;/span&gt;   &lt;span class=&quot;nv&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;no&quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
ospfd=&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt;  &lt;span class=&quot;s2&quot;&gt;&quot;yes&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;openstack_hosts_routing_ospf_enabled&lt;/span&gt;  &lt;span class=&quot;nv&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;no&quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
ospf6d=&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;yes&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;openstack_hosts_routing_ospf6_enabled&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;no&quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
ripd=&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt;   &lt;span class=&quot;s2&quot;&gt;&quot;yes&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;openstack_hosts_routing_rip_enabled&lt;/span&gt;   &lt;span class=&quot;nv&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;no&quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
ripngd=&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;yes&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;openstack_hosts_routing_ripng_enabled&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;no&quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
isisd=&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt;  &lt;span class=&quot;s2&quot;&gt;&quot;yes&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;openstack_hosts_routing_isis_enabled&lt;/span&gt;  &lt;span class=&quot;nv&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;no&quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
pimd=&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt;   &lt;span class=&quot;s2&quot;&gt;&quot;yes&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;openstack_hosts_routing_pim_enabled&lt;/span&gt;   &lt;span class=&quot;nv&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;no&quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
ldpd=&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt;   &lt;span class=&quot;s2&quot;&gt;&quot;yes&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;openstack_hosts_routing_ldp_enabled&lt;/span&gt;   &lt;span class=&quot;nv&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;no&quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
nhrpd=&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt;  &lt;span class=&quot;s2&quot;&gt;&quot;yes&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;openstack_hosts_routing_nhrp_enabled&lt;/span&gt;  &lt;span class=&quot;nv&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;no&quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
eigrpd=&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;yes&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;openstack_hosts_routing_eigrp_enabled&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;no&quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
babeld=&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;yes&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;openstack_hosts_routing_babel_enabled&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;no&quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
sharpd=&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;yes&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;openstack_hosts_routing_sharp_enabled&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;no&quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
pbrd=&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt;   &lt;span class=&quot;s2&quot;&gt;&quot;yes&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;openstack_hosts_routing_pbr_enabled&lt;/span&gt;   &lt;span class=&quot;nv&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;no&quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
bfdd=&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt;   &lt;span class=&quot;s2&quot;&gt;&quot;yes&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;openstack_hosts_routing_bfd_enabled&lt;/span&gt;   &lt;span class=&quot;nv&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;no&quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;

#
# If this option is set the /etc/init.d/frr script automatically loads
# the config via &quot;vtysh -b&quot; when the servers are started.
# Check /etc/pam.d/frr if you intend to use &quot;vtysh&quot;!
#
vtysh_enable=yes
zebra_options=&quot;  --daemon -A 127.0.0.1 -s 90000000&quot;
bgpd_options=&quot;   --daemon -A 127.0.0.1&quot;
ospfd_options=&quot;  --daemon -A 127.0.0.1&quot;
ospf6d_options=&quot; --daemon -A ::1&quot;
ripd_options=&quot;   --daemon -A 127.0.0.1&quot;
ripngd_options=&quot; --daemon -A ::1&quot;
isisd_options=&quot;  --daemon -A 127.0.0.1&quot;
pimd_options=&quot;   --daemon -A 127.0.0.1&quot;
ldpd_options=&quot;   --daemon -A 127.0.0.1&quot;
nhrpd_options=&quot;  --daemon -A 127.0.0.1&quot;
eigrpd_options=&quot; --daemon -A 127.0.0.1&quot;
babeld_options=&quot; --daemon -A 127.0.0.1&quot;
sharpd_options=&quot; --daemon -A 127.0.0.1&quot;
pbrd_options=&quot;   --daemon -A 127.0.0.1&quot;
staticd_options=&quot;--daemon -A 127.0.0.1&quot;
bfdd_options=&quot;   --daemon -A 127.0.0.1&quot;

# The list of daemons to watch is automatically generated by the init script.
watchfrr_options=&quot;-r '/usr/lib/frr/watchfrr.sh restart %s' -s '/usr/lib/frr/watchfrr.sh start %s' -k '/usr/lib/frr/watchfrr.sh stop %s'&quot;

# for debugging purposes, you can specify a &quot;wrap&quot; command to start instead
# of starting the daemon directly, e.g. to use valgrind on ospfd:
#   ospfd_wrap=&quot;/usr/bin/valgrind&quot;
# or you can use &quot;all_wrap&quot; for all daemons, e.g. to use perf record:
#   all_wrap=&quot;/usr/bin/perf record --call-graph -&quot;
# the normal daemon command is added to this at the end.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;!--  --&gt;

&lt;p&gt;There are two differences in the above file, as compared to our switches “daemons” file:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;On our hosts, we do not need to specify that the “zebra” daemon is to run, as this is presumed by default in version 6.0.2 (the latest version at the time of writing).&lt;/li&gt;
  &lt;li&gt;We need to include the options that our daemons will be started (“$DAEMON_options=”). I’ve just used the &lt;a href=&quot;http://docs.frrouting.org/en/latest/setup.html#daemons-configuration-file&quot;&gt;defaults&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;  &lt;!--- Used to add a double line break ---&gt;&lt;/p&gt;

&lt;p&gt;Before we dive into our routing protocol configuration, let’s also get our “frr.conf” file started.&lt;br /&gt;
The task:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Set FRR running configuration&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;frr.conf.j2&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;/etc/frr/frr.conf&quot;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;notify&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Reload FRR&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The handler:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Reload FRR&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;service&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;frr&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;reloaded&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And the template “frr.conf.j2”:&lt;/p&gt;

&lt;!--  --&gt;
&lt;div class=&quot;language-jinja highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;! &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ansible_managed&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
!
frr defaults datacenter
!
hostname &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;inventory_hostname&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
!
service integrated-vtysh-config
!
log syslog informational
!
line vty
!
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;!--  --&gt;

&lt;p&gt;Nothing has changed here from our switches initial FRR configuration.&lt;/p&gt;

&lt;p&gt;We’ll also add a task at the end of our role to start FRR after the configuration has been set:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Start and Enable FRR&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;service&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;frr&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;started&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;enabled&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;yes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;ospf&quot;&gt;OSPF&lt;/h3&gt;

&lt;p&gt;Seeing as our goal with OSPF is very close to that of our switches, with the only addition being that we’re advertising the bridge IP addressing, it’ll be no surprise that our configuration is very close on each as well:&lt;/p&gt;

&lt;!--  --&gt;
&lt;div class=&quot;language-jinja highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;!
router-id &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;openstack_host_loopback_address&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;| &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ipaddr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'address'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
!
!
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;openstack_hosts_routing_ospf_enabled&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;{# Configure switchports as OSPF point-to-point #}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;mac&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;openstack_hosts_network_interfaces.items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;| &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sort&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
interface &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
  ip ospf network point-to-point
!
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endfor&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
!
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;bridge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;address&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;openstack_host_network_bridges.items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;| &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sort&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;address&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;none&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
interface &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;bridge&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
  no link-detect
!
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endif&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endfor&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;host_number&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;openstack_host_loopback_address&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;| &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ipaddr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'address'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'.'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
!
router ospf
  ospf router-id &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;openstack_host_loopback_address&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;| &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ipaddr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'address'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
  network &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;openstack_host_loopback_address&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt; area 0
  passive-interface lo
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;bridge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;address&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;openstack_host_network_bridges.items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;| &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sort&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;address&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;none&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
  network &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;address&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;| &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ipaddr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'network/prefix'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt; area &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;host_number&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
  passive-interface &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;bridge&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endif&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endfor&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
  area &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;host_number&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt; range 10.&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;host_number&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;.0.0/16
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endif&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
!
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;!--  --&gt;

&lt;p&gt;  &lt;!--- Used to add a double line break ---&gt;&lt;/p&gt;

&lt;p&gt;I’ll cover some sections of note.&lt;/p&gt;

&lt;!--  --&gt;
&lt;div class=&quot;language-jinja highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;bridge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;address&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;openstack_host_network_bridges.items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;| &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sort&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;address&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;none&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
interface &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;bridge&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
  no link-detect
!
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endif&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endfor&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;!--  --&gt;

&lt;p&gt;FRR considers the bridge interfaces we’ve configured as ‘down’, because don’t have any member interfaces (yet).&lt;br /&gt;
To bypass this, we need tell FRR to not care (detect) whether the link is up or down when deciding whether to advertise the associated networks.&lt;/p&gt;

&lt;!--  --&gt;
&lt;div class=&quot;language-jinja highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;host_number&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;openstack_host_loopback_address&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;| &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ipaddr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'address'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'.'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
...
  area &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;host_number&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt; range 10.&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;host_number&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;.0.0/16
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;!--  --&gt;

&lt;p&gt;Because we’ve addressed our bridge interfaces in such a way that they can be summarised on each host, we can use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;area x range 10.x.0.0/16&lt;/code&gt; command.&lt;br /&gt;
This will tell the host to send out a summary route (/16) instead of individual routes.&lt;br /&gt;
To determine how to summarise, we take the take octet of the loopback address and set this to a variable using Jinja2’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;set&lt;/code&gt; command.&lt;/p&gt;

&lt;h3 id=&quot;bgp&quot;&gt;BGP&lt;/h3&gt;

&lt;p&gt;Our BGP is going to be very similar too, with the only changes being:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;We don’t require logic to check if we need BGP because it’ll be present on all (well, “both” in our lab) hosts.&lt;/li&gt;
  &lt;li&gt;We don’t need the route reflector configuration, because we’re configuring our hosts as clients only.&lt;/li&gt;
&lt;/ul&gt;

&lt;!--  --&gt;
&lt;div class=&quot;language-jinja highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;!
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;openstack_hosts_routing_bgp_enabled&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
router bgp &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ibgp_autonomous_system&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
  bgp router-id &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;openstack_host_loopback_address&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;| &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ipaddr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'address'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;{# Defines a peer group where common configuration to be defined for all peers #}&lt;/span&gt;
  neighbor iBGP-RRs peer-group
  neighbor iBGP-RRs remote-as internal
&lt;span class=&quot;c&quot;&gt;{# Forms a neighborship with spine switches/route reflectors #}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;spine&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;groups&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'openstack_cumulus_spines'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
  neighbor &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;hostvars&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;spine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;cumulus_host_loopback_address&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;| &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ipaddr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'address'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt; peer-group iBGP-RRs
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endfor&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;openstack_hosts_routing_bgp_evpn_enabled&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;{# Enables advetisement of EVPN address family #}&lt;/span&gt;
  address-family l2vpn evpn
    neighbor iBGP-RRs activate
    advertise-all-vni
  exit-address-family
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endif&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endif&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
!
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;!--  --&gt;

&lt;h1 id=&quot;testing&quot;&gt;Testing&lt;/h1&gt;

&lt;p&gt;After another &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vagrant up&lt;/code&gt;, the above configuration is applied and we can log into our hosts with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vagrant ssh&lt;/code&gt; to check everything is working.&lt;br /&gt;
The below is taken from the perspective of one of the hosts.&lt;/p&gt;

&lt;p&gt;The first check we should complete is to ensure FRR and its’ daemons are running:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;systemctl status frr.service
● frr.service - FRRouting
   Loaded: loaded &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;/lib/systemd/system/frr.service&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; enabled&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; vendor preset: enabled&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
   Active: active &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;running&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; since Sun 2019-02-17 03:13:41 UTC&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; 1h 8min ago
     Docs: https://frrouting.readthedocs.io/en/latest/setup.html
  Process: 570 &lt;span class=&quot;nv&quot;&gt;ExecStart&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/usr/lib/frr/frrinit.sh start &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;exited, &lt;span class=&quot;nv&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0/SUCCESS&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    Tasks: 11 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;limit: 4915&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
   CGroup: /system.slice/frr.service
           ├─603 /usr/lib/frr/watchfrr &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-r&lt;/span&gt; /usr/lib/frr/watchfrr.sh restart %s &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; /usr/lib/frr/watchfrr.sh start %s &lt;span class=&quot;nt&quot;&gt;-k&lt;/span&gt; /usr/lib/frr/watchfrr.sh stop %s zebra bgpd ospfd staticd
           ├─631 /usr/lib/frr/zebra &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--daemon&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-A&lt;/span&gt; 127.0.0.1 &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; 90000000
           ├─710 /usr/lib/frr/bgpd &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--daemon&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-A&lt;/span&gt; 127.0.0.1
           ├─841 /usr/lib/frr/ospfd &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--daemon&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-A&lt;/span&gt; 127.0.0.1
           └─968 /usr/lib/frr/staticd &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--daemon&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-A&lt;/span&gt; 127.0.0.1

Feb 17 03:13:41 vagrant watchfrr[603]: bgpd state -&amp;gt; up : connect succeeded
Feb 17 03:13:41 vagrant watchfrr[603]: ospfd state -&amp;gt; up : connect succeeded
Feb 17 03:13:41 vagrant watchfrr[603]: staticd state -&amp;gt; up : connect succeeded
Feb 17 03:13:41 vagrant watchfrr[603]: all daemons up, doing startup-complete notify
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Looking good. Now let’s confirm our routing protocols look happy.&lt;/p&gt;

&lt;h2 id=&quot;ospf-testing&quot;&gt;OSPF Testing&lt;/h2&gt;

&lt;p&gt;We’ll start with OSPF because that’s our routing underlay (BGP won’t come up without OSPF working first).&lt;/p&gt;

&lt;p&gt;Let’s check neighborship to the leaf switches:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo vtysh

Hello, this is FRRouting (version 6.0.2).
Copyright 1996-2005 Kunihiro Ishiguro, et al.

vagrant# show ip ospf neighbor

Neighbor ID     Pri State           Dead Time Address         Interface            RXmtL RqstL DBsmL
192.168.11.113    1 Full/DROther      37.310s 192.168.11.113  enp0s8:192.168.11.132     0     0     0
192.168.11.114    1 Full/DROther      37.518s 192.168.11.114  enp0s9:192.168.11.132     0     0     0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Are we receiving OSPF routes?&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;vagrant# show ip route ospf
Codes: K - kernel route, C - connected, S - static, R - RIP,
       O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP,
       T - Table, v - VNC, V - VNC-Direct, A - Babel, D - SHARP,
       F - PBR,
       &amp;gt; - selected route, * - FIB route

O&amp;gt;* 192.168.11.101/32 [110/200] via 192.168.11.113, enp0s8 onlink, 00:09:45
  *                             via 192.168.11.114, enp0s9 onlink, 00:09:45
O&amp;gt;* 192.168.11.102/32 [110/200] via 192.168.11.113, enp0s8 onlink, 00:09:45
  *                             via 192.168.11.114, enp0s9 onlink, 00:09:45
O&amp;gt;* 192.168.11.111/32 [110/300] via 192.168.11.113, enp0s8 onlink, 00:09:45
  *                             via 192.168.11.114, enp0s9 onlink, 00:09:45
O&amp;gt;* 192.168.11.112/32 [110/300] via 192.168.11.113, enp0s8 onlink, 00:09:45
  *                             via 192.168.11.114, enp0s9 onlink, 00:09:45
O&amp;gt;* 192.168.11.113/32 [110/100] via 192.168.11.113, enp0s8 onlink, 00:09:45
O&amp;gt;* 192.168.11.114/32 [110/100] via 192.168.11.114, enp0s9 onlink, 00:09:45
O&amp;gt;* 192.168.11.131/32 [110/400] via 192.168.11.113, enp0s8 onlink, 00:09:46
  *                             via 192.168.11.114, enp0s9 onlink, 00:09:46
O   192.168.11.132/32 [110/0] is directly connected, lo, 01:13:49
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is great. Not only can we see that we’re receiving routes all the way from the other OpenStack host (192.168.11.131/32), but all of the routes are installed as ECMP routes too (indicated by the presence of two “routes” to each prefix and the asterisk at the start of each of the route lines).&lt;/p&gt;

&lt;h2 id=&quot;bgp-testing&quot;&gt;BGP Testing&lt;/h2&gt;

&lt;p&gt;Now that we know that we have IP connectivity to the spines/route reflectors, we shouldn’t have any issues with BGP right?&lt;br /&gt;
We can confirm this from vtysh as well:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo vtysh

Hello, this is FRRouting (version 6.0.2).
Copyright 1996-2005 Kunihiro Ishiguro, et al.

vagrant# show ip bgp summary

IPv4 Unicast Summary:
BGP router identifier 192.168.11.132, local AS number 65000 vrf-id 0
BGP table version 0
RIB entries 11, using 1760 bytes of memory
Peers 2, using 41 KiB of memory
Peer groups 1, using 64 bytes of memory

Neighbor        V         AS MsgRcvd MsgSent   TblVer  InQ OutQ  Up/Down State/PfxRcd
192.168.11.101  4      65000    1562    1562        0    0    0 00:10:55            3
192.168.11.102  4      65000    1562    1562        0    0    0 00:10:55            3

Total number of neighbors 2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Both neighbours are showing as up, which is great.&lt;/p&gt;

&lt;p&gt;We’re also receiving prefixes from both peers (as indicated by the “3” under the header “State/PfxRcd”).&lt;br /&gt;
We can find what these are using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;show ip route bgp&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;vagrant# show ip route bgp
Codes: K - kernel route, C - connected, S - static, R - RIP,
       O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP,
       T - Table, v - VNC, V - VNC-Direct, A - Babel, D - SHARP,
       F - PBR,
       &amp;gt; - selected route, * - FIB route

B&amp;gt;  172.16.131.0/24 [200/0] via 192.168.11.131 (recursive), 00:12:01
  *                           via 192.168.11.113, enp0s8 onlink, 00:12:01
  *                           via 192.168.11.114, enp0s9 onlink, 00:12:01
B&amp;gt;  172.17.131.0/24 [200/0] via 192.168.11.131 (recursive), 00:12:01
  *                           via 192.168.11.113, enp0s8 onlink, 00:12:01
  *                           via 192.168.11.114, enp0s9 onlink, 00:12:01
B&amp;gt;  172.18.131.0/24 [200/0] via 192.168.11.131 (recursive), 00:12:01
  *                           via 192.168.11.113, enp0s8 onlink, 00:12:01
  *                           via 192.168.11.114, enp0s9 onlink, 00:12:01
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is mimicked by the kernel routing table, which we can look at by using iproute2’s “ip route show” command:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;ip route show
default via 192.168.11.1 dev enp0s3 proto dhcp src 192.168.11.232 metric 100
172.16.131.0/24 proto bgp metric 20
	nexthop via 192.168.11.113 dev enp0s8 weight 1 onlink
	nexthop via 192.168.11.114 dev enp0s9 weight 1 onlink
172.16.132.0/24 dev mgmt proto kernel scope &lt;span class=&quot;nb&quot;&gt;link &lt;/span&gt;src 172.16.132.1 linkdown
172.17.131.0/24 proto bgp metric 20
	nexthop via 192.168.11.113 dev enp0s8 weight 1 onlink
	nexthop via 192.168.11.114 dev enp0s9 weight 1 onlink
172.17.132.0/24 dev storage proto kernel scope &lt;span class=&quot;nb&quot;&gt;link &lt;/span&gt;src 172.17.132.1 linkdown
172.18.131.0/24 proto bgp metric 20
	nexthop via 192.168.11.113 dev enp0s8 weight 1 onlink
	nexthop via 192.168.11.114 dev enp0s9 weight 1 onlink
172.18.132.0/24 dev vxlan proto kernel scope &lt;span class=&quot;nb&quot;&gt;link &lt;/span&gt;src 172.18.132.1 linkdown
192.168.11.0/24 dev enp0s3 proto kernel scope &lt;span class=&quot;nb&quot;&gt;link &lt;/span&gt;src 192.168.11.232
192.168.11.1 dev enp0s3 proto dhcp scope &lt;span class=&quot;nb&quot;&gt;link &lt;/span&gt;src 192.168.11.232 metric 100
192.168.11.101 proto ospf metric 20
	nexthop via 192.168.11.113 dev enp0s8 weight 1 onlink
	nexthop via 192.168.11.114 dev enp0s9 weight 1 onlink
192.168.11.102 proto ospf metric 20
	nexthop via 192.168.11.113 dev enp0s8 weight 1 onlink
	nexthop via 192.168.11.114 dev enp0s9 weight 1 onlink
192.168.11.111 proto ospf metric 20
	nexthop via 192.168.11.113 dev enp0s8 weight 1 onlink
	nexthop via 192.168.11.114 dev enp0s9 weight 1 onlink
192.168.11.112 proto ospf metric 20
	nexthop via 192.168.11.113 dev enp0s8 weight 1 onlink
	nexthop via 192.168.11.114 dev enp0s9 weight 1 onlink
192.168.11.113 via 192.168.11.113 dev enp0s8 proto ospf metric 20 onlink
192.168.11.114 via 192.168.11.114 dev enp0s9 proto ospf metric 20 onlink
192.168.11.131 proto ospf metric 20
	nexthop via 192.168.11.113 dev enp0s8 weight 1 onlink
	nexthop via 192.168.11.114 dev enp0s9 weight 1 onlink
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;In this post, we covered how to set up FRR on our OpenStack hosts in preparation of them advertising their VXLAN networks to each other.&lt;/p&gt;

&lt;p&gt;In the &lt;a href=&quot;https://wadman.co.nz/2019/04/14/OpenStack-Lab-Deployment-Preparation/&quot;&gt;next post&lt;/a&gt;, we’ll be preparing our hosts for deployment of OpenStack-Ansible.&lt;/p&gt;

&lt;h2 id=&quot;references&quot;&gt;References:&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/include_tasks_module.html&quot;&gt;Ansible - “include_tasks” module&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/apt_module.html&quot;&gt;Ansible - “apt” module&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/reboot_module.html&quot;&gt;Ansible - “reboot” module&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/include_role_module.html&quot;&gt;Ansible - “include_role” module&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://docs.ansible.com/ansible/latest/plugins/lookup/template.html&quot;&gt;Ansible - “template” module&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/service_module.html&quot;&gt;Ansible - “service” module&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://github.com/mrlesmithjr/ansible-frr&quot;&gt;ansible-frr role&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://github.com/FRRouting/frr/wiki/Features-and-Kernel-Support&quot;&gt;FRR - Features and Kernel Support&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;versions-used&quot;&gt;Versions used:&lt;/h2&gt;

&lt;p&gt;Desktop Machine: &lt;em&gt;kubuntu-18.04&lt;/em&gt;&lt;br /&gt;
VirtualBox: &lt;em&gt;virtualbox-5.2.18&lt;/em&gt;&lt;br /&gt;
Vagrant: &lt;em&gt;2.2.3&lt;/em&gt;&lt;br /&gt;
Cumulus VX Vagrant Box: &lt;em&gt;CumulusCommunity/cumulus-vx (virtualbox, 3.7.2)&lt;/em&gt;&lt;br /&gt;
Ubuntu Server Vagrant Box: &lt;em&gt;geerlingguy/ubuntu1804 (virtualbox, 1.0.6)&lt;/em&gt;&lt;br /&gt;
Ansible: &lt;em&gt;2.7.6&lt;/em&gt;&lt;/p&gt;
</description>
        <pubDate>Sun, 03 Feb 2019 00:00:00 +0000</pubDate>
        <link>https://mwadman.github.io/2019/02/03/OpenStack-Lab-Host-Routing/</link>
        <guid isPermaLink="true">https://mwadman.github.io/2019/02/03/OpenStack-Lab-Host-Routing/</guid>
        
        <category>OpenStack</category>
        
        <category>Networking</category>
        
        <category>OSPF</category>
        
        <category>BGP</category>
        
        <category>EVPN</category>
        
        <category>Ansible</category>
        
        <category>Vagrant</category>
        
        <category>VirtualBox</category>
        
        <category>Ubuntu</category>
        
        
      </item>
    
      <item>
        <title>OpenStack Lab Network - Host Network Interfaces</title>
        <description>&lt;h1 id=&quot;overview&quot;&gt;Overview&lt;/h1&gt;

&lt;p&gt;This post is the eighth in a series that plans to document my progress through installing and configuring a small OpenStack Lab.&lt;/p&gt;

&lt;p&gt;For other posts in this series, see the overview section of the &lt;a href=&quot;https://www.wadman.co.nz/2018/02/08/OpenStack-Lab-Network-Introduction/#overview&quot;&gt;introduction post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the &lt;a href=&quot;https://wadman.co.nz/2018/12/09/OpenStack-Lab-Network-Switch-Routing/&quot;&gt;last post&lt;/a&gt;, we covered the routing configuration on our Cumulus switches.&lt;br /&gt;
In this post, we’ll go over the network interface configuration that our OpenStack hosts require in order to participate in the network that we have set up for them.&lt;/p&gt;

&lt;h1 id=&quot;configuration&quot;&gt;Configuration&lt;/h1&gt;

&lt;p&gt;In terms of networking on our OpenStack hosts, we want to accomplish a few things before we even think about installing and running OpenStack itself.&lt;br /&gt;
The first, and what we’ll cover in this post, will be configuring our network interfaces to support our routing protocols and our OpenStack configuration.&lt;/p&gt;

&lt;p&gt;At this point, it might be important to remind ourselves that we’re preparing our hosts for an OpenStack deployment via OpenStack-Ansible.
Their &lt;a href=&quot;https://docs.openstack.org/project-deploy-guide/openstack-ansible/latest/&quot;&gt;deployment guide&lt;/a&gt; contains tons of useful information when going through a first install.&lt;br /&gt;
Also of note for this series of posts is their &lt;a href=&quot;https://docs.openstack.org/openstack-ansible/latest/user/l3pods/example.html&quot;&gt;routed environment example&lt;/a&gt;, as the configuration involved and the end state of the hosts is similar to what we want to deploy.&lt;/p&gt;

&lt;h2 id=&quot;ansible-playbook&quot;&gt;Ansible Playbook&lt;/h2&gt;

&lt;p&gt;As usual, our starting place is the playbook.&lt;br /&gt;
Because we’re no longer working with our Cumulus switches and instead on our OpenStack hosts themselves, let’s separate out any roles that we use into a new playbook. It’ll be called “openstack-hosts.yml”&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Configuring OpenStack hosts&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;hosts&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;openstack_hosts&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;become&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;gather_facts&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;roles&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;role&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;openstack-interfaces&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;openstack-interfaces&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;ansible-role&quot;&gt;Ansible Role&lt;/h2&gt;

&lt;p&gt;I’ve already spoiled the name of the role we’ll create in the playbook above.&lt;br /&gt;
I’ll create the directory structure for it as usual.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; /etc/ansible/roles/openstack-interfaces/tasks/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Let’s start adding tasks.&lt;/p&gt;

&lt;h2 id=&quot;packages&quot;&gt;Packages&lt;/h2&gt;

&lt;p&gt;Although the OpenStack-Ansible documentation includes a &lt;a href=&quot;https://docs.openstack.org/project-deploy-guide/openstack-ansible/latest/targethosts.html#configure-ubuntu&quot;&gt;list of required packages&lt;/a&gt;, we’ll not be installing all of them in this role.&lt;br /&gt;
In fact, the only package we are going to include from the documentation is “bridge-utils”, which allows the configuration of network bridges.&lt;/p&gt;

&lt;p&gt;We’ve gone over installing packages in previous posts, so I won’t go into too much detail now.&lt;br /&gt;
Here’s the first task in our file “/etc/ansible/roles/openstack-interfaces/tasks/main.yml”&lt;/p&gt;

&lt;!--  --&gt;
&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Install prerequisite packages&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;apt&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;bridge-utils&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;present&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;cache_valid_time&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;3600&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;!--  --&gt;

&lt;p&gt;Let’s move on to our configuration.&lt;/p&gt;

&lt;h2 id=&quot;interfaces&quot;&gt;Interfaces&lt;/h2&gt;

&lt;p&gt;Unlike our Cumulus switches, where our interfaces are configured via the file “/etc/network/interfaces” and brought up with the “networking” service, Ubuntu 18.04 implements a different tool for configuration called &lt;a href=&quot;https://netplan.io/&quot;&gt;Netplan&lt;/a&gt; and brings this configuration to fruition through the newer “systemd-networkd” service.&lt;/p&gt;

&lt;p&gt;Netplan is just another layer of configuration abstraction that sits on top of existing linux networking tools.&lt;br /&gt;
What this means for us is that we’re moving where we define our network interface configuration (“/etc/netplan/”), changing the format of this configuration to the more readable YAML (yes, the same configuration language that Ansible uses) and then calling Netplan to have this applied, through the appropriate tool, onto the network.&lt;/p&gt;

&lt;p&gt;Let’s take a look at some example configuration that is already being used on our hosts.&lt;br /&gt;
The below configuration exists in the file “/etc/netplan/01-netcfg.yaml”, which is the default configuration file for Ubuntu 18.04 hosts:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# This file describes the network interfaces available on your system&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# For more information, see netplan(5).&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;network&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;networkd&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;ethernets&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;enp0s3&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;dhcp4&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;yes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Pretty simple for the entire starting network configuration of our host right?&lt;br /&gt;
Let’s go over some core parts before we start our own configuration:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;network: Top-level node. Always present.&lt;/li&gt;
  &lt;li&gt;version: The version of YAML being used.&lt;/li&gt;
  &lt;li&gt;renderer: The network daemon that Netplan will configure. At the time of writing two options are available - NetworkManager (which is what our Cumulus switches use) and Systemd-networkd (which is what our Ubuntu hosts use by default).&lt;/li&gt;
  &lt;li&gt;ethernets: A block specifying the type of interfaces being configured, under which new interfaces can be defined. Other types include wifis, bridges, bonds, tunnels and vlans.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;  &lt;!--- Used to add a double line break ---&gt;&lt;/p&gt;

&lt;p&gt;Now that I’ve covered how Netplan works a little, I think it’s best if we dive right into our Ansible task and handlers.&lt;/p&gt;

&lt;p&gt;Netplan configuration files live in “/etc/netplan” (as seen above) and must end in “.yaml” to be picked up.&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Configure Interfaces&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;interfaces_custom.j2&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;/etc/netplan/interfaces_custom.yaml&quot;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;notify&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Apply Netplan configuration&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This requires the presence of a handler file (“handlers/main.yml”) to run the command “netplan apply”, which tells Netplan to put our configuration file into action.&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Apply Netplan configuration&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;netplan apply&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I’ll cover the content of the template file in two parts, starting with the configuration of the loopback and physical interfaces on our hosts.&lt;/p&gt;

&lt;h3 id=&quot;loopback-and-physical-interfaces&quot;&gt;Loopback and Physical Interfaces&lt;/h3&gt;

&lt;p&gt;As with our Cumulus switches, our loopback and physical ports are there to support the routing topology over which OpenStack will communicate.&lt;br /&gt;
Our requirements for configuration will also remain the same, with our loopback interface needing an IP address so that BGP peering relationships can be established; and our physical interfaces using the same address for OSPF unnumbered (which I covered in my &lt;a href=&quot;https://wadman.co.nz/2018/12/09/OpenStack-Lab-Network-Switch-Routing/#ospf-unnumbered&quot;&gt;previous post&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;I’m going to mix it up this time and define our variables before diving into our template.&lt;br /&gt;
We’re going to want to define two items as variables for both hosts - our loopback IP addresses and physical interface numbers.&lt;/p&gt;

&lt;p&gt;Because our hosts share the same physical port layout (through our &lt;a href=&quot;https://wadman.co.nz/2018/04/08/OpenStack-Lab-Network-Vagrant/#networking&quot;&gt;Vagrant/VirtualBox configuration&lt;/a&gt;), they both end up with the same network interface names for their physical ports (enp0s8 and enp0s9). We can, therefore, use the same variable for both of our hosts.&lt;br /&gt;
I’ll create this variable in the new file “/etc/ansible/group_vars/openstack_hosts/vars.yml”:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;openstack_hosts_network_interfaces&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;enp0s8&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;enp0s9&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# OSPF Routing&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;openstack_hosts_routing_ospf_unnumbered&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;True&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;openstack_hosts_routing_ospf_enabled&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;True&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# BGP Routing&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;openstack_hosts_routing_bgp_enabled&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;True&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;openstack_hosts_routing_bgp_evpn_enabled&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You’ll see that I’ve also created some other variables that we used in our Cumulus interface and routing configurations. These let us say whether we’re using a given protocol on our hosts.&lt;/p&gt;

&lt;p&gt;We also need to define the IP address that each host will use on its’ loopback interface.&lt;br /&gt;
Here’s what “/etc/ansible/host_vars/openstack-compute/vars.yml” looks like as an example:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;openstack_host_loopback_address&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;192.168.11.132/32&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;  &lt;!--- Used to add a double line break ---&gt;&lt;/p&gt;

&lt;p&gt;Now that we’ve set ourselves up with some variables, let’s begin writing our template (“templates/interfaces_custom.j2”):&lt;/p&gt;

&lt;!--  --&gt;
&lt;div class=&quot;language-jinja highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;network:
  version: 2
  renderer: networkd
  ethernets:
    &lt;span class=&quot;c&quot;&gt;#######################&lt;/span&gt;
    # Loopback Interfaces #
    &lt;span class=&quot;c&quot;&gt;#######################&lt;/span&gt;
    lo:
      match:
        name: lo
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;openstack_host_loopback_address&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;defined&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
      addresses:
        - &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;openstack_host_loopback_address&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endif&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;#######################&lt;/span&gt;
    # Physical Interfaces #
    &lt;span class=&quot;c&quot;&gt;#######################&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;openstack_hosts_network_interfaces&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;| &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sort&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;:
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;openstack_hosts_routing_ospf_unnumbered&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
      addresses:
        - &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;openstack_host_loopback_address&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endif&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
      mtu: &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;openstack_lab_mtu&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endfor&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;!--  --&gt;

&lt;p&gt;This template starts with the same configuration lines as the default one that we looked at above.&lt;br /&gt;
After we specify the interface type with “ethernets:”, we can define the interfaces that we want to bring up underneath.&lt;/p&gt;

&lt;p&gt;The first of which is our loopback interface.&lt;br /&gt;
Because we are simply adding an IP address to an existing interface (“lo”), Netplan needs us to tell which interface we are adding configuration to.&lt;br /&gt;
This is done with the “match” and “name” keys, essentially telling Netplan to configure the interface that already exists with the name of “lo”.&lt;br /&gt;
We then use the “addresses” key followed by a list (of one in our case) of IP addresses that we want configured.&lt;/p&gt;

&lt;p&gt;Our physical interfaces are very similar. Define the interface name, give it an IP address and then configure the MTU by using the “mtu” key.&lt;/p&gt;

&lt;h3 id=&quot;openstack-bridges&quot;&gt;OpenStack Bridges&lt;/h3&gt;

&lt;p&gt;As I eluded to before, I’m also going to include in this template the configuration of the network bridges required by OpenStack-Ansible.&lt;br /&gt;
This is simply so that we don’t need to configure this file again in another role.&lt;/p&gt;

&lt;p&gt;OpenStack-Ansible utilises containers to operate the many services that are included in an OpenStack installation. To connect to the outside world, the containers need to talk via bridges that need to be set up on the host before deployment.&lt;br /&gt;
These bridges are as follows:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;br-mgmt: Provides management of and communication between the infrastructure and OpenStack services.&lt;/li&gt;
  &lt;li&gt;br-storage: Provides access between OpenStack services and storage devices.&lt;/li&gt;
  &lt;li&gt;br-vlan: Provides internal communication between tenant networks that are VLAN tagged or flat (no VLAN tag) and external communication to outside of the OpenStack network through “Provider networks” (NAT).&lt;/li&gt;
  &lt;li&gt;br-vxlan: Only required if the environment is configured create virtual networks using VXLAN. Provides internal communication between tenant networks that use VXLAN tunnelling.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;https://docs.openstack.org/project-deploy-guide/openstack-ansible/rocky/targethosts.html#configuring-the-network&quot;&gt;The documentation&lt;/a&gt; helps out here, by showing which bridges need to be present on a given host.&lt;br /&gt;
For our lab deployment, both hosts are going to be acting as network (control), compute and storage nodes.&lt;br /&gt;
This translates to needing all 4 bridges (br-mgmt, br-storage, br-vxlan and br-vlan) on both hosts, with IP addresses on all except br-vlan.&lt;/p&gt;

&lt;p&gt;  &lt;!--- Used to add a double line break ---&gt;&lt;/p&gt;

&lt;p&gt;Like in our above step, let’s define variables first.&lt;br /&gt;
Because the IP addresses that we configure on these bridges are going to be different on each host, let’s define the variables under the “host_vars” hierarchy.&lt;br /&gt;
Here’s what I’ve added to “/etc/ansible/host_vars/openstack-compute/vars.yml” as an example:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;openstack_host_network_bridges&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;mgmt&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;10.131.16.1/24&quot;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;storage&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;10.131.17.1/24&quot;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;vxlan&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;10.131.18.1/24&quot;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;vlan&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note the blank value for the “vlan” key, because that bridge will not have an IP address configured.&lt;/p&gt;

&lt;p&gt;  &lt;!--- Used to add a double line break ---&gt;&lt;/p&gt;

&lt;p&gt;These variables come together to form the below addition to our interface configuration template:&lt;/p&gt;

&lt;!--  --&gt;
&lt;div class=&quot;language-jinja highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;###########################&lt;/span&gt;
# Local Bridge Interfaces #
&lt;span class=&quot;c&quot;&gt;###########################&lt;/span&gt;
bridges:
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;bridge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;address&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;openstack_host_network_bridges.items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;| &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sort&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
  &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;bridge&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;:
    interfaces: []
    parameters:
      stp: false
      forward-delay: 0
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;address&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;none&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
    addresses:
      - &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;address&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endif&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endfor&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;!--  --&gt;

&lt;p&gt;Most of this configuration was done by looking at &lt;a href=&quot;https://docs.openstack.org/openstack-ansible/latest/user/l3pods/example.html#host-network-configuration&quot;&gt;OpenStack-Ansible’s examples&lt;/a&gt; and translating this into to the Netplan syntax for &lt;a href=&quot;https://netplan.io/reference#properties-for-device-type-bridges&quot;&gt;configuration of bridges&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let’s walk through the configuration of each bridge:&lt;br /&gt;
&lt;!--  --&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bridges:&lt;/code&gt; - Tells Netplan that the following interfaces are bridges.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{{ bridge }}&lt;/code&gt; - For every key that exists in the variable “openstack_host_network_bridges” for the host, create an interface with the name of the key with the following configuration underneath.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;interfaces: []&lt;/code&gt; - Usually we would assign network interfaces that are participating in the bridge here, but instead we say that there are none. OpenStack-Ansible is going to add ports to this bridge when it creates the appropriate containers.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;parameters:&lt;/code&gt; - Tells Netplan to set special bridge options, depending on the nested keys and values.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stp: false&lt;/code&gt; - The first option we use to turn spanning tree off . This is because the bridges aren’t uplinking to any other switches (rather, this bridge will be advertised as a prefix by iBGP for reachability between hosts).&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;forward-delay: 0&lt;/code&gt; - The second option says that there is to be no forwarding delay on the bridge (Tells the bridge to forward traffic immediately instead of going through the usual listening and learning stages).&lt;/li&gt;
  &lt;li&gt;If the bridge has an IP address specified, we set this using the standard syntax.
&lt;!--  --&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As simple as that, we’ve configured all prerequisite network interfaces.&lt;/p&gt;

&lt;h2 id=&quot;vagrant&quot;&gt;Vagrant&lt;/h2&gt;

&lt;p&gt;The last thing we need to do is tell Vagrant that it needs to run the playbook after it has set up both OpenStack hosts.&lt;br /&gt;
I’ll accomplish this by including the provision block after the last OpenStack host, just like we did with the &lt;a href=&quot;https://wadman.co.nz/2018/11/18/OpenStack-Lab-Network-Switch-Base/#running-with-vagrant&quot;&gt;Cumulus provisioning block&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;openstack_compute&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;device&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# Ansible Playbook for all OpenStack hosts&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;device&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;provision&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:ansible&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ansible&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ansible&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;inventory_path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/etc/ansible/hosts&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ansible&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;playbook&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/etc/ansible/playbooks/openstack-hosts.yml&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ansible&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;limit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;openstack_hosts&quot;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;testing&quot;&gt;Testing&lt;/h1&gt;

&lt;p&gt;After all of our configuration, when we run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vagrant up&lt;/code&gt; on our local machine, we get the following output after it has created the two OpenStack hosts:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;vagrant up
...
&lt;span class=&quot;o&quot;&gt;==&amp;gt;&lt;/span&gt; openstack_compute: Running provisioner: ansible...
    openstack_compute: Running ansible-playbook...

PLAY &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Configuring OpenStack hosts] &lt;span class=&quot;k&quot;&gt;*********************************************&lt;/span&gt;

TASK &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Gathering Facts] &lt;span class=&quot;k&quot;&gt;*********************************************************&lt;/span&gt;
ok: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;openstack-control]
ok: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;openstack-compute]

TASK &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;openstack-interfaces : Install prerequisite packages] &lt;span class=&quot;k&quot;&gt;********************&lt;/span&gt;
changed: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;openstack-compute]
changed: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;openstack-control]

TASK &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;openstack-interfaces : Configure Interfaces] &lt;span class=&quot;k&quot;&gt;*****************************&lt;/span&gt;
changed: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;openstack-control]
changed: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;openstack-compute]

RUNNING HANDLER &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;openstack-interfaces : Apply Netplan configuration] &lt;span class=&quot;k&quot;&gt;***********&lt;/span&gt;
changed: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;openstack-compute]
changed: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;openstack-control]

PLAY RECAP &lt;span class=&quot;k&quot;&gt;*********************************************************************&lt;/span&gt;
openstack-compute          : &lt;span class=&quot;nv&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1    &lt;span class=&quot;nv&quot;&gt;changed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;3    &lt;span class=&quot;nv&quot;&gt;unreachable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0    &lt;span class=&quot;nv&quot;&gt;failed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0   
openstack-control          : &lt;span class=&quot;nv&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1    &lt;span class=&quot;nv&quot;&gt;changed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;3    &lt;span class=&quot;nv&quot;&gt;unreachable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0    &lt;span class=&quot;nv&quot;&gt;failed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Looks like everything was configured, let’s check that it’s taken effect on the hosts.&lt;/p&gt;

&lt;h2 id=&quot;interfaces-1&quot;&gt;Interfaces&lt;/h2&gt;

&lt;p&gt;Using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vagrant ssh $host&lt;/code&gt; we can connect to both of our hosts and find out whether everything looks as it should.&lt;/p&gt;

&lt;p&gt;Firstly, let’s check whether our bridges exist:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;brctl show
bridge name   bridge &lt;span class=&quot;nb&quot;&gt;id           &lt;/span&gt;STP enabled   interfaces
mgmt          8000.ce995af87981   no		
storage       8000.864182527489   no		
vlan          8000.daeb42cdd17b   no		
vxlan         8000.000000000000   no
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Although the command doesn’t show a lot of information (yet - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;brctl&lt;/code&gt; becomes a very useful command once MAC addresses are being learnt by each bridge), it does confirm that we’ve created the bridges on the host.&lt;/p&gt;

&lt;p&gt;We can confirm this with the command &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ip address show&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;ip address show | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;UP&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\|&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;inet&quot;&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;inet6&quot;&lt;/span&gt;
1: lo: &amp;lt;LOOPBACK,UP,LOWER_UP&amp;gt; mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
    inet 127.0.0.1/8 scope host lo
    inet 192.168.11.132/32 brd 192.168.11.132 scope global lo:1
2: enp0s3: &amp;lt;BROADCAST,MULTICAST,UP,LOWER_UP&amp;gt; mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    inet 192.168.11.232/24 brd 192.168.11.255 scope global enp0s3
3: enp0s8: &amp;lt;BROADCAST,MULTICAST,UP,LOWER_UP&amp;gt; mtu 9000 qdisc pfifo_fast state UP group default qlen 1000
    inet 192.168.11.132/32 brd 192.168.11.132 scope global enp0s8
4: enp0s9: &amp;lt;BROADCAST,MULTICAST,UP,LOWER_UP&amp;gt; mtu 9000 qdisc pfifo_fast state UP group default qlen 1000
    inet 192.168.11.132/32 brd 192.168.11.132 scope global enp0s9
5: vxlan: &amp;lt;NO-CARRIER,BROADCAST,MULTICAST,UP&amp;gt; mtu 1500 qdisc noqueue state DOWN group default qlen 1000
    inet 172.16.2.132/24 brd 172.16.2.255 scope global vxlan
6: vlan: &amp;lt;NO-CARRIER,BROADCAST,MULTICAST,UP&amp;gt; mtu 1500 qdisc noqueue state DOWN group default qlen 1000
7: storage: &amp;lt;NO-CARRIER,BROADCAST,MULTICAST,UP&amp;gt; mtu 1500 qdisc noqueue state DOWN group default qlen 1000
    inet 172.16.1.132/24 brd 172.16.1.255 scope global storage
8: mgmt: &amp;lt;NO-CARRIER,BROADCAST,MULTICAST,UP&amp;gt; mtu 1500 qdisc noqueue state DOWN group default qlen 1000
    inet 172.16.0.132/24 brd 172.16.0.255 scope global mgmt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This command shows us each interface present and its’ associated IP address.&lt;/p&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;In this post, we covered some basic network interface configuration on our OpenStack hosts, including the bridges that OpenStack-Ansible needs present.&lt;/p&gt;

&lt;p&gt;In the &lt;a href=&quot;https://wadman.co.nz/2019/02/03/OpenStack-Lab-Host-Routing/&quot;&gt;next post&lt;/a&gt;, we’ll build on top of this configuration by bringing up OSPF and iBGP.&lt;/p&gt;

&lt;h1 id=&quot;appendices&quot;&gt;Appendices&lt;/h1&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://docs.ansible.com/ansible/latest/plugins/lookup/template.html&quot;&gt;Ansible - “template” module&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/service_module.html&quot;&gt;Ansible - “service” module&lt;/a&gt; &lt;br /&gt;
&lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/command_module.html&quot;&gt;Ansible - “command” module&lt;/a&gt; &lt;br /&gt;
&lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/apt_module.html&quot;&gt;Ansible - “apt” module&lt;/a&gt; &lt;br /&gt;
&lt;a href=&quot;https://netplan.io/reference#general-structure&quot;&gt;Netplan - Reference Documentation&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://docs.openstack.org/project-deploy-guide/openstack-ansible/latest/&quot;&gt;OpenStack Ansible - Deployment Guide&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://docs.openstack.org/openstack-ansible/latest/user/l3pods/example.html&quot;&gt;OpenStack Ansible - Routed Environment Example&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;versions-used&quot;&gt;Versions used&lt;/h2&gt;

&lt;p&gt;Desktop Machine: &lt;em&gt;kubuntu-18.04&lt;/em&gt;&lt;br /&gt;
VirtualBox: &lt;em&gt;virtualbox-5.2.18&lt;/em&gt;&lt;br /&gt;
Vagrant: &lt;em&gt;2.2.3&lt;/em&gt;&lt;br /&gt;
Cumulus VX Vagrant Box: &lt;em&gt;CumulusCommunity/cumulus-vx (virtualbox, 3.7.2)&lt;/em&gt;&lt;br /&gt;
Ubuntu Server Vagrant Box: &lt;em&gt;geerlingguy/ubuntu1804 (virtualbox, 1.0.6)&lt;/em&gt;&lt;br /&gt;
Ansible: &lt;em&gt;2.7.6&lt;/em&gt;&lt;/p&gt;
</description>
        <pubDate>Sat, 26 Jan 2019 00:00:00 +0000</pubDate>
        <link>https://mwadman.github.io/2019/01/26/OpenStack-Lab-Host-Interfaces/</link>
        <guid isPermaLink="true">https://mwadman.github.io/2019/01/26/OpenStack-Lab-Host-Interfaces/</guid>
        
        <category>OpenStack</category>
        
        <category>Networking</category>
        
        <category>Ansible</category>
        
        <category>Vagrant</category>
        
        <category>VirtualBox</category>
        
        <category>Ubuntu</category>
        
        
      </item>
    
      <item>
        <title>OpenStack Lab Network - Switch Configuration (Part 3)</title>
        <description>&lt;h1 id=&quot;overview&quot;&gt;Overview&lt;/h1&gt;

&lt;p&gt;This post is the seventh in a series that plans to document my progress through installing and configuring a small OpenStack Lab.&lt;/p&gt;

&lt;p&gt;For other posts in this series, see the overview section of the &lt;a href=&quot;https://www.wadman.co.nz/2018/02/08/OpenStack-Lab-Network-Introduction/#overview&quot;&gt;introduction post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the &lt;a href=&quot;https://wadman.co.nz/2018/11/23/OpenStack-Lab-Network-Switch-Interfaces/&quot;&gt;last post&lt;/a&gt;, we covered some basic configuration of interfaces on a Cumulus switch.&lt;br /&gt;
This post will cover the last of our configuration required on our Cumulus switches - routing.&lt;/p&gt;

&lt;h1 id=&quot;configuration&quot;&gt;Configuration&lt;/h1&gt;

&lt;p&gt;First, I think it might be a good idea to recap what we want to be accomplished in terms of routing.
Let’s take a look back to our production network diagram.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/openstack-lab-network.png&quot; alt=&quot;OpenStack Lab Production Network&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Our end goal with this topology is to have our OpenStack virtual machines able to talk to each other, even if they’re on the same subnet.&lt;br /&gt;
This can be accomplished by telling OpenStack to tag traffic with VLANs when it communicates across the network, which can work on a small scale quite well, but comes with the downsides of using VLANs as well such as requiring Spanning Tree be run to prevent loops from forming. It’s also not what I set out to learn about.&lt;br /&gt;
The other option is to tell OpenStack to use VXLANs to communicate over the network (Unfortunately at this stage OpenStack doesn’t yet support &lt;a href=&quot;https://tools.ietf.org/html/draft-ietf-nvo3-geneve&quot;&gt;GENEVE&lt;/a&gt; as an option).&lt;/p&gt;

&lt;p&gt;  &lt;!--- Used to add a double line break ---&gt;&lt;/p&gt;

&lt;p&gt;I won’t dive into the technical details of VXLAN in this post. Just know that VXLAN VTEPs (Virtual Tunnel Endpoints - The OpenStack hosts on our environment) send traffic by encapsulating received frames and tunnelling this across a layer 3 network to remote VTEPs.
VTEPs need a way to learn what VNIs (Virtual Network Identifiers - VXLANs segment identifier, similar to a VLAN) are present in the network and on what hosts they reside on. They also need a mechanism to learn where MAC addresses within each VNI exist (What VTEP they terminate to).&lt;/p&gt;

&lt;p&gt;VXLAN does have a native learning capability built in that &lt;a href=&quot;https://tools.ietf.org/html/rfc7348#section-4.2&quot;&gt;uses multicast&lt;/a&gt;, but this has its shortcomings (like needing to run multicast in your network). That’s where EVPN comes in.&lt;br /&gt;
EVPN can act as a control plane for VXLAN and does so by advertising VXLAN information over BGP.&lt;/p&gt;

&lt;p&gt;  &lt;!--- Used to add a double line break ---&gt;&lt;/p&gt;

&lt;p&gt;Okay, we have some requirements:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Have IP reachability across our network so that VXLAN can tunnel traffic.&lt;/li&gt;
  &lt;li&gt;Support the OpenStack nodes in advertising VXLAN information over BGP using EVPN.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’ve decided to deploy OSPF as an underlay routing protocol. This will advertise loopback addresses between all hosts (switches and OpenStack nodes) for IP reachability.&lt;/p&gt;

&lt;p&gt;Loopback reachability is also required for BGP, which we’ll be deploying on the spine switches in addition to the OpenStack nodes.&lt;br /&gt;
While the spine switches won’t be participating in the VXLAN network (they won’t have any VNI’s or MAC addresses to advertise), they will be acting as route reflectors.&lt;br /&gt;
The deployment of route reflectors isn’t needed in an environment this small but quickly becomes important in a larger network.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;For further reading on other EVPN+BGP network designs, I would recommend taking a look at &lt;a href=&quot;https://www.ipspace.net/Data_Center_BGP/BGP_in_EVPN-Based_Data_Center_Fabrics&quot;&gt;this post&lt;/a&gt; over on ipspace.net&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That’s it for the design. Let’s jump into the configuration.&lt;/p&gt;

&lt;h2 id=&quot;ansible-playbookrole&quot;&gt;Ansible Playbook/Role&lt;/h2&gt;

&lt;p&gt;We’ve already created the playbook in a previous post, which references the “cumulus-base” and “cumulus-interface” roles. I’ll create a new one named “cumulus-routing”.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; /etc/ansible/roles/cumulus-routing/tasks/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And add this to our playbook - “openstack-cumulus.yml”:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Configuring Cumulus switches&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;hosts&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;openstack_cumulus&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;become&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;gather_facts&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;roles&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;role&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;cumulus-base&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;cumulus-base&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;role&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;cumulus-interface&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;cumulus-interface&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;role&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;cumulus-routing&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;cumulus-routing&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Onto our role.&lt;/p&gt;

&lt;h2 id=&quot;free-range-routing&quot;&gt;Free Range Routing&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://frrouting.org/&quot;&gt;Free Range Routing&lt;/a&gt; (sometimes referred to as FRRouting or simply FRR) is an open source routing suite that Cumulus deploys on their switches. FRR manages the operations of any routing processes running on the switch, including OSPF and BGP.&lt;/p&gt;

&lt;p&gt;FRR has a few main configuration files, stored under the directory “/etc/frr”:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-alh&lt;/span&gt; /etc/frr/
total 16K
drwxrwxr-x 1 frr  frr      74 Dec  8 13:52 &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
drwxr-xr-x 1 root root   3.5K Dec  8 13:46 ..
&lt;span class=&quot;nt&quot;&gt;-rw-r--r--&lt;/span&gt; 1 frr  frr    1016 Nov  8 11:28 daemons
&lt;span class=&quot;nt&quot;&gt;-rw-r--r--&lt;/span&gt; 1 frr  frr    1.2K Nov  8 11:28 daemons.conf
&lt;span class=&quot;nt&quot;&gt;-rw-r--r--&lt;/span&gt; 1 frr  frr     120 Nov  8 11:28 frr.conf
&lt;span class=&quot;nt&quot;&gt;-rw-r--r--&lt;/span&gt; 1 frr  frrvty   60 Nov 14 07:30 vtysh.conf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Let’s quickly go over what each is used for:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;File&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;Purpose&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;daemons&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Controls what daemons (routing processes) are run. All daemons are disabled by default.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;daemons.conf&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Controls the options passed to daemons when they start (If they’re enabled in the above file).&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;frr.conf&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Controls the configuration of all daemons. The meat of the routing configuration.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;vtysh.conf&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Controls how the command line interface utility (vtysh) operates.&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;In the context of the configuration we’re writing in this role, the files “daemons.conf” and “vtysh.conf” can be left alone.&lt;/p&gt;

&lt;p&gt;That leaves us with needing to change the “daemons” and “frr.conf” files, which we’re going to do with the Ansible template module.
Our “tasks/”main.yml” file ends up looking like the below for this role:&lt;/p&gt;

&lt;!--  --&gt;
&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Configure FRR (Free Range Routing)&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;}}.j2&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;cumulus_frr_config_dir&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;}}{{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;}}&quot;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;loop&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;daemons&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;frr.conf&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;notify&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Reload FRR&lt;/span&gt;

&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Start and Enable FRR&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;service&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;cumulus_frr_service_name&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;}}&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;started&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;enabled&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;yes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;!--  --&gt;

&lt;p&gt;Note how we’ve only got two tasks:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Configure Free Range Routing.&lt;/li&gt;
  &lt;li&gt;Ensure that the FRR service is started (Because this is disabled by default).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;  &lt;!--- Used to add a double line break ---&gt;&lt;/p&gt;

&lt;p&gt;We’ve also included a handler as a part of our configuration task above, so we need to define a “handlers/main.yml” file as well.&lt;/p&gt;

&lt;!--  --&gt;
&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Reload FRR&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;service&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;cumulus_frr_service_name&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;}}&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;reloaded&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;!--  --&gt;

&lt;p&gt;Lastly, we’ve referenced two new variables in the above files.&lt;br /&gt;
Because these variables are I’m going to use a new file, “defaults/main.yml”, and define the variables here.&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# FRR Service Configuration&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;cumulus_frr_service_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;frr&quot;&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;cumulus_frr_config_dir&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;/etc/frr/&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The defaults file allows for the definition of role-specific variables which take the standard value for that variable.&lt;br /&gt;
This allows for overwriting the variable in other locations (e.g. in group_vars/host_vars) if need be. &lt;br /&gt;
Note that a variable defined in this file is assumed to be of the &lt;a href=&quot;https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#variable-precedence-where-should-i-put-a-variable&quot;&gt;lowest precedence&lt;/a&gt;, so any other definition of the variable overwrites it.&lt;/p&gt;

&lt;p&gt;  &lt;!--- Used to add a double line break ---&gt;&lt;/p&gt;

&lt;p&gt;Now that we’ve done the groundwork, let’s get into our two jinja templates.&lt;/p&gt;

&lt;h3 id=&quot;frr-daemons&quot;&gt;FRR Daemons&lt;/h3&gt;

&lt;p&gt;The first (and more simple) of the two templates that we’ll create is “/etc/ansible/roles/cumulus-routing/templates/daemons.j2”.&lt;br /&gt;
I’ll show you what this looks like and then explain what I’ve changed:&lt;/p&gt;

&lt;!--  --&gt;
&lt;div class=&quot;language-jinja highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ansible_managed&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
# This file tells the frr package which daemons to start.
#
# Entries are in the format: &lt;span class=&quot;nt&quot;&gt;&amp;lt;daemon&amp;gt;&lt;/span&gt;=(yes|no|priority)
#   0, &quot;no&quot;  = disabled
#   1, &quot;yes&quot; = highest priority
#   2 .. 10  = lower priorities
# Read /usr/share/doc/frr/README.Debian for details.
#
# Sample configurations for these daemons can be found in
# /usr/share/doc/frr/examples/.
#
# ATTENTION:
#
# When activation a daemon at the first time, a config file, even if it is
# empty, has to be present *and* be owned by the user and group &quot;frr&quot;, else
# the daemon will not be started by /etc/init.d/frr. The permissions should
# be u=rw,g=r,o=.
# When using &quot;vtysh&quot; such a config file is also needed. It should be owned by
# group &quot;frrvty&quot; and set to ug=rw,o= though. Check /etc/pam.d/frr, too.
#
# The watchfrr daemon is always started. Per default in monitoring-only but
# that can be changed via /etc/frr/daemons.conf.
#
zebra=&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;yes&quot;&lt;/span&gt;  &lt;span class=&quot;nv&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;cumulus_routing_bgp_enabled&lt;/span&gt;
                &lt;span class=&quot;nv&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_routing_ospf_enabled&lt;/span&gt;
                &lt;span class=&quot;nv&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_routing_ospf6_enabled&lt;/span&gt;
                &lt;span class=&quot;nv&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_routing_rip_enabled&lt;/span&gt;
                &lt;span class=&quot;nv&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_routing_ripng_enabled&lt;/span&gt;
                &lt;span class=&quot;nv&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_routing_isis_enabled&lt;/span&gt;
                &lt;span class=&quot;nv&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_routing_pim_enabled&lt;/span&gt;
                &lt;span class=&quot;nv&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_routing_ldp_enabled&lt;/span&gt;
                &lt;span class=&quot;nv&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_routing_nhrp_enabled&lt;/span&gt;
                &lt;span class=&quot;nv&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_routing_eigrp_enabled&lt;/span&gt;
                &lt;span class=&quot;nv&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_routing_babel_enabled&lt;/span&gt;
                &lt;span class=&quot;nv&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_routing_sharp_enabled&lt;/span&gt;
                &lt;span class=&quot;nv&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_routing_pbr_enabled&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;nv&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;no&quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
bgpd=&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt;   &lt;span class=&quot;s2&quot;&gt;&quot;yes&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_routing_bgp_enabled&lt;/span&gt;   &lt;span class=&quot;nv&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;no&quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
ospfd=&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt;  &lt;span class=&quot;s2&quot;&gt;&quot;yes&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_routing_ospf_enabled&lt;/span&gt;  &lt;span class=&quot;nv&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;no&quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
ospf6d=&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;yes&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_routing_ospf6_enabled&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;no&quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
ripd=&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt;   &lt;span class=&quot;s2&quot;&gt;&quot;yes&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_routing_rip_enabled&lt;/span&gt;   &lt;span class=&quot;nv&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;no&quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
ripngd=&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;yes&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_routing_ripng_enabled&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;no&quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
isisd=&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt;  &lt;span class=&quot;s2&quot;&gt;&quot;yes&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_routing_isis_enabled&lt;/span&gt;  &lt;span class=&quot;nv&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;no&quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
pimd=&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt;   &lt;span class=&quot;s2&quot;&gt;&quot;yes&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_routing_pim_enabled&lt;/span&gt;   &lt;span class=&quot;nv&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;no&quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
ldpd=&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt;   &lt;span class=&quot;s2&quot;&gt;&quot;yes&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_routing_ldp_enabled&lt;/span&gt;   &lt;span class=&quot;nv&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;no&quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
nhrpd=&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt;  &lt;span class=&quot;s2&quot;&gt;&quot;yes&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_routing_nhrp_enabled&lt;/span&gt;  &lt;span class=&quot;nv&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;no&quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
eigrpd=&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;yes&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_routing_eigrp_enabled&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;no&quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
babeld=&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;yes&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_routing_babel_enabled&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;no&quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
sharpd=&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;yes&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_routing_sharp_enabled&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;no&quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
pbrd=&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt;   &lt;span class=&quot;s2&quot;&gt;&quot;yes&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_routing_pbr_enabled&lt;/span&gt;   &lt;span class=&quot;nv&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;no&quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;!--  --&gt;

&lt;p&gt;There are two halves to the above file, the lines of comments at the top of the file and then the setting of each daemon to “yes” or “no” in the bottom half.&lt;/p&gt;

&lt;p&gt;We accomplish the setting of each daemon using Jinja &lt;a href=&quot;http://jinja.pocoo.org/docs/2.10/templates/#if-expression&quot;&gt;inline &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if&lt;/code&gt; statements&lt;/a&gt;. If the variable we’re referencing is &lt;em&gt;True&lt;/em&gt; then we set write “yes” (telling FRR to turn the daemon on), and if it isn’t then we write “no”.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;zebra&lt;/code&gt; daemon at the top of the list manages all of the other routing processes, including kernel routing table updates, interface lookups, and redistribution.&lt;br /&gt;
This needs to be enabled if any one of the individual protocol daemons is, and we accomplish this through &lt;a href=&quot;http://jinja.pocoo.org/docs/2.10/templates/#line-statements&quot;&gt;multiple lines&lt;/a&gt; of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;or&lt;/code&gt; statements.&lt;/p&gt;

&lt;p&gt;  &lt;!--- Used to add a double line break ---&gt;&lt;/p&gt;

&lt;p&gt;We’ll then define all of the above variables in “defaults/main.yml”, setting them to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;False&lt;/code&gt; by default.&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# FRR Service Configuration&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;cumulus_frr_service_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;frr&quot;&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;cumulus_frr_config_dir&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;/etc/frr/&quot;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# FRR Daemons&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;cumulus_routing_bgp_enabled&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;False&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;cumulus_routing_ospf_enabled&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;False&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;cumulus_routing_ospf6_enabled&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;False&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;cumulus_routing_rip_enabled&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;False&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;cumulus_routing_ripng_enabled&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;False&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;cumulus_routing_isis_enabled&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;False&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;cumulus_routing_pim_enabled&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;False&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;cumulus_routing_ldp_enabled&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;False&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;cumulus_routing_nhrp_enabled&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;False&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;cumulus_routing_eigrp_enabled&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;False&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;cumulus_routing_babel_enabled&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;False&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;cumulus_routing_sharp_enabled&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;False&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;cumulus_routing_pbr_enabled&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;False&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;  &lt;!--- Used to add a double line break ---&gt;&lt;/p&gt;

&lt;p&gt;Lastly, because we want our switches to run OSPF and BGP, we’ll set “cumulus_routing_bgp_enabled” to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;True&lt;/code&gt; in the file “/etc/ansible/group_vars/openstack_cumulus/vars.yml”:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Management&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;cumulus_management_interface&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;eth0&quot;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# OSPF Routing&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;cumulus_routing_ospf_unnumbered&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;True&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;cumulus_routing_ospf_enabled&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;True&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# BGP Routing&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;cumulus_routing_bgp_enabled&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;frr-routing-configuration&quot;&gt;FRR Routing Configuration&lt;/h3&gt;

&lt;p&gt;The second template that we’re creating is “/etc/ansible/roles/cumulus-routing/templates/frr.conf.j2”.&lt;br /&gt;
This file will end up looking like the output of the traditional &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;show running-configuration&lt;/code&gt; command on a Cisco router, as the syntax is very similar.&lt;/p&gt;

&lt;p&gt;I’m going to split the writing of this file into many separate parts, as it’ll be easier to explain that way.&lt;/p&gt;

&lt;h4 id=&quot;standard-frr-configuration&quot;&gt;Standard FRR Configuration&lt;/h4&gt;

&lt;p&gt;We’ll start with the top of this template:&lt;/p&gt;

&lt;!--  --&gt;
&lt;div class=&quot;language-jinja highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;! &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ansible_managed&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
!
frr defaults datacenter
!
hostname &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;inventory_hostname&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
username cumulus nopassword
!
service integrated-vtysh-config
!
log syslog informational
!
line vty
!
router-id &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_host_loopback_address&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;| &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ipaddr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'address'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
!
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;!--  --&gt;

&lt;p&gt;We’re just setting some base daemon information here:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frr defaults datacenter&lt;/code&gt; - Configuring &lt;a href=&quot;https://docs.cumulusnetworks.com/display/HOSTPACK/Configuring+FRRouting+on+the+Host#ConfiguringFRRoutingontheHost-CumulusFRRDefaultsfortheDataCenter&quot;&gt;routing process defaults&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hostname&lt;/code&gt; - What the hostname of the router is, using the “inventory_hostname” variable.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;username&lt;/code&gt; - The base user.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;service integrated-vtysh-config&lt;/code&gt; - Tells FRR to use one config file, frr.conf.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;log syslog informational&lt;/code&gt; - Output all logs to “/var/log/frr/frr.log”.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;line vty&lt;/code&gt; - Configuration of access to the command line interface. Note that this is &lt;em&gt;not&lt;/em&gt; configuration of a physical console port, but the shell access through vtysh.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;router-id&lt;/code&gt; - Sets the global router ID for the switch. As this should not include the subnet CIDR notation, we strip this out using the Jinja &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ipaddr&lt;/code&gt; filter.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nothing too fancy. Let’s move on.&lt;/p&gt;

&lt;h4 id=&quot;ospf-unnumbered&quot;&gt;OSPF Unnumbered&lt;/h4&gt;

&lt;p&gt;&lt;a href=&quot;https://docs.cumulusnetworks.com/display/DOCS/Open+Shortest+Path+First+-+OSPF+-+Protocol#OpenShortestPathFirst-OSPF-Protocol-ospf_unnumUnnumberedInterfaces&quot;&gt;OSPF Unnumbered&lt;/a&gt; is a way for network devices to talk OSPF to each other over interfaces that don’t themselves have unique IP addresses.&lt;br /&gt;
I say unique because the interfaces still have IP addresses configured on them, but in an unnumbered environment all interfaces can take the same IP address (the loopback for example).&lt;/p&gt;

&lt;p&gt;We did exactly that in the &lt;a href=&quot;https://wadman.co.nz/2018/11/23/OpenStack-Lab-Network-Switch-Interfaces/#Interface-IP-Addresses&quot;&gt;previous post&lt;/a&gt;, where we configured the loopback address of each host and configured this on each switchport interface as well.&lt;br /&gt;
This tells the Cumulus switches to use the loopback address for OSPF messages on the link instead of unique addressing, making for easier configuration and reduces the OSPF database size as there aren’t individual link addresses for each switchport.&lt;/p&gt;

&lt;p&gt;  &lt;!--- Used to add a double line break ---&gt;&lt;/p&gt;

&lt;p&gt;The one caveat is that unnumbered interfaces are only supported on OSPF point-to-point links.&lt;br /&gt;
Let’s make sure we don’t miss that by adding the below configuration into our template:&lt;/p&gt;

&lt;!--  --&gt;
&lt;div class=&quot;language-jinja highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;!
&lt;span class=&quot;c&quot;&gt;{# Configure switchports as OSPF point-to-point #}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_routing_ospf_enabled&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_switchgroup_switchports&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;| &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sort&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
interface &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
 ip ospf network point-to-point
!
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endfor&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endif&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
!
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;!--  --&gt;

&lt;p&gt;The logic on this one is pretty simple. As long as OSPF is enabled, set each switchport to OSPF point-to-point.&lt;/p&gt;

&lt;h4 id=&quot;ospf-underlay&quot;&gt;OSPF Underlay&lt;/h4&gt;

&lt;p&gt;Again, we’ll jump into the configuration and then cover what it does.&lt;/p&gt;

&lt;!--  --&gt;
&lt;div class=&quot;language-jinja highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;!
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_routing_ospf_enabled&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;{# Configure switchports as OSPF point-to-point #}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_switchgroup_switchports.items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;| &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sort&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
interface &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
  ip ospf network point-to-point
!
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endfor&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
!
router ospf
  ospf router-id &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_host_loopback_address&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;| &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ipaddr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'address'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
  network &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_host_loopback_address&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt; area 0.0.0.0
  passive-interface lo
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endif&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
!
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;!--  --&gt;

&lt;p&gt;Because we’re including the underlay configuration inside of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if&lt;/code&gt; loop we created before, we don’t need to check again if OSPF should be enabled. So we jump straight into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;router ospf&lt;/code&gt; configuration hierachy.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ospf router-id&lt;/code&gt; defines the router ID that the OSPF process will use.&lt;br /&gt;
Side note - Because we’ve defined this globally we don’t &lt;em&gt;need&lt;/em&gt; to do this, but it’s good practice to hardcode this in the case the global router-id changes for any reason.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;network&lt;/code&gt; configuration line accomplishes two things. Firstly, it indicates to OSPF that it can start sending and listening for messages on all interfaces that have the loopback address configured (the loopback interface and, with our configuration in the previous section, all switchports too).
This also tells OSPF to advertise the loopback address to its neighbours in area “0.0.0.0”. This is required for IP reachability between each device and ultimately enables BGP peerings to be established from the OpenStack hosts to the spine switches.&lt;/p&gt;

&lt;p&gt;Finally, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;passive-interface lo&lt;/code&gt; disables OSPF from sending and listening for messages on the loopback interface.&lt;/p&gt;

&lt;p&gt;  &lt;!--- Used to add a double line break ---&gt;&lt;/p&gt;

&lt;p&gt;And that’s it for OSPF. Easy huh?&lt;br /&gt;
Other changes that might be applicable to a larger production environment would include:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Configuring a different OSPF area for each rack and summarizing on the leaf switches.&lt;/li&gt;
  &lt;li&gt;Configuring border leaf switches to advertise external/default routes into OSPF.&lt;/li&gt;
  &lt;li&gt;Configuring authentication for OSPF interfaces so that unwanted speakers can’t participate.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;ibgp-overlay&quot;&gt;iBGP Overlay&lt;/h4&gt;

&lt;p&gt;Here’s the configuration:&lt;/p&gt;

&lt;!--  --&gt;
&lt;div class=&quot;language-jinja highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_routing_bgp_enabled&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ansible_hostname&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;groups&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'openstack_cumulus_spines'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
router bgp &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ibgp_autonomous_system&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt; view iBGP-RR
  bgp router-id &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_host_loopback_address&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;| &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ipaddr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'address'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
  bgp cluster-id 1
&lt;span class=&quot;c&quot;&gt;{# Defines a peer group where common configuration to be defined for all peers #}&lt;/span&gt;
  neighbor iBGP-RR-Clients peer-group
  neighbor iBGP-RR-Clients remote-as internal
&lt;span class=&quot;c&quot;&gt;{# Forms a neighborship with the other spine switches #}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;spine&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;groups&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'openstack_cumulus_spines'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;| &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;difference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;inventory_hostname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
  neighbor &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;hostvars&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;spine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;cumulus_host_loopback_address&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt; peer-group iBGP-RR-Clients
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endfor&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;{# Enables the BGP speaker to peer with all hosts within a network range #}&lt;/span&gt;
  bgp listen range &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_spines_bgp_RR_network&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt; peer-group iBGP-RR-Clients
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_routing_bgp_evpn_enabled&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;{# Enables advetisement of EVPN address family #}&lt;/span&gt;
  address-family l2vpn evpn
    neighbor iBGP-RR-Clients activate
    neighbor iBGP-RR-Clients route-reflector-client
  exit-address-family
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endif&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endif&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;!--  --&gt;

&lt;p&gt;This one might take a little bit to explain. We’ll take it one step at a time.&lt;/p&gt;

&lt;p&gt;Just like the other sections, we want to check whether BGP should be configured on the host.&lt;br /&gt;
This time it isn’t enough to check whether “cumulus_routing_bgp_enabled” has been set because we only need to configure BGP on the spine switches.&lt;br /&gt;
The second check is completed by asking whether the current host the Ansible role is running against is in the host group “openstack_cumulus_spines”.&lt;/p&gt;

&lt;p&gt;If the host clears the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if&lt;/code&gt; logic, we start by entering into the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;router bgp&lt;/code&gt; hierachy by stating the AS number and view.&lt;br /&gt;
Because we’re running iBGP between the spine switches and the OpenStack hosts, the AS number will be the same between them. We’ll define this variable shortly.&lt;br /&gt;
&lt;a href=&quot;http://docs.frrouting.org/en/latest/bgp.html#views&quot;&gt;BGP views&lt;/a&gt; are something that I hadn’t come across until writing this post. Simply put, BGP processes configured with a view participate in BGP like any other speaker, with the only difference being that routes learnt in the view process are not installed into the kernel routing table (and therefore the forwarding table) of the device.&lt;br /&gt;
This is perfect for spine switches, as they won’t need to install the EVPN routes learnt from the OpenStack clients, freeing up resources for other uses.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bgp router-id&lt;/code&gt; simply tells BGP which ID to use when communicating. We’ll set that to the loopback address, just like we did with OSPF.&lt;/p&gt;

&lt;p&gt;Setting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bgp cluster-id&lt;/code&gt; configures the BGP process to act as a route reflector for any devices that peer with it.&lt;br /&gt;
I’ve decided to use the same cluster ID on both of our route reflectors (spine switches), but it is possible to configure different a ID on each. &lt;a href=&quot;https://orhanergun.net/2015/02/bgp-route-reflector-clusters/&quot;&gt;Orhan Ergun&lt;/a&gt; writes a nice post on the topic of when to use unique cluster IDs.&lt;br /&gt;
In a topology like ours where our servers are the route reflector clients instead of the leaf switches, the risk of losing reachability between clients due to not knowing about the other RR’s routes is decreased due to each host connecting to two upstream leaf switches - therefore having 4 paths to each RR (and each other OpenStack node in another “rack”) instead of just the two.&lt;br /&gt;
In an OpenStack EVPN environment, where the route reflectors are going to be learning routes for every MAC address present, my recommendation would be to configure the cluster-id the same on each RR. You can then size up how many entries are present in the route table and determine whether having more than one copy is possible.&lt;/p&gt;

&lt;p&gt;The next two lines create a BGP neighbour group named “iBGP-RR-Clients”. Neighbour groups allow for easier configuration of neighbours with common settings.&lt;br /&gt;
The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;peer-group&lt;/code&gt; line simply defines the neighbour group.&lt;br /&gt;
The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;remote-as internal&lt;/code&gt; line tells BGP that all neighbours in the group will be iBGP neighbours.&lt;/p&gt;

&lt;p&gt;The next for loop, setting the line &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;neighbor ... peer-group iBGP-RR-Clients&lt;/code&gt;, configures a BGP neighborship manually with the other spine switches in the topology (in our case, just the other 1).&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bgp listen range&lt;/code&gt; allows the BGP speakers to form peerings with any host in the defined network.&lt;br /&gt;
For this, we’re referencing a new variable which will house the range that we expect the clients (OpenStack hosts) loopbacks to be inside - 192.168.11.0/24.&lt;/p&gt;

&lt;p&gt;The last lines tell the route reflectors to participate in the IPv4 and EVPN address family so that IP address and VXLAN information can be transferred between clients.&lt;/p&gt;

&lt;p&gt;  &lt;!--- Used to add a double line break ---&gt;&lt;/p&gt;

&lt;p&gt;We’ve referenced a few new variables in the above configuration. Let’s define these now.&lt;/p&gt;

&lt;p&gt;“cumulus_routing_bgp_evpn_enabled” will have a default of “False”, but needs to be enabled for our environment.&lt;br /&gt;
In our role defaults:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# FRR Routing Configuration&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;cumulus_routing_bgp_evpn_enabled&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;False&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And “/etc/ansible/group_vars/openstack_cumulus/vars.yml”:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# BGP Routing&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;cumulus_routing_bgp_enabled&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;True&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;cumulus_routing_bgp_evpn_enabled&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I’ve placed the iBGP autonomous system number variable in “/etc/ansible/group_vars/openstack_lab/vars.yml” so that all hosts (switches and OpenStack servers) can access it:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# IP Routing&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;ibgp_autonomous_system&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;65000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Lastly, our route reflector client network only needs to be accessible to the spine switches.&lt;br /&gt;
In “/etc/ansible/group_vars/openstack_cumulus_spines/vars.yml”:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# BGP routing&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;cumulus_spines_bgp_RR_network&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;192.168.11.0/24&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;testing&quot;&gt;Testing&lt;/h1&gt;

&lt;p&gt;Now that we’re done with our configuration we can deploy this to our hosts and test that it is working.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;ansible-playbook /etc/ansible/playbooks/openstack-cumlus.yml
...
PLAY RECAP &lt;span class=&quot;k&quot;&gt;****************************************************************&lt;/span&gt;
openstack-cumulus-leaf01   : &lt;span class=&quot;nv&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;11   &lt;span class=&quot;nv&quot;&gt;changed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;5    &lt;span class=&quot;nv&quot;&gt;unreachable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0    &lt;span class=&quot;nv&quot;&gt;failed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0
openstack-cumulus-leaf02   : &lt;span class=&quot;nv&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;11   &lt;span class=&quot;nv&quot;&gt;changed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;5    &lt;span class=&quot;nv&quot;&gt;unreachable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0    &lt;span class=&quot;nv&quot;&gt;failed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0
openstack-cumulus-leaf03   : &lt;span class=&quot;nv&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;11   &lt;span class=&quot;nv&quot;&gt;changed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;5    &lt;span class=&quot;nv&quot;&gt;unreachable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0    &lt;span class=&quot;nv&quot;&gt;failed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0
openstack-cumulus-leaf04   : &lt;span class=&quot;nv&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;11   &lt;span class=&quot;nv&quot;&gt;changed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;5    &lt;span class=&quot;nv&quot;&gt;unreachable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0    &lt;span class=&quot;nv&quot;&gt;failed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0
openstack-cumulus-spine01  : &lt;span class=&quot;nv&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;11   &lt;span class=&quot;nv&quot;&gt;changed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;5    &lt;span class=&quot;nv&quot;&gt;unreachable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0    &lt;span class=&quot;nv&quot;&gt;failed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0
openstack-cumulus-spine02  : &lt;span class=&quot;nv&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;11   &lt;span class=&quot;nv&quot;&gt;changed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;5    &lt;span class=&quot;nv&quot;&gt;unreachable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0    &lt;span class=&quot;nv&quot;&gt;failed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We can then log into our switches (using the tool &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vagrant ssh&lt;/code&gt;) and check that everything still looks okay.&lt;br /&gt;
As an initial check, let’s look at how the FRR service is doing:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;systemctl status frr
● frr.service - FRRouting
   Loaded: loaded &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;/lib/systemd/system/frr.service&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; enabled&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
   Active: active &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;running&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;Result: exit-code&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; since Sun 2018-12-09 15:18:32 NZDT&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; 30s ago
  Process: 10291 &lt;span class=&quot;nv&quot;&gt;ExecReload&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/usr/lib/frr/frr-reload.py &lt;span class=&quot;nt&quot;&gt;--reload&lt;/span&gt; /etc/frr/frr.conf &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;exited, &lt;span class=&quot;nv&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0/SUCCESS&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  Process: 6500 &lt;span class=&quot;nv&quot;&gt;ExecStart&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/usr/lib/frr/frr start &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;exited, &lt;span class=&quot;nv&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0/SUCCESS&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
   CGroup: /system.slice/frr.service
           ├─6517 /usr/lib/frr/zebra &lt;span class=&quot;nt&quot;&gt;-M&lt;/span&gt; snmp &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; 90000000 &lt;span class=&quot;nt&quot;&gt;--daemon&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-A&lt;/span&gt; 127.0.0.1
           ├─6524 /usr/lib/frr/bgpd &lt;span class=&quot;nt&quot;&gt;-M&lt;/span&gt; snmp &lt;span class=&quot;nt&quot;&gt;--daemon&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-A&lt;/span&gt; 127.0.0.1
           ├─6533 /usr/lib/frr/ospfd &lt;span class=&quot;nt&quot;&gt;-M&lt;/span&gt; snmp &lt;span class=&quot;nt&quot;&gt;--daemon&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-A&lt;/span&gt; 127.0.0.1
           └─6539 /usr/lib/frr/watchfrr &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-r&lt;/span&gt; /usr/sbin/servicebBfrrbBrestartbB%s &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; /usr/sbin/servicebBfrrbBstartbB%s &lt;span class=&quot;nt&quot;&gt;-k&lt;/span&gt; /usr/sbin/servicebBfrrbBstopbB%s &lt;span class=&quot;nt&quot;&gt;-b&lt;/span&gt; bB zebra bgpd ospfd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There are a few important details in the output above.&lt;br /&gt;
First (and most importantly) the service started successfully and is now running.&lt;br /&gt;
Also, under the control group (CGroup) heading we can see that several processes have spawned. “zebra”, “bgpd” and “ospfd” are present as expected and the watchdog &lt;a href=&quot;https://github.com/FRRouting/frr/blob/master/doc/manpages/watchfrr.rst&quot;&gt;watchfrr&lt;/a&gt; (which we haven’t talked about yet) is running as well.&lt;/p&gt;

&lt;h2 id=&quot;ospf-testing&quot;&gt;OSPF Testing&lt;/h2&gt;

&lt;p&gt;In terms of checking the status of network connectivity and routing protocols, Cumulus switches give us two options:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Utilize Cumulus’ “&lt;a href=&quot;https://docs.cumulusnetworks.com/display/DOCS/Network+Command+Line+Utility+-+NCLU&quot;&gt;NCLU&lt;/a&gt;” command line utility.&lt;/li&gt;
  &lt;li&gt;Login into FRR’s console shell (vtysh).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because NCLU simply piggybacks on top of vtysh, I’ll only be showing the NCLU commands in this section.&lt;br /&gt;
I’ll be performing these checks from the perspective of leaf #1.&lt;/p&gt;

&lt;p&gt;  &lt;!--- Used to add a double line break ---&gt;&lt;/p&gt;

&lt;p&gt;The first OSPF check should be whether our interface configuration has been picked up.&lt;br /&gt;
To complete this with NCLU, we type in commands from the main bash shell of the devices:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;net show ospf interface | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;lo is&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\|&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;swp&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\|&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Area&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\|&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Network&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\|&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Neighbor&quot;&lt;/span&gt;
lo is up
  Internet Address 192.168.11.111/32, Area 0.0.0.0
  Router ID 192.168.11.111, Network Type LOOPBACK, Cost: 10
  Neighbor Count is 0, Adjacent neighbor count is 0
swp1 is up
  This interface is UNNUMBERED, Area 0.0.0.0
  Router ID 192.168.11.111, Network Type POINTOPOINT, Cost: 100
  Neighbor Count is 1, Adjacent neighbor count is 1
swp2 is up
  This interface is UNNUMBERED, Area 0.0.0.0
  Router ID 192.168.11.111, Network Type POINTOPOINT, Cost: 100
  Neighbor Count is 1, Adjacent neighbor count is 1
swp3 is up
  This interface is UNNUMBERED, Area 0.0.0.0
  Router ID 192.168.11.111, Network Type POINTOPOINT, Cost: 100
  Neighbor Count is 0, Adjacent neighbor count is 0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;From here we can see that all of our interfaces are up, that they’re using the loopback interfaces address and how many neighbours are present on each.&lt;br /&gt;
Note how there aren’t any neighbours present on switchport 3, as this is a downlink to an OpenStack machine that isn’t configured yet.&lt;/p&gt;

&lt;p&gt;  &lt;!--- Used to add a double line break ---&gt;&lt;/p&gt;

&lt;p&gt;Next up is confirming the neighbourships.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;net show ospf neighbor

Neighbor ID     Pri State           Dead Time Address         Interface            RXmtL RqstL DBsmL
192.168.11.101    1 Full/DROther      30.670s 192.168.11.101  swp1:192.168.11.111      0     0     0
192.168.11.102    1 Full/DROther      30.484s 192.168.11.102  swp2:192.168.11.111      0     0     0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As expected, two neighbourships - one to each spine switch.&lt;/p&gt;

&lt;p&gt;  &lt;!--- Used to add a double line break ---&gt;&lt;/p&gt;

&lt;p&gt;Let’s also take a look at the OSPF routing table, as that should now be populated with the loopback addresses of each switch in the network:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;net show ospf route
&lt;span class=&quot;o&quot;&gt;============&lt;/span&gt; OSPF network routing table &lt;span class=&quot;o&quot;&gt;============&lt;/span&gt;
N    192.168.11.101/32     &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;100] area: 0.0.0.0
                           via 192.168.11.101, swp1
N    192.168.11.102/32     &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;100] area: 0.0.0.0
                           via 192.168.11.102, swp2
N    192.168.11.111/32     &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;0] area: 0.0.0.0
                           directly attached to lo
N    192.168.11.112/32     &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;200] area: 0.0.0.0
                           via 192.168.11.101, swp1
                           via 192.168.11.102, swp2
N    192.168.11.113/32     &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;200] area: 0.0.0.0
                           via 192.168.11.101, swp1
                           via 192.168.11.102, swp2
N    192.168.11.114/32     &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;200] area: 0.0.0.0
                           via 192.168.11.101, swp1
                           via 192.168.11.102, swp2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It’s important to check that we’re receiving two routes for each other leaf switch’s loopback address as that confirms that each spine is receiving and readvertising them.&lt;/p&gt;

&lt;p&gt;  &lt;!--- Used to add a double line break ---&gt;&lt;/p&gt;

&lt;p&gt;Lastly, we’ll check the routing table to confirm that the routes above have been installed.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;net show route ipv4
Codes: K - kernel route, C - connected, S - static, R - RIP,
       O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP,
       T - Table, v - VNC, V - VNC-Direct, A - Babel, D - SHARP,
       F - PBR,
       &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; - selected route, &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; - FIB route

K&amp;gt;&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; 0.0.0.0/0 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;0/0] via 192.168.11.1, eth0, 02:21:44
C&amp;gt;&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; 192.168.11.0/24 is directly connected, eth0, 02:21:44
O&amp;gt;&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; 192.168.11.101/32 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;110/100] via 192.168.11.101, swp1 onlink, 00:39:49
O&amp;gt;&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; 192.168.11.102/32 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;110/100] via 192.168.11.102, swp2 onlink, 02:21:24
C &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; 192.168.11.111/32 is directly connected, swp3, 02:21:45
C &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; 192.168.11.111/32 is directly connected, swp2, 02:21:45
C &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; 192.168.11.111/32 is directly connected, swp1, 02:21:45
O   192.168.11.111/32 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;110/0] is directly connected, lo, 02:21:45
C&amp;gt;&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; 192.168.11.111/32 is directly connected, lo, 02:21:45
O&amp;gt;&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; 192.168.11.112/32 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;110/200] via 192.168.11.101, swp1 onlink, 00:39:49
  &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;                             via 192.168.11.102, swp2 onlink, 00:39:49
O&amp;gt;&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; 192.168.11.113/32 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;110/200] via 192.168.11.101, swp1 onlink, 00:39:39
  &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;                             via 192.168.11.102, swp2 onlink, 00:39:39
O&amp;gt;&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; 192.168.11.114/32 &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;110/200] via 192.168.11.101, swp1 onlink, 00:39:39
  &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;                             via 192.168.11.102, swp2 onlink, 00:39:39
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;ip route
default via 192.168.11.1 dev eth0
192.168.11.0/24 dev eth0  proto kernel  scope &lt;span class=&quot;nb&quot;&gt;link  &lt;/span&gt;src 192.168.11.211
192.168.11.101 via 192.168.11.101 dev swp1  proto ospf  metric 20 onlink
192.168.11.102 via 192.168.11.102 dev swp2  proto ospf  metric 20 onlink
192.168.11.112  proto ospf  metric 20
	nexthop via 192.168.11.101  dev swp1 weight 1 onlink
	nexthop via 192.168.11.102  dev swp2 weight 1 onlink
192.168.11.113  proto ospf  metric 20
	nexthop via 192.168.11.101  dev swp1 weight 1 onlink
	nexthop via 192.168.11.102  dev swp2 weight 1 onlink
192.168.11.114  proto ospf  metric 20
	nexthop via 192.168.11.101  dev swp1 weight 1 onlink
	nexthop via 192.168.11.102  dev swp2 weight 1 onlink
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The top command shows FRR’s view of the kernel routing table, where we can see that routes are present.&lt;br /&gt;
Importantly, we can see that both routes received to leaf switch loopbacks are installed, to be used for ECMP load balancing.
We can confirm that Linux is thinking the same way by running the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ip route show&lt;/code&gt; command (or just &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ip route&lt;/code&gt; for short).&lt;/p&gt;

&lt;h2 id=&quot;bgp-testing&quot;&gt;BGP Testing&lt;/h2&gt;

&lt;p&gt;Unfortunately, we can’t check much on the BGP front at this stage, as our spine switches don’t have any clients peered yet.&lt;br /&gt;
We’ll cover some good BGP (and EVPN) checks in a later post where we configure FRR on the OpenStack hosts.&lt;/p&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;In this (quite lengthy - sorry!) post, we’ve configured the routing protocols needed for our Cumulus switches to support the OpenStack network.&lt;/p&gt;

&lt;p&gt;In the &lt;a href=&quot;https://wadman.co.nz/2019/01/26/OpenStack-Lab-Host-Interfaces/&quot;&gt;next post&lt;/a&gt;, I’ll start to dive into the network interface configuration required on our OpenStack hosts, before following up with the routing configuration using FRR.&lt;/p&gt;

&lt;h1 id=&quot;appendices&quot;&gt;Appendices&lt;/h1&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://docs.ansible.com/ansible/latest/plugins/lookup/template.html&quot;&gt;Ansible - “template” module&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/service_module.html&quot;&gt;Ansible - “service” module&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://jinja.pocoo.org/docs/2.10/templates/#if-expression&quot;&gt;Jinja - Inline if Statements&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://jinja.pocoo.org/docs/2.10/templates/#line-statements&quot;&gt;Jinja - Multi-line expressions&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://docs.cumulusnetworks.com/display/DOCS/Configuring+FRRouting&quot;&gt;Cumulus Linux - FRR Configuration&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://docs.cumulusnetworks.com/display/DOCS/Open+Shortest+Path+First+-+OSPF+-+Protocol&quot;&gt;Cumulus Linux - OSPF&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://docs.cumulusnetworks.com/display/DOCS/Equal+Cost+Multipath+Load+Sharing+-+Hardware+ECMP&quot;&gt;Cumulus Linux - ECMP&lt;/a&gt;
&lt;a href=&quot;http://docs.frrouting.org/en/latest/index.html&quot;&gt;Free Range Routing - User Guide&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://orhanergun.net/2015/02/bgp-route-reflector-clusters/&quot;&gt;Orhan Ergun - BGP Route Reflector Clusters&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://tools.ietf.org/html/rfc7348&quot;&gt;RFC7348 - VXLAN&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://tools.ietf.org/html/rfc8365&quot;&gt;RFC8365 - Network Virtualization Overlay Using EVPN&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;versions-used&quot;&gt;Versions used&lt;/h2&gt;

&lt;p&gt;Desktop Machine: &lt;em&gt;kubuntu-18.04&lt;/em&gt;&lt;br /&gt;
VirtualBox: &lt;em&gt;virtualbox-5.2.18&lt;/em&gt;&lt;br /&gt;
Vagrant: &lt;em&gt;2.2.2&lt;/em&gt;&lt;br /&gt;
Cumulus VX Vagrant Box: &lt;em&gt;CumulusCommunity/cumulus-vx (virtualbox, 3.7.2)&lt;/em&gt;&lt;br /&gt;
Ansible: &lt;em&gt;2.7.4&lt;/em&gt;&lt;/p&gt;
</description>
        <pubDate>Sun, 09 Dec 2018 00:00:00 +0000</pubDate>
        <link>https://mwadman.github.io/2018/12/09/OpenStack-Lab-Network-Switch-Routing/</link>
        <guid isPermaLink="true">https://mwadman.github.io/2018/12/09/OpenStack-Lab-Network-Switch-Routing/</guid>
        
        <category>OpenStack</category>
        
        <category>Networking</category>
        
        <category>BGP</category>
        
        <category>OSPF</category>
        
        <category>EVPN</category>
        
        <category>Ansible</category>
        
        <category>Cumulus</category>
        
        <category>Vagrant</category>
        
        <category>VirtualBox</category>
        
        
      </item>
    
      <item>
        <title>OpenStack Lab Network - Switch Configuration (Part 2)</title>
        <description>&lt;h1 id=&quot;overview&quot;&gt;Overview&lt;/h1&gt;

&lt;p&gt;This post is the sixth in a series that plans to document my progress through installing and configuring a small OpenStack Lab.&lt;/p&gt;

&lt;p&gt;For other posts in this series, see the overview section of the &lt;a href=&quot;https://www.wadman.co.nz/2018/02/08/OpenStack-Lab-Network-Introduction/#overview&quot;&gt;introduction post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the &lt;a href=&quot;https://wadman.co.nz/2018/11/18/OpenStack-Lab-Network-Switch-Base/&quot;&gt;last post&lt;/a&gt;, we finished the base configuration of our Cumulus switches using Ansible.
This post will cover the configuration of network interfaces on Cumulus switches.&lt;/p&gt;

&lt;h1 id=&quot;configuration&quot;&gt;Configuration&lt;/h1&gt;

&lt;p&gt;For me, configuring the interfaces on a network device isn’t just enabling the required physical ports.&lt;br /&gt;
I think of this stage as laying the framework that our routing configuration will sit on top of.&lt;/p&gt;

&lt;p&gt;What do we need to do before we bring up OSPF or BGP? I can think of a few things:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Configuration of the loopback interface&lt;/li&gt;
  &lt;li&gt;Setting the physical properties of required ports&lt;/li&gt;
  &lt;li&gt;Setting the MTU of all interfaces&lt;/li&gt;
  &lt;li&gt;Naming/Describing all interfaces&lt;/li&gt;
  &lt;li&gt;Configuring IP addresses on interfaces&lt;/li&gt;
  &lt;li&gt;Bringing up LLDP&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Outside of our topology, you might also include some other steps. For example:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Creation of VLANs/Bridges&lt;/li&gt;
  &lt;li&gt;Configuration of LAGs (Including MCLAG)&lt;/li&gt;
  &lt;li&gt;Configuration of STP&lt;/li&gt;
  &lt;li&gt;Configuring and testing &lt;a href=&quot;https://docs.cumulusnetworks.com/display/DOCS/Prescriptive+Topology+Manager+-+PTM&quot;&gt;Cumulus PTM&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Configuring 802.1X for port authentication&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;ansible-playbookrole&quot;&gt;Ansible Playbook/Role&lt;/h2&gt;

&lt;p&gt;We’ve already created the playbook in the previous post, which references the “cumulus-base” role.&lt;br /&gt;
All we need to do now is create a new role for the interface configuration, “cumulus-interface”, and reference this in our existing playbook.&lt;/p&gt;

&lt;p&gt;Creating the role directory:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; /etc/ansible/roles/cumulus-interface/tasks/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And adding this to our playbook - “openstack-cumulus.yml”:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Configuring Cumulus switches&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;hosts&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;openstack_cumulus&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;become&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;gather_facts&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;roles&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;role&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;cumulus-base&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;cumulus-base&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;role&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;cumulus-interface&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;cumulus-interface&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;  &lt;!--- Used to add a double line break ---&gt;&lt;/p&gt;

&lt;p&gt;I’d like to make a quick digression here.&lt;br /&gt;
While we could have made only one role, named something like “cumulus-configure”, I believe that it is better to try and separate out the functions of roles.&lt;/p&gt;

&lt;p&gt;I can think of two examples of why this might be useful&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Say I wanted to include the base configuration of the switches in the ZTP script instead. With separate roles this is as easy as removing the role from the playbook, whereas with a single role you would need to manually prune the tasks in the role.&lt;/li&gt;
  &lt;li&gt;In the case that you wanted to deploy an utterly different topology onto the switches, where the difference in interface configuration would be too complex to bundle into a single role, you can simply rename the existing role to “cumulus-interface-openstack” and create a new role for the new topology.&lt;br /&gt;
(It’s important to think about the tradeoff you’re making with this reduction in complexity because you might end up making more work in the future maintaining two roles instead of just the one.)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;cumulus-interface-configuration&quot;&gt;Cumulus Interface Configuration&lt;/h2&gt;

&lt;p&gt;For network interface configuration, Cumulus again follows closely to how &lt;a href=&quot;https://wiki.debian.org/NetworkConfiguration&quot;&gt;Debian does it.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On Debian, network interface configuration is held in the file “/etc/network/interfaces”. Optionally, this file can also include (“source” is the appropriate configuration term) configuration files, usually held in the directory “/etc/network/interfaces.d/”.&lt;br /&gt;
The Debian network interface management tool “ifupdown” is then run (with this file as an input) to configure the interfaces.&lt;/p&gt;

&lt;p&gt;The only difference when it comes to Cumulus is that “ifupdown” is replaced with their own implementation - “&lt;a href=&quot;https://github.com/CumulusNetworks/ifupdown2&quot;&gt;ifupdown2&lt;/a&gt;”.&lt;/p&gt;

&lt;p&gt;  &lt;!--- Used to add a double line break ---&gt;&lt;/p&gt;

&lt;p&gt;Let’s have a look at the default “/etc/network/interfaces” file on a Cumulus box:&lt;/p&gt;

&lt;div class=&quot;language-config highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).
&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt; /&lt;span class=&quot;n&quot;&gt;etc&lt;/span&gt;/&lt;span class=&quot;n&quot;&gt;network&lt;/span&gt;/&lt;span class=&quot;n&quot;&gt;interfaces&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;/*.&lt;span class=&quot;n&quot;&gt;intf&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# The loopback network interface  
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lo&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;iface&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lo&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inet&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;loopback&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# The primary network interface  
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eth0&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;iface&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eth0&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inet&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dhcp&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I’ll also check whether there are any files already in “/etc/network/interfaces.d/”&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-alh&lt;/span&gt; /etc/network/interfaces.d/
total 0
drwxr-xr-x 1 root root   0 Nov  7 09:56 &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
drwxr-xr-x 1 root root 132 Nov 14 07:47 ..
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now that we know where to configure our interfaces, let’s jump into our first task.&lt;/p&gt;

&lt;h3 id=&quot;loopback-interface-configuration&quot;&gt;Loopback Interface Configuration&lt;/h3&gt;

&lt;p&gt;As you can see in the above section, the loopback interface is already defined by default.&lt;br /&gt;
However, this interface doesn’t have an IP address - which is needed for connectivity in our implementation of BGP.&lt;br /&gt;
Let’s change that.&lt;/p&gt;

&lt;p&gt;In the new role, under “tasks/main.yml”, I’ve created the following task:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Configure Interfaces&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;interfaces_custom.j2&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;/etc/network/interfaces.d/interfaces_custom.intf&quot;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;notify&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Restart networking&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The jinja template file (“templates/interfaces_custom.j2”) looks like the following:&lt;/p&gt;

&lt;!--  --&gt;
&lt;div class=&quot;language-jinja highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ansible_managed&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;######################&lt;/span&gt;
# Loopback Interface #
&lt;span class=&quot;c&quot;&gt;######################&lt;/span&gt;
auto lo
iface lo inet loopback
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_host_loopback_address&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;defined&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
    address &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_host_loopback_address&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endif&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;!--  --&gt;

&lt;p&gt;Because of the above, I’m also going to create the variable “cumulus_host_loopback_address” for all of our Cumulus hosts.&lt;br /&gt;
Because each switch will have a different loopback address, I’m going to create six different host variable files (one for each switch) and create the variable for each.&lt;br /&gt;
Here’s what “/etc/ansible/host_vars/cumulus-spine01/vars.yml” looks like as an example:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;cumulus_host_loopback_address&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;192.168.11.101/32&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Finally, we need to restart the “networking” service on the switches if there are any changes made.&lt;br /&gt;
Here’s what my “handlers/main.yml” file looks like:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Restart networking&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;service&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;networking&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;restarted&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;physical-interface-configuration&quot;&gt;Physical Interface Configuration&lt;/h3&gt;

&lt;p&gt;Physical network configuration is completed in the same way as the loopback, just with different naming and a few more options to consider.&lt;br /&gt;
The ones that we’re going to start with are “auto &lt;em&gt;port&lt;/em&gt;” and “iface &lt;em&gt;port&lt;/em&gt;”, which both need to be present for ifupdown to load a given port.&lt;/p&gt;

&lt;p&gt;Because we’ve already written the task to copy our interfaces template file into the sourced directory, we simply need to append the physical interface configuration to our existing template:&lt;/p&gt;

&lt;!--  --&gt;
&lt;div class=&quot;language-jinja highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#########################&lt;/span&gt;
# Switchport Interfaces #
&lt;span class=&quot;c&quot;&gt;#########################&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_switchgroup_switchports.items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;| &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sort&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
auto &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
iface &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;

&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endfor&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;!--  --&gt;

&lt;p&gt;If we remember back to when the &lt;a href=&quot;https://wadman.co.nz/2018/06/08/OpenStack-Lab-Network-DHCP/#hosts&quot;&gt;Ansible hosts file&lt;/a&gt; was created, the groups “openstack_cumulus_spines”, “openstack_cumulus_leafgroup1” and “openstack_cumulus_leafgroup2”. This was because the switches in each group have something in common - every switch connects to the same devices.&lt;br /&gt;
As an example, the leaf switches 01 and 02 both have one uplink port to each spine switch and one downlink port to the connected OpenStack host.&lt;/p&gt;

&lt;p&gt;Before we dive into the logic of the above template, I think it might be better to show you the variable files that I’m creating for each group first.&lt;br /&gt;
Here’s what the “/etc/ansible/group_vars/openstack_cumulus_spines/vars.yml” looks like:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;cumulus_switchgroup_switchports&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;swp1&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;downlink-cumulus-leaf01&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;swp2&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;downlink-cumulus-leaf02&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;swp3&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;downlink-cumulus-leaf03&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;swp4&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;downlink-cumulus-leaf04&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And “/etc/ansible/group_vars/openstack_cumulus_leafgroup1/vars.yml”:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;cumulus_switchgroup_switchports&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;swp1&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;uplink-cumulus-spine01&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;swp2&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;uplink-cumulus-spine02&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;swp3&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;downlink-openstack-control01&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;  &lt;!--- Used to add a double line break ---&gt;&lt;/p&gt;

&lt;p&gt;Now back to the logic of the template.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;For every key (ports/”swp&lt;em&gt;X&lt;/em&gt;” entries) in the dictionary “cumulus_switchgroup_switchports”, and their associated values:
    &lt;ul&gt;
      &lt;li&gt;First sort them, so that they are being iterated over in numerical order.&lt;/li&gt;
      &lt;li&gt;Write the key string into the file, first after “auto” and again after “iface”.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This might look a little more complicated than it needs to be, and you would be right if you thought this way. However, this is because we’re going to be expanding on this loop in the next configuration steps.&lt;/p&gt;

&lt;h3 id=&quot;mtu&quot;&gt;MTU&lt;/h3&gt;

&lt;p&gt;MTU on Cumulus needs to be configured under each interface individually - unless you’re okay with using the default of 1500.&lt;br /&gt;
This is set by adding an indented line of “mtu &lt;em&gt;value&lt;/em&gt;” under the “iface &lt;em&gt;port&lt;/em&gt;” line for the port.&lt;/p&gt;

&lt;p&gt;Now that we have a base template for each switch port, this shouldn’t be too hard.&lt;br /&gt;
First, let’s create a variable for the MTU, which will be shared across all ports.&lt;br /&gt;
In “/etc/ansible/group_vars/openstack_lab/vars.yml”, we’ll make the variable “openstack_lab_mtu”:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Network Interfaces&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;openstack_lab_mtu&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;9000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Next is to include it in the template:&lt;/p&gt;

&lt;!--  --&gt;
&lt;div class=&quot;language-jinja highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#########################&lt;/span&gt;
# Switchport Interfaces #
&lt;span class=&quot;c&quot;&gt;#########################&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_switchgroup_switchports.items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;| &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sort&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
auto &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
iface &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
    mtu &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;openstack_lab_mtu&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endfor&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;!--  --&gt;

&lt;p&gt;Note that because this is a global variable we didn’t need to include this in each switch group’s variable file.&lt;br /&gt;
Likewise, the reference in the template is to the global variable and not to either the port or value in the loop.&lt;/p&gt;

&lt;h3 id=&quot;interface-descriptions&quot;&gt;Interface Descriptions&lt;/h3&gt;

&lt;p&gt;Interface descriptions in Debian network configuration are referred to as “aliases”, and configured as such.&lt;br /&gt;
Like with the MTU for a port, the alias is configured with another indented line under “iface &lt;em&gt;port&lt;/em&gt;”, this time with “alias &lt;em&gt;value&lt;/em&gt;”.&lt;/p&gt;

&lt;p&gt;If you’ve been observant, you’ll notice that we have already created a key named “alias” under each switch port in the switch group variables.&lt;br /&gt;
That way we can use this in our template, which now becomes:&lt;/p&gt;

&lt;!--  --&gt;
&lt;div class=&quot;language-jinja highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#########################&lt;/span&gt;
# Switchport Interfaces #
&lt;span class=&quot;c&quot;&gt;#########################&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_switchgroup_switchports.items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;| &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sort&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
auto &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
iface &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
    mtu &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;openstack_lab_mtu&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'alias'&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;{# Description of the interface #}&lt;/span&gt;
    alias &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;value.alias&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endif&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;

&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endfor&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;!--  --&gt;

&lt;p&gt;Let’s come back to the logic for the loop again and expand on it to cover the alias inclusion.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;For every key (ports/”swp&lt;em&gt;X&lt;/em&gt;” entries) in the dictionary “cumulus_switchgroup_switchports”, and their associated values:
    &lt;ul&gt;
      &lt;li&gt;First sort them, so that they are being iterated over in numerical order.&lt;/li&gt;
      &lt;li&gt;Write the key string into the file, first after “auto” and again after “iface”.&lt;/li&gt;
      &lt;li&gt;Write “mtu” followed by what the variable “openstack_lab_mtu” is set to.&lt;/li&gt;
      &lt;li&gt;If the key has a value inside of it with the name of “alias” then write “alias” followed what the value is set to.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;interface-ip-addresses&quot;&gt;Interface IP Addresses&lt;/h3&gt;

&lt;p&gt;The last interface configuration change we’ll make is to add an IP address to each interface.&lt;br /&gt;
This won’t be just any IP address though, as we’re going to reuse the loopback address so that we can take advantage of &lt;a href=&quot;https://docs.cumulusnetworks.com/display/DOCS/Open+Shortest+Path+First+-+OSPF+-+Protocol#OpenShortestPathFirst-OSPF-Protocol-ospf_unnumUnnumberedInterfaces&quot;&gt;OSPF unnumbered&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I’ll cover this in detail in the next post on routing configuration.&lt;/p&gt;

&lt;!--  --&gt;
&lt;div class=&quot;language-jinja highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#########################&lt;/span&gt;
# Switchport Interfaces #
&lt;span class=&quot;c&quot;&gt;#########################&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_switchgroup_switchports.items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;| &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sort&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
auto &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
iface &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
    mtu &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;openstack_lab_mtu&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_routing_ospf_unnumbered&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
    address &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_host_loopback_address&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endif&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'alias'&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;{# Description of the interface #}&lt;/span&gt;
    alias &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;value.alias&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endif&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;

&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endfor&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;!--  --&gt;

&lt;p&gt;In “/etc/ansible/group_vars/openstack_cumulus/vars.yml”, we’ll make the variable “cumulus_routing_ospf_unnumbered” and set this to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;True&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Management&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;cumulus_management_interface&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;eth0&quot;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Routing&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;cumulus_routing_ospf_unnumbered&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;configuring-lldp&quot;&gt;Configuring LLDP&lt;/h2&gt;

&lt;p&gt;LLDP on Cumulus is implemented with &lt;a href=&quot;https://vincentbernat.github.io/lldpd/&quot;&gt;lldpd&lt;/a&gt; and is enabled by default on all interfaces.
Therefore, all I’m going to configure in this step is what interfaces LLDP should &lt;em&gt;not&lt;/em&gt; run on.&lt;br /&gt;
This is done with the file “/etc/lldpd.d/exclude.conf”:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Configure LLDP&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;lldpexclude.conf.j2&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/etc/lldpd.d/exclude.conf&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;notify&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Restart LLDP&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is a pretty simple file, with just one line of configuration:&lt;/p&gt;

&lt;!--  --&gt;
&lt;div class=&quot;language-jinja highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ansible_managed&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
configure system interface pattern-blacklist &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_management_interface&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;!--  --&gt;

&lt;p&gt;And the handler simply restarts the “lldp” service:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Restart LLDP&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;service&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;lldpd&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;restarted&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If we were deploying this into a production environment, I would probably want to add &lt;a href=&quot;https://docs.cumulusnetworks.com/display/DOCS/Prescriptive+Topology+Manager+-+PTM&quot;&gt;Cumulus PTM&lt;/a&gt; configuration to this step as well.&lt;br /&gt;
As this is a lab, where I might be changing connections at any time, I’m going to leave this for now.&lt;/p&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;In this post, I covered some basic configuration of interfaces on a Cumulus switch.&lt;/p&gt;

&lt;p&gt;In the &lt;a href=&quot;https://wadman.co.nz/2018/12/09/OpenStack-Lab-Network-Switch-Routing/&quot;&gt;next post&lt;/a&gt;, I’ll start to dive into the routing configuration required for our OpenStack deployment.&lt;/p&gt;

&lt;h1 id=&quot;appendices&quot;&gt;Appendices&lt;/h1&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://docs.ansible.com/ansible/latest/plugins/lookup/template.html&quot;&gt;Ansible - “template” module&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/service_module.html&quot;&gt;Ansible - “service” module&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://wiki.debian.org/NetworkConfiguration&quot;&gt;Debian Network Configuration&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://docs.cumulusnetworks.com/display/DOCS/Interface+Configuration+and+Management&quot;&gt;Cumulus Linux - Interface Configuration&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://docs.cumulusnetworks.com/display/DOCS/Switch+Port+Attributes&quot;&gt;Cumulus Linux - Switchport Attributes&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://docs.cumulusnetworks.com/display/DOCS/Open+Shortest+Path+First+-+OSPF+-+Protocol#OpenShortestPathFirst-OSPF-Protocol-ospf_unnumUnnumberedInterfaces&quot;&gt;Cumulus Linux - OSPF Unnumbered&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://docs.cumulusnetworks.com/display/DOCS/Link+Layer+Discovery+Protocol&quot;&gt;Cumulus Linux - LLDP&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;versions-used&quot;&gt;Versions used&lt;/h2&gt;

&lt;p&gt;Desktop Machine: &lt;em&gt;kubuntu-18.04&lt;/em&gt;&lt;br /&gt;
VirtualBox: &lt;em&gt;virtualbox-5.2.10&lt;/em&gt;&lt;br /&gt;
Vagrant: &lt;em&gt;2.2.1&lt;/em&gt;&lt;br /&gt;
Cumulus VX Vagrant Box: &lt;em&gt;CumulusCommunity/cumulus-vx (virtualbox, 3.7.2)&lt;/em&gt;&lt;br /&gt;
Ansible: &lt;em&gt;2.7.2&lt;/em&gt;&lt;/p&gt;
</description>
        <pubDate>Fri, 23 Nov 2018 00:00:00 +0000</pubDate>
        <link>https://mwadman.github.io/2018/11/23/OpenStack-Lab-Network-Switch-Interfaces/</link>
        <guid isPermaLink="true">https://mwadman.github.io/2018/11/23/OpenStack-Lab-Network-Switch-Interfaces/</guid>
        
        <category>OpenStack</category>
        
        <category>Networking</category>
        
        <category>Ansible</category>
        
        <category>Cumulus</category>
        
        <category>Vagrant</category>
        
        <category>VirtualBox</category>
        
        
      </item>
    
      <item>
        <title>OpenStack Lab Network - Switch Configuration (Part 1)</title>
        <description>&lt;h1 id=&quot;overview&quot;&gt;Overview&lt;/h1&gt;

&lt;p&gt;This post is the fifth in a series that plans to document my progress through installing and configuring a small OpenStack Lab.&lt;/p&gt;

&lt;p&gt;For other posts in this series, see the overview section of the &lt;a href=&quot;https://www.wadman.co.nz/2018/02/08/OpenStack-Lab-Network-Introduction/#overview&quot;&gt;introduction post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the &lt;a href=&quot;https://wadman.co.nz/2018/08/03/OpenStack-Lab-Network-HTTP/&quot;&gt;last post&lt;/a&gt;, we configured the HTTP part of the ZTP server and then showed that we were able to bring everything up with Vagrant.
This post will cover the base configuration of the Cumulus switches using Ansible.&lt;/p&gt;

&lt;h1 id=&quot;configuration&quot;&gt;Configuration&lt;/h1&gt;

&lt;p&gt;So what constitutes “base” configuration?&lt;br /&gt;
When I think of ‘base’, I think of everything that is done &lt;em&gt;before&lt;/em&gt; any network configuration is made:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Installing any prerequisite/additional packages&lt;/li&gt;
  &lt;li&gt;&lt;del&gt;Install the licence&lt;/del&gt; (Not relevant for Cumulus VX)&lt;/li&gt;
  &lt;li&gt;Configuring DNS (Including hostname)&lt;/li&gt;
  &lt;li&gt;Configuring NTP&lt;/li&gt;
  &lt;li&gt;Configuring Authentication&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first one is definitely a new one for network devices as most network operating systems wouldn’t allow for any packages to be installed, but as the switch is a Linux device I’m going to install some packages that I like.&lt;/p&gt;

&lt;h2 id=&quot;ansible-playbook&quot;&gt;Ansible Playbook&lt;/h2&gt;

&lt;p&gt;We’ll start by writing the playbook that we’ll call.&lt;br /&gt;
In the directory “/etc/ansible/playbooks/” I’m creating another file, this time with the name “openstack-cumulus.yml”:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Configuring Cumulus switches&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;hosts&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;openstack_cumulus&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;become&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;gather_facts&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;roles&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;role&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;cumulus-base&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;cumulus-because&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Super simple. We want to run a single role (“cumulus-base”, which we’ll create next) on all of our switches to configure them.&lt;/p&gt;

&lt;h2 id=&quot;ansible-role&quot;&gt;Ansible Role&lt;/h2&gt;

&lt;p&gt;To start, we’ll create the roles “tasks” directory:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; /etc/ansible/roles/cumulus-base/tasks/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Within this directory, let’s make a “main.yml” file and start adding tasks.&lt;/p&gt;

&lt;h3 id=&quot;installing-packages&quot;&gt;Installing packages&lt;/h3&gt;

&lt;p&gt;The first thing listed is the installation of packages.&lt;br /&gt;
Cumulus runs on top of Debian Jessie and uses “apt” as its’ package manager, so we’ll use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apt&lt;/code&gt; Ansible module for this step.&lt;/p&gt;

&lt;p&gt;With the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apt&lt;/code&gt; module, I like to start with a base state of declaring the name of each package and then the state that I want Ansible to keep it at.&lt;br /&gt;
I think this is a good habit to get into as it reminds me to think about whether I want a given package to remain stable or not.&lt;/p&gt;

&lt;p&gt;The only other option I’ll include is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cache_valid_time&lt;/code&gt; and set this to something a larger than the time between test runs of a playbook (I’ve found 15 minutes to be a good place to set this) so that the task isn’t running every time I test.&lt;/p&gt;

&lt;p&gt;I’m just going to install some troubleshooting packages, “bwm-ng” and “mtr”, but because we added the Debian repositories to apt as a part of our ZTP script we could install any others that we saw fit.&lt;/p&gt;

&lt;!--  --&gt;
&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Install apt packages&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;apt&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;item.name&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;}}&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;item.state&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;}}&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;cache_valid_time&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;900&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;loop&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;bwm-ng&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;latest&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;mtr&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;latest&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;packages&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;!--  --&gt;

&lt;h3 id=&quot;configuring-dns&quot;&gt;Configuring DNS&lt;/h3&gt;

&lt;p&gt;Because we can skip installing a licence (Cumulus VX doesn’t require one), next on our list is DNS configuration.&lt;/p&gt;

&lt;p&gt;DNS configuration on a switch means&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Setting DNS Servers&lt;/li&gt;
  &lt;li&gt;Setting the hostname of the device&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can (again) skip a step, in setting the DNS servers, this time because our switch receives these via DHCP when it boots.&lt;/p&gt;

&lt;p&gt;To set the hostname with Ansible we use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hostname&lt;/code&gt; module and pass it the hostname that we’ve entered into our Ansible “hosts” file (another reason why this is important).&lt;/p&gt;

&lt;!--  --&gt;
&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Set hostname&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;hostname&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;inventory_hostname&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;}}&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;!--  --&gt;

&lt;h3 id=&quot;configuring-ntp&quot;&gt;Configuring NTP&lt;/h3&gt;

&lt;p&gt;NTP configuration consists of setting the timezone and then the NTP servers to get the time from.&lt;br /&gt;
On Debian, both of these are set within files and then the appropriate service reloaded.&lt;/p&gt;

&lt;h4 id=&quot;configuring-timezone&quot;&gt;Configuring Timezone&lt;/h4&gt;

&lt;p&gt;This one is nice and easy as the file we’re changing, “/etc/timezone/”, consists of a single line that is set to a &lt;a href=&quot;https://en.wikipedia.org/wiki/List_of_tz_database_time_zones&quot;&gt;&lt;em&gt;Continent/City&lt;/em&gt;&lt;/a&gt; pair string.&lt;br /&gt;
For me, that’s “Pacific/Auckland”.&lt;/p&gt;

&lt;p&gt;Because this is a text file, we can set this in multiple ways with Ansible.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;copy&lt;/code&gt; module using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;content&lt;/code&gt; option.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;template&lt;/code&gt; module and a source jinja template.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As we’ll see going forward, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;copy&lt;/code&gt; option would end up being incredibly messy for some of the longer files. This paired with the idea that it might be nice to use the same module throughout all of our configuration tasks means that I’ll go with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;template&lt;/code&gt; instead.&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Set Timezone&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;timezone.j2&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/etc/timezone&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;notify&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Reload timezone&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This does mean that we need to create a few more directories and files for the template and handler.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; /etc/ansible/roles/cumulus-base/templates
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; /etc/ansible/roles/cumulus-base/handlers
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In the “templates” folder we’ll create “timezone.j2”, which will contain one variable which we’ll call “timezone”:&lt;/p&gt;

&lt;!--  --&gt;
&lt;div class=&quot;language-jinja highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;timezone&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;!--  --&gt;

&lt;p&gt;We now need to tell Ansible what this variable should be set to. Because this is a widely applicable variable (not just applicable to an openstack lab) I’m going to put this into “/etc/ansible/group_vars/all/vars.yml” so that all hosts can reference it.&lt;br /&gt;
I’ll also add the NTP servers at the same time that we’ll reference in the next task below.&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# NTP&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;timezone&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Pacific/Auckland&quot;&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;ntp_servers&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;0.nz.pool.ntp.org&quot;&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;1.nz.pool.ntp.org&quot;&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;2.nz.pool.ntp.org&quot;&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;3.nz.pool.ntp.org&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In the “handlers” folder we’ll create “main.yml” and create a handler that tells the system to reload the timezone if a change is made.&lt;br /&gt;
On Debian, this is done by telling dpkg to reconfigure the “tzdata” package.&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Reload timezone&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;dpkg-reconfigure&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;--frontend&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;noninteractive&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;tzdata&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;configuring-ntp-servers&quot;&gt;Configuring NTP Servers&lt;/h4&gt;

&lt;p&gt;The task to configure NTP servers is going to look very similar to the timezone task, as we’re using the template module to modify an existing file and then run a handler if something changes.&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Configure NTP&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ntp.j2&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/etc/ntp.conf&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;notify&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Restart NTP&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For the template, I’m simply going to copy the existing configuration file, remove the extraneous comments, and then add in our NTP servers using a jinja ‘for’ loop.&lt;/p&gt;

&lt;!--  --&gt;
&lt;div class=&quot;language-jinja highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ansible_managed&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
# /etc/ntp.conf, configuration for ntpd; see ntp.conf(5) for help

driftfile /var/lib/ntp/ntp.drift

statistics loopstats peerstats clockstats
filegen loopstats file loopstats type day enable
filegen peerstats file peerstats type day enable
filegen clockstats file clockstats type day enable

# NTP Servers
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;item&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ntp_servers&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
server &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;item&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endfor&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;

# By default, exchange time with everybody, but don't allow configuration.
restrict -4 default kod notrap nomodify nopeer noquery
restrict -6 default kod notrap nomodify nopeer noquery

# Local users may interrogate the ntp server more closely.
restrict 127.0.0.1
restrict ::1

# Specify interfaces, don't listen on switch ports
interface listen &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;cumulus_management_interface&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;!--  --&gt;

&lt;p&gt;On the last line we’re telling the switch to listen for NTP only on the management interface.&lt;br /&gt;
We’re going to be refering to the management interface again (in later posts), so I’m going to define a variable so I only have to change this in one place if the need arises.&lt;/p&gt;

&lt;p&gt;Because the variable is only relevant to the cumulus switches, I’m going to put this into a new file - “/etc/ansible/group_vars/openstack-cumulus/vars.yml”:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# Management&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;cumulus_management_interface&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;eth0&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;  &lt;!--- Used to add a double line break ---&gt;&lt;/p&gt;

&lt;p&gt;The handler looks a little simpler for this task though, as we can use the “service” module to restart NTP on the hosts.&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Restart NTP&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;service&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ntp&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;restarted&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;configuring-authentication&quot;&gt;Configuring Authentication&lt;/h3&gt;

&lt;p&gt;Authentication in a production environment should probably include incorporation into the existing authentication service (RADIUS/TACACS/LDAP), but because we’re running a lab I’ll leave it out for now.&lt;/p&gt;

&lt;p&gt;However, Cumulus does include their own command-line-esque tool called “netd” which requires users to be given permission to run commands.&lt;br /&gt;
This is controlled in the configuration file “/etc/netd.conf”:&lt;/p&gt;

&lt;div class=&quot;language-ini highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Control which users/groups are allowed to run &quot;add&quot;, &quot;del&quot;,  
# &quot;clear&quot;, &quot;abort&quot;, and &quot;commit&quot; commands.  
&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;users_with_edit&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;root, cumulus  &lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;groups_with_edit&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;netedit&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Control which users/groups are allowed to run &quot;show&quot; commands.  
&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;users_with_show&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;root, cumulus  &lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;groups_with_show&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;netshow, netedit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Because I might want to play with this in the future, I’ll add the user “vagrant” into the “netedit” group using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;user&lt;/code&gt; module in Ansible:&lt;/p&gt;

&lt;!--  --&gt;
&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Allow administrator access to NCLU (net commands)&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;ansible_user&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;}}'&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;groups&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;netedit&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;yes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;!--  --&gt;

&lt;p&gt;Remember that the variable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ansible_user&lt;/code&gt; refers to the user we’re using to log into the device with, which we set in an earlier post in the “hosts” inventory file.&lt;/p&gt;

&lt;h1 id=&quot;testing&quot;&gt;Testing&lt;/h1&gt;

&lt;p&gt;Now that our role is all put together, let’s give this a test run to make sure that everything works as intended:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;ansible-playbook /etc/ansible/playbooks/openstack-cumlus.yml
...
PLAY RECAP &lt;span class=&quot;k&quot;&gt;****************************************************************&lt;/span&gt;
cumulus-leaf01             : &lt;span class=&quot;nv&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;8    &lt;span class=&quot;nv&quot;&gt;changed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;7    &lt;span class=&quot;nv&quot;&gt;unreachable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0    &lt;span class=&quot;nv&quot;&gt;failed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0
cumulus-leaf02             : &lt;span class=&quot;nv&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;8    &lt;span class=&quot;nv&quot;&gt;changed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;7    &lt;span class=&quot;nv&quot;&gt;unreachable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0    &lt;span class=&quot;nv&quot;&gt;failed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0
cumulus-leaf03             : &lt;span class=&quot;nv&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;8    &lt;span class=&quot;nv&quot;&gt;changed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;7    &lt;span class=&quot;nv&quot;&gt;unreachable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0    &lt;span class=&quot;nv&quot;&gt;failed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0
cumulus-leaf04             : &lt;span class=&quot;nv&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;8    &lt;span class=&quot;nv&quot;&gt;changed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;7    &lt;span class=&quot;nv&quot;&gt;unreachable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0    &lt;span class=&quot;nv&quot;&gt;failed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0
cumulus-spine01            : &lt;span class=&quot;nv&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;8    &lt;span class=&quot;nv&quot;&gt;changed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;7    &lt;span class=&quot;nv&quot;&gt;unreachable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0    &lt;span class=&quot;nv&quot;&gt;failed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0
cumulus-spine02            : &lt;span class=&quot;nv&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;8    &lt;span class=&quot;nv&quot;&gt;changed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;7    &lt;span class=&quot;nv&quot;&gt;unreachable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0    &lt;span class=&quot;nv&quot;&gt;failed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And one more run to make sure that nothing changes the second time:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;ansible-playbook /etc/ansible/playbooks/openstack-cumlus.yml
...
PLAY RECAP &lt;span class=&quot;k&quot;&gt;****************************************************************&lt;/span&gt;
cumulus-leaf01             : &lt;span class=&quot;nv&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;6    &lt;span class=&quot;nv&quot;&gt;changed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0    &lt;span class=&quot;nv&quot;&gt;unreachable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0    &lt;span class=&quot;nv&quot;&gt;failed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0
cumulus-leaf02             : &lt;span class=&quot;nv&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;6    &lt;span class=&quot;nv&quot;&gt;changed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0    &lt;span class=&quot;nv&quot;&gt;unreachable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0    &lt;span class=&quot;nv&quot;&gt;failed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0
cumulus-leaf03             : &lt;span class=&quot;nv&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;6    &lt;span class=&quot;nv&quot;&gt;changed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0    &lt;span class=&quot;nv&quot;&gt;unreachable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0    &lt;span class=&quot;nv&quot;&gt;failed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0
cumulus-leaf04             : &lt;span class=&quot;nv&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;6    &lt;span class=&quot;nv&quot;&gt;changed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0    &lt;span class=&quot;nv&quot;&gt;unreachable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0    &lt;span class=&quot;nv&quot;&gt;failed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0
cumulus-spine01            : &lt;span class=&quot;nv&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;6    &lt;span class=&quot;nv&quot;&gt;changed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0    &lt;span class=&quot;nv&quot;&gt;unreachable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0    &lt;span class=&quot;nv&quot;&gt;failed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0
cumulus-spine02            : &lt;span class=&quot;nv&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;6    &lt;span class=&quot;nv&quot;&gt;changed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0    &lt;span class=&quot;nv&quot;&gt;unreachable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0    &lt;span class=&quot;nv&quot;&gt;failed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;running-with-vagrant&quot;&gt;Running with Vagrant&lt;/h2&gt;

&lt;p&gt;Now that we’ve got a playbook written we can incorporate this into Vagrant.&lt;br /&gt;
The aim is that this will be run when &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vagrant up&lt;/code&gt; is called, just like the ZTP playbook in the &lt;a href=&quot;https://wadman.co.nz/2018/08/03/OpenStack-Lab-Network-HTTP/&quot;&gt;last post&lt;/a&gt;.&lt;br /&gt;
To recap, this simply requires the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.vm.provision&lt;/code&gt; block somewhere in our Vagrantfile.&lt;/p&gt;

&lt;p&gt;However, unlike our previous post, we are running this playbook against multiple guest machines instead of just the one, so we end up with two options to have the playbook run:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Include the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.vm.provision&lt;/code&gt; block each individual Cumulus guest block, and use the &lt;a href=&quot;https://www.vagrantup.com/docs/provisioning/ansible_common.html#limit&quot;&gt;limit&lt;/a&gt; option that the provisioner provides. This would run the playbook once for every machine specified and only against that one machine.&lt;/li&gt;
  &lt;li&gt;Include the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.vm.provision&lt;/code&gt; block only once, in the last Cumulus guest block.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’m going to go with the second option as I believe this to be a cleaner way of completing this.&lt;br /&gt;
However, I can see that you might want to run this individually if there was a requirement to have one device fully configured before bringing up the next.&lt;/p&gt;

&lt;p&gt;  &lt;!--- Used to add a double line break ---&gt;&lt;/p&gt;

&lt;p&gt;This is what the Vagrantfile ends up looking like. I’ve included a skeleton of the last Cumulus machine’s configuration to illustrate the provisioners’ position in the configuration hierachy.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# Leaf 4&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;cumulus_leaf04&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;device&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# Ansible Playbook for all Cumulus switches&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;device&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;vm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;provision&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:ansible&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ansible&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ansible&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;playbook&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/etc/ansible/playbooks/openstack-cumulus.yml&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ansible&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;inventory_path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/etc/ansible/hosts&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ansible&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;limit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;openstack_cumulus&quot;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The only thing to note here is that we also need to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ansible.limit&lt;/code&gt; to specify all of the hosts we want to run against, as otherwise Vagrant will tell Ansible to only run this against the hosts which are in the same block; which in this case would be just “cumulus_leaf04”.&lt;/p&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;In this post I started an Ansible playbook to configure some basic functions on Cumulus hosts and covered how to include this in our Vagrantfile.&lt;/p&gt;

&lt;p&gt;In the &lt;a href=&quot;https://wadman.co.nz/2018/11/23/OpenStack-Lab-Network-Switch-Interfaces/&quot;&gt;next post&lt;/a&gt;, I’ll dive into the network interface configuration of the switches, including LLDP and PTMD (I’ll cover what PTMD is as well) configuration on Cumulus.&lt;/p&gt;

&lt;h1 id=&quot;appendices&quot;&gt;Appendices&lt;/h1&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/apt_module.html&quot;&gt;Ansible - “apt” module&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/hostname_module.html&quot;&gt;Ansible - “hostname” module&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://docs.ansible.com/ansible/latest/plugins/lookup/template.html&quot;&gt;Ansible - “template” module&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/command_module.html&quot;&gt;Ansible - “command” module&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/service_module.html&quot;&gt;Ansible - “service” module&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/user_module.html&quot;&gt;Ansible - “user” module&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://www.vagrantup.com/docs/provisioning/ansible.html&quot;&gt;Vagrant - Ansible Provisioner&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://docs.cumulusnetworks.com/display/DOCS/Quick+Start+Guide#QuickStartGuide-ConfiguretheHostnameandTimezone&quot;&gt;Cumulus Linux - Setting the hostname&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://docs.cumulusnetworks.com/display/DOCS/Setting+Date+and+Time&quot;&gt;Cumulus Linux - Setting Date and Time&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://docs.cumulusnetworks.com/display/DOCS/Network+Command+Line+Utility+-+NCLU#NetworkCommandLineUtility-NCLU-Editthenetd.confFile&quot;&gt;Cumulus Linux - NCLU, Editing netd.conf&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;versions-used&quot;&gt;Versions used&lt;/h2&gt;

&lt;p&gt;Desktop Machine: &lt;em&gt;kubuntu-18.04&lt;/em&gt;&lt;br /&gt;
VirtualBox: &lt;em&gt;virtualbox-5.2.10&lt;/em&gt;&lt;br /&gt;
Vagrant: &lt;em&gt;2.2.1&lt;/em&gt;&lt;br /&gt;
Cumulus VX Vagrant Box: &lt;em&gt;CumulusCommunity/cumulus-vx (virtualbox, 3.7.2)&lt;/em&gt;  &lt;br /&gt;
Ansible: &lt;em&gt;2.7.2&lt;/em&gt;&lt;/p&gt;
</description>
        <pubDate>Sun, 18 Nov 2018 00:00:00 +0000</pubDate>
        <link>https://mwadman.github.io/2018/11/18/OpenStack-Lab-Network-Switch-Base/</link>
        <guid isPermaLink="true">https://mwadman.github.io/2018/11/18/OpenStack-Lab-Network-Switch-Base/</guid>
        
        <category>OpenStack</category>
        
        <category>Networking</category>
        
        <category>Ansible</category>
        
        <category>Cumulus</category>
        
        <category>Vagrant</category>
        
        <category>VirtualBox</category>
        
        
      </item>
    
      <item>
        <title>Ansible - Firewalld Module on Ubuntu</title>
        <description>&lt;h1 id=&quot;overview&quot;&gt;Overview&lt;/h1&gt;

&lt;p&gt;When trying to run an Ansible “firewalld” task on an Ubuntu machine recently, I received the following error:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;TASK &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Firewalld Task] &lt;span class=&quot;k&quot;&gt;**************************&lt;/span&gt;
fatal: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;vagrant-test]: FAILED! &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;changed&quot;&lt;/span&gt;: &lt;span class=&quot;nb&quot;&gt;false&lt;/span&gt;, &lt;span class=&quot;s2&quot;&gt;&quot;msg&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;Python Module not found: firewalld and its python module are required for this module, version 0.2.11 or newer required (0.3.9 or newer for offline operations)&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here is the task that I’m running:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Firewalld Test Task&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;firewalld&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;service&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;https&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;enabled&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;investigation&quot;&gt;Investigation&lt;/h1&gt;

&lt;p&gt;After a quick google search, I found some &lt;a href=&quot;https://github.com/ansible/ansible/issues/24855&quot;&gt;other&lt;/a&gt; &lt;a href=&quot;https://github.com/ansible/ansible-modules-extras/issues/1282&quot;&gt;people&lt;/a&gt; have run into this as well.&lt;br /&gt;
Although there were some fixes noted in the above issues, none of them sat well with me as they required installing extra packages.&lt;/p&gt;

&lt;p&gt;There has to be a better way right?&lt;/p&gt;

&lt;p&gt;Hunting further took me back to the Ansible &lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/firewalld_module.html&quot;&gt;firewalld module documentation&lt;/a&gt;, which includes the following notes:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Not tested on any Debian based system.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Requires the python2 bindings of firewalld, which may not be installed by default.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;For distributions where the python2 firewalld bindings are unavailable (e.g Fedora 28 and later) you will have to set the ansible_python_interpreter for these hosts to the python3 interpreter path and install the python3 bindings.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Those last points ring true with us. But how do we go about fixing this?&lt;/p&gt;

&lt;h1 id=&quot;rectification&quot;&gt;Rectification&lt;/h1&gt;

&lt;p&gt;Well, turns out that the fix is considerably easier than installing extra packages.&lt;/p&gt;

&lt;p&gt;Following the advice from that last note in the documentation, we first need to check what version of the bindings we’re using:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;apt-cache depends firewalld | &lt;span class=&quot;nb&quot;&gt;grep &lt;/span&gt;Depends | &lt;span class=&quot;nb&quot;&gt;grep &lt;/span&gt;python
  Depends: python3-dbus
  Depends: python3-gi
  Depends: python3-slip-dbus
  Depends: &amp;lt;python3:any&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now that we’ve confirmed we’re using the python3 bindings, we’ll simply tell Ansible to use python3 when running the task.&lt;br /&gt;
This is accomplished by setting the variable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ansible_python_interpreter&lt;/code&gt; to “/usr/bin/python3”.&lt;/p&gt;

&lt;p&gt;In true Ansible fashion, the variable can be set in multiple ways/places. But because I don’t want it to impact the running of my other tasks, I’m going to use the task level &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vars&lt;/code&gt; option, as below:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Firewalld Test Task&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;firewalld&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;service&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;https&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;enabled&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;vars&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;ansible_python_interpreter&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;/usr/bin/python3'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This results in a happy firewalld task and a change of the firewalld state on the host:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;TASK &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Firewalld Task] &lt;span class=&quot;k&quot;&gt;**************************&lt;/span&gt;
changed: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;vagrant-test]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;This was another quick post, which may help other people who are running into a similar issue.&lt;/p&gt;

&lt;p&gt;I could have gone into more detail around how I might refactor this task to include logic so that the python interpreter is only changed when running against Ubuntu machines, but I wanted to keep this quick and easy to read.&lt;/p&gt;

&lt;h1 id=&quot;appendices&quot;&gt;Appendices&lt;/h1&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/ansible/ansible/issues/24855&quot;&gt;Ansible Github Issue #24855&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://github.com/ansible/ansible-modules-extras/issues/1282&quot;&gt;Ansible Modules Extras Github Issue #1282&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;versions-used&quot;&gt;Versions used&lt;/h2&gt;

&lt;p&gt;Local Machine:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Operating System: &lt;em&gt;Kubuntu-18.04.1&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;Ansible: &lt;em&gt;2.7.2&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Remote Machine:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Operating System: &lt;em&gt;Ubuntu-16.04.5&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;Firewalld: &lt;em&gt;0.4.0&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Sat, 17 Nov 2018 00:00:00 +0000</pubDate>
        <link>https://mwadman.github.io/2018/11/17/Ansible-Firewalld-Module-On-Ubuntu/</link>
        <guid isPermaLink="true">https://mwadman.github.io/2018/11/17/Ansible-Firewalld-Module-On-Ubuntu/</guid>
        
        <category>Ansible</category>
        
        <category>Ubuntu</category>
        
        
      </item>
    
      <item>
        <title>Python Virtualenv for Dummies</title>
        <description>&lt;h1 id=&quot;overview&quot;&gt;Overview&lt;/h1&gt;

&lt;p&gt;Recently I was trying to write a &lt;a href=&quot;https://gitlab.com/mwadman/artstation-downloader&quot;&gt;script&lt;/a&gt; that had dependencies on pip packages.
Now, I am fortunate enough to know that it’s a bad idea to install pip packages globally &lt;a href=&quot;https://askubuntu.com/a/802594&quot;&gt;(especially&lt;/a&gt;&lt;a href=&quot;https://stackoverflow.com/a/15028735&quot;&gt; using &lt;/a&gt;&lt;a href=&quot;https://stackoverflow.com/a/47268013&quot;&gt;sudo)&lt;/a&gt;, so I set about to find the best way to install those dependencies without breaking my system.&lt;/p&gt;

&lt;p&gt;I’d heard about virtualenv (Virtual Environment) before, and after a quick google this seemed to be the solution I needed.&lt;br /&gt;
Simply put, a virtualenv is a secluded environment (directory) where you install the dependencies your application requires so that it can’t interfere with the rest of your operating system (and its’ possible separate dependencies).&lt;/p&gt;

&lt;p&gt;However, installing and using virtualenv seemed far too complicated, especially for a python newbie like myself.&lt;/p&gt;

&lt;p&gt;This post is meant as a “Python Virtualenv for Dummies”; both so that I have a quick document to refer back to, and hopefully to help those as helpless as I am.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Note that this post uses an installation of Ubuntu 18.04 with Python v3.6.
If you were wanting to install Virtualenv for Python 2 instead, simply remove the “3” off the end of the install commands.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id=&quot;installation&quot;&gt;Installation&lt;/h1&gt;

&lt;p&gt;First up is installing python and pip, both of which are done through apt:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-get &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;python3 python3-pip
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Next is installing virtualenv using pip. We’ll install this only for our user, so we don’t need to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;pip3 &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--user&lt;/span&gt; virtualenv
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;using-virtualenv&quot;&gt;Using Virtualenv&lt;/h1&gt;

&lt;p&gt;First we need to create an environment, this is done in the root directory of your project:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /path/to/project/dir
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;virtualenv venv
New python executable &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;venv/bin/python
Installing setuptools, pip, wheel...done.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The only argument supplied to the command is the subdirectory to create within the directory.&lt;br /&gt;
The name “venv” is a common one, but you can name it whatever you want.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Don’t forget to add this directory to your .gitignore (or equivalent) if you’re using SCM.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Within this newly created directory are the python binaries that we can use to only affect our project.
For example, to install pip packages to our environment:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;venv/bin/pip &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$PackageName&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Or to run a python program:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;venv/bin/python &lt;span class=&quot;nv&quot;&gt;$ProgramName&lt;/span&gt;.py
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;activating-the-environment&quot;&gt;Activating the environment&lt;/h2&gt;

&lt;p&gt;If you’re like me and are too lazy to type in the path to the binaries folder every time you want to run a command, then there is the option to &lt;a href=&quot;https://virtualenv.pypa.io/en/stable/userguide/#activate-script&quot;&gt;activate&lt;/a&gt; the environment.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;source &lt;/span&gt;venv/bin/activate
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will change your shell prompt to show you that you’re running python commands from within a venv as well.&lt;/p&gt;

&lt;p&gt;Now we can run commands without referencing the binaries folder:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;pip &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$PackageName&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Behind the scenes, all this does is change the $PATH entry for the current shell session so that the first entry is the local virtualenv.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ $PATH&lt;/span&gt;
bash: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;source &lt;/span&gt;venv/bin/activate
&lt;span class=&quot;nv&quot;&gt;$ $PATH&lt;/span&gt;
bash: /path/to/project/dir/venv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To reverse this, either leave the current shell session or run the deactivate script:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;deactivate
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;Hopefully this post was short and simple enough to understand, as I expect to refer back to this myself once I inevitably forget how to use virtualenv in a month.&lt;/p&gt;

&lt;h1 id=&quot;appendices&quot;&gt;Appendices&lt;/h1&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://virtualenv.pypa.io/en/stable/&quot;&gt;Virtualenv Official Documentation&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://www.dabapps.com/blog/introduction-to-pip-and-virtualenv-python/&quot;&gt;A non-magical introduction to Pip and Virtualenv for Python beginners&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;versions-used&quot;&gt;Versions used&lt;/h2&gt;

&lt;p&gt;Desktop Machine: &lt;em&gt;kubuntu-18.04.1&lt;/em&gt;&lt;br /&gt;
Python: &lt;em&gt;Python 2.7.15rc1&lt;/em&gt;&lt;br /&gt;
Virtualenv: &lt;em&gt;16.0.0&lt;/em&gt;&lt;/p&gt;
</description>
        <pubDate>Sun, 05 Aug 2018 00:00:00 +0000</pubDate>
        <link>https://mwadman.github.io/2018/08/05/Python-virtualenvs-for-Dummies/</link>
        <guid isPermaLink="true">https://mwadman.github.io/2018/08/05/Python-virtualenvs-for-Dummies/</guid>
        
        <category>Python</category>
        
        
      </item>
    
  </channel>
</rss>
