lots of fun changes to the lab plugin. added a basic TODO / README, added run_command support to remote_workstation, added support for dynagen (though it needs more testing), added a vixr controller and driver but the lack of snapshots is a little sad. see the README for more info on how to use it

git-svn-id: file:///home/svn/framework3/trunk@12700 4d416f70-5f16-0410-b530-b9f4589650da
unstable
Jonathan Cran 2011-05-24 15:56:32 +00:00
parent 046e65fbce
commit 563acc280b
15 changed files with 597 additions and 472 deletions

60
lib/lab/README Normal file
View File

@ -0,0 +1,60 @@
This folder contains the libraries necessary to run the lab plugin, and can also be used in a standalone way to automate virtual machines.
Currently you will need to have this code running on a linux box, and your VMHost will likely need to be linux as well. If you're interested in porting it to windows, please contact jcran@metasploit.com.
#########
CONCEPTS:
#########
Controllers - TODO
Drivers - TODO
Currently Supported:
workstation (wraps vmrun command)
workstation_vixr (uses the vixr gem from rhythmx)
remote_workstation (wraps vmrun command on a remote host)
virtualbox
dynagen (underlying vm for GNS3 - cisco hardware)
Planned:
qemu
qemudo
amazon
others?
DEPENDENCIES:
- whatever vm software is necessary for the driver you're using
- net/ssh - the gem (net-ssh), not the msf library. Required to perform ssh_exec in the case tools are not installed on the device. Not necessary if tools are installed.
- net/scp - the gem (net-scp). Required to copy files to/from the devices in the case that tools are not installed. Not necessary if tools are installed.
###########
LAB PLUGIN:
###########
BACKGROUND:
The lab plugin adds a number of commands which may be useful if you're interested in automating remote hosts with rc scripts. If you are testing an IPS / IDS, or determing if an exploit was successful, you'll need to have targets which can be easily started / reverted. The lab plugin provides those commands.
USAGE:
msf> load lab
msf> lab_help
msf> lab_load <path_to_lab_file> // see data/lab/test_targets.yml for an example
msf> lab_start vm1
msf> lab_snapshot vm1 emosheep
// do some stuff
msf> lab_revert vm1 emosheep
msf> lab_stop vm1
###########
STANDALONE:
###########
BACKGROUND:
The lab libraries add tons of useful functionality that isn't exposed through the lab plugin, such as the ability to run commands on hosts. This library can serve as an excellent base for more complex operations on a remote host as well.
USAGE:
You must first create a yaml file which describes your vm. See data/lab/test_targets.yml for an example.
require 'vm_controller'
vm_controller = ::Lab::Controllers::VmController.new(YAML.load_file(lab_def))
vm_controller['vm1'].start
vm_controller['vm1'].snapshot("clean")
vm_controller['vm1'].run_command("rm /etc/resolv.conf")
vm_controller['vm1'].open_uri("http://autopwn:8080")
vm_controller['vm1'].revert("clean")

6
lib/lab/TODO Normal file
View File

@ -0,0 +1,6 @@
- qemu
- qemudo
- amazon ec2
- kvm
look at fog as a potential drop-in replacement

View File

@ -1,19 +0,0 @@
require 'rubygems'
require 'AWS' ## requires the amazon-ec2 gem
module Lab
module AmazonController
@ec2 = AWS::EC2::Base.new(:access_key_id => ENV['ACCESS_KEY_ID'], :secret_access_key => ENV['SECRET_ACCESS_KEY'])
def list_amazon
@ec2.describe_images(:owner_id => "amazon").imagesSet.item.each do |image|
print_line "image: #{image}"
end
end
end
end

View File

@ -1,85 +0,0 @@
require 'vm_driver'
##
## $Id$
##
module Lab
module Drivers
class AmazonDriver < VmDriver
include Lab::Amazon_Controller
attr_accessor :type
attr_accessor :location
def initialize(location, key, secret_key)
if !File.exist?(location)
raise ArgumentError,"Couldn't find: " + location
end
@access_key = key
@secret_access_key = secret_key
@location = filter_input(location)
@type = "amazon"
end
def register
end
def unregister
end
def start
end
def stop
end
def suspend
end
def pause
end
def reset
end
def create_snapshot(name)
end
def revert_snapshot(name)
end
def delete_snapshot(name)
end
def run_command(command, arguments, user, pass)
end
def copy_from(user, pass, from, to)
end
def copy_to(user, pass, from, to)
end
def check_file_exists(user, pass, file)
end
def create_directory(user, pass, directory)
end
def cleanup
end
def running?
return false
end
end
end
end

View File

@ -0,0 +1,14 @@
module Lab
module Controllers
module DynagenController
def self.running_list
raise "Unsupported"
end
def self.dir_list(basepath=nil)
raise "Unsupported"
end
end
end
end

View File

