Pexpect, running ssh-copy-id hangs when trying to call the second process

I am making a Python script where I need to call several ssh-copy-id processes and they need to enter a password, so I use PExpect.

I basically have this:

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

and then I want to create another process, I no longer care about it whether it is finished or not.

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

And the code hangs on the second "spawn"

However, if I comment on the first call, the second works, so I assume that the fact that the first one is still working or something does not allow it to work.

Now, another thing that I could not do is wait until the first one stops. I tried:
child.close () - it hangs (both with True and False parameters as parameters) child.read (-1) - it hangs
child.expect (pexpect.EOF) - it hangs.
child.terminate () - it hangs (both with True and False parameters as parameters)

Any ideas on what could happen?
NOTE. I am 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 spawn works well with other processes, even if they don't return. In addition, it is obvious that ssh-copy-id never returns EOF.

+7
python process pexpect
source share
4 answers

Fortunately or not, the OpenSSH client seems very picky about passwords and where they came from.

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

+3
source share

I think the problem is that SSH is trying to open PTY, and this does not work on anything other than PTY for security reasons. This will not work 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

This is open-source, you can use it. What you are trying to do is more teams, but you don’t have to expect at all.

  • Install it manually first, then do the following:

  • Run dssh-agent, add the password you need as follows:

     dssh-add -l < passwordfile 
    • or if it is a safe car, that is, no one else can enter there, it is very important, otherwise it will be a huge security hole:

       echo "name-of-server;22;root;password;" | dssh-add -l 
    • password file will look something like this:

       name-of-server;22;root;password; 
  • And do something like (replace CONTENTS OF ... with the actual contents of this 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 does all this, otherwise you have a race condition).

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

The DSSH installation guide is in the archive.

I don’t know an easier way to do this, OpenSSH ssh-copy-id is very picky where the password comes from ...

+1
source share

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

I would suggest several different options, depending on your needs:

1) Kill the spawned process. However, this can lead to corruption in your work, so I do not know what you want.

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

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

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

3) Use a different copy for all children, and then wait for them all at the end - and this is 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 the spawn object will hang until the command completes.

0
source share

Actually, I tried many of these alternatives, and none of them worked.

  • Calling the close () or terminate () function (with both True and False parameters as parameters)
  • Waiting for a call () or reading (-1) or waiting (pexpect.EOF) freezes
  • calf call again, not caring about the previous belt command, freezes

I conducted several tests with other commands (for example, "ftp", and they work as I would expect, for example, if you call .expect ("something"), and something will not be found until EOF, t they wait forever, they throw an exception, so I believe this is due to the ssh-copy-id command.

0
source share

All Articles