#!/usr/bin/env ruby require 'fileutils' require 'instalatron' require 'yaml' require 'mixlib/cli' require 'logger' require 'erb' def play_session(vm_name, script, custom_seq = nil, key_press_delay = 0) ctrlc_gap = 0 basedir = File.dirname(script) if File.exist?(basedir + '/config.rb') include Instalatron begin require basedir + '/config.rb' rescue Exception => e raise Exception.new("Error loading config.rb file: #{e.message}") end begin tmpl = ERB.new(File.read(script)) script = YAML.load(tmpl.result) rescue Exception => e raise Exception.new("Error rendering ERB template from script.yml: #{e.message}") end else script = YAML.load_file(script) end if custom_seq new_seq = script[0] new_seq[:sequence] = custom_seq script[0] = new_seq end step = 1 script.each do |screen| ref_img = "#{basedir}/#{File.basename(screen[:image])}" loop do begin img = Instalatron.detect_screen(vm_name) if Instalatron.same_image?(ref_img, img) puts "Screen detected: #{screen[:name]}" Instalatron.command_window screen[:sequence], vm_name, key_press_delay break end rescue Interrupt, SystemExit if Time.now.to_f - ctrlc_gap < 0.5 puts "\n\nDouble Ctrl-c detected. Aborting." return else ctrlc_gap = Time.now.to_f end puts "Skipping #{screen[:name]}" break end end step += 1 end end def required_option(cli, opt) if cli.config[opt].nil? $stderr.puts "\n#{opt.to_s} argument requied.\n\n" $stderr.puts cli.opt_parser.help exit 1 end return cli.config[opt] end def usage(cli) $stderr.puts cli.opt_parser.help exit 1 end class MyCLI include Mixlib::CLI option :vm_name, :short => "-n NAME", :long => "--vm-name NAME", :description => "Virtual Machine Name", :default => "instalatron_#{Time.now.strftime('%s')}" option :iso_file, :short => "-i ISO", :long => "--iso-file ISO", :description => "ISO file to boot the VM with" option :script, :short => "-s SCRIPT", :long => "--script SCRIPT", :description => "Path to the script file (script.yml) or directory." option :custom_sequence, :short => "-c SEQUENCE", :long => "--custom-sequence SEQUENCE", :description => "Replace first step key sequence" option :destroy_vm, :long => "--destroy-vm", :description => "Destroy the VM after running the tests" option :headless, :long => "--headless", :description => "Run the VMs without GUI", :default => false option :key_press_delay, :long => "--key-press-delay SECS", :description => "Delay between key presses", :default => 0 option :nic_config, :long => "--nic-config CFG", :description => "VM NIC config (nic:device:mode)" option :vm_memory, :long => "--vm-memory MEM", :description => "VM Memory", :default => 512 option :vm_disk_size, :long => "--vm-disk-size SIZE", :description => "VM Disk Size in MB", :default => 10024 option :help, :short => "-h", :long => "--help", :description => "Show this message", :on => :tail, :boolean => true, :show_options => true, :exit => 0 end Log = Logger.new($stdout) cli = MyCLI.new cli.parse_options vm_name = cli.config[:vm_name] script = required_option(cli, :script) if File.directory?(script) script = script + '/script.yml' end if not File.exist?(script) $stderr.puts "Script file script.yml not found.\n\n" usage(cli) end iso_file = required_option(cli, :iso_file) if not File.exist?(iso_file) $stderr.puts "Invalid ISO file.\n\n" usage(cli) end # Create VBox VM first Log.debug "Creating VM #{vm_name}" Instalatron.create_vm :vm_disk_size => cli.config[:vm_disk_size], :vm_memory => cli.config[:vm_memory], :vm_name => vm_name, :iso_file => iso_file, :headless => cli.config[:headless] nic_config = cli.config[:nic_config] if nic_config nic, device, mode = nic_config.split ':' Log.debug "Setting nic mode #{nic} #{device} #{mode}" Instalatron.set_nic_mode(vm_name, nic, device, mode) end puts "Playing script using VM #{vm_name}\n\n" play_session vm_name, script, cli.config[:custom_sequence], cli.config[:key_press_delay] if cli.config[:destroy_vm] puts "Unregistering and deleting VM #{vm_name}" Instalatron.destroy_vm(vm_name) end