When HW/virtualized/containerized network element offers NETCONF interface to manage, it is extremely beneficial to use it for repetitive tasks (upgrades, sanity checking, route table checking etc).
NETCONF can be used over different transports as below:
|
netconf-ssh 830/tcp NETCONF-over-SSH # [RFC4742] netconf-beep 831/tcp NETCONF-over-BEEP # [RFC4744] netconfsoaphttp 832/tcp NETCONF-for-SOAP-over-HTTPS # [RFC4743] netconfsoapbeep 833/tcp NETCONF-for-SOAP-over-BEEP # [RFC4743] netconf-tls 6513/tcp NETCONF-over-TLS # [RFC5539] |
In case SSH is used then it must be made sure that SSH subsystem is enabled in SSH config on a device.
If a YANG model is available then TailF offers a client and Java class generator under:
https://github.com/tail-f-systems/JNC
Alternatively, as in the example below, Python can be used to manually connect over SSH and based on YANG model (if used) instruct the device to perform a specific task.
There is a library in Python for that purpose called ncclient (NETCONF client):
https://github.com/ncclient/ncclient
Firstly we need to do the proper import in our client script after installing the library:
|
from ncclient import manager from ncclient.xml_ import * from ncclient.operations.rpc import RPC |
Let’s define method used for connecting to the device:
|
def connect_to_the_device(host, port, user, password): return manager.connect(host=host, port=port, username=user, password=password, hostkey_verify=False) |
Create an object class that inherits from RPC class of ncclient library and define a method that will be compose an XML NETCONF message based on YANG model:
|
class Action(RPC): def perform_yang_action1(self, arg1, arg2, arg3): action1 = etree.Element("action", {"xmlns": "http://tail-f.com/ns/netconf/actions/1.0" } data = etree.SubElement(action, 'data') perform_action1 = etree.SubElement(data, 'action1', {"xmlns": "http://stackblog.net/ns/yang/action1"}) etree.SubElement(perform_action1, 'arg1').text = arg1 etree.SubElement(perform_action1, 'arg2').text = arg2 etree.SubElement(perform_action1, 'arg3').text = arg3 return self._request(action1) |
Connect to the device and perform requested action (probably not the safest way to use clear text password to connect):
|
connectionManager = connect_to_the_device("1.2.3.4", "22", "netconf", "netconf") #create action and invoke it action1 = Action(connectionManager._session, connectionManager._device_handler, timeout=2) action1.perform_yang_action1(arg1 = "arg1", arg2 = "arg2", arg3 = "arg3") time.sleep(1) #Print the result of the invoked action if action1.reply != None: action1.print_reply() #close the session to the device connectionManager.close_session() |
The request in NETCONF formatted XML would look as follows:
|
<nca:action xmlns:nca="http://tail-f.com/ns/netconf/actions/1.0"> <nca:data> <action1 xmlns:"http://stackblog.net/ns/yang/actions/action1"> <arg1>arg1</arg1> <arg2>arg2</arg2> <arg3>arg3</arg3> </action1> </nca:data> </nca:action> </nc:rpc> |
And a corresponding YANG model:
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
|
module actions { yang-version "1"; namespace: "http://stackblog.net/ns/yang/actions"; prefix "actions"; import tailf { prefix "yang/common"; } rpc action1 { input { leaf arg1 { type string; } leaf arg2 { type string; } leaf arg3 { type string; } } output { leaf status { type string; } } } } |
Lastly in XML:
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
|
<?xml version="1.0" encoding="UTF-8"?> <module name="actions" xmlns="urn:ietf:params:xml:ns:yang:yin:1" xmlns:actions="http://stackblog.net/ns/yang/actions" xmlns:tailf="http://tail-f.com/yang/common"> <namespace uri="http://stackblog.net/ns/yang/actions"/> <tailf:action name="action1"> <input> <leaf name="arg1"> <type name="string"/> </leaf> <leaf name="arg2"> <type name="string"/> </leaf> <leaf name="arg3"> <type name="string"/> </leaf> </input> <output> <leaf name="status"> <type name="string"> </leaf> </output> </tailf:action> </module> |