This is a modified and much simpler version of my production program where I replicated the error I´m having. My program should load a list of IP addresses (for routers) and work with them by sending commands and collecting return information. The list is loaded with all IPs, but my program logic should skip the ones which are not online (online
variable is False
), that is, commands should not be run in those routers which are offline.
Class Router
represents each router in the list of IPs. It has 3 object-level variables: addr
for router address, online
for online status (True
or False
) and infoBasic
for a dict of information like {'Name': 'router name', 'Uptime': 'time router is up', 'OS': 'IOS version'}
and so on. For routers which are not online, this dict should be empty ({}
). The main program will never interact with this class as it is instantiated by the next class (RouterList
)
class RouterList
represents a list of all the Router
objects, and this is the one that has methods to interact with the main
. Initially it loads a list of IP addresses into routerList
variable, then it instantiates each router and saves into a dict routerDict
the IP address as the key, and the Router object as the value. To mix things up, I manually set the second IP as offline.
In RouterList
, my getName method
(and all the other methods) should loop through routerDict
and run commands to get the router names and write that info in the Router
object, in the dict variable infoBasic
. In this case, getName
calls getBasic
passing the Router
object, which calls the Router
object runComm
method passing the string "sh version"
. Don´t mind the silly logic here, in my real production program I´m using caching decorators to run a command only once and store it for later use.
In this same getName
method inside the loop it should skip offline routers. At the end of the program I call getRouters
, which should just print this dict of routerList
and its inner information. Not only it populated the information in the router which was offline, but it also duplicated the same information in all the router objects (more specifically it looks like it applied the same thing for all items of the dict, so the last one was the one that overlapped at the end).
Here is my full program:
class Router:
addr = None
online = False
infoBasic = {}
def __init__(self, addr = None):
self.addr = addr
if self.addr == '192.168.10.50':
self.online = False
else:
self.online = True
def runComm(self, command = None):
if command == None:
return "Error"
return "Return of command for router {}".format(self.addr)
class RouterList:
routerList = None
routerDict = {}
def __init__(self, routerList = None):
if routerList == None:
self.routerList = ['192.168.10.10', '192.168.10.50', '192.168.10.100']
else:
self.routerList = routerList
for routerAddr in self.routerList:
router = Router(routerAddr)
self.routerDict[routerAddr] = router
print("Router list loaded")
def getRouters(self):
""" Return list of routers """
for router in self.routerDict.values():
# print below should show the 3 routers but only .10 and .100 with infoBasic populated
print(router.addr + ', online = ' + str(router.online) + ' - ' + str(router.infoBasic))
def getBasic(self, *args, **kwargs):
""" Call router runComm method and return show version output """
return args[0].runComm("sh version")
def getName(self):
""" Call router runComm method and return show version output """
for router in self.routerDict.values():
if router.online == True:
print('Setting name for ' + router.addr)
# below I tried to use the self dict to write the return of getBasic
self.routerDict[router.addr].infoBasic['Name'] = self.getBasic(router)
def getUptime(self):
""" Return router uptime """
for router in self.routerDict.values():
if router.online == True:
# below I tried to use the router variable from the for loop to write the return of getBasic
router.infoBasic['Uptime'] = self.getBasic(router)
if __name__ == '__main__':
rl = RouterList()
rl.getName()
rl.getUptime()
rl.getRouters()
This is the output:
# python3 simulate-error.py
Router list loaded
Setting name for 192.168.10.10
Setting name for 192.168.10.100
192.168.10.10, online = True - {'Name': 'Return of command for router 192.168.10.100', 'Uptime': 'Return of command for router 192.168.10.100'}
192.168.10.50, online = False - {'Name': 'Return of command for router 192.168.10.100', 'Uptime': 'Return of command for router 192.168.10.100'}
192.168.10.100, online = True - {'Name': 'Return of command for router 192.168.10.100', 'Uptime': 'Return of command for router 192.168.10.100'}
As you can see, in the "Setting name for..." area, it looks like the routers which were offline really were skipped. But still in the end, all routers ended up with the same information. I know I may be overlooking something really foolish and obvious but I can´t find it no matter how many times I review. Can you help?