Question

I currently have a working python script that SSHs into a remote Linux machine and executes commands on that machine. I'm using paramiko to handle ssh connectivity. Here is the code in action, executing an hostname -s command:

blade = '192.168.1.15'
username='root'
password=''
# now, connect 
try:
    client = paramiko.SSHClient()
    client.load_system_host_keys()
    client.set_missing_host_key_policy(paramiko.WarningPolicy())
    print '*** Connecting...'
    client.connect(blade, 22, username, password)
# print hostname for verification
    stdin, stdout, stderr  = client.exec_command('hostname --short')
    print stdout.readlines()
except Exception, e:
    print '*** Caught exception: %s: %s' % (e.__class__, e)
    traceback.print_exc()
    try:
        client.close()
    except:
        pass
    sys.exit(1)

This works fine, but what I'm actually trying to do is more complicated. What I would actually like to do is SSH into that same Linux machine, as I did above, but then create a temporary virtual machine on it, and execute a command on that virtual machine. Here is my (nonworking) attempt:

blade='192.168.1.15'
username='root'
password=''
# now, connect 
try:
   # client = paramiko.SSHClient()
    client.load_system_host_keys()
    client.set_missing_host_key_policy(paramiko.WarningPolicy())
    print '*** Connecting...'
    client.connect(blade, 22, username, password)
   # create VM, log in, and print hostname for verification
    stdin, stdout, stderr = client.exec_command('sudo kvm -m 1024 -drive file=/var/lib/libvirt/images/oa4-vm$
    time.sleep(60) #delay to allow VM to initialize
    stdin.write(username + '\n') #log into VM
    stdin.write(password + '\n') #log into VM
    stdin, stdout, stderr  = client.exec_command('hostname --short')
    print stdout.readlines()
except Exception, e:
    print '*** Caught exception: %s: %s' % (e.__class__, e)
    traceback.print_exc()
    try:
        client.close()
    except:
        pass
    sys.exit(1)

When I run this, I get the following:

joe@computer:~$ python automata.py
*** Connecting...
/home/joe/.local/lib/python2.7/site-packages/paramiko/client.py:95: UserWarning: Unknown ssh-rsa host key for 192.168.1.15: 25f6a84613a635f6bcb5cceae2c2b435
  (key.get_name(), hostname, hexlify(key.get_fingerprint())))
*** Caught exception: <class 'socket.error'>: Socket is closed
Traceback (most recent call last):
  File "automata.py", line 32, in function1
stdin.write(username + '\n') #log into VM
  File "/home/joe/.local/lib/python2.7/site-packages/paramiko/file.py", line 314, in write
self._write_all(data)
  File "/home/joe/.local/lib/python2.7/site-packages/paramiko/file.py", line 439, in _write_all
    count = self._write(data)
  File "/home/joe/.local/lib/python2.7/site-packages/paramiko/channel.py", line 1263, in _write
    self.channel.sendall(data)
  File "/home/joe/.local/lib/python2.7/site-packages/paramiko/channel.py", line 796, in sendall
    raise socket.error('Socket is closed')
error: Socket is closed

I'm not sure how to interpret this error -- "socket is closed" makes me think the SSH connection is terminating one I try to create the VM. Does anyone have any pointers?

update

I'm attempting to use the pexpect wrapper and having trouble getting it to interact with the un/pw prompt. I'm testing the process by ssh'ing into a remote machine and running a test.py script which prompts me for a username, then saves the username in a text file. Here is my fab file:

env.hosts = ['hostname']
env.user = 'userame'
env.password = 'password'


def vm_create():
        run("python test.py")

And the contents of test.py on the remote machine are:

#! /usr/bin/env python

uname = raw_input("Enter Username: ")

f = open('output.txt','w')
f.write(uname + "\n")
f.close

So, I can execute "fab vm_create" on the local machine and it successfully establishes the SSH connection and prompts me for the username, as defined by test.py. However, if I execute a third python file on my local machine with the pexpect wrapper, like this:

import pexpect
child = pexpect.spawn('fab vm_create')
child.expect ('Enter Username: ')
child.sendline ('password')

Nothing seems to happen. I get no errors, and no output.txt is created on the remote machine. Am I using pexpect incorrectly?

Was it helpful?

Solution

As much as I love paramiko, this may be better suited to using Fabric.

Here's a sample fabfile.py:

from fabric.api import run
from fabric.api import sudo
from fabric.api import env

env.user = 'root'
env.password = ''
env.host = ='192.168.1.15'

def vm_up():
  sudo("kvm -m 1024 -drive file=/var/lib/libvirt/images/oa4-vm$...")
  run("hostname --short")

To then run this, use

$ fab vm_up

If you don't set the host and password in the fabfile itself (rightly so), then you can set these at the command line:

$ fab -H 192.168.1.15 -p PASSWORD vm_up

However, your kvm line is still expecting input. To send input (and wait for the expected prompts), write another script that uses pexpect to call fab:

child = pexpect.spawn('fab vm_up')
child.expect('username:') # Put this in the format you're expecting
child.send('root')

OTHER TIPS

use fabric http://docs.fabfile.org/en/1.8/

Fabric is a Python (2.5 or higher) library and command-line tool for streamlining the use of SSH for application deployment or systems administration tasks

from fabric.api import run

def host_name():
    run('hostname -s')
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top