当前位置: 动力学知识库 > 问答 > 编程问答 >

python - pexpect and ssh: how to format a string of commands after su - root -c

问题描述:

I am trying to iterate through a list of servers & passwords to change the sshd configs on a group of servers so that I can login/run commands via root using passwordless SSH keys.

I can do this easily in bash but I'm trying to learn Python and (obviously) would like to forego entering in passwords manually.

Here's the bash of what I want to do:

scp ~/.ssh/id_rsa.pub /etc/ssh/sshd_config [email protected]:/tmp/

ssh -o StrictHostKeyChecking=no -t [email protected] "su - root -c \"chown root:root /tmp/id_rsa.pub; chmod 600 /tmp/id_rsa.pub; chown root:root /tmp/sshd_config; mkdir /root/.ssh; chown root:root /root/.ssh; chmod 700 /root/.ssh; mv /tmp/id_rsa.pub /root/.ssh/authorized_keys; mv /tmp/sshd_config /etc/ssh/; service sshd reload\""

I've gotten close to doing this in Python with pexpect:

import pexpect

USER="user"

HOST="192.168.1.1"

USERPASS="userpass"

ROOTPASS="rootpass"

COMMAND1="scp /Users/user/.ssh/id_rsa.pub /Users/user/github/ssh-pexpect/sshd_config %[email protected]%s:/tmp/" % (USER, HOST)

COMMAND2="ssh -o StrictHostKeyChecking=no -t %[email protected]%s \"su - root -c \"chown root:root /tmp/id_rsa.pub; chmod 600 /tmp/id_rsa.pub; chown root:root /tmp/sshd_config; mkdir /root/.ssh; chown root:root /root/.ssh; chmod 700 /root/.ssh; mv /tmp/id_rsa.pub /root/.ssh/authorized_keys; mv /tmp/sshd_config /etc/ssh/; service sshd reload\"\"" % (USER, HOST)

child = pexpect.spawn(COMMAND1)

child.expect('password:')

child.sendline(USERPASS)

child.expect(pexpect.EOF)

print child.before

child = pexpect.spawn(COMMAND2)

child.expect('password:')

child.sendline(USERPASS)

child.expect('Password:')

child.sendline(ROOTPASS)

child.expect(pexpect.EOF)

print child.before

When I run that COMMAND1 (scp'ing) works fine.

But COMMAND2 fails:

server1:ssh-pexpect user$ python test4.py

id_rsa.pub 100% 410 0.4KB/s 00:00

sshd_config 100% 3498 3.4KB/s 00:00

Traceback (most recent call last):

File "test4.py", line 25, in <module>

child.expect(pexpect.EOF)

File "/Library/Python/2.7/site-packages/pexpect.py", line 1316, in expect

return self.expect_list(compiled_pattern_list, timeout, searchwindowsize)

File "/Library/Python/2.7/site-packages/pexpect.py", line 1330, in expect_list

return self.expect_loop(searcher_re(pattern_list), timeout, searchwindowsize)

File "/Library/Python/2.7/site-packages/pexpect.py", line 1414, in expect_loop

raise TIMEOUT (str(e) + '\n' + str(self))

pexpect.TIMEOUT: Timeout exceeded in read_nonblocking().

<pexpect.spawn object at 0x102b796d0>

version: 2.4 ($Revision: 516 $)

command: /usr/bin/ssh

args: ['/usr/bin/ssh', '-o', 'StrictHostKeyChecking=no', '-t', '[email protected]', 'su - root -c chown', 'root:root', '/tmp/id_rsa.pub;', 'chmod', '600', '/tmp/id_rsa.pub;', 'chown', 'root:root', '/tmp/sshd_config;', 'mkdir', '/root/.ssh;', 'chown', 'root:root', '/root/.ssh;', 'chmod', '700', '/root/.ssh;', 'mv', '/tmp/id_rsa.pub', '/root/.ssh/authorized_keys;', 'mv', '/tmp/sshd_config', '/etc/ssh/;', 'service', 'sshd', 'reload']

searcher: searcher_re:

0: EOF

buffer (last 100 chars): : Permission denied

mv: try to overwrite `/etc/ssh/sshd_config', overriding mode 0600 (rw-------)?

before (last 100 chars): : Permission denied

mv: try to overwrite `/etc/ssh/sshd_config', overriding mode 0600 (rw-------)?

after: <class 'pexpect.TIMEOUT'>

match: None

match_index: None

exitstatus: None

flag_eof: False

pid: 3612

child_fd: 4

closed: False

timeout: 30

delimiter: <class 'pexpect.EOF'>

logfile: None

logfile_read: None

logfile_send: None

maxread: 2000

ignorecase: False

searchwindowsize: None

delaybeforesend: 0.05

delayafterclose: 0.1

delayafterterminate: 0.1

If I remove the /etc/ssh/sshd_config file on the remote server before running the script I get:

server1:ssh-pexpect user$ python test4.py

id_rsa.pub 100% 410 0.4KB/s 00:00

sshd_config 100% 3498 3.4KB/s 00:00

chown: missing operand

Try `chown --help' for more information.

chown: changing ownership of `/tmp/sshd_config': Operation not permitted

mkdir: cannot create directory `/root/.ssh': Permission denied

chown: cannot access `/root/.ssh': Permission denied

chmod: cannot access `/root/.ssh': Permission denied

mv: accessing `/root/.ssh/authorized_keys': Permission denied

mv: cannot move `/tmp/sshd_config' to `/etc/ssh/sshd_config': Permission denied

bash: service: command not found

Connection to 192.168.1.1 closed.

I'm not even sure how to debug this to see where it's messing up. I don't think it's parsing COMMAND2 properly, though.

Pretty new to Python so any advice is appreciated.

Thanks.

网友答案:

You have COMMAND2 in double quotes and correctly escape any embedded double quotes, but you also need to double-escape any already-escaped double quotes. In other words, not really a Python problem. You could switch to Python triple quotes for the outermost quotes, though. It would be easier to read, too.

Edit: Actually, any proper disambiguation of the quoting will do. Since the shell offers single quotes as well, your solution with single quotes is fine. Python would allow you to use single quotes or a number of other quoting facilities, which I would recommend if you hadn't already solved the problem (because then you can choose quotes which don't require any changes to the string itself; less room for error).

