Overheads
"""pyvix2/cli.py Command-line Control of VM's.
An shell interface with slightly simpler syntax.
"""
from __future__ import print_function
import sys
import cmd
import re
import pprint
import shlex
import os
import time
import getpass
import traceback
import argparse
import logging
import logging.config
try:
import readline
except ImportError:
pass
This module provides a command-line interface to pyvix2.
We might be able to use import pyvix2.vmrun as pyvix2
to provide an alternate VIX interface via vmrun.
Global Configuration
There’s a global configuratio read from a configuration
file. See Sample Configuration File.
This must be three Python global variables.
hosts: | A mapping from host name to connection parameters. |
vms: | A mapping from VMX name to full local filesystem path. |
default_host: | The host name to launch by default. |
-
pyvix2.cli.get_config(*names)
def get_config( *names ):
settings= {}
for location in names:
if location is None: continue
try:
execfile( location, settings )
break # It worked! We're done.
except IOError as e:
pass # It didn't work, try something else.
return settings
This global shows a little extra traceback information so that the
pyvix2 request that failed is shown.
The host we’re working with. Yes. It’s a global. It might be better
as an instance variable inside VMCommand. However, it’s
based on configuration and reasonably public, and probably easier to
deal with as a global.
Alternative to print
-
pyvix2.cli.show(text, **kw)
A handy output function. This is an alternative to print
that handles an iterable and prefaces each line with a marker.
def show( text, **kw ):
for line in text:
print( ">>>", line.rstrip(), **kw )
The Command Interpreter
-
class pyvix2.cli.VMCommand
A subclass of cmd.Cmd that implements the various commands.
class VMCommand( cmd.Cmd ):
"""Pick a VMWare host and control it."""
prompt= "vm< "
undoc_header= "Other Commands"
def __init__( self, *args, **kw ):
cmd.Cmd.__init__( self, *args, **kw )
self.current_vm= None
self.snapshot= None
self.procs= None
Commands for controlling the pyvix2.Host.
def do_host( self, args ):
"""<name>: Choose the Host to work with."""
host.disconnect()
if not args:
args= configuration['default_host']
host_args= configuration['hosts'][args]
print( host_args )
host.connect( **host_args )
def do_list( self, args ):
"""List running VM's on the current Host"""
try:
running= host.find_items()
show( running )
except pyvix2.Error as e:
print( e )
if DEBUG: traceback.print_exc(limit=1)
Commands for selecting the pyvix2.VM.
def print_vm_list( self ):
print( " Available VMX" )
for name in configuration['vmx']:
print( " {0}: {1}".format( name, configuration['vmx'][name] ) )
def pick_vm( self, args ):
if not args:
if not self.current_vm:
self.print_vm_list()
return
else:
if args not in configuration['vmx']:
print( "{0!r} unknown".format(args) )
self.print_vm_list()
self.current_vm= None
return
try:
self.current_vm= host.openVM(configuration['vmx'][args])
self.prompt= "{0}< ".format( args )
except pyvix2.Error as e:
print( e )
if DEBUG: traceback.print_exc(limit=1)
self.current_vm= None
return
def do_vm( self, args ):
"""vm <vmx>: Set the VM to work with."""
self.pick_vm( args )
if not self.current_vm: return
try:
self.current_vm.wait_for_tools_in_guest(10)
except pyvix2.Error as e:
print( e )
if DEBUG: traceback.print_exc(limit=1)
def do_start( self, args ):
"""start <vmx>: Start a guest OS."""
self.pick_vm( args )
if not self.current_vm: return
try:
self.current_vm.power_on()
print( "Check for tools...", end="" )
self.current_vm.wait_for_tools_in_guest(120)
except pyvix2.Error as e:
print( e )
if DEBUG: traceback.print_exc(limit=1)
def do_stop( self, args ):
"""stop <vmx>: Stop a guest OS."""
self.pick_vm( args )
if not self.current_vm: return
try:
self.current_vm.wait_for_tools_in_guest(10)
except pyvix2.Error as e:
print( e )
if DEBUG: traceback.print_exc(limit=1)
try:
self.current_vm.power_off()
except pyvix2.Error as e:
print( e )
if DEBUG: traceback.print_exc(limit=1)
Commands for login and logout of the current pyvix2.VM.
If the VM doesn’t have tools installed, these report errors.
def do_login( self, args ):
"""login <username>: Login to the current VM; prompts for password."""
self.pick_vm( '' )
if not self.current_vm: return
if args:
username= args
else:
username= raw_input( 'username: ' )
password = getpass.getpass( 'password: ' )
try:
self.current_vm.login( username, password )
except pyvix2.Error as e:
print( e )
if DEBUG: traceback.print_exc(limit=1)
def do_logout( self, args ):
"""logout: Logout of the current VM."""
self.pick_vm( '' )
if not self.current_vm: return
self.current_vm.logout()
Commands to interact with the current pyvix2.VM processes.
If the VM doesn’t have tools installed, these report errors.
If the user isn’t logged in, these report errors.
def get_procs( self, args ):
"""Get the list of processes."""
self.pick_vm( args )
if not self.current_vm: return
try:
self.current_vm.wait_for_tools_in_guest(10)
except pyvix2.Error as e:
print( e )
if DEBUG: traceback.print_exc(limit=1)
try:
self.procs= self.current_vm.process_list()
return self.procs
except pyvix2.Error as e:
print( e )
if DEBUG: traceback.print_exc(limit=1)
def do_running( self, args ):
"""running: What's running in the current VM? (Login required.)"""
procs= self.get_procs(args)
if not procs: return
for pid, owner, name, start_time, command in procs:
start_string= time.asctime( time.localtime(start_time) )
print( pid, owner, start_string, command )
def do_check( self, args ):
"""check <words>: Check the current VM running proc names. (Login required.)"""
procs= self.get_procs('')
if not procs: return
words= shlex.split( args )
print( "Looking for", repr(words) )
for pid, owner, name, start_time, command in procs:
if any( w in command for w in words ):
start_string= time.asctime( time.localtime(start_time) )
print( pid, owner, start_string, command )
def do_python( self, args ):
"""python <file>: Execute a Python program on the Guest OS. (Login required.)"""
if not self.current_vm:
self.pick_vm(None)
return
try:
self.current_vm.program_run( "/usr/bin/python2.6", args )
except pyvix2.Error as e:
print( e )
if DEBUG: traceback.print_exc(limit=1)
def do_bash( self, args ):
"""bash <command>: Execute a single bash statement on the Guest OS. (Login required.)"""
if not self.current_vm:
self.pick_vm(None)
return
try:
self.current_vm.script_run( "/bin/bash", args )
except pyvix2.Error as e:
print( e )
if DEBUG: traceback.print_exc(limit=1)
Commands to interact with the current pyvix2.VM files and directories.
If the VM doesn’t have tools installed, these report errors.
If the user isn’t logged in, these report errors.
def do_get( self, args ):
"""get <guestfile> <hostfile>: Get a file from the Guest OS. (Login required.)"""
if not self.current_vm:
self.pick_vm(None)
return
try:
guest_name, host_name = shlex.split( args )
except ValueError as e:
print( "get <guestfile> <hostfile>" )
return
try:
self.procs= self.current_vm.file_copy_from_guest( guest_name, host_name )
except pyvix2.Error as e:
print( e )
if DEBUG: traceback.print_exc(limit=1)
return
print( host_name )
with open( host_name, "r" ) as result:
show( result )
print()
def do_put( self, args ):
"""put <hostfile> <guestfile>: Put a file onto the Guest OS. (Login required.)"""
if not self.current_vm:
self.pick_vm(None)
return
try:
host_name, guest_name = shlex.split( args )
except ValueError as e:
print( "put <hostfile> <guestfile>" )
return
try:
self.procs= self.current_vm.file_copy_to_guest( host_name, guest_name )
except pyvix2.Error as e:
print( e )
if DEBUG: traceback.print_exc(limit=1)
return
def do_ls( self, args ):
"""ls <path>: Directory listing of the given path. (Login required.)"""
if not self.current_vm:
self.pick_vm(None)
return
try:
self.files= self.current_vm.directory_list( args )
for name, flags, mod_time in self.files:
if name.startswith('.'): continue
time_string= time.asctime( time.localtime(mod_time) )
print( 'd' if flags else ' ', name, time_string )
except pyvix2.Error as e:
print( e )
if DEBUG: traceback.print_exc(limit=1)
return
Commands to interact with the current pyvix2.VM snapshots.
These don’t work with VMPlayer.
def do_snapshot( self, args ):
"""snapshot <name> <description>: Create a snapshot of the VM."""
try:
name, description = shlex.split( args )
except ValueError as e:
print( "snapshot <name> <description>" )
return
if not self.current_vm:
self.pick_vm(None)
return
try:
self.snapshot= self.current_vm.snapshot( name, description )
except pyvix2.Error as e:
print( e )
if DEBUG: traceback.print_exc(limit=1)
return
def do_getsnap( self, args ):
"""getsnap [<name>]: Get a named snapshot or the current snapshot."""
if not self.current_vm:
self.pick_vm(None)
return
try:
if args:
self.snapshot= self.current_vm.snapshot_get_byname( args )
else:
self.snapshot= self.current_vm.snapshot_get()
except pyvix2.Error as e:
print( e )
if DEBUG: traceback.print_exc(limit=1)
return
def do_remsnap( self, args ):
"""remsnap: Remove the snapshot found with getsnap."""
if not self.current_vm:
self.pick_vm(None)
return
if not self.snapshot:
print( "Use getsnap to locate a snapshot." )
return
try:
self.current_vm.snapshot_remove( self.snapshot )
except pyvix2.Error as e:
print( e )
if DEBUG: traceback.print_exc(limit=1)
return
def do_revert( self, args ):
"""revert: Revert the VM to the snapshot found with getsnap."""
if not self.current_vm:
self.pick_vm(None)
return
if not self.snapshot:
print( "Use getsnap to locate a snapshot." )
return
try:
self.current_vm.snapshot_revert( self.snapshot )
except pyvix2.Error as e:
print( e )
if DEBUG: traceback.print_exc(limit=1)
return
Variations on the “bye” theme.
def do_EOF( self, args ):
"""All done."""
host.disconnect()
return True
def do_quit( self, args ):
"""All done."""
host.disconnect()
return True
def do_bye( self, args ):
"""All done."""
host.disconnect()
return True
Main Import Switch
Any command-line arguments are presumed
to be a single-line command. "start VM", for example.
if __name__ == "__main__":
# 1. Command-line argument parsing.
parser= argparse.ArgumentParser()
parser.add_argument( '-d', '--debug', action='store_true' )
parser.add_argument( '-v', '--verbosity', action='store_const', const=logging.DEBUG, default=logging.INFO )
parser.add_argument( '-c', '--config', action='store', type=file )
parser.add_argument( 'command', nargs='*' )
args= parser.parse_args()
# 2. Configuration
try:
logging.config.dictConfig( "logging.ini" )
except Exception:
logging.basicConfig( stream= sys.stderr )
logging.getLogger().setLevel( args.verbosity )
DEBUG= args.debug
configuration= get_config( args.config, 'pyvix2.conf' ) # And any other places.
# To work with non-local hosts, you must
# host.service_provider= pyvix2.VIX_SERVICEPROVIDER_VMWARE_SERVER
# Or, perhaps this...
# host.service_provider= pyvix2.VIX_SERVICEPROVIDER_VMWARE_WORKSTATION
host_args= configuration['hosts'][configuration['default_host']]
host.connect( **host_args )
# 3. Real Work
repl= VMCommand()
try:
if args.command:
txt= repl.precmd( args.command )
stop= repl.onecmd( txt )
repl.postcmd( stop, txt )
else:
repl.cmdloop("vm manager for {0}".format(configuration['default_host']))
print( "Normal Exit" )
finally:
logging.shutdown()