Cableplan Application

The Cable Plan module allows the programmer to easily import existing cable plans from XML files, import the currently running cable plan from an APIC controller, export previously imported cable plans to a file, and compare cable plans.

More advanced users can use the Cable Plan to easily build a cable plan XML file, query a cable plan, and modify a cable plan.

Using the Cable Plan

Invoking

The Cable Plan module is imported from cableplan.py which can be found in the acitoolkit/applications/cableplan directory.

>>>from cableplan import CABLEPLAN

When you want to create a cable plan from the current running topology of an ACI fabric, simply do the following:

>>>cp = CABLEPLAN.get(session)

Where session is an ACI session object generated using the acitoolkit. cp will be the cable plan object.

You can export that cable plan by opening a file and calling the export() method as follows:

>>>cpFile = open('cableplan1.xml','w')
>>>cp.export(cpFile)
>>>cpFile.close()

The cable plan will be written to the cableplan1.xml file.

Reading an existing cable plan xml file is equally easy.:

>>>fileName = 'cableplan2.xml'
>>>cp2 = CABLEPLAN.get(fileName)

Note that you don’t have to explicitly open or close the file. The get(fileName) method will take care of that for you.

Comparing cable plans is one of the more interesting cabablilities of the Cable Plan module and is very easy to do using the “difference” methods. When generating the difference between two cable plans, the module will return those items that exist in the first cable plan, but not in the second.

For example, assume that in the above example, the second cable plan read from the cableplan2.xml file does not have switch “Spine3” and the first cable plan does have it. The following example will print all of the switches in the first cable plan and not in the second.:

>>>missing_switches = cp1.difference_switch(cp2)
>>>for switch in missing_switches :
>>>    print switch.get_name()
Spine3

Similiarly, the following example will print all of the missing links:

>>>missing_links = cp1.difference_link(cp2)
>>>for link in missing_links :
>>>    print link.get_name()

To understand all of the differences between two cable plans it is necessary to compare them in both directions

>>>missing_links = cp1.difference_link(cp2)
>>>extra_links = cp2.difference_link(cp1)
>>>print 'The following links are missing from the second cable plan'
>>>for link in missing_links :
>>>    print link.get_name()
>>>print 'The following links are extra links in the second cable plan'
>>>for link in extra_links:
>>>    print link.get_name()

If multiple ports are specified in the link object with minPorts and maxPorts attributes (see Cable Plan XML Syntax below), it is possible that a link object in the first cable plan is only partially met by the link objects in the second cable plan. The remainingNeed() method of the CP_LINK object.:

>>>missing_links = cp1.difference_link(cp2)
>>>for link in missing_links :
>>>   print 'Link',link.get_name(), 'still needs',link.remainingNeed(),'links to satisfy its mimimum requirement'

There is a similar method, remainingAvail() that returns the number of physical links the link object could match.

The remainingNeed() and remainingAvail() values are reset when the difference_link() method is invoked.

It might be necessary to compare cable plans when the names of the switches are different, but the topologies are the same. This can easily done by simply changing the names of the switches that are different and then doing the comparisons.:

>>>switch = cp1.get_switch('Spine1')
>>>switch.set_name('Spine1_new_name')

This will automatically also fix-up all of the link names that are connected to the switch whose name is being changed. Note that this is also an easy way to change the name of a switch in a cable plan file. Simply read it in, change the switch name, and export it out. The following example will read in cable_plan2.xml, change the name of ‘Leaf1’ to ‘Leaf35’, and then export to the same file the modified cable plan:

>>>fileName = 'cable_plan2.xml'
>>>cp2 = CABLEPLAN.get(fileName)
>>>switch = cp2.get_switch('Leaf1')
>>>switch.set_name('Leaf35')
>>>f = open(fileName,'w')
>>>cp2.export(f)
>>>f.close()

Cable Plan XML Syntax

The cable plan XML looks like the following

<?xml version="1.0" encoding="UTF-8"?>
<?created by cable.py?>
<CISCO_NETWORK_TYPES version="None" xmlns="http://www.cisco.com/cableplan/Schema2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="nxos-cable-plan-schema.xsd">
   <DATA_CENTER networkLocation="None" idFormat="hostname">
      <CHASSIS_INFO sourceChassis="spine1" type="n9k">
         <LINK_INFO sourcePort="eth2/35" destChassis="leaf1" destPort="eth1/50"/>
         <LINK_INFO sourcePort="eth2/3" destChassis="leaf3" destPort="eth1/50"/>
         <LINK_INFO sourcePort="eth2/2" destChassis="leaf2" destPort="eth1/50"/>
      </CHASSIS_INFO>
      <CHASSIS_INFO sourceChassis="spine2" type="n9k">
         <LINK_INFO sourcePort="eth2/1" destChassis="leaf1" destPort="eth1/49"/>
         <LINK_INFO sourcePort="eth2/3" destChassis="leaf3" destPort="eth1/49"/>
         <LINK_INFO sourcePort="eth2/2" destChassis="leaf2" destPort="eth1/49"/>
      </CHASSIS_INFO>
   </DATA_CENTER>
</CISCO_NETWORK_TYPES>

The CHASSIS_INFO tag normally identifies the spine switches and the leaf switches are contained in the LINK_INFO. When the XML is read in, both leaf and spine switch objects will be created and the get_switch() and get_link() methods can be used to access them.

The LINK_INFO syntax also allows more flexible and loose specifications of the links. If the sourcePort or destPort attributes are left out, then any port on that corresponding switch can be used. The sourcePort and destPort attributes can also take port ranges, and lists as shown here:

<LINK_INFO sourcePort="eth1/1-eth1/15, eth1/20" destChassis =
"leaf3"/>

In addition, you can add minPorts and maxPorts attributes to specify the minimum number of ports or maximum number of ports when multiple are defined.:

<LINK_INFO sourcePort="eth2/3, eth3/4 - eth3/10",
destChassis="leaf2", destPort="eth1/1 - eth1/8", minPorts=3,
maxPorts=5>

If minPorts is omitted, the default will be 1. If maxPorts is omitted, the default will be unlimited.

When comparing two cable plans using the difference_link() method, if the minimum number of links in the first cable plan can be met with second cable plan, then the difference will show no difference. Note that it is possible that requirements of several links specified in one cable plan may be met by one or more links in the other. Basically, the difference is calculated such that the minimum requirements of the first cable plan are met without exceeding the maximum capacity of the second cable plan.

Cable Plan API Reference

class cableplan.CP_PORT(portSet)

This class holds the information for a link’s port. Since the port can be a single port, a list or a range, putting it in a class allows more flexible operations on it.

list()
name()
remove_available_port(port)
resetAccounting()
export(chassis, level)

Will return string of XML describing the LINK_INFO. It will use ‘chassis’ to determine which is the source chassis so that it will be omitted from the XML and the other chassis will become the destination. ‘level’ is the indentation level.

Parameters:
  • chassis – Chassis that is the parent of the LINK_INFO xml
  • level – Indentation level
Returns:

str

get_name()
hasPortInCommon(link)

Returns True if link has any ports that match self. It will compare all ports included expanded lists of port sets.

Parameters:link – link to check to see if matches, or overlaps, with self
Returns:Boolean
isConnected(switch1, switch2=None)

Returns True if switch1 is one of the switch endpoints of the link and switch2 is unspecified otherwise is will return True if both switch1 and switch2 are switch endpoints of the link. If switch1 is the same as switch2, it will return False.

Parameters:
  • switch1 – first switch to check if it an end-point of the link
  • switch2 – optional second switch to check if it an end-point of the link
Returns:

True if switch1 (and optional switch2) is an end-point of the link

This will match-up link1 and link2 and increment the reference count in each link for each of the matches that happen. It will do this until the minimum number of links has been reached for link1. It will return the number of matches that occurred.

Parameters:
  • link1 – first link of type CP_LINK that is part of the matching
  • link2 – second link of type CP_LINK that is part of the matching
Returns:

number of matches that occured.

order()

Calculates the order of the link defined by the maximum number of physical links this link can represent

Returns:int
remainingAvail()

returns the remaining number of physical links available to match against The parameters used to calculate this value are reset by the resetAccounting() method which is typically invoked when invoking a difference_link() method on the CABLEPLAN parent object.

Returns:int
remainingNeed()

returns the remaining number of physical links needed to match against self to satisfy requirements. The parameters used to calculate this value are reset by the resetAccounting() method which is typically invoked when invoking a difference_link() method on the CABLEPLAN parent object.

Returns:int
resetAccounting()

Resets account on the source and dest ports as well as reference count

class cableplan.CP_SWITCH(name, chassis_type=None, spine=False, parent=None)

class holding a switch

export(level)

returns a list of CP_LINKS from the parent CABLEPLAN that are connected to self.

Returns:list of CP_LINKS
get_name()

Gets the name of the chassis.

Returns:str
get_type()

Gets the chassis type. Examples of chassis types are ‘n7k’ or ‘n9k’

Returns:str
isSpine()

Checks if the ‘spine’ flag is set.

Returns:True if the spine flag is set, otherwise False
merge(new_switch)

Merges the content of new_switch with self. If self has variables set, then they will not be changed. If they have not been set, then they will be assigned the value from new_switch.

Parameters:new_switch – switch object to merge with self
set_name(name)

Sets the switch name. This will over-ride any preexisting name. Note that this new name will now become part of the link name for all the links attached to this switch.

Parameters:name – name string to set in the switch
set_parent(parent)

Sets the parent of the switch. Parent must be of type CABLEPLAN. If a parent CABLEPLAN was already set and it is differnt from parent, then an error is raised.

Parameters:parent – parent object of type CABLEPLAN
class cableplan.CABLEPLAN(version=None)

Will add a link to the CABLEPLAN. Duplicates will not be allow, but overlapping will be.

Parameters:new_link – Link to be added of type CP_LINK
Returns:None
add_switch(new_switch)

This will new_switch to the CABLEPLAN. If the switch already exists, it will merge the new_switch with the existing one. It will also set the parent of the switch to be the CABLEPLAN. It will return the final switch, i.e. new_switch if no merge occurred or the newly merged switch if a merge did occur.

Parameters:new_switch – switch to be added of type CP_SWITCH
Returns:CP_SWITCH
delete_switch(old_switch)

returns a list of links that are in self, but not in cp.

:param cp : cable plan of type CABLEPLAN

Returns:list of CP_LINK
difference_switch(cp)

Will return a list of switches that are in self, but not in cp.

Parameters:cp – cable plan
Returns:list of CP_SWITCH
exists_switch(switch)
export(outFile=None, level=0)

Will generate XML text of the entire CABLEPLAN and return it as a string. If outFile is specified, it will write the XML to that file. outFile should be opened for writing before calling this method. ‘level’ specifies the amount of indentation to start with.

export_data_center(level=0)

Will generate the XML of the CABLEPLAN with DATA_CENTER as the root. This will then be returned a string. ‘level’ specifies the indentation level to start with.

Parameters:level – optional indention level, integer
Returns:string that is the DATA_CENTER xml
classmethod get(source)

This will get input a cable plan from ‘source’. If source is a string, it will get the cable plan from XML in a file whose name is source. If it is a Session, it will read the corresponding APIC to get the cable plan.

Parameters:source – filename of type string or Session of type Session
Returns:CABLEPLAN

Returns a list of links. If switch is unspecified, it will return all links. If switch is specified, it will return all of the links that are connected to switch. If both switch1 and swithc2 are specified, it will return all links that are connected between the two switches.

Parameters:
  • switch1 – optional first switch of type CP_SWITCH
  • switch2 – optional second switch of type CP_SWITCH
Returns:

list of links of type CP_LINK

get_spines()

Will return list of switches that are spines

Returns:list of CP_SWITCH
get_switch(switch_name=None)