I'm writing a simple Python:Pexpect script that is a replacement of an old TCL:Expect working script I used to push configuration changes or command to our network switches.
If I write:
h_ls = open(hostls,"r")
c_ls = open(commands,"r")
for host in h_ls:
host = host.strip()
try:
s = pxssh.pxssh(timeout=5,logfile = sys.stdout,options={
"StrictHostKeyChecking": "no",
"UserKnownHostsFile": "/dev/null",
"AddKeysToAgent": "yes"},encoding='utf-8')
s.login (host, user, password,\
auto_prompt_reset=False,\
original_prompt=r'.*#')
print (">>>>> Working on "+host+" @ "+str(now)+" <<<<<\n")
s.prompt()
for cmd in c_ls:
s.sendline(cmd+"\n")
s.prompt()
print(s.before)
s.logout()
except pxssh.ExceptionPxssh as e:
print("***pxssh failed on login***")
#traceback.print_exc()
print("***"+str(e)+" "+host+"***")
commands contained in the "commands" variable get executed only once, in the first host of the list "hostls"
Instead if I write:
h_ls = open(hostls,"r")
for host in h_ls:
host = host.strip()
try:
s = pxssh.pxssh(timeout=5,logfile = sys.stdout,options={
"StrictHostKeyChecking": "no",
"UserKnownHostsFile": "/dev/null",
"AddKeysToAgent": "yes"},encoding='utf-8')
s.login (host, user, password,\
auto_prompt_reset=False,\
original_prompt=r'.*#')
print (">>>>> Working on "+host+" @ "+str(now)+" <<<<<\n")
s.prompt()
c_ls = open(commands,"r")
for cmd in c_ls:
s.sendline(cmd+"\n")
s.prompt()
print(s.before)
s.logout()
except pxssh.ExceptionPxssh as e:
print("***pxssh failed on login***")
#traceback.print_exc()
print("***"+str(e)+" "+host+"***")
commands get correctly executed for every host of the "hostls" variable. What is that I do not understand?
Just for completeness, in the Tcl:Expect brother of this script, I've a logic similar to the one of the first example and it works correctly, so probably I'm missing something in my knowledge of Python. Has it something to do on how the block "try except" is managed? I searched info about it, but I didn't find anything meaningful about this specific argument.
It's not about error handling. Pay attention to scope of
c_ls- in the first example, you're opening the file outside the loop, so object is created once, and when you iterate over it, it gets exhausted after the first iteration, leaving no commands to execute for the remaining hosts. In 2nd code however, you're opening the file inside the that loop, which means that a newc_lsobject is created for each host, so it contains all the commands to be iterated over.