Moving SuperPutty config to Linux Pac Manager

I have transitioning from a primary Windows desktop environment to a Linux desktop, and found that I wanted to get my saved connections from superputty, which my co-workers are using to a Linux tool. I found a tool called PAC Manager which does what I needed.

The main thing I wanted was a tree hierarchy what the routers are split by location. SupperPutty uses an XML based config file and PAC Manager uses YAML files. The main problem was finding a way to discover and map out the tree structure, because SupperPutty list the hierarchy like a file listing with a separator of “/”.

I was able to use a Python to extract the XML elements, and create a list of directory tree objects and element objects. In PAC’s YaML you need to list each folder and element separately, you also need to show the parent child relationships in both the folder and they element. I have attached the current version of my Python code below. I may later develop this further into a library that abstracts and can import and export both formats fully, but the current code meets my current need.

import uuid
import xml.etree.ElementTree as ET

def branchListImport(devices):
    temp = []
    branches = {}
    for y in devices:
        x = y['SessionId'].split('/')[:-1]
        if "/".join(y['SessionId'].split('/')[:-1]) not in branches:
            if x[0] not in branches:
                branches.update({str(x[0]) : {'name' : str(x[0]), 'description' : str(x[0]), 'uuidNumber' : uuid.uuid4(), 'parent' : "__PAC__EXPORTED__"}})
            if len(x) > 1:
                for y in range(1,len(x)):
                  if "/".join(x[:(y+1)]) not in branches:
                      branches.update({"/".join(x[:(y+1)]) : {'name': "/".join(x[:(y+1)]), 'description' : str(x[y]), 'uuidNumber' : uuid.uuid4(), 'parent' : str(branches["/".join(x[:y])]['uuidNumber'])}})
    for x in sorted(branches.items()):
    for x in temp:
        for y in temp:
            if str(x.uuid) == str(y.parent):
    return temp

def deviceListImport(devices, branchList):
    temp = []
    for x in devices:
        temp.append(device(description=x['SessionName'], parentName="/".join(x['SessionId'].split('/')[:-1]), ip=x['Host'], port=x['Port'], method=x['Proto'], username=x['Username'] ))
    for x in temp:
        for y in branchList:
            if x.parentName ==
                x.parentUuid = str(y.uuid)
    return temp

class device(object):
    def __init__(self, description="", parentName="Unknown", parentUuid=False, uuidNumber=False, ip="", port="", method="", username="", password=False):
        self.description = description
        self.parentName = parentName
        self.parentUuid = parentUuid
        if uuidNumber == False:
            self.uuid = uuid.uuid4()
            if isinstance(uuidNumber, uuid.UUID):
                self.uuid = uuidNumber
            elif isinstance(uuidNumber, str):
                self.uuid = uuid.UUID(uuidNumber)
        self.ip = ip
        self.port = port
        if method.upper() == "SSH":
            self.method = "SSH"
        elif method.upper() == "TELNET":
            self.method = "Telnet"
            self.method = method.upper()
        self.username = username
        self.password = password
    def __hash__(self):
        return hash(self.description, self.parentName, self.parentUuid, self.uuid, self.ip, self.port, self.method, self.username, self.password)
    def __str__(self):
        return str(self.uuid)
    def __repr__(self):
        return 'pac_template.device(description="{}", parentName={}, parentUuid="{}", uuidNumber="{}", ip="{}", port="{}", method="{}", username="{}", password="{}"'.format(self.description, self.parentName, self.parentUuid, self.uuid, self.ip, self.port, self.method, self.username, self.password)
    def ymlString(self):
        if self.password == False:
            password = "<<ASK_PASS>>"
            password = self.password
        return elementTemplate.format(uuid=self.uuid, ip=self.ip, desc=self.description, parent=self.parentUuid, port=self.port, method=self.method, username=self.username, password=password)

class branchPoint(object):
    def __init__(self, description="", name="", parent="__PAC__EXPORTED__", children=False,uuidNumber=False):
        self.description = description = name
        self.parent = parent
        self.children = children
        if uuidNumber == False:
            self.uuid = uuid.uuid4()
            if isinstance(uuidNumber, uuid.UUID):
                self.uuid = uuidNumber
            elif isinstance(uuidNumber, str):
                self.uuid = uuid.UUID(uuidNumber)
    def __hash__(self):
        return hash(self.uuid,, self.description, self.parent, self.children)
    def __str__(self):
        return str(self.uuid)
    def __repr__(self):
        return 'pac_template.branchPoint(description="{}", name={}, parent="{}", children={}, uuidNumber="{}"'.format(self.description,, self.parent, self.children, self.uuid)
    def addChild(self, child):
        if self.children == False:
            self.children = []
    def ymlString(self):
        temp = "{}:\n  _is_group: 1\n  _protected: 0\n  children:\n".format(str(self.uuid))
        if self.children != False:
            for x in self.children:
                temp += "    {}: 1\n".format(x)
        temp += "  cluster: []\n  description: Connection group '{0}'\n  name: {0}\n  parent: {1}\n  screenshots: ~\n  variables: []".format(self.description, self.parent)
        return temp

elementTemplate = """{uuid}:
  KPX title regexp: '.*{desc}.*'
  _is_group: 0
  _protected: 0
  auth fallback: 1
  auth type: userpass
  autoreconnect: ''
  autossh: ''
  children: {{}}
  cluster: []
  description: "Connection with '{desc}'"
  embed: 0
  expect: []
  favourite: 0
  infer from KPX where: 3
  infer user pass from KPX: ''
  ip: {ip}
  local after: []
  local before: []
  local connected: []
  mac: ''
  macros: []
  method: {method}
  name: '{desc}'
  options: ' -X'
  parent: {parent}
  pass: '{password}'
  passphrase: ''
  passphrase user: ''
  port: {port}
  prepend command: ''
  proxy ip: ''
  proxy pass: ''
  proxy port: 8080
  proxy user: ''
  public key: /home/braaen
  quote command: ''
  remove control chars: ''
  save session logs: ''
  screenshots: ~
  search pass on KPX: 0
  send slow: 0
  send string active: ''
  send string every: 60
  send string intro: 1
  send string txt: ''
  session log pattern: <UUID>_<NAME>_<DATE_Y><DATE_M><DATE_D>_<TIME_H><TIME_M><TIME_S>.txt
  session logs amount: 10
  session logs folder: ~/.config/pac/session_logs
  startup launch: ''
  startup script: ''
  startup script name:
  terminal options:
    audible bell: ''
    back color: '#000000000000'
    bold color: '#cc62cc62cc62'
    bold color like text: 1
    command prompt: '[#%\$>]|\:\/\s*$'
    cursor shape: block
    disable ALT key bindings: ''
    disable CTRL key bindings: ''
    disable SHIFT key bindings: ''
    open in tab: 1
    password prompt: "([p|P]ass|[p|P]ass[w|W]or[d|t]|ontrase.a|Enter passphrase for key '.+'):\\s*$"
    tab back color: '#000000000000'
    terminal backspace: auto
    terminal character encoding: UTF-8
    terminal emulation: xterm
    terminal font: Monospace 9
    terminal scrollback lines: 5000
    terminal select words: \.:_\/-A-Za-z0-9
    terminal transparency: 0
    terminal window hsize: 800
    terminal window vsize: 600
    text color: '#cc62cc62cc62'
    timeout command: 40
    timeout connect: 40
    use personal settings: ''
    use tab back color: ''
    username prompt: '([l|L]ogin|[u|u]suario|[u|U]ser-?[n|N]ame|[u|U]ser):\s*$'
    visible bell: ''
  title: '{desc}'
  use prepend command: ''
  use proxy: 0
  use sudo: ''
  user: {username}
  variables: []"""

def main():
    temp = []
    tree = ET.parse('Sessions.xml')
    root = tree.getroot()
    devices = []
    for child in root:
        if child.tag == 'SessionData':
    branchList = branchListImport(devices)
    deviceList = deviceListImport(devices, branchList)

    temp.append("---\n__PAC__EXPORTED__:\n  children:")
    temp += ["    {}: 1".format(str(x.uuid)) for x in branchList if '__PAC__EXPORTED__' == x.parent]
    temp += [x.ymlString for x in branchList]
    temp += [x.ymlString for x in deviceList]

    print "\n".join(temp)

if __name__ == "__main__":

Moving to the dark side

Things have been crazy this past year. After 10 years of working at my old job, last march I took a position at a new job. I am moving from working as an engineer working on IOS and IOS-XR service provider networks, to now working in the Healthcare industry at a regional health care provider.

One of the biggest technical differences, which I was and am excited about was being to be able to work with a platform I have been watching for awhile. I am now moving over to the dark side….


Yes, I have been watching Junos and noticing how IOS-XR which I was growing fond of seemed to mirror many Junos examples I saw. In addition to working with Juniper devices, but I am working on F5 load balancers and Infoblox IPAM. I am planning to work on some more post in the next few months and modify some of the drafts I had from earlier to be non-vendor specific. I also may also start adding articles that are not about networking at all, as I may be posting things related to my interest and work with audio and recording.


BGP workaround for backbone issue

I had an interesting issue where I had to use BGP traffic engineering to work around an unusual quark with a major backbone provider. The site I was working with was dual-homed using a major national provider and a smaller local provider. In order to better load traffic between the circuits we attempted to use some BGP as-path prepending to favor the major connection less. When we added more than two prepends to the major provider, all traffic on the link stopped and we only saw about 4kbps to traffic on the link.
Continue reading “BGP workaround for backbone issue”


Better way of formatting Mac Addresses in Python

Following up on my Formating mac addresses using python post I have a better way of using Mac addresses.  I have been using the netaddr library for ip and mac address manipulations.  To convert a binary mac address to an EUI object you can use the following code

import netaddr
from netaddr import EUI

def convertMac(octet):
This Function converts a binary mac address to a hexadecimal string representation
return EUI(netaddr.strategy.eui48.packed_to_int(octet))

with the EUI object you have multiple options to format with.

>>> from netaddr import EUI
>>> import netaddr
>>> mac = EUI('01-23-45-67-89-0A')
>>> print mac
>>> mac.dialect = netaddr.mac_cisco
>>> print mac
>>> mac.dialect = netaddr.mac_unix
>>> print mac
>>> mac.dialect = netaddr.mac_bare
>>> print mac
>>> mac.dialect = netaddr.mac_unix_expanded
>>> print mac
>>> mac.dialect = netaddr.mac_eui48
>>> print mac

Mercurial for Tracking Cisco Configs

As I have been working with different routers I have squired a small repository of configuration files that I use for examples, backups, and ways of remembering the way the network was set up before a change. At the start I maintained each config as a separate file, usually containing the date (i.e. router1-071012.cfg). While that worked for a while it got cumbersome when I wanted to track more than one legacy version of a config file. Continue reading “Mercurial for Tracking Cisco Configs”


Allowing UNI or protected ports on Cisco switch to reach each other using IP

When deploying Metro Ethernet service and Colocated services, best practice it to put the ports in protected mode or uni. This is to prevent customers from causing interference to each other with layer2 protocols. It also allows the user of service provider traffic filtering. The downside is without additional configuration, customer traffic to another customer is blackholed when they exist in the same subnet. Continue reading “Allowing UNI or protected ports on Cisco switch to reach each other using IP”