So, any of these should be fine:

COMMAND2='ssh -o StrictHostKeyChecking=no -t %[email protected]%s "su - root -c \"chown root:root /tmp/id_rsa.pub; chmod 600 /tmp/id_rsa.pub; chown root:root /tmp/sshd_config; mkdir /root/.ssh; chown root:root /root/.ssh; chmod 700 /root/.ssh; mv /tmp/id_rsa.pub /root/.ssh/authorized_keys; mv /tmp/sshd_config /etc/ssh/; service sshd reload\""' % (USER, HOST)

COMMAND2="""ssh -o StrictHostKeyChecking=no -t %[email protected]%s "su - root -c \"chown root:root /tmp/id_rsa.pub; chmod 600 /tmp/id_rsa.pub; chown root:root /tmp/sshd_config; mkdir /root/.ssh; chown root:root /root/.ssh; chmod 700 /root/.ssh; mv /tmp/id_rsa.pub /root/.ssh/authorized_keys; mv /tmp/sshd_config /etc/ssh/; service sshd reload\"" """ % (USER, HOST)

COMMAND2="ssh -o StrictHostKeyChecking=no -t %[email protected]%s 'su - root -c \"chown root:root /tmp/id_rsa.pub; chmod 600 /tmp/id_rsa.pub; chown root:root /tmp/sshd_config; mkdir /root/.ssh; chown root:root /root/.ssh; chmod 700 /root/.ssh; mv /tmp/id_rsa.pub /root/.ssh/authorized_keys; mv /tmp/sshd_config /etc/ssh/; service sshd reload\"'" % (USER, HOST)

I needed to add a space to the triple-quotes in order to disambiguate the adjacent double quote. But you could use triple single quotes instead. Also, triple quotes (single or double) allow you to embed newlines, which improves legibility significantly:

COMMAND2='''ssh -o StrictHostKeyChecking=no -t %[email protected]%s "su - root -c '
    chown root:root /tmp/id_rsa.pub
    chmod 600 /tmp/id_rsa.pub
    chown root:root /tmp/sshd_config
    mkdir /root/.ssh
    chown root:root /root/.ssh
    chmod 700 /root/.ssh
    mv /tmp/id_rsa.pub /root/.ssh/authorized_keys
    mv /tmp/sshd_config /etc/ssh/
    service sshd reload'"''' % (USER, HOST)
网友答案:

I ended up going for single quotes instead of trying to figure out how to escape the double quotes:

COMMAND2="ssh -o StrictHostKeyChecking=no -t %[email protected]%s \"su - root -c 'chown root:root /tmp/id_rsa.pub; chmod 600 /tmp/id_rsa.pub; chown root:root /tmp/sshd_config; mkdir /root/.ssh; chown root:root /root/.ssh; chmod 700 /root/.ssh; mv /tmp/id_rsa.pub /root/.ssh/authorized_keys; mv /tmp/sshd_config /etc/ssh/; service sshd reload'\"" % (USER, HOST)
分享给朋友:
您可能感兴趣的文章:
随机阅读: