Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python pexpect: SSHing then updating the date

I have finally have my python pexpect script working except for the most important part updating the date! I am able to SSH in the box but my second command does not execute properly. I have been banging my head on the wall trying to figure out why. I have checked the output of the sting and it should be working based on whats coded. I am not a expert when it comes to python or pexpect so I am in need of a bit of help figuring out why my time is not updating.

my original code:

list = ["089"]
sn = 0

ssh_new_conn = 'Are you sure you want to continue connecting'

class ThreadClass(threading.Thread):
def __init__(self, index):
super(ThreadClass, self).__init__()
self.index = index
def run(self):

sn = storelist[self.index]


#easterndate = (currenttime + datetime.timedelta(0, 3600))
#easterndate = easterndate

est = timezone('US/Eastern')
cst = timezone('US/Central')
#currenttime = (datetime.now())
currenttime = cst.localize(datetime.now())
#easterndate = (currenttime + timedelta(0, 3600))
#easterndate = easterndate.strftime("%a %b %d %H:%M:%S %Z %Y")
easterndate = currenttime.astimezone(est).strftime("%a %b %d %H:%M:%S %Z %Y")
command1 = "/usr/bin/ssh %(username)s@%(hostname)s" % locals()
command2 = " sudo date -s\"%(easterndate)s\"" % locals()
command3 = " sudo date -s\"%(currenttime)s\"" % locals()
now = datetime.now()

#central
if sn == "073" or sn == "066" or sn == "016": #or sn == "022":
    p = pexpect.spawn((command1 + command3), timeout=360)


#eastern
else:
    print(command1 + command2)
    p = pexpect.spawn((command1 + command2), timeout=360)


# Handles the 3 possible connection outcomes:
# a) Ssh to the remote host for the first time, triggering 'Are you sure you want to continue connecting'
# b) ask you for password
# c) No password is needed at all, because you already have the key.
i = p.expect([ssh_new_conn,'[pP]assword:',pexpect.EOF])
print ' Initial pexpect command output: ', i
if i == 0:
    # send 'yes'
    p.sendline('yes')
    i = p.expect(['[pP]assword:',pexpect.EOF])
    print 'sent yes. pexpect command output', i
    if i == 0:
        # send the password
        print "logging into box %(sn)s" % locals()
        p.sendline(password)
        print "login successful"
        print "Setting the time..."

elif i == 1:
    # send the password
    print "logging into box %(sn)s" % locals()
    p.sendline(password)
    print "login successful"
    print "Setting the time..."
    p.close()

elif i == 2:
    print "pexpect faced key or connection timeout"
    pass

print p.before

for i in range(len(list)):
  t = ThreadClass(i)
  t.start()

New Code:

class ThreadClass(threading.Thread):
def __init__(self, index):
   super(ThreadClass, self).__init__()
   self.index = index
def run(self):

    try:
        sn = storelist[self.index]
        username = raw_input('username: ')
        password = raw_input('password: ')
        hostname = "[hostname]"
        est = timezone('US/Eastern')
        cst = timezone('US/Central')
        #currenttime = (datetime.now())
        currenttime = cst.localize(datetime.now())
        #easterndate = (currenttime + timedelta(0, 3600))
        #easterndate = easterndate.strftime("%a %b %d %H:%M:%S %Z %Y")
        easterndate = currenttime.astimezone(est).strftime("%a %b %d %H:%M:%S %Z %Y")
        ssh = pxssh.pxssh()

        print(hostname + " " + username + " " + password)
        ssh.login(hostname, username, password)

        if sn == "073" or sn == "066" or sn == "016": #or sn == "022":
            ssh.sendline ('date')       # run a command
            ssh.prompt()                # match the prompt
            print(s.before)           # print everything before the prompt.
            ssh.sendline ('sudo date -s\"%(currenttime)s\"' % locals())  # run a command
            ssh.expect('(?i)password.*:')  # match password prompt for sudo
            ssh.sendline(password)
            ssh.prompt()
            print(s.before)
            ssh.logout()
        else:
            ssh.sendline ('date')       # run a command
            ssh.prompt()                # match the prompt
            print(s.before)           # print everything before the prompt.
            ssh.sendline ('sudo date -s\"%(easterndate)s\"' % locals())  # run a command
            ssh.expect('(?i)password.*:')  # match password prompt for sudo
            ssh.sendline(password)
            ssh.prompt()
            print(s.before)
            ssh.logout()

    except pxssh.ExceptionPxssh as e:
        print(e)


