##
## $Id$
##
## This is the main lab controller which will call out to other controller
## libraries. Requiring this file and specifying the type of VM at initialization
## will allow you to start/stop/snapshot/revert & run commands on VMs
##
## $Revision$
##

$:.unshift(File.expand_path(File.dirname(__FILE__))) ## Msf Test libraries

require 'find'
require 'vmware_controller'

## Not implemented yet!
#require 'vbox_controller'
#require 'qemu_controller'
#require 'ec2_controller'

#
# ~Higher-level lab methods which are generic to the types of things we want to do with a lab of machines
#  Note that any generic vm functionality should be pushed down into the controller class. 

class LabController 

	attr_accessor :labdef
	attr_accessor :controller

	def initialize (labdef = nil, labtype="vmware")
		
		if !labdef 
			## Just use a blank lab to start
			@labdef = {}
		else
			@labdef = labdef
		end		

		### AHH, traverse again, looking for nils, cuz ruby is teh fail - TODO -  value?		
		@labdef.each do |key,value|
			@labdef[key].each do |subkey,subvalue|
				if !subvalue
					@labdef[key][subkey] = ""
				end
			end
		end
		
				
		## set up the controller. note that this is likely to change in the future (to provide for additional vm libs)
		if labtype == "vmware"
			@controller = VmwareController.new
			@file_extension = "vmx"

