Site icon Karneliuk

Automation 3. Configuring of Nokia SROS via NETCONF/YANG with pySROS and Python

Hello my friend,

we continue the review and tutorial of pySROS, the Nokia Python library to manage the Nokia SR OS based routers via NETCONF/YANG. In previous blogposts we’ve covered how to poll the configuration and operational data and how to structure the received data and explore its YANG modules. Today we’ll take a look how to configure Nokia SR OS based devices.


1
2
3
4
5
No part of this blogpost could be reproduced, stored in a
retrieval system, or transmitted in any form or by any
means, electronic, mechanical or photocopying, recording,
or otherwise, for commercial purposes without the
prior permission of the author.

I Have Software Developers in My Company. Why Should I Do Automation?

This is one of the trickiest questions, which doesn’t have a simple answer. Really, why should you, network or security engineer, bother yourself and step into completely new and unknown world of automation and development? The reason for that very simple: network and security automation (and infrastructure automation in general) requires detailed knowledge of the network and security infrastructure first of all. We always say at our trainings: automation is automation of your knowledge and skills. So

On top of that, we recently learned that Network Automation Engineers earns more than Software Developers. So it is your chance to turn your career into a good direction 😉

At our trainings, zero-to-hero network automation and automation with Nornir (2nd step after zero-to-hero network automation), we give you detailed knowledge of all the technologies relevant:

It was really nice to take the training. Now I’m able to put all pieces of network automation puzzle and start may journey.

Andrew Cervantes @ Senior Network Engineer, MSI Amerikas

Technologies themselves are good, but it is not good enough for us. Therefore, we put all of them in the context of the real use cases, which our team has solved and are solving in various projects in the service providers, enterprise and data centre networks and systems across the Europe and USA. That gives you opportunity to ask questions to understand the solutions in-depts and have discussions about your own projects. And on top of that, each technology is provided with online demos and you are doing the lab afterwards to master your skills. Such a mixture creates a unique learning environment, which all students value so much. Join us and unleash your potential.

Both trainings are available in live class and online formats. And more trainings coming soon!

Start your automation study today.

Brief Description

The programmable network management, especially configuration of network devices is both the most simple and the most complicated part of the network automation

Obviously, with help of our professional services and trainings you will learn, how to do automation right. Don’t loose your time and get in touch with us now.

In this concept, of the “network automation done right”, Python is playing and important part and libraries, which allows us to interact with the network devices playing are crucial. Among other parameters, the simplicity is a key factor: the easier is that to work with a certain library, the less probability is that you will break something.

What are the contributing factors for simplicity? Per my view, one of the most important factors for simplicity is a usage of Python native data formats: strings, integers, lists and dictionaries. Some people have different opinions and consider data classes a better option. I don’t believe it is true. Data classes are not bad and very useful in a certain contexts, but they are complex. As such, it is easy to do a lot of mistakes when working with them and also their mutation is often very tricky. At the same time, usage of standard Python data types gives you clear control of all aspects of data life cycle: from it is creation to reading and updating data to its deletion (create, read, update, delete – CRUD, memorise this term).

This approach we have implemented in pyGNMI for multivendor network management with Python over GNMI.

The same idea have Nokia software developers, as they implemented the similar idea in pySROS. You might have noticed that previously, when we were polling the configuration and operational data from devices in the first blogpost in this series. The same is applicable here for configuration of the Nokia SR OS based network device with pySROS:

It is possible to wrap the data in the custom data classes, such as Leaf, Containers, etc, but I don’t believe it is a good idea, to be honest. It is a good though that there is a choice and you can figure out yourself, what do you prefer more.

One of my favourites quotes, which are referred to Linus Torvald, is “Talk is cheap. Show me the code.” Let’s take a look how you can create a code to manage your Nokia devices (e.g., Nokia 7250 IXR-e/s, Nokia 7750 SR, Nokia 7950 IXR, etc).

Lab Setup

We are continuing using the setup we define in our first lab in this series:

To remind you what are the components are being used:

Read about setup in earlier blogposts: part 1 and part 2.

Scenario Description

From the practical standpoint, we are focusing today on two things:

Join our Network Automation Training to learn more about YANG.

