Quick Start

Installing

pip install pytanga

Basic Usage

Pytanga uses a Composite pattern to abstract YANG models, so each component has an add method which is we ed to compose the payload.

Therefore, to build the desired payload it will be necessary to instantiate all modules equivalent to the YANG models and use the add method building the necessary hierarchy, as the example bellow:

from pytanga.components import configComponent
from pytanga.components.OpenConfig.routing import networkInstancesComponent
from pytanga.components.OpenConfig.routing import networkInstanceComponent
from pytanga.components.OpenConfig.routing import protocolsComponent
from pytanga.components.OpenConfig.routing import protocolComponent
from pytanga.components.OpenConfig.routing.static import staticroutesComponent
from pytanga.components.OpenConfig.routing.static import staticComponent
from pytanga.components.OpenConfig.routing.static import nexthopsComponent
from pytanga.components.OpenConfig.routing.static import nexthopComponent
from pytanga.components.OpenConfig.routing.static import interfacerefComponent
from pytanga.visitors import NETCONFVisitor
from xml.dom.minidom import parseString

config = configComponent()
netInsts = networkInstancesComponent()
netinst = networkInstanceComponent()
protos = protocolsComponent()
proto = protocolComponent(identifier ='STATIC' , name='DEFAULT')
staticroutes = staticroutesComponent()
static = staticComponent(prefix= '172.30.0.0/24')
nexthops = nexthopsComponent()
nexthop = nexthopComponent(index='NETCONF' , next_hop='192.168.0.4')

nexthops.add(nexthop)
static.add(nexthops)
staticroutes.add(static)
proto.add(staticroutes)
protos.add(proto)
netinst.add(protos)
netInsts.add(netinst)
config.add(netInsts)

serializer = NETCONFVisitor()
output = static.parse(serializer)
xml_string = serializer.print(output)
print(parseString(xml_string).toprettyxml())

Resulting in the following output

<static>
    <prefix>172.30.0.0/24</prefix>
    <config>
        <prefix>172.30.0.0/24</prefix>
    </config>
    <next-hops>
        <next-hop>
            <index>NETCONF</index>
            <config>
                <index>NETCONF</index>
                <next-hop>192.168.0.4</next-hop>
            </config>
        </next-hop>
    </next-hops>
</static>

Configuring BGP

For configure BGP use the ConfigureBGP Helper

from pytanga.components import configComponent
from pytanga.components.Cisco.xe import nativeComponent
from pytanga.components.Cisco.xe import routerComponent
from pytanga.helpers.Cisco.xe import ConfigureBGP
from pytanga.visitors import NETCONFVisitor
from xml.dom.minidom import parseString

BGPHelper = ConfigureBGP(asn=100 , router_id='10.0.0.2')
BGPHelper.addAfi_Safi(afi_name ='ipv4' , safi_name='unicast')
BGPHelper.addNeighbor(address= '10.0.0.1'  , remote_as='100')
BGPHelper.addNeighbor(address= '10.0.0.3'  , remote_as='100')
BGPHelper.addAfiSafiNeighbor(afi_safi='ipv4-unicast' , address= '10.0.0.1')
BGPHelper.addAfiSafiNeighbor(afi_safi='ipv4-unicast' , address= '10.0.0.3')
BGPHelper.addAfiSafiNeighborRouteMap(afi_safi='ipv4-unicast' , nei_address= '10.0.0.3' , inout='in' , name='Teste')
BGPHelper.addAfiSafiNetwork(afi_safi='ipv4-unicast' , network="10.0.0.0" , mask='255.255.255.255')
BGP = BGPHelper.getBGP()

router = routerComponent()
XENative = nativeComponent()
config = configComponent()

router.add(BGP)
XENative.add(router)
config.add(XENative)

serializer = NETCONFVisitor()
output = config.parse(serializer)
xml_string = serializer.print(output)
print(parseString(xml_string).toprettyxml())

Resulting in the following output

<config>
    <native xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-native">
        <router>
            <bgp xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-bgp">
                <id>100</id>
                <bgp>
                    <router-id>
                        <ip-id>10.0.0.1</ip-id>
                    </router-id>
                </bgp>
                <address-family>
                    <no-vrf>
                        <ipv4>
                            <af-name>unicast</af-name>
                            <ipv4-unicast>
                                <neighbor>
                                    <id>10.0.0.2</id>
                                </neighbor>
                                <neighbor>
                                    <id>10.0.0.3</id>
                                    <route-map>
                                        <inout>in</inout>
                                        <route-map-name>Teste</route-map-name>
                                    </route-map>
                                </neighbor>
                                <network>
                                    <with-mask>
                                        <number>10.0.0.0</number>
                                        <mask>255.255.255.255</mask>
                                    </with-mask>
                                </network>
                            </ipv4-unicast>
                        </ipv4>
                    </no-vrf>
                </address-family>
                <neighbor>
                    <id>10.0.0.2</id>
                    <remote-as>100</remote-as>
                </neighbor>
                <neighbor>
                    <id>10.0.0.3</id>
                    <remote-as>100</remote-as>
                </neighbor>
            </bgp>
        </router>
    </native>
