Getting Started with Netconf/Yang/Python on a Cicso Catalyst 9300

     I put together this quick reference guide for Netconf/Yang with Python for the Catalyst 9300. I assume this with work on the 3850 as well (have not tested it)




Enable Netconf Yang on the device.
!Create a user account with level 15 access
username admin privilege 15 secret cisco123
 
!enable netconf-yang 
netconf-yang


https://developer.cisco.com/docs/ios-xe/#!enabling-netconf-on-ios-xe/netconf


Run examples.
Requirement
Python 3.6
 Installing python dependencies:
    > pip3 install lxml ncclient

    Running script: (save as example.py)
    > python example.py
-u <username> -p <password> --host <ip/hostname> --port 830
*I am testing these scripts from Linux* 

you can get all code in listed on github

git clone https://github.com/caiena78/Netconf_Part1.git


Get the config.
import sys
from argparse import ArgumentParser
from ncclient import manager

import xml.dom.minidom

filter = '''
  <native xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-native"/>
'''
if __name__ == '__main__':
    parser = ArgumentParser(description='Select options.')
    # Input parameters
    parser.add_argument('--host', type=str, required=True,
                        help='The device IP or DN. Required')
    parser.add_argument('-u', '--username', type=str, required=True,
                        help='Username on the device. Required')
    parser.add_argument('-p', '--password', type=str, required=True,
                        help='Password for the username. Required')
    parser.add_argument('--port', type=int, default=830,
                        help='Specify this if you want a non-default port. Default: 830')

    args = parser.parse_args()

    m = manager.connect(host=args.host,
                        port=args.port,
                        username=args.username,
                        password=args.password,
                        device_params={'name':'csr'})

    if len(filter) > 0:
        data = '''<filter>%s</filter>''' % filter
    else:
        data = None
        m.timeout = 120

    reply = m.get(data)
    # Pretty print the XML reply
    xmlDom = xml.dom.minidom.parseString(str(reply))
    print(xmlDom.toprettyxml(indent='  '))

List the capabilities of the switch
import sys
from argparse import ArgumentParser
from ncclient import manager

import xml.dom.minidom


if __name__ == '__main__':
        parser = ArgumentParser(description='Select options.')

        # Input parameters
        parser.add_argument('--host', type=str, required=True,
                        help='The device IP or DN. Required')
        parser.add_argument('-u', '--username', type=str, required=True,
                        help='Username on the device. Required')
        parser.add_argument('-p', '--password', type=str, required=True,
                        help='Password for the username. Required')
        parser.add_argument('--port', type=int, default=830,
                        help='Specify this if you want a non-default port. Default: 830')

        args = parser.parse_args()

        m = manager.connect(host=args.host,
                        port=args.port,
                        username=args.username,
                        password=args.password,
                        device_params={'name':'csr'})
        for c in m.server_capabilities:
                print(c)

Get a list of all interfaces
import sys
from argparse import ArgumentParser
from ncclient import manager

import xml.dom.minidom


data='''
<filter>
<native xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-native">
  <interface/>
</native>
</filter>
'''

if __name__ == '__main__':

    parser = ArgumentParser(description='Select options.')

    # Input parameters
    parser.add_argument('--host', type=str, required=True,
                        help='The device IP or DN. Required')
    parser.add_argument('-u', '--username', type=str, required=True,
                        help='Username on the device. Required')
    parser.add_argument('-p', '--password', type=str, required=True,
                        help='Password for the username. Required')
    parser.add_argument('--port', type=int, default=830,
                        help='Specify this if you want a non-default port. Default: 830')

    args = parser.parse_args()

    m = manager.connect(host=args.host,
                        port=args.port,
                        username=args.username,
                        password=args.password,
                        device_params={'name':'csr'})

     m.timeout = 120

    reply = m.get(data)
    # Pretty print the XML reply
    xmlDom = xml.dom.minidom.parseString(str(reply))
    print(xmlDom.toprettyxml(indent='  '))

List details on GigabitEthernet1/0/10 interface

import sys
from argparse import ArgumentParser
from ncclient import manager

import xml.dom.minidom


data='''
<filter>
  <native xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-native">
        <interface>
          <GigabitEthernet>
            <name>1/0/10</name>
          </GigabitEthernet>
        </interface>
      </native>
</filter>
'''

if __name__ == '__main__':

    parser = ArgumentParser(description='Select options.')

    # Input parameters
    parser.add_argument('--host', type=str, required=True,
                        help='The device IP or DN. Required')
    parser.add_argument('-u', '--username', type=str, required=True,
                        help='Username on the device. Required')
    parser.add_argument('-p', '--password', type=str, required=True,
                        help='Password for the username. Required')
    parser.add_argument('--port', type=int, default=830,
                        help='Specify this if you want a non-default port. Default: 830')

    args = parser.parse_args()

    m = manager.connect(host=args.host,
                        port=args.port,
                        username=args.username,
                        password=args.password,
                        device_params={'name':'csr'})

     m.timeout = 120

    reply = m.get(data)
    # Pretty print the XML reply
    xmlDom = xml.dom.minidom.parseString(str(reply))
    print(xmlDom.toprettyxml(indent='  '))

Disable a interface with a description.

import sys
from argparse import ArgumentParser
from ncclient import manager

import xml.dom.minidom

payload = '''
<config>
      <native xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-native">
        <interface>
          <GigabitEthernet>
            <name>1/0/10</name>
            <description>disabled by Netconf</description>
            <shutdown/>
          </GigabitEthernet>
        </interface>
      </native>
</config>
'''


if __name__ == '__main__':

    parser = ArgumentParser(description='Select options.')

    # Input parameters
    parser.add_argument('--host', type=str, required=True,
                        help='The device IP or DN. Required')
    parser.add_argument('-u', '--username', type=str, required=True,
                        help='Username on the device. Required')
    parser.add_argument('-p', '--password', type=str, required=True,
                        help='Password for the username. Required')
    parser.add_argument('--port', type=int, default=830,
                        help='Specify this if you want a non-default port. Default: 830')

    args = parser.parse_args()

    m = manager.connect(host=args.host,
                        port=args.port,
                        username=args.username,
                        password=args.password,
                        device_params={'name':'csr'})


    reply = m.edit_config(payload,target='running')
    xmlDom = xml.dom.minidom.parseString(str(reply))
    print(xmlDom.toprettyxml(indent='  '))

Enable a Interface with a description.
***If the interface is not shutdown you will receive a error if you try to no shut a interface that
 is already enabled*** 

import sys
from argparse import ArgumentParser
from ncclient import manager

import xml.dom.minidom

payload = '''
   <config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
      <native xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-native">
        <interface>
          <GigabitEthernet>
            <name>1/0/10</name>
            <description>Enabled by Netconf</description>
<!--If you try to enable a interface that is enabled already it  will cause an RPC error -->
            <shutdown xc:operation="delete"/>
          </GigabitEthernet>
        </interface>
      </native>
    </config>
'''



if __name__ == '__main__':

    parser = ArgumentParser(description='Select options.')

    # Input parameters
    parser.add_argument('--host', type=str, required=True,
                        help='The device IP or DN. Required')
    parser.add_argument('-u', '--username', type=str, required=True,
                        help='Username on the device. Required')
    parser.add_argument('-p', '--password', type=str, required=True,
                        help='Password for the username. Required')
    parser.add_argument('--port', type=int, default=830,
                        help='Specify this if you want a non-default port. Default: 830')

    args = parser.parse_args()

    m = manager.connect(host=args.host,
                        port=args.port,
                        username=args.username,
                        password=args.password,
                        device_params={'name':'csr'})


    reply = m.edit_config(payload,target='running')
    xmlDom = xml.dom.minidom.parseString(str(reply))
    print(xmlDom.toprettyxml(indent='  '))



configure a trunk interface with allowed vlan's configured (100,200). 
***If the interface is not shutdown you will receive a error if you try to no shut a interface that
 is already enabled*** 

import lxml.etree as ET
from argparse import ArgumentParser
from ncclient import manager
from ncclient.operations import RPCError

payload = """
<config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
      <native xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-native">
        <interface>
          <GigabitEthernet>
            <name>1/0/9</name>
            <description>Netconf Trunk Port</description>
  <!--If you try to enable a interface that is enabled already it  will cause an RPC error -->
            <shutdown xc:operation="delete"/>
           <switchport>
            <mode xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-switch">
              <trunk/>
            </mode>
            <trunk xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-switch">
              <allowed>
                <vlan>
                  <vlans>100,200</vlans>
                </vlan>
              </allowed>
            </trunk>
          </switchport>
          </GigabitEthernet>
        </interface>
      </native>
    </config>
"""

if __name__ == '__main__':

    parser = ArgumentParser(description='Usage:')

    # script arguments
    parser.add_argument('-a', '--host', type=str, required=True,
                        help="Device IP address or Hostname")
    parser.add_argument('-u', '--username', type=str, required=True,
                        help="Device Username (netconf agent username)")
    parser.add_argument('-p', '--password', type=str, required=True,
                        help="Device Password (netconf agent password)")
    parser.add_argument('--port', type=int, default=830,
                        help="Netconf agent port")
    args = parser.parse_args()

    # connect to netconf agent
    with manager.connect(host=args.host,
                         port=args.port,
                         username=args.username,
                         password=args.password,
                         timeout=90,
                         hostkey_verify=False,
                         device_params={'name': 'csr'}) as m:

        # execute netconf operation
        try:
            data  = m.edit_config(target='running', config=payload).xml
        except RPCError as e:
            data = e._raw
        print(data)

Comments

Popular Posts