for i in range(len(storelist)):
  t = ThreadClass(i)
  t.start()

New Error I am getting:

Traceback (most recent call last):
  File "./sshtest.py", line 8, in <module>
    s.login (hostname, username, password)
  File "/usr/lib/python2.6/dist-packages/pxssh.py", line 243, in login
    if not self.synch_original_prompt():
  File "/usr/lib/python2.6/dist-packages/pxssh.py", line 134, in synch_original_prompt
    self.read_nonblocking(size=10000,timeout=1) # GAS: Clear out the cache before getting the prompt
  File "/usr/lib/python2.6/dist-packages/pexpect.py", line 824, in read_nonblocking
    raise TIMEOUT ('Timeout exceeded in read_nonblocking().')
pexpect.TIMEOUT: Timeout exceeded in read_nonblocking().

SOLUTION TO ERROR

I figured out the solution to the error I was getting. Due to a known bug I had to add the following lines to usr/lib/python.2.6/dist-packages/pxssh.py:

self.sendline()       #line 134
time.sleep(0.5)       #line 135
self.read_nonblocking(size=10000,timeout=1) # GAS: Clear out the cache before getting the prompt
like image 699
WorkerBee Avatar asked Apr 09 '13 19:04

WorkerBee


People also ask

How do you update a set in Python?

Python update () function in set adds elements from a set (passed as an argument) to the set. Here set1 is the set in which set2 will be added. Parameters : Update () method takes only a single argument. The single argument can be a set, list, tuples or a dictionary.

What is pexpect in Python?

Pexpect is a Python library for spawning child processes and controlling them automatically. Pexpect can be used to automate interactive applications such as SSH, FTP, password, telnet, etc. Pexpect works by spawning child processes and responding to expected patterns.

What is the use of update parameter in Python?

Parameters : Update () method takes only a single argument. The single argument can be a set, list, tuples or a dictionary. It automatically converts into a set and adds to the set. Return value : This method adds set2 to set1 and returns nothing.

How do I update a specific version of a Python package?

Update/Upgrade Python Package To Specific Version with Pip By default, the specified package will be updated or upgraded to the latest version. But this can be a problem if we need a specific version of the Python package. This generally occurs where some software depends on and supports a specific version of the Python package.


2 Answers

SOLUTION TO ERROR

I figured out the solution to the error I was getting. Due to a known bug I had to add the following lines to usr/lib/python.2.6/dist-packages/pxssh.py:

self.sendline()       #line 134
time.sleep(0.5)       #line 135
self.read_nonblocking(size=10000,timeout=1) # GAS: Clear out the cache before getting the prompt
like image 67
WorkerBee Avatar answered Oct 15 '22 22:10

WorkerBee


You should probably handle the sudo password prompt (+ -t ssh option to get a tty) and use p.expect(EOF) before p.close() to avoid killing the child process prematurely.

Here's an example based on pexpect docs:

import pxssh
try:
    s = pxssh.pxssh()
    s.login (hostname, username, password)
    s.sendline ('date')       # run a command
    s.prompt()                # match the prompt
    print(s.before)           # print everything before the prompt.
    s.sendline ('sudo date')  # run a command
    s.expect('(?i)password.*:')  # match password prompt for sudo
    s.sendline(password)
    s.prompt()
    print(s.before)
    s.logout()
except pxssh.ExceptionPxssh as e:
    print(e)

You could also try fabric:

# fabfile.py
from fabric.api import run, sudo

def date():
    run('date')
    sudo('date')

Usage:

$ fab -H localhost,user@host date
like image 41
jfs Avatar answered Oct 15 '22 22:10

jfs