Pexpect, running ssh

I'm doing a Python script where I need to spawn several ssh-copy-id processes, and they need for me to type in a password, so i'm using PExpect.

I have basically this:

child = pexpect.spawn('command')
child.expect('password:')
child.sendline('the password')

and then I want to spawn another process, I don't care about this one anymore, whether it ended or not.

child = pexpect.spawn('command2')
child.expect('password:')
child.sendline('the password')

And the code is hanging at the second "spawn"

However, if I comment out the first call, the second one works, so i'm guessing that the fact that the first one is still running or something is keeping it from working.

Now, the other thing I haven't been able to do is wait until the first one stops. I've tried:
child.close() - it hangs (both with True and False as parameters) child.read(-1) - it hangs
child.expect(pexpect.EOF) - it hangs.
child.terminate() - it hangs (both with True and False as parameters)

Any ideas on what could be happening?
NOTE: I'm not a Python expert, and i have never used pexpect before, so ANY idea is more than welcome.

Thanks!


UPDATE: This is definitely related to ssh-copy-id, because with other processes, spawn works well even if they don't return. Also, apparently ssh-copy-id never returns an EOF.


Fortunately or not, but OpenSSH client seems to be very picky about passwords and where they come from.

You may try using Paramiko Python SSH2 library. Here's a simple example how to use it with password authentication, then issue some shell commands ( echo "..." >> $HOME/.ssh/authorized_keys being the simplest) to add your public key on remote host.


I think the problem is, that SSH tries to open PTY and it does not work on anything else than PTY for security reasons. This won't work well with pexpect.

I have another ssh client:

http://www.digmia.com/index.php?option=com_content&view=article&id=54:Digmia%20Enterprise%20SSH&Itemid=56

It's open-source, you can use it. What you are trying to do would be more commands, but you don't need expect at all.

  • First install it accordingly to manual, then do something like this:

  • Run dssh-agent, add the password you need like this:

    dssh-add -l < passwordfile
    
  • or if it is a secure machine, ie no one else can log in there, this is very important, otherwise this would be a huge security hole:

    echo "name-of-server;22;root;password;" | dssh-add -l
    
  • password file would be something like:

    name-of-server;22;root;password;
    
  • And the do something like (replace CONTENTS OF ... with actual content of that file):

    dssh root@name-of-server -- echo "CONTENTS OF ~/.ssh/identity.pub" > .ssh/authorized_keys ; chmod og-w .ssh .ssh/authorized_keys
    
  • You can (optionally) do

    dssh-add -f passwords
    
  • (make sure no one else is doing all this stuff, otherwise you would have a race condition).

    Also, pexpect should probably work with dssh itself (so you don't need to use dssh-agent). But using dssh-agent is simpler and safer.

    Installation manual for DSSH is contained in the tarball.

    I don't know any simpler way of doing this, OpenSSH ssh-copy-id is very picky about where the password comes from...


    Reading pexpect documentation for spawn, I think it is waiting for the command to terminate.

    I would suggest a couple of different possibilities, depending on your needs:

    1) Kill the spawned process. However, this may lead to corruption in your operation, so I do not know if it is what you want.

    child = pexpect.spawn('command')
    child.expect('password:')
    child.sendline('the password')
    child.close(True)
    

    2) Wait for completion of the initial task before moving to the next one

    child = pexpect.spawn('command')
    child.expect('password:')
    child.sendline('the password')
    child.wait()
    child = pexpect.spawn('command2')
    ...
    

    3) Use a different instance for all children, then wait on all of them at the end - and this would be most probably the best solution

    def exec_command(cmd):
      child = pexpect.spawn(cmd)
      child.expect('password:')
      child.sendline('the password')
      return child
    
    commands = ['command1', 'command2']
    childrens = [exec_command(cmd) for cmd in commands]
    for child in childrens:
      child.wait()    
    

    Note: all of the code here is untested, and written under the assumption that your script is hanging because deleting a spawn object will hang until the command will terminate.

    链接地址: http://www.djcxy.com/p/42126.html

    上一篇: 有没有好的电影/电影API?

    下一篇: Pexpect,运行ssh