Sync prefix-lists via Junos PyEZ on several routers

Yesterday I saw a question in the official Junos PyEZ Google Group if it is possible to automate the synchronization of prefix list and policy statement configurations on several routers. Of course, you can do this with PyEZ 🙂 So I decided to answer the question with a blog article and a basic script. In this blog article, I will only focus on syncing prefix lists but handling other configuration parts is quite the same.

Setup / prefix-lists

Below you will find my setup for this test. I will use two vMX (vMX1, vMX2) and two vSRX (vSRX1, vSRX2), and all of the routers will be configured and controlled by my laptop using Junos PyEZ:

sync-prefix-lists-topology

So the topology or the transfer networks do not matter cause we will only check the prefix-lists on each router and if those are up-to-date. We will use the following two prefix-lists listA and listB for our test:

As you can see, both prefix lists consists of four prefixes – 10.0.0.x and 20.0.0.x.

Approach

Before starting with coding, we should think about our approach. So finally we want the same prefix-list to exist on all routers. If we change the prefix lists, we want to deploy the new lists to all routers. So the current prefix lists are on our laptop. We will then connect to every router to check if our prefix-lists are configured and if they are up-to-date. If not we have to do some configuration changes on the particular router.

How to organize your prefix-lists locally

First, we have to declare locally all the prefix-lists we want to sync with our routers. We will use YAML but you could also use another data format. However, you could also skip this part and use the Junos configuration snippet directly. Our prefix-lists are in a YAML-file in the “prefix-lists” folder. The YAML-file “prefix-lists.yml” will be loaded at the beginning of our script:

After loading the YAML-file, we have the information of the prefixes, but we need to generate a configuration snippet out of this data. We will handle this in combination with Jinja2, so we create a simple template:

We will use this template in combination with the data from the YAML-file. It is essential that we add the “replace:” tag within the template cause otherwise our script would not work correctly – older prefix entries would stay within the configuration. If we put all together we will get the following Python code for generating the prefix-lists configuration through our YAML-file and Jinja template:

If we print down “config” to the console we will get:

We will use this configuration snippet later for checking and configuring the prefix-lists.

Checking several routers

Since we want to automate the check of our routers with one execution of the script we need to define the routers we want to check. For doing this we will also use YAML 🙂 So every router is stored in a file called “routers.yml”:

Of course, you can also add the login credentials within the YAML file for each router. We can then load this file and loop through all the routers:

So our basic skeleton for checking all routers will be like this:

Check every router if prefix-list is up-to-date

There are different ways to check if the prefix lists are already configured and up-to-date. We will use the simple config load mechanismus via “dev.cu.load(config, format=”text”, merge=False)”. Via “dev.cu.diff()” we will test if we have to do some config changes cause this returns the difference between the candidate and running configuration.

If there is no difference (=None), everything is fine. If a difference is detected and you should do some config changes you will be asked to enter if you would like to commit these changes (Yes/No). Below you will find the whole part of the prefix-list check:

Current configuration

On vMX1 both prefix-lists are up to date and furthermore there are only the two prefix-lists listA and listB configured:

On router vMX2 the current listA and another list listABC is configured:

On SRX1, the following outdated listB is configured and listA is missing:

On vSRX2 both prefix lists listA and listB are missing but there is another list configured named listXYZ:

Testing the script – Hell yeah!

Okay, let’s check if everything is working as expected 🙂 We will execute the script, and we will see if our script initiates the correct config changes if needed:

If we now check the prefix-lists on all routers (vMX1, vMX2, vSRX1, vSRX2) we will see that our script did a great job 🙂 You can find the whole project in a repo on Github.

Please be aware that the script above is not yet production ready! You have to add e.g. exception handling by yourself 😉 Keep also in mind that if you delete a prefix-list completely from the YAML-file “prefix-lists.yml” it won’t be removed from the configuration on the routers by our script, yet. High five, thanks for reading this blog article.

9 comments on “Sync prefix-lists via Junos PyEZ on several routers”

  1. Hi – super blog-article
    Im pondering on how to create a script that could check for route-consistency
    Soppose I have network running plain IP and some BGP.
    What would your approach be to create a script that checks tables for a given route and compares the output?

    1. Hi Christian,

      it depends on what you would like to achieve or display as an output. First – I would suppose – you need a list of prefixes as a base of information. You could write these prefixes down manually as e.g. a YAML file. Of course, it would be more beautiful to generate this list generically via the information e.g. on your PEs or your network topology.

      Then connect to your routers and compare the route table against your list to see the differences of prefixes (checking for e.g. missing prefixes). You could check every single prefix if it exists on the router or downloading the hole route table for doing offline comparison. For checking a single prefix the XML RPC for the show route is the following:

      https://gist.github.com/stephanbehrens/b69885a12de9412a0e5b861100b512a2

      So you could check a specific route via:

      —–
      rpc_route = dev.rpc.get_route_information(destination=”10.0.0.2/32″, exact=True, normalize=True)
      —–

      But I would prefer using Table/View – see: https://stebe.info/2016/11/checking-bgp-with-pyez-table-view/

      best regards
      Stephan

  2. I tried your script in my lab setup – worked fine, had to do some imports on top but the only thing that confused me was the input method -? I had to use the raw_input instead otherwise it said that “NameError: name ‘Yes’ is not defined”
    What is the difference between the two?

    1. Hi Christian,

      yes, this is cause I have used Python 3 and you are using Python 2 – sorry did not mention that in the blog post above. They changed input() / raw_input() with Python 3.

      Python 3: input() returns the string. // like raw_input() with Python 2
      Python 2: input() expects a python expression.

      So you are getting a NameError cause Python does not know what “Yes” is and your workaround with changing input() back to raw_input() fixes it.

      best regards
      Stephan

Leave a Reply

Your email address will not be published. Required fields are marked *

© 2016 made with ♡ by stephan behrens - impress