##	
##	Not implemented yet!
##
##		elsif labtype == "qemu"
##			@controller = QemuController.new
##			@file_extension = "img"
##		elsif labtype == "ec2"
##			@controller = Ec2Controller.new

		else
			raise "Invalid Lab Controller"
		end
	end

	def contains?(vmid)
		if get_full_path(vmid)
		 	true
	 	end
	end 
	
	def build_lab_from_running()
		vm_array = self.list_lab_running.split("\n") ## this should probably return an array
		vm_array.shift
		hlp_stuff_array_into_lab(vm_array)
	end

	def build_lab_from_files(basepath=nil)
		vm_array = Find.find(basepath).select { |f| 
			f =~ /\.#{@file_extension}$/ #&& File.executable?(f)
		}

		hlp_stuff_array_into_lab(vm_array)
	end

	def hlp_stuff_array_into_lab(arr)
		return false unless arr.kind_of? Array
	
		arr.each_with_index {|v,i|
			## give us a vmid!
			index = @labdef.count + 1

			## eliminate dooops
			fresh = true
			@labdef.each { |vmid, definition| fresh = false if labdef[vmid]['file'] == 'v' }
			
			if fresh
				@labdef[index.to_s] = {'file' => v }
			end
			#end
		}
		return @labdef
	end

	def run_command_on_lab_vm(vmid,command,arguments=nil)
		if @labdef[vmid]["tools"]
			@controller.run_command(get_full_path(vmid), command, @labdef[vmid]["user"],@labdef[vmid]["pass"])
		else
			if @labdef[vmid]["os"] == "linux"
				@controller.run_ssh_command(@labdef[vmid]["hostname"], command , @labdef[vmid]["user"])
			else
				raise "OS Not Supported"
			end
		end
	end

	def run_browser_on_lab_vm(vmid,uri)
		if @labdef[vmid]["os"] == "linux"
			command = "firefox " + uri
		elsif @labdef[vmid]['os'] == "windows"
			command = "C:\\Progra~1\\intern~1\\iexplore.exe " + uri
		else
			raise "Don't know how to browse to '" + uri + "'."
		end
		run_command_on_lab_vm(vmid,command)
	end

	def start_lab_vm(vmid)
		if running?(vmid)
			self.list_lab_running
		else
			@controller.start(get_full_path(vmid)) 
		end
	end
	
	def reset_lab_vm(vmid)
		@controller.reset(get_full_path(vmid))
	end

	def pause_lab_vm(vmid)
		if !running?(vmid)
			self.list_lab_running
		else
			@controller.pause(get_full_path(vmid)) 
		end
	end

	def suspend_lab_vm(vmid)
		if !running?(vmid)
			self.list_lab_running
		else
				@controller.suspend(get_full_path(vmid))
		end
	end

	def snapshot_lab_vm(vmid, snapshot)
		if !running?(vmid)
			self.list_lab_running
		else
			@controller.create_snapshot(get_full_path(vmid),snapshot)
		end
	end

	def revert_lab_vm(vmid, snapshot, run=true)
		if !running?(vmid)
			self.list_lab_running
		else
			@controller.revert_snapshot(get_full_path(vmid),snapshot)

			## If you revert w/ vmrun, you need to restart
			if run 
				sleep 5
				@controller.start(get_full_path(vmid))
			end
		end
	end

	def stop_lab_vm(vmid)
		if !running?(vmid)
			self.list_lab_running
		else
			@controller.stop(get_full_path(vmid))
		end
	end

	def start_lab
		@labdef.each { | key, value |
			if value
				self.start_lab_vm(key)
			end
		}
	end

	def pause_lab
		@labdef.each { | key, value |
			if value
				self.pause_lab_vm(key)
			end

		}
	end


	def stop_lab
		@labdef.each { | key, value |
			if value
				self.stop_lab_vm(key)
			end
		}

	end

	def reset_lab
		@labdef.each { | key, value |
			if value
				self.reset_lab_vm(key)
			end
		}
	end


	def suspend_lab
		@labdef.each { | key, value |
			if value 
				self.suspend_lab_vm(key)
			end
		}
	end

	def snapshot_lab(snapshot)
		@labdef.each { | key, value |
			if value
				self.snapshot_lab_vm(key,snapshot)
			end
		}
	end

	def revert_lab(snapshot)
		@labdef.each { | key, value |
			if value
				self.revert_lab_vm(key,snapshot)
			end
		}
	end

        def run_command_on_lab(command)
                @labdef.each { | key, value |
                        if value
                                self.run_command_on_lab_vm(key, command)
                        end
                }
        end

	def copy_to_lab(file)	
		@labdef.each { | key, value |
			if value
				self.copy_to_lab_vm(key,file)
			end
		}
	end

	def copy_from_lab(file)	
		@labdef.each { | key, value | 
#			next unless line =~ /^#{@vmbase}(.*)/
			if value
				self.copy_from_lab_vm(key,file)
			end
		}
	end

	def copy_to_lab_vm(vmid,file)
		## handle linux
		
		guestpath  = ""
		
		if (@labdef[vmid]["os"] == "linux")
			guestpath = "/tmp/"
		else
			guestpath = "C:\\temp_msf\\\\" ## double-escaping because it's being used in a system command. 
		end

		name = File.basename(file)

		## if we've installed vm-tools on the box, use that to copy. if not, use scp
		if (@labdef[vmid]["tools"] == "true")			
			@controller.create_directory_in_guest(get_full_path(vmid),@labdef[vmid]["user"],@labdef[vmid]["pass"], guestpath)
			@controller.copy_file_to(get_full_path(vmid),@labdef[vmid]["user"],@labdef[vmid]["pass"],file, guestpath + name)
		else
			@controller.scp_copy_file_to(@labdef[vmid]["hostname"], @labdef[vmid]["user"], file, guestpath + name)
		end
	end
	
	def copy_from_lab_vm(vmid,file)
		hostpath = "/tmp/"

		name = File.basename(file.gsub("\\","/")) 

		@controller.copy_file_from(get_full_path(vmid),@labdef[vmid]["user"],@labdef[vmid]["pass"],file,hostpath + name)
	end
	
	def list_lab_running
		@controller.get_running	
	end

	def list_lab
		str = ""
		@labdef.sort.each { |key,val|

			if val != nil
				str = str + key.to_s + ": "  + val["file"].to_s + "\n"
			end
		 }
		return str
	end

        def find_lab_vm(search)
		str = ""
                @labdef.sort.each { |key,val|
                        if val != nil
				if (val["file"].to_s.downcase.index(search.downcase) != nil)
	                                str = str + key.to_s + ": "  + val["file"].to_s + "\n"
				end
                        end
                 }
		return str
        end

	def exists?(vmid)
		if get_full_path(vmid)
			return true
		end
		return false
	end

	def running?(vmid)
		if @controller.running?(get_full_path(vmid))
			return true
		end
		return false
	end

	def get_full_path(vmid)
		if @labdef[vmid]
			@labdef[vmid]["file"].to_s		## handle linux
		else
			nil
		end
	end
end
