pyvix2/cli.py

The pyvix2.cli module is a command-line interface that allows a user to control VM’s.

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.

import pyvix2

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.

DEBUG=False

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.

host= pyvix2.Host()

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()

Table Of Contents

Previous topic

pyvix2/get_enum.py

Next topic

Sample Configuration File

This Page