</config>

IOS-XE 16.9.1 resulting configuration:

router bgp 100
 bgp router-id 10.0.0.2
 bgp log-neighbor-changes
 neighbor 10.0.0.1 remote-as 100
 neighbor 10.0.0.3 remote-as 100
 !
 address-family ipv4
  network 10.0.0.0 mask 255.255.255.255
  neighbor 10.0.0.1 activate
  neighbor 10.0.0.3 activate
  neighbor 10.0.0.3 route-map Teste in
 exit-address-family

Configuring Prefix-List

For configure prefix list use the ConfigurePrefixList Helper

from pytanga.components import configComponent
from pytanga.components.Cisco.xe import nativeComponent
from pytanga.components.Cisco.xe.ip import ipComponent
from pytanga.helpers.Cisco.xe import ConfigurePrefixList
from pytanga.visitors import NETCONFVisitor
from xml.dom.minidom import parseString

config = configComponent()
native = nativeComponent()
ip = ipComponent()
PrefixListHelper = ConfigurePrefixList(name="TEST-AS")
PrefixListHelper.addPrefix(action="permit" , network="10.0.40.0/24")
PrefixListHelper.addPrefix(action="permit" , network="10.0.50.0/24")

ip.add(PrefixListHelper.getPrefixList())
native.add(ip)
config.add(native)

serializer = NETCONFVisitor()
output = config.parse(serializer)
xml_string = serializer.print(output)
print(parseString(xml_string).toprettyxml())

Resulting in the following output

<config>
    <native xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-native">
        <ip>
            <prefix-list>
                <prefixes>
                    <name>TEST-AS</name>
                    <seq>
                        <no>5</no>
                        <permit>
                            <ip>10.0.40.0/24</ip>
                        </permit>
                    </seq>
                    <seq>
                        <no>10</no>
                        <permit>
                            <ip>10.0.50.0/24</ip>
                        </permit>
                    </seq>
                </prefixes>
            </prefix-list>
        </ip>
    </native>
</config>

IOS-XE 16.9.1 resulting configuration:

ip prefix-list TEST-AS seq 5 permit 10.0.40.0/24
ip prefix-list TEST-AS seq 10 permit 10.0.50.0/24

Configuring IP Interface with OpenConfig

For configure an IP Interface use the CreateIPInterface Helper

from pytanga.components import configComponent
from pytanga.helpers.OpenConfig.interfaces import createIPInterface
from pytanga.components.OpenConfig.interfaces import interfacesComponent
from pytanga.visitors import NETCONFVisitor
from xml.dom.minidom import parseString

interfaces = interfacesComponent()
interface = createIPInterface(name="GigabitEthernet2",
                  if_type='ethernet',
                  ip_version=4,
                  address='10.0.0.5',
                  prefix_length=30,
                  if_mtu= 1650,
                  if_description='Test Configuration',
                  enabled=True)

interfaces.add(interface)
config = configComponent()
config.add(interfaces)
serializer = NETCONFVisitor()
output = config.parse(serializer)
xml_string = serializer.print(output)
print(parseString(xml_string).toprettyxml())

Resulting in the following output

<config>
    <interfaces xmlns="http://openconfig.net/yang/interfaces" xmlns:oc-ip="http://openconfig.net/yang/interfaces/ip">
        <interface>
            <name>GigabitEthernet2</name>
            <config>
                <description>Test Configuration</description>
                <mtu>1650</mtu>
                <enabled>true</enabled>
                <type xmlns:ianaift="urn:ietf:params:xml:ns:yang:iana-if-type">ianaift:ethernetCsmacd</type>
            </config>
            <subinterfaces>
                <subinterface>
                    <index>0</index>
                    <oc-ip:ipv4>
                        <oc-ip:addresses>
                            <oc-ip:address>
                                <oc-ip:ip>10.0.0.5</oc-ip:ip>
                                <oc-ip:config>
                                    <oc-ip:ip>10.0.0.5</oc-ip:ip>
                                    <oc-ip:prefix-length>30</oc-ip:prefix-length>
                                </oc-ip:config>
                            </oc-ip:address>
                        </oc-ip:addresses>
                    </oc-ip:ipv4>
                </subinterface>
            </subinterfaces>
        </interface>
    </interfaces>
</config>

IOS-XE 16.9.1 resulting configuration:

interface GigabitEthernet2
 description Test Configuration
 mtu 1650
 ip address 10.0.0.5 255.255.255.252
end