@ -1,14 +1,13 @@
require 'vm_driver'
##
## $Id$
##
## To use this driver, you have to have a lab which is preconfigured. The best / easies
## way to set up a lab is to use GNS3 to configure it
##
#
# $Id$
#
#
# To use this driver, you have to have a lab which is preconfigured. The best / easiest
# way i've found to to set up a lab is GNS3
#
module Lab
module Drivers
@ -17,23 +16,26 @@ module Drivers
attr_accessor :type
attr_accessor :location
def initialize(location)
def initialize(vmid,location,platform)
@vmid = filter_input(vmid)
@location = filter_input(location)
if !File.exist?(location)
raise ArgumentError,"Couldn't find: " + location
end
@location = filter_input(location)
@type = "dynagen"
@running = false
## start background dynamips process
system_command("nice dynamips -H 7200 &")
@platform = filter_input(platform)
@credentials = []
end
def start
## TODO - write the location-file to a temp-file and set the
## autostart property
# TODO - write the location-file to a temp-file
# and set the autostart property
## start background dynamips process
system_command("dynamips -H #{@platform} &")
system_command("dynagen #{@location}")
@running = true
end
@ -43,50 +45,6 @@ module Drivers
@running = false
end
def suspend
raise Exception, "Unsupported Command"
end
def pause
raise Exception, "Unsupported Command"
end
def reset
raise Exception, "Unsupported Command"
end
def create_snapshot(name)
raise Exception, "Unsupported Command"
end
def revert_snapshot(name)
raise Exception, "Unsupported Command"
end
def delete_snapshot(name)
raise Exception, "Unsupported Command"
end
def run_command(command, arguments, user, pass)
raise Exception, "Unsupported Command"
end
def copy_from(user, pass, from, to)
raise Exception, "Unsupported Command"
end
def copy_to(user, pass, from, to)
raise Exception, "Unsupported Command"
end
def check_file_exists(user, pass, file)
raise Exception, "Unsupported Command"
end
def create_directory(user, pass, directory)
raise Exception, "Unsupported Command"
end
def cleanup
`killall dynagen`
`killall dynamips`

View File

@ -9,151 +9,182 @@ module Drivers
class RemoteWorkstationDriver < VmDriver
attr_accessor :type
attr_accessor :location
attr_accessor :location # among other things
def initialize(location, user=nil, host=nil, credentials=nil)
def initialize(vmid, location, os=nil, tools=false, user=nil, host=nil, credentials=nil)
## TODO - Should proabably check file existence?
unless user then raise ArgumentError, "Must provide a username" end
unless host then raise ArgumentError, "Must provide a hostname" end
@vmid = filter_input(vmid)
@location = filter_input(location)
@user = filter_input(user)
@host = filter_input(host)
@credentials = filter_input_credentials(credentials)
@type = "remote_workstation"
@credentials = credentials # individually filtered
@tools = tools # not used in command lines, no filter
@os = os # not used in command lines, no filter
# TODO - Currently only implemented for the first set
if @credentials.count > 0
@vm_user = filter_input(@credentials[0]['user'])
@vm_pass = filter_input(@credentials[0]['pass'])
@vm_keyfile = filter_input(@credentials[0]['keyfile'])
end
end
def start
system_command("ssh #{@user}@#{@host} vmrun -T ws start \\\'#{@location}\\\' nogui")
system_command("ssh #{@user}@#{@host} vmrun -T ws start \'#{@location}\' nogui")
end
def stop
system_command("ssh #{@user}@#{@host} vmrun -T ws stop \\\'#{@location}\\\' nogui")
system_command("ssh #{@user}@#{@host} vmrun -T ws stop \'#{@location}\' nogui")
end
def suspend
system_command("ssh #{@user}@#{@host} vmrun -T ws suspend \\\'#{@location}\\\' nogui")
system_command("ssh #{@user}@#{@host} vmrun -T ws suspend \'#{@location}\' nogui")
end
def pause
system_command("ssh #{@user}@#{@host} vmrun -T ws pause \\\'#{@location}\\\' nogui")
system_command("ssh #{@user}@#{@host} vmrun -T ws pause \'#{@location}\' nogui")
end
def reset
system_command("ssh #{@user}@#{@host} vmrun -T ws reset \\\'#{@location}\\\' nogui")
system_command("ssh #{@user}@#{@host} vmrun -T ws reset \'#{@location}\' nogui")
end
def create_snapshot(snapshot)
snapshot = filter_input(snapshot)
system_command("ssh #{@user}@#{@host} vmrun -T ws snapshot \\\'#{@location}\\\' #{snapshot} nogui")
system_command("ssh #{@user}@#{@host} vmrun -T ws snapshot \'#{@location}\' #{snapshot} nogui")
end
def revert_snapshot(snapshot)
snapshot = filter_input(snapshot)
system_command("ssh #{@user}@#{@host} vmrun -T ws revertToSnapshot \\\'#{@location}\\\' #{snapshot} nogui")
system_command("ssh #{@user}@#{@host} vmrun -T ws revertToSnapshot \'#{@location}\' #{snapshot} nogui")
end
def delete_snapshot(snapshot)
snapshot = filter_input(snapshot)
system_command("ssh #{@user}@#{@host} vmrun -T ws deleteSnapshot \\\'#{@location}\\\' #{snapshot} nogui" )
end
def run_command(command, named_user=nil)
command = filter_input(command)
## this will return the first user if named_user doesn't exist
## -- that may not be entirely obvious...
cred = get_best_creds(named_user)
user = cred['user']
pass = cred['pass']
admin = cred['admin']
vmrunstr = "ssh #{@user}@#{@host} vmrun -T ws -gu \\\'{user}\\\' -gp \\\'{pass}\\\' runProgramInGuest \\\'#{@location}\\\' \\\'{command}\\\' -noWait -activeWindow nogui"
system_command(vmrunstr)
system_command("ssh #{@user}@#{@host} vmrun -T ws deleteSnapshot \'#{@location}\' #{snapshot} nogui" )
end
def copy_from(from, to, named_user=nil)
def run_command(command)
# generate local & remote script paths
script_rand_name = rand(10000)
if @os == "windows"
local_tempfile_path = "/tmp/lab_script_#{script_rand_name}.bat"
remote_tempfile_path = "C:\\\\lab_script_#{script_rand_name}.bat"
remote_run_command = remote_tempfile_path
else
local_tempfile_path = "/tmp/lab_script_#{script_rand_name}.sh"
remote_tempfile_path = "/tmp/lab_script_#{script_rand_name}.sh"
remote_run_command = "/bin/sh #{remote_tempfile_path}"
end
# write out our script locally
File.open(local_tempfile_path, 'w') {|f| f.write(command) }
# we really can't filter command, so we're gonna stick it in a script
if @tools
# copy it to the vm host - this is because we're a remote driver
remote_copy_command = "scp #{local_tempfile_path} #{@user}@#{@host}:#{local_tempfile_path}"
system_command(remote_copy_command)
# we have it on the vm host, copy it to the vm guest
vmrunstr = "ssh #{@user}@#{@host} \"vmrun -T ws -gu #{@vm_user} -gp #{@vm_pass} " +
"copyFileFromHostToGuest \'#{@location}\' \'#{local_tempfile_path}\' " +
"\'#{remote_tempfile_path}\' nogui\""
system_command(vmrunstr)
# now run it on the guest
vmrunstr = "ssh #{@user}@#{@host} \"vmrun -T ws -gu #{@vm_user} -gp #{@vm_pass} " +
"runProgramInGuest \'#{@location}\' -noWait -activeWindow \'#{remote_run_command}\'\""
system_command(vmrunstr)
## CLEANUP
# delete it on the guest
vmrunstr = "ssh #{@user}@#{@host} \"vmrun -T ws -gu #{@vm_user} -gp #{@vm_pass} " +
"deleteFileInGuest \'#{@location}\' \'#{remote_tempfile_path}\'\""
system_command(vmrunstr)
# and delete it on the vm host
vmhost_delete_command = "ssh #{@user}@#{@host} rm #{local_tempfile_path}"
system_command(vmhost_delete_command)
# delete it locally
local_delete_command = "rm #{local_tempfile_path}"
system_command(local_delete_command)
else
# since we can't copy easily w/o tools, let's just run it directly :/
if @os == "linux"
scp_to(local_tempfile_path, remote_tempfile_path)
ssh_exec(remote_run_command)
ssh_exec("rm #{remote_tempfile_path}")
else
raise "zomgwtfbbqnotools"
end
end
end
def copy_from(from, to)
from = filter_input(from)
to = filter_input(to)
if @tools
vmrunstr = "\"ssh #{@user}@#{@host} vmrun -T ws -gu #{@vm_user} -gp #{@vm_pass} " +
"copyFileFromGuestToHost \'#{@location}\' \'{from}\' \'{to}\' nogui\""
system_command(vmrunstr)
else
scp_to(from,to)
end
end
## this will return the first user if named_user doesn't exist
## -- that may not be entirely obvious...
cred = get_best_creds(named_user)
def copy_to(from, to)
user = cred['user']
pass = cred['pass']
admin = cred['admin']
from = filter_input(from)
to = filter_input(to)
vmrunstr = "ssh #{@user}@#{@host} vmrun -T ws -gu {user} -gp {pass} copyFileFromGuestToHost \\\'#{@location}\\\' \\\'{from}\\\' \\\'{to}\\\' nogui"
system_command(vmrunstr)
if @tools
vmrunstr = "\"ssh #{@user}@#{@host} vmrun -T ws -gu #{@vm_user} -gp #{@vmpass} " +
"copyFileFromHostToGuest \'#{@location}\' \'{from}\' \'{to}\' nogui\""
system_command(vmrunstr)
else
scp_to(from,to)
end
end
def copy_to(from, to, named_user=nil)
def check_file_exists(file)
if @tools
from = filter_input(from)
to = filter_input(to)
## this will return the first user if named_user doesn't exist
## -- that may not be entirely obvious...
cred = get_best_creds(named_user)
user = cred['user']
pass = cred['pass']
admin = cred['admin']
vmrunstr = "ssh #{@user}@#{@host} vmrun -T ws -gu {user} -gp {pass} copyFileFromHostToGuest \\\'#{@location}\\\' \\\'{from}\\\' \\\'{to}\\\' nogui"
system_command(vmrunstr)
file = filter_input(file)
vmrunstr = "\"ssh #{@user}@#{@host} vmrun -T ws -gu #{@vm_user} -gp #{@vm_pass} " +
"fileExistsInGuest \'#{@location}\' \'{file}\' nogui\""
system_command(vmrunstr)
else
raise "not implemented"
end
end
def check_file_exists(file, named_user=nil)
file = filter_input(file)
## this will return the first user if named_user doesn't exist
## -- that may not be entirely obvious...
cred = get_best_creds(named_user)
user = cred['user']
pass = cred['pass']
admin = cred['admin']
vmrunstr = "ssh #{@user}@#{@host} vmrun -T ws -gu {user} -gp {pass} fileExistsInGuest \\\'#{@location}\\\' \\\'{file}\\\' nogui"
system_command(vmrunstr)
end
def create_directory(directory, named_user=nil)
def create_directory(directory)
directory = filter_input(directory)
## this will return the first user if named_user doesn't exist
## -- that may not be entirely obvious...
cred = get_best_creds(named_user)
user = cred['user']
pass = cred['pass']
admin = cred['admin']
vmrunstr = "ssh #{@user}@#{@host} vmrun -T ws -gu {user} -gp {pass} createDirectoryInGuest \\\'#{@location}\\\' \\\'#{directory}\\\' nogui"
system_command(vmrunstr)
if @tools
vmrunstr = "\"ssh #{@user}@#{@host} vmrun -T ws -gu #{@vm_user} -gp #{@vm_pass} " +
"createDirectoryInGuest \'#{@location}\' \'#{directory}\' nogui\""
system_command(vmrunstr)
else
ssh_exec(command)
end
end
def cleanup
end
def running?
## Get running Vms
## Get running VMs
running = `ssh #{@user}@#{@host} vmrun list nogui`
running_array = running.split("\n")
running_array.shift

View File

@ -8,16 +8,13 @@ module Lab
module Drivers
class VirtualBoxDriver < VmDriver
attr_accessor :type
attr_accessor :location
def initialize(vmid, location=nil)
def initialize(vmid, location=nil, credentials=nil)
@vmid = filter_input(vmid)
@location = filter_input(location)
@type = "virtualbox"
## Check to see if we already know this vm, if not, go on location
vmid_list = ::Lab::Controllers::VirtualBoxController::config_list
unless vmid_list.include? @vmid
@ -33,6 +30,15 @@ module Drivers
vmInfo = `VBoxManage showvminfo \"#{@vmid}\" --machinereadable`
@location = vmInfo.scan(/CfgFile=\"(.*?)\"/).flatten[0].to_s
@credentials = credentials
# TODO - Currently only implemented for the first set
if @credentials.count > 0
@vm_user = filter_input(@credentials[0]['user'])
@vm_pass = filter_input(@credentials[0]['pass'])
end
end
def register_and_return_vmid
@ -75,42 +81,55 @@ module Drivers
def create_snapshot(snapshot)
snapshot = filter_input(snapshot)
system_command("VBoxManage snapshot \"#{@vmid}\" take " + snapshot)
system_command("VBoxManage snapshot \"#{@vmid}\" take #{snapshot}")
end
def revert_snapshot(snapshot)
snapshot = filter_input(snapshot)
system_command("VBoxManage snapshot \"#{@vmid}\" restore " + snapshot)
system_command("VBoxManage snapshot \"#{@vmid}\" restore #{snapshot}")
end
def delete_snapshot(snapshot)
snapshot = filter_input(snapshot)
system_command("VBoxManage snapshot \"#{@vmid}\" delete " + snapshot)
system_command("VBoxManage snapshot \"#{@vmid}\" delete #{snapshot}")
end
def run_command(command, arguments, user, pass)
command = "VBoxManage guestcontrol exec \"#{@vmid}\" \"#{command}\" --username \"#{user}\"
--password \"#{pass}\" --arguments \"#{arguments}\""
def run_command(command, arguments=nil)
command = filter_input(command)
arguments = filter_input(arguments)
command = "VBoxManage guestcontrol exec \"#{@vmid}\" \"#{command}\" --username \"#{@vm_user}\"" +
" --password \"#{@vm_pass}\" --arguments \"#{arguments}\""
system_command(command)
end
def copy_from(user, pass, from, to)
def copy_from(from, to)
from = filter_input(from)
to = filter_input(to)
raise "Not supported by Virtual Box"
end
def copy_to(user, pass, from, to)
command = "VBoxManage guestcontrol copyto \"#{@vmid}\" \"#{from}\" \"#{to}\"
--username \"#{user}\" --password \"#{pass}\""
def copy_to(from, to)
from = filter_input(from)
to = filter_input(to)
command = "VBoxManage guestcontrol copyto \"#{@vmid}\" \"#{from}\" \"#{to}\" " +
"--username \"#{@vm_user}\" --password \"#{@vm_pass}\""
system_command(command)
end
def check_file_exists(user, pass, file)
def check_file_exists(file)
file = filter_input(file)
raise "Not supported by Virtual Box"
end
def create_directory(user, pass, directory)
command = "VBoxManage guestcontrol createdir \"#{@vmid}\" \"#{directory}\"
--username \"#{user}\" --password \"#{pass}\""
def create_directory(directory)
directory = filter_input(directory)
command = "VBoxManage guestcontrol createdir \"#{@vmid}\" \"#{directory}\" " +
"--username \"#{@vm_user}\" --password \"#{@vm_pass}\""
system_command(command)
end

View File

@ -3,67 +3,86 @@
##
require 'workstation_driver'
require 'workstation_vixr_driver'
require 'remote_workstation_driver'
#require 'dynagen_driver'
require 'virtualbox_driver'
require 'dynagen_driver'
#require 'amazon_driver'
#require 'qemu_driver'
#require 'qemudo_driver'
module Lab
class Vm
attr_accessor :vmid
attr_accessor :location
attr_accessor :driver
attr_accessor :credentials
attr_accessor :tools
attr_accessor :type
attr_accessor :user
attr_accessor :host
attr_accessor :os
attr_accessor :arch
## Initialize takes a vm configuration hash of the form
## - vmid (unique identifier)
## driver (vm technology)
## user (if applicable)
## host (if applicable)
## user (if applicable - remote system)
## host (if applicable - remote system)
## location (file / uri)
## credentials (of the form [ {'user'=>"user",'pass'=>"pass", 'admin' => false}, ... ])
## os (currently only linux / windows)
## arch (currently only 32 / 64
def initialize(config = {})
## Mandatory
# Mandatory
@vmid = config['vmid']
raise Exception, "Invalid VMID" unless @vmid
raise "Invalid VMID" unless @vmid
@driver = nil
driver_type = config['driver']
driver_type = filter_input(config['driver'])
driver_type.downcase!
## Optional
@location = config['location'] ## only optional in the case of virtualbox (currently)
@type = config['type'] || "unspecified"
@tools = config['tools'] || false ## TODO
@type = filter_input(config['type']) || "unspecified"
@tools = config['tools'] || false # don't filter this, not used in cmdlines
@os = config['os'] || nil
@arch = config['arch'] || nil
@credentials = config['credentials'] || []
@operating_system = nil ## TODO
@ports = nil ## TODO
@vulns = nil ## TODO
## Only applicable to remote systems
# Optional for virtualbox
@location = filter_input(config['location'])
# Only applicable to remote systems
@user = config['user'] || nil
@host = config['host'] || nil
#Only dynagen
@platform = config['platform']
if driver_type == "workstation"
@driver = Lab::Drivers::WorkstationDriver.new(@location, @credentials)
@driver = Lab::Drivers::WorkstationDriver.new(@vmid, @location, @credentials)
elsif driver_type == "workstation_vixr"
@driver = Lab::Drivers::WorkstationVixrDriver.new(@vmid, @location, @user, @host, @credentials)
elsif driver_type == "remote_workstation"
@driver = Lab::Drivers::RemoteWorkstationDriver.new(@location, @user, @host, @credentials)
#elsif driver_type == "dynagen"
# @driver = Lab::Drivers::DynagenDriver.new
@driver = Lab::Drivers::RemoteWorkstationDriver.new(@vmid, @location, @os, @tools, @user, @host, @credentials)
elsif driver_type == "virtualbox"
@driver = Lab::Drivers::VirtualBoxDriver.new(@vmid, @location)
@driver = Lab::Drivers::VirtualBoxDriver.new(@vmid, @location, @credentials)
elsif driver_type == "dynagen"
@driver = Lab::Drivers::DynagenDriver.new(@vmid, @location,@platform)
#elsif driver_type == "qemu"
# @driver = Lab::Drivers::QemuDriver.new
#elsif driver_type == "qemudo"
# @driver = Lab::Drivers::QemudoDriver.new
#elsif driver_type == "amazon"
# @driver = Lab::Drivers::AmazonDriver.new
else
raise Exception, "Unknown Driver Type"
raise "Unknown Driver Type"
end
end
def running?
@driver.running?
@ -114,24 +133,40 @@ class Vm
self.start
end
def copy_to(from_file,to_file)
raise Exception, "not implemented"
def copy_to(from,to)
@driver.copy_to(from,to)
end
def copy_from(from_file,to_file)
raise Exception, "not implemented"
def copy_from(from,to)
@driver.copy_from(from,to)
end
def run_command(command,arguments=nil)
raise Exception, "not implemented"
def run_command(command)
@driver.run_command(command)
end
def check_file_exists(file)
@driver.check_file_exists(file)
end
def create_directory(directory)
@driver.create_directory(directory)
end
def open_uri(uri)
raise Exception, "not implemented"
# we don't filter the uri, as it's getting tossed into a script
# by the driver
if @os == "windows"
command = "\"C:\\program files\\internet explorer\\iexplore.exe\" #{uri}"
else
command = "firefox #{uri}"
end
@driver.run_command(command)
end
def to_s
return @vmid.to_s + ": " + @location.to_s
return "#{@vmid}: #{@location}"
end
def to_yaml
@ -140,20 +175,34 @@ class Vm
out += " location: #{@driver.location}\n"
out += " type: #{@type}\n"
out += " tools: #{@tools}\n"
out += " os: #{@os}\n"
out += " arch: #{@arch}\n"
out += " credentials:\n"
@credentials.each do |credential|
out += " - user: #{credential['user']}\n"
out += " pass: #{credential['pass']}\n"
out += " admin: #{credential['admin']}\n"
end
if @server_user or @server_host
out += " server_user: #{@server_user}\n"
out += " server_host: #{@server_host}\n"
# Remote systems
if @user or @host
out += " user: #{@server_user}\n"
out += " host: #{@server_host}\n"
end
return out
end
end
end
private
def filter_input(string)
return unless string
if !(string =~ /^[\d*\w*\s*\[\]\{\}\/\\\.\-\"\(\)]*$/)
raise "WARNING! Invalid character in: #{string}"
end
string
end
end
end

View File

@ -12,11 +12,13 @@ require 'enumerator'
require 'vm'
require 'yaml'
require 'workstation_controller'
require 'workstation_vixr_controller'
require 'remote_workstation_controller'
#require 'qemu_controller'
#require 'amazon_controller'
require 'virtualbox_controller'
#require 'dynagen_controller'
require 'dynagen_controller'
#require 'qemu_controller'
#require 'qemudo_controller'
#require 'amazon_controller'
module Lab
module Controllers
@ -24,14 +26,17 @@ module Controllers
include Enumerable
include Lab::Controllers::WorkstationController ## gives access to workstation-specific controller methods
include Lab::Controllers::WorkstationVixrController ## gives access to workstation-specific controller methods
include Lab::Controllers::RemoteWorkstationController ## gives access to workstation-specific controller methods
#include Lab::Controllers::QemuController ## gives access to qemu-specific controller methods
#include Lab::Controllers::AmazonController ## gives access to amazon-specific controller methods
include Lab::Controllers::VirtualBoxController ## gives access to virtualbox-specific controller methods
#include Lab::Controllers::DynagenController ## gives access to dynagen-specific controller methods
include Lab::Controllers::DynagenController ## gives access to dynagen-specific controller methods
#include Lab::Controllers::QemuController ## gives access to qemu-specific controller methods
#include Lab::Controllers::QemudoController ## gives access to qemudo-specific controller methods
#include Lab::Controllers::AmazonController ## gives access to amazon-specific controller methods
def initialize (labdef = nil)
def initialize (labdef=nil)
@vms = [] ## Start with an empty array of vms
## labdef is a big array of hashes, use yaml to store
@ -83,6 +88,7 @@ module Controllers
@vms << vm unless includes_vmid? vm.vmid
rescue Exception => e
puts "Invalid VM definition"
puts "Exception: #{e.to_s}"
end
end
end

View File

@ -1,138 +1,133 @@
##
## $Id$
##
#
# !!WARNING!! - All drivers are expected to filter input before running
# anything based on it. This is particularly important in the case
# of the drivers which wrap a command line program to provide
# functionality.
#
module Lab
module Drivers
class VmDriver
attr_accessor :type
attr_accessor :location
def initialize(location)
@location = location
@host = host
@user = user
@credentials = credentials
@type = ""
end
def register
def register # Must be implemented in a child *_driver class
raise Exception, "Command not Implemented"
end
def unregister
def unregister # Must be implemented in a child *_driver class
raise Exception, "Command Not Implemented"
end
def start
def start # Must be implemented in a child *_driver class
raise Exception, "Command Not Implemented"
end
def stop
def stop # Must be implemented in a child *_driver class
raise Exception, "Command Not Implemented"
end
def suspend
def suspend # Must be implemented in a child *_driver class
raise Exception, "Command Not Implemented"
end
def pause
def pause # Must be implemented in a child *_driver class
raise Exception, "Command Not Implemented"
end
def reset
def reset # Must be implemented in a child *_driver class
raise Exception, "Command Not Implemented"
end
def create_snapshot(snapshot)
def create_snapshot(snapshot) # Must be implemented in a child *_driver class
raise Exception, "Command Not Implemented"
end
def revert_snapshot(snapshot)
def revert_snapshot(snapshot) # Must be implemented in a child *_driver class
raise Exception, "Command Not Implemented"
end
def delete_snapshot(snapshot)
def delete_snapshot(snapshot) # Must be implemented in a child *_driver class
raise Exception, "Command Not Implemented"
end
def run_command(command, named_user=nil)
def run_command(command) # Must be implemented in a child *_driver class
raise Exception, "Command Not Implemented"
end
def copy_from(from, to, named_user=nil)
def copy_from(from, to) # Must be implemented in a child *_driver class
raise Exception, "Command Not Implemented"
end
def copy_to(from, to, named_user=nil)
def copy_to(from, to) # Must be implemented in a child *_driver class
raise Exception, "Command Not Implemented"
end
def check_file_exists(file, named_user=nil)
def check_file_exists(file) # Must be implemented in a child *_driver class
raise Exception, "Command Not Implemented"
end
def create_directory(directory, named_user=nil)
def create_directory(directory) # Must be implemented in a child *_driver class
raise Exception, "Command Not Implemented"
end
=begin
def ssh_exec(host, command, user)
ssh_command = "ssh " + @user + "@" + @host + " " + command
system_command(ssh_command)
def cleanup # Must be implemented in a child *_driver class
raise Exception, "Command Not Implemented"
end
def scp_from(host, user, from, to)
vmrunstr = "scp -r \"" + @user + "@" + @host + ":" + from + "\" \"" + to + "\""
system_command(vmrunstr)
private
def scp_to(from,to)
gem 'net-ssh'
require 'net/ssh'
gem 'net-scp'
require 'net/scp'
# upload a file to a remote server
Net::SCP.start(@vmid, @vm_user, :password => @vm_pass) do |scp|
scp.upload!(from,to)
end
end
def scp_to(host, user, from, to)
vmrunstr = "scp -r \"" + from + "\" \"" + @user + "@" + @host + ":" + to + "\""
system_command(vmrunstr)
end
=end
def cleanup
end
private
def filter_input(string)
return unless string
if !(string =~ /^[\w\s\[\]\{\}\/\\\.\-\"\(\)]*$/)
raise Exception, "WARNING! Invalid character in: #{string}"
end
string
end
def filter_input_credentials(credentials)
return unless credentials
def scp_from(from,to)
gem 'net-ssh'
require 'net/ssh'
credentials.each { |credential|
credential['user'] = filter_input(credential['user'])
credential['pass'] = filter_input(credential['pass'])
}
return credentials
end
gem 'net-scp'
require 'net/scp'
## Takes a username in the form of a string
## and returns a credentials hash
def get_best_creds(named_user)
if !@credentials.empty?
return get_named_user_creds(named_user) || @credentials[0]
else
raise Exception, "No credentials for this VM ):"
end
end
# download a file from a remote server
Net::SCP.start(@vmid, @vm_user, :password => @vm_pass) do |scp|
scp.download!(from,to)
end
end
def ssh_exec(command)
gem 'net-ssh'
require 'net/ssh'
## Checks the array of credentials to see if we have one
## with this user's username. returns the first.
def get_named_user_creds(user)
@credentials.each do |credential|
if credential['user'].downcase == user.downcase
return credential
end
end
return nil
end
def system_command(command)
system(command)
Net::SSH.start(@vmid, @vm_user, :password => @vm_pass) do |ssh|
result = ssh.exec!(command)
end
end
def filter_input(string)
return unless string
if !(string =~ /^[\w\s\[\]\{\}\/\\\.\-\"\(\)]*$/)
raise "WARNING! Invalid character in: #{string}"
end
string
end
def system_command(command)
puts "DEBUG: running command #{command}"
system(command)
end
end
end

View File

@ -5,13 +5,11 @@ module WorkstationController
def self.running_list
vm_list = `vmrun list`.split("\n")
vm_list.shift
return vm_list
end
def self.dir_list(basepath=nil)
vm_list = Find.find(basepath).select { |f| f =~ /\.vmx$/ }
return vm_list
end
end

View File

@ -12,17 +12,20 @@ class WorkstationDriver < VmDriver
attr_accessor :type
attr_accessor :location
def initialize(location, credentials=nil)
def initialize(vmid, location, credentials=nil)
@vmid = filter_input(vmid)
@location = filter_input(location)
if !File.exist?(@location)
raise ArgumentError,"Couldn't find: " + location
end
@credentials = filter_input_credentials(credentials)
@credentials = credentials
@type = "workstation"
# TODO - Currently only implemented for the first set
if @credentials.count > 0
@vm_user = filter_input(@credentials[0]['user'])
@vm_pass = filter_input(@credentials[0]['pass'])
end
end
def start
@ -60,88 +63,40 @@ class WorkstationDriver < VmDriver
system_command("vmrun -T ws deleteSnapshot " + "\"#{@location}\" \"#{snapshot}\"" )
end
def run_command(command, named_user=nil)
def run_command(command)
command = filter_input(command)
## this will return the first user if named_user doesn't exist
## -- that may not be entirely obvious...
cred = get_best_creds(named_user)
user = cred['user']
pass = cred['pass']
admin = cred['admin']
vmrunstr = "vmrun -T ws -gu \"{user}\" -gp \"{pass}\" runProgramInGuest \"#{@location}\" \"{command}\" -noWait -activeWindow"
vmrunstr = "vmrun -T ws -gu \"#{@vm_user}\" -gp \"#{@vm_pass} \" " +
"runProgramInGuest \"#{@location}\" \"{command}\" -noWait -activeWindow"
system_command(vmrunstr)
end
def copy_from(from, to, named_user=nil)
def copy_from(from, to)
from = filter_input(from)
to = filter_input(to)
## this will return the first user if named_user doesn't exist
## -- that may not be entirely obvious...
cred = get_best_creds(named_user)
user = cred['user']
pass = cred['pass']
admin = cred['admin']
vmrunstr = "vmrun -T ws -gu {user} -gp {pass} copyFileFromGuestToHost \"#{@location}\" \"{from}\" \"{to}\""
vmrunstr = "vmrun -T ws -gu #{@vm_user} -gp #{@vm_pass} copyFileFromGuestToHost" +
" \"#{@location}\" \"{from}\" \"{to}\""
system_command(vmrunstr)
end
def copy_to(from, to, named_user=nil)
def copy_to(from, to)
from = filter_input(from)
to = filter_input(to)
## this will return the first user if named_user doesn't exist
## -- that may not be entirely obvious...
cred = get_best_creds(named_user)
user = cred['user']
pass = cred['pass']
admin = cred['admin']
vmrunstr = "vmrun -T ws -gu {user} -gp {pass} copyFileFromHostToGuest \"#{@location}\" \"{from}\" \"{to}\""
vmrunstr = "vmrun -T ws -gu #{@vm_user} -gp #{@vm_pass} copyFileFromHostToGuest" +
" \"#{@location}\" \"{from}\" \"{to}\""
system_command(vmrunstr)
end
def check_file_exists(file, named_user=nil)
def check_file_exists(file)
file = filter_input(file)
## this will return the first user if named_user doesn't exist
## -- that may not be entirely obvious...
cred = get_best_creds(named_user)
user = cred['user']
pass = cred['pass']
admin = cred['admin']
vmrunstr = "vmrun -T ws -gu {user} -gp {pass} fileExistsInGuest \"#{@location}\" \"{file}\" "
vmrunstr = "vmrun -T ws -gu {user} -gp #{@vm_pass} fileExistsInGuest " +
"\"#{@location}\" \"{file}\" "
system_command(vmrunstr)
end
def create_directory(directory, named_user=nil)
def create_directory(directory)
directory = filter_input(directory)
## this will return the first user if named_user doesn't exist
## -- that may not be entirely obvious...
cred = get_best_creds(named_user)
user = cred['user']
pass = cred['pass']
admin = cred['admin']
vmrunstr = "vmrun -T ws -gu {user} -gp {pass} createDirectoryInGuest \"#{@location}\" \"#{directory}\" "
vmrunstr = "vmrun -T ws -gu #{@vm_user} -gp #{@vm_pass} createDirectoryInGuest " +
" \"#{@location}\" \"#{directory}\" "
system_command(vmrunstr)
end

View File

@ -0,0 +1,19 @@
module Lab
module Controllers
module WorkstationVixrController
def self.running_list
vm_list = `vmrun list`.split("\n")
vm_list.shift
return vm_list
end
def self.dir_list(basepath=nil)
vm_list = Find.find(basepath).select { |f| f =~ /\.vmx$/ }
return vm_list
end
end
end
end

View File

@ -0,0 +1,119 @@
require 'vm_driver'
##
## $Id: workstation_driver.rb 11753 2011-02-16 02:15:24Z jcran $
##
# This requires rhythmx's vixr driver from https://github.com/rhythmx/vixr
# and below that, the VIX api from vmware http://www.vmware.com/support/developer/vix-api/
module Lab
module Drivers
class WorkstationVixrDriver < VmDriver
attr_accessor :type
attr_accessor :location
def initialize(vmid, location, credentials=nil)
begin
require 'vixr'
rescue
raise "Oops, no vixr installed. Consider using the regular workstation driver."
end
@vmid = filter_input(vmid)
@location = filter_input(location)
if !File.exist?(@location)
raise ArgumentError,"Couldn't find: " + location
end
@credentials = credentials
# TODO - Currently only implemented for the first set
if @credentials.count > 0
@vm_user = filter_input(@credentials[0]['user'])
@vm_pass = filter_input(@credentials[0]['pass'])
end
host = VixR.connect()
vm = host.op0n_vmx(@location)
end
def start
vm.power_on
end
def stop
vm.power_off
end
def suspend
vm.suspend
end
def pause
vm.pause
end
def reset
vm.reset
end
def create_snapshot(snapshot)
snapshot = filter_input(snapshot)
system_command("ssh #{@user}@#{@host} vmrun -T ws snapshot \\\'#{@location}\\\' #{snapshot} nogui")
end
def revert_snapshot(snapshot)
snapshot = filter_input(snapshot)
system_command("ssh #{@user}@#{@host} vmrun -T ws revertToSnapshot \\\'#{@location}\\\' #{snapshot} nogui")
end
def delete_snapshot(snapshot)
snapshot = filter_input(snapshot)
system_command("ssh #{@user}@#{@host} vmrun -T ws deleteSnapshot \\\'#{@location}\\\' #{snapshot} nogui" )
end
def run_command(command)
command = filter_input(command)
if vm.login(@vm_user,@vm_pass)
vm.run_prog(command)
end
end
def copy_from(from, to)
from = filter_input(from)
to = filter_input(to)
cp_from_host(from,to)
end
def copy_to(from, to)
from = filter_input(from)
to = filter_input(to)
vm.cp_to_guest(from,to)
end
def check_file_exists(file)
file = filter_input(file)
file_exists?(file)
end
def create_directory(directory)
directory = filter_input(directory)
end
def cleanup
end
def running?
vm.running?
end
end
end
end