Besides that, we’ll review a few useful scenarios, how to deal with exceptions, which may arise when you use pysros.

Python Script Development

Let’s configure the configure the following element in our device:

For configuration of this interface we’ll use OpenConfig YANG modules.

OpenConfig is leading multi vendor YANG modules supported by Cisco, Nokia, Juniper, Huawei and many others.

Step #1. Get Existing Config from a Specific Path

First of all, let’s try to collect the information about this interface before we configure it. To do that we will use the script similar to one we created in the first blogpost in this series:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#!/usr/bin/env python

# Modules
import datetime
import os
from dotenv import load_dotenv
from pysros.management import connect
from pysros.pprint import printTree


# Variables
xpath = "/openconfig-interfaces:interfaces/interface[name="loopback"]"

# Body
if __name__ == "__main__":
    ## Get connectivity details
    load_dotenv()
    host={
            "ip_address": os.getenv("NOKIA_IP"),
            "username": os.getenv("NOKIA_USER"),
            "password": os.getenv("NOKIA_PASS")
         }

    ## Timestamp: started
    t1 = datetime.datetime.now()

    ## Interecting with the device
    connect_obj = connect(host=host["ip_address"], username=host["username"],
                          password=host["password"])

    ## Collect the configuration of an interface in OpenConfig YANG modules
    r1 = connect_obj.running.get(path=xpath)

    connect_obj.disconnect()

    ## Timestamp: completed
    t2 = datetime.datetime.now()

    ## Printing results
    tl = os.get_terminal_size()
    print(f"{'=' * tl.columns}\nCompleted in {t2 -t1}\n{'=' * tl.columns}\n")

    ## Printing collected data
    print("Pre-change collection:")
    if isinstance(r1, str):
        print(r1)
    else:
        printTree(r1)

    print(f"\n{'=' * tl.columns}\n")

Read original blogpost for details.

Let’s try to run the script to collect the information…


1
2
3
4
5
6
7
8
9
10
11
12
13
# python pysros_set_config.py
Traceback (most recent call last):
  File "/root/nokia/pysros_set_config.py", line 31, in <module>
    r1 = connect_obj.running.get(path="/openconfig-interfaces:interfaces/interface[name="loopback"]")
  File "/root/nokia/venv/lib/python3.9/site-packages/pysros/management.py", line 535, in get
    return self._get(path, defaults=defaults, config_only=config_only)
  File "/root/nokia/venv/lib/python3.9/site-packages/pysros/management.py", line 421, in _get
    raise e from None
  File "/root/nokia/venv/lib/python3.9/site-packages/pysros/management.py", line 416, in _get
    current = rd.process_path(model_walker, strict=True)
  File "/root/nokia/venv/lib/python3.9/site-packages/pysros/request_data.py", line 44, in process_path
    raise make_exception(pysros_err_no_data_found)
LookupError: No data found

… Ouch. We have a lot of tracebacks. Something definitely went not as expected.

Step #2. Analyse Exception

Before analysing the traceback output, let’s recap how NETCONF get rpc works:

  1. Get rpc is performed against the running datastore. In other words, whatever you see when you type show info or show router interfaces, this is a running datastore.
  2. If there is a resource existing (i.e., if there is already some data or the path exists at least), then the response to get rpc will contain data field, which will be storing the collected content.
  3. If the path doesn’t exist, then the response to get rpc contains an empty data key; however, the key data exists itself.

At our Network Automation Training you will learn NETCONF in and out to be able to use Nokia and other devices with pySROS and other libraries.

Now, looking on the exception raised by pySROS:


1
2
3
! OUTPUT IS TRUNCATED FOR BREVITY
!
LookupError: No data found

Basically, this exception means that there is no data existing. I don’t think though, that the application should stop its execution, as it may be a desired state to start configuration (i.e., there is no configuration for a certain left to start your workflow). Therefore, we’ll amend the original logic or Nokia software developers with try/except construction:


1
2
3
4
5
6
7
8
9
10
! OUTPUT IS TRUNCATED FOR BREVITY
!
    ## Collect the configuration of an interface in OpenConfig YANG modules
    try:
        r1 = connect_obj.running.get(path=xpath)

    except LookupError as e:
        r1 = f"{e} for {xpath}"
!
! OUTPUR IS TRUNCATED FOR BREVITY

This simple code modification allows us not to terminate the execution of our code in case there is no repose received, but rather to notify the user back, that there is no data for the requested paths. Let’ see how it works now:


1
2
3
4
5
6
7
8
# python pysros_set_config.py
==========================================================================================================
Completed in 0:00:04.600006
==========================================================================================================

No data found for /openconfig-interfaces:interfaces/interface[name="loopback"]

==========================================================================================================

Now let’s proceed wit the configuration itself.

Step #3. Configure Nokia SR OS with pySROS

To change the configuration on the network device, pysros using set method, which requires two parameters:

Set method of pysros performs NETCONF edit-config method.

Per OpenConfig YANG modules, in order to create an interface, you first need to provide a container; therefore, first we will use dictionary to make such a configuration:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#!/usr/bin/env python

# Modules
import datetime
import os
from dotenv import load_dotenv
from pysros.management import connect
from pysros.pprint import printTree


# Variables
xpath = "/openconfig-interfaces:interfaces/interface[name="loopback"]"
yang_container_value = {
                            "config": {
                                "name": "loopback",
                                "type": "softwareLoopback",
                                "description": "test-pysros-loopback",
                                "enabled": True
                            }
                       }


# Functions
def get_nokia_netconf(nc_sesion, xpath: str) -> dict:
    result = {}

    try:
        result = nc_sesion.running.get(path=xpath)

    except LookupError as e:
        result = f"{e} for {xpath}"

    return result


# Body
if __name__ == "__main__":
    ## Get connectivity details
    load_dotenv()
    host={
            "ip_address": os.getenv("NOKIA_IP"),
            "username": os.getenv("NOKIA_USER"),
            "password": os.getenv("NOKIA_PASS")
         }

    ## Timestamp: started
    t1 = datetime.datetime.now()

    ## Interecting with the device
    connect_obj = connect(host=host["ip_address"], username=host["username"],
                          password=host["password"])

    ## Collect the configuration of an interface in OpenConfig YANG modules
    r1 = get_nokia_netconf(nc_sesion=connect_obj, xpath=xpath)

    # Setting a nested value (YANG container or list)
    connect_obj.candidate.set(path=xpath, value=yang_container_value)

    ## Collect the configuration of an interface in OpenConfig YANG modules
    r2 = get_nokia_netconf(nc_sesion=connect_obj, xpath=xpath)

    connect_obj.disconnect()

    ## Timestamp: completed
    t2 = datetime.datetime.now()

    ## Printing results
    tl = os.get_terminal_size()
    print(f"{'=' * tl.columns}\nCompleted in {t2 -t1}\n{'=' * tl.columns}\n")

    print("Pre-change collection:")
    if isinstance(r1, str):
        print(r1)
    else:
        printTree(r1)

    print("\nPost-change collection:")
    printTree(r2)

    print(f"\n{'=' * tl.columns}\n")

There are few modifications to original code:

  1. The collection part, as we need to repeat it, moved a user defined function get_nokia_netconf, which takes two arguments:
    1. nc_session should receive the object with opened NETCONF session from main function.
    2. xpath should receive the string with XPath for the endpoint to be polled.
  2. New variable yang_container_value added, which is a Python dictionary, storing the values, which we want to configure on the network device. Its structure is based on the OpenConfig YANG module for interfaces.
  3. The configuration itself is used applied using connect_obj.candidate.set() method, which has two aforementioned keys.
  4. The collection of the configuration is done twice: before and after change.

The set method of pysros connect() class allows to make to do a NETCONF edit-config towards candidate datastore, which is committed afterwards if successful, following the Nokia MD-CLI logic.

Join our Network Automation Training to learn how to use OpenConfig and NETCONF in real life use cases.

Let’s run the script again:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# python pysros_set_config.py
==========================================================================================================
Completed in 0:00:05.169435
==========================================================================================================

Pre-change collection:
No data found for /openconfig-interfaces:interfaces/interface[name="loopback"]

Post-change collection:
+-- config:
|   +-- name: loopback
|   +-- type: softwareLoopback
|   +-- description: test-pysros-loopback
|   `-- enabled: True
+-- state:
|   +-- name: loopback
|   +-- type: softwareLoopback
|   `-- description: test-pysros-loopback
`-- name: loopback

==========================================================================================================

As you, the configuration is properly applied and interface is created! We almost there; however, we haven’t yet configured the IP addresses as we planned in the beginning of the task. To do so, we need only to modify our input variable (and only it):


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
! OUTPUT IS TRUNCATED FOR BREVITY
!
yang_container_value = {
                            "config": {
                                "name": "loopback",
                                "type": "softwareLoopback",
                                "description": "test-pysros-loopback",
                                "enabled": True
                            },
                            "subinterfaces": {
                                "subinterface": {
                                    0: {
                                        "config": {
                                            "index": 0
                                        },
                                        "ipv4": {
                                            "addresses": {
                                                "address": {
                                                    "10.0.254.11": {
                                                        "config": {
                                                            "ip": "10.0.254.11",
                                                            "prefix-length": 32
                                                        }
                                                    }
                                                }
                                            }
                                        },
                                        "ipv6": {
                                            "addresses": {
                                                "address": {
                                                    "fc00:10:0:254::11": {
                                                        "config": {
                                                            "ip": "fc00:10:0:254::11",
                                                            "prefix-length": 128
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                       }
!
! OUTPUT IS TRUNCATED FOR BREVITY

Whilst I was preparing this dictionary, I made an interesting observation. The implementation of YANG List in pySROS is a dictionary. It may be related to the fact, that in YANG’s List element there is at least one mandatory key, which is generally shall be unique across the list (e.g., interface name in the list of all the interfaces). In order to simplify the enforcement of such behaviour, the pySROS developers turned that into a dictionary, where the key name is this mandatory key, which shall be enforced.

This behaviour is different to pyangbind, which uses lists for YANG Lists.

Now, let’s re-run our application again:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# python pysros_set_config.py
==========================================================================================================
Completed in 0:00:05.473757
==========================================================================================================

Pre-change collection:
+-- config:
|   +-- name: loopback
|   +-- type: softwareLoopback
|   +-- description: test-pysros-loopback
|   `-- enabled: True
+-- state:
|   +-- name: loopback
|   +-- type: softwareLoopback
|   `-- description: test-pysros-loopback
`-- name: loopback

Post-change collection:
+-- config:
|   +-- name: loopback
|   +-- type: softwareLoopback
|   +-- description: test-pysros-loopback
|   `-- enabled: True
+-- state:
|   +-- name: loopback
|   +-- type: softwareLoopback
|   `-- description: test-pysros-loopback
+-- subinterfaces:
|   `-- subinterface:
|       `-- 0:
|           +-- config:
|           |   `-- index: 0
|           +-- ipv4:
|           |   `-- addresses:
|           |       `-- address:
|           |           `-- 10.0.254.11:
|           |               +-- config:
|           |               |   +-- ip: 10.0.254.11
|           |               |   `-- prefix-length: 32
|           |               `-- ip: 10.0.254.11
|           +-- ipv6:
|           |   `-- addresses:
|           |       `-- address:
|           |           `-- fc00:10:0:254::11:
|           |               +-- config:
|           |               |   +-- ip: fc00:10:0:254::11
|           |               |   `-- prefix-length: 128
|           |               `-- ip: fc00:10:0:254::11
|           `-- index: 0
`-- name: loopback

==========================================================================================================

As you see, configuration is correctly applied to your Nokia SR OS based network device and our original configuration goal is set.

The last use case will be much simpler that the full configuration: you will learn how to set a simple YANG Leaf. To do that, we’ll introduce two new variables:

Also, you’d need to amend the configuration lines to use new variables in pySROS functions:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
! OUTPUT IS TRUNCATED FOR BREVITY
!
xpath2 = "/openconfig-interfaces:interfaces/interface[name="loopback"]/config/description"
description_str = "new-pysros-description"
!
! OUTPUT IS TRUNCATED FOR BREVITY
!
    ## Collect the configuration of an interface in OpenConfig YANG modules
#    r1 = get_nokia_netconf(nc_sesion=connect_obj, xpath=xpath)
    r1 = get_nokia_netconf(nc_sesion=connect_obj, xpath=xpath2)

    # Setting a nested value (YANG container or list)
#    connect_obj.candidate.set(path=xpath, value=yang_container_value)
    connect_obj.candidate.set(path=xpath2, value=description_str)

    ## Collect the configuration of an interface in OpenConfig YANG modules
#    r2 = get_nokia_netconf(nc_sesion=connect_obj, xpath=xpath)
    r2 = get_nokia_netconf(nc_sesion=connect_obj, xpath=xpath2)
!
! OUTPUT IS TRUNCATED FOR BREVITY

And re-run the application finally:


1
2
3
4
5
6
7
8
9
10
11
12
# python pysros_set_config.py
==========================================================================================================
Completed in 0:00:05.428860
==========================================================================================================

Pre-change collection:
test-pysros-loopback

Post-change collection:
new-pysros-description

==========================================================================================================

And configuration for YANG Leaf is updated as well.

Step #4. Some Other Exceptions in pySROS

Earlier in this blogpost you have already seen some information about exceptions. Here we have collected some others we have so far seen during preparing the example:


1
TypeError: Malformed keys for '/openconfig-interfaces:interfaces/openconfig-interfaces:interface' with value '{1: {'config': {'index': 1, 'description': 'another test', 'enabled': True}}}'

This exception was raised, when we tried to apply wrong container to an XPath.


1
TypeError: can only concatenate str (not "dict") to str

This exception was raised, when we tried to make the following code: print(“Output :” + r1 + “\n”) and the result was a dictionary, rather than a string.


1
TypeError: Value 'true' is not correct for leaf enabled

This exception means that in the input variables the leaf has a wrong data type: instead of true we typed “true”, whereas the YANG model expects to receive value in boolean rather than a string format.


1
TypeError: MO contents not a dict '[{0: {'config': {'index': 0}, 'ipv4': {'addresses': {'address': [{'10.0.254.11': {'config': {'ip': '10.0.254.11', 'prefix-lenght': 32}}}]}}, 'ipv6': {'addresses': {'address': [{'fc00:10:0:254::11': {'config': {'ip': 'fc00:10:0:254::11', 'prefix-lenght': 128}}}]}}}}]'

This exception related to the fact described beforehand: YANG Lists are implemented by pySROS as Python dictionaries, whereas we tried to provide list in variables.


1
pysros.exceptions.SrosMgmtError: Cannot find child with name 'prefix-lenght' in path 'openconfig-interfaces:interfaces openconfig-interfaces:interface openconfig-interfaces:subinterfaces openconfig-interfaces:subinterface openconfig-if-ip:ipv4 openconfig-if-ip:addresses openconfig-if-ip:address openconfig-if-ip:config'

This exception was raised when we did a typo in a name of they key in YANG module and created key prefix-lenght instead of prefix-length. As such key isn’t defined in the used YANG modules (OpenConfig Interfaces), the validation didn’t pass.

Examples in GitHub

You can find this and other examples in our GitHub repository.

Lessons Learned

The implementation of NETCONF with pySROS is somewhat different to what we experienced before using ncclient directly (we discussed in the first blogpost about pySROS that it is based on ncclient transport). As such, the standard approach based on requesting information for non-existing resource without any issues is not working directly and you need to use a bit more advanced Python components based on the exceptions handling. However, if you know the Python basics, you can deal with that.

And you can create your rock solid foundation in Python at our Network Automation Training.

Conclusion

You’ve made till the end of the blogpost, congratulations. Now you are well armed to manage your Nokia SR OS based network devices and can start doing an automation in your network: namely, you have learned how to use the set method to apply the big configuration blogs as well as a standalone values. In one of the following blogs you will learn how to run Nokia pySROS directly on Nokia SR OS based device. Take care and good bye.

Support us





P.S.

If you have further questions or you need help with your networks, we are happy to assist you, just send us a message. Also don’t forget to share the article on your social media, if you like it.

BR,

Anton Karneliuk

Exit mobile version