From ff2c1177b4d8e28403c600a6ff6b67386c7d8944 Mon Sep 17 00:00:00 2001 From: Patrick Debois Date: Thu, 11 Nov 2010 21:46:20 +0100 Subject: [PATCH] Almost working --- .gitignore | 2 + Rakefile | 126 +++++--- lib/args.rb | 12 - lib/sendkeystrokes.rb | 79 ----- lib/veewee.rb | 140 -------- lib/veewee/scancode.rb | 101 ++++++ lib/veewee/session.rb | 300 ++++++++++++++++++ lib/{ => veewee}/ssh.rb | 18 +- lib/veewee/web.rb | 41 +++ lib/web.rb | 19 -- .../{installer.rb => definition.rb} | 0 .../{installer.rb => definition.rb} | 0 trials/docu-vbox.txt | 83 +++++ {lib => trials}/f.rb | 0 trials/t.rb | 15 + 15 files changed, 635 insertions(+), 301 deletions(-) delete mode 100644 lib/args.rb delete mode 100644 lib/sendkeystrokes.rb delete mode 100644 lib/veewee.rb create mode 100644 lib/veewee/scancode.rb create mode 100644 lib/veewee/session.rb rename lib/{ => veewee}/ssh.rb (61%) create mode 100644 lib/veewee/web.rb delete mode 100644 lib/web.rb rename templates/centos-5-4-32bit/{installer.rb => definition.rb} (100%) rename templates/ubuntu-10-10-64bit/{installer.rb => definition.rb} (100%) create mode 100644 trials/docu-vbox.txt rename {lib => trials}/f.rb (100%) create mode 100644 trials/t.rb diff --git a/.gitignore b/.gitignore index 2d7f2b6a..e9a57a1b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +.DS_Store gems/* iso/* tmp/* +definitions/* diff --git a/Rakefile b/Rakefile index 558d4a00..b7c2f2cc 100644 --- a/Rakefile +++ b/Rakefile @@ -1,44 +1,94 @@ -base_dir= File.dirname(__FILE__) -box_definition_dir= File.dirname(__FILE__)+"/"+"definitions" +ENV['GEM_PATH']=File.dirname(__FILE__) +ENV['GEM_HOME']=File.dirname(__FILE__) -desc 'Default: list option' -task :default => [:test] +def check_environment + begin + require 'vagrant' + rescue LoadError + puts "you need to install depedencies: gem instal vagrant" + exit + end + + begin + require 'net/ssh' + require 'virtualbox' + require 'webrick' + rescue LoadError + puts "hmm you had vagrant installed but are missing the net-ssh or virtualbox gem: gem instal virtualbox net-ssh" + exit + end +end + +#See if all gems and so are installed +check_environment + +#Setup some base variables to use +veewee_dir= File.dirname(__FILE__) +definition_dir= File.expand_path(File.join(veewee_dir, "definitions")) +lib_dir= File.expand_path(File.join(veewee_dir, "lib")) +template_dir=File.expand_path(File.join(veewee_dir, "templates")) +vbox_dir=File.expand_path(File.join(veewee_dir, "tmp")) +iso_dir=File.expand_path(File.join(veewee_dir, "iso")) +ENV['VBOX_USER_HOME']=vbox_dir + +#Load Veewee::Session libraries +Dir.glob(File.join(lib_dir, '**','*.rb')).each {|f| + require f } + +#Initialize +Veewee::Session.setenv({:veewee_dir => veewee_dir, :definition_dir => definition_dir, :template_dir => template_dir, :iso_dir => iso_dir}) + +desc 'Default: list templates' +task :default => [:templates] + +desc 'List templates' +task :templates do + Veewee::Session.list_templates +end + +desc 'Define box' +task :define, [:boxname,:template_name] do |t,args| + if args.to_hash.size!=2 + puts "needs two arguments: rake define['boxname','template_name']" + exit + end + Veewee::Session.define(args.boxname,args.template_name) +end + +desc 'Undefine box' +task :undefine, [:boxname] do |t,args| + if args.to_hash.size!=1 + puts "needs one arguments: rake undefine[\"yourname\"]" + exit + end + Veewee::Session.undefine(args.boxname) +end + +desc 'List Definitions' +task :definitions do + Veewee::Session.list_definitions +end desc 'Build box' -task :build, [:box] do |t,args| - box=args.box - if File.directory?("#{box_definition_dir}/#{box}") - if run_box.length!=0 - puts "Executing #{run_box}" - require("#{run_box}") - end - end - -end - -desc 'Test box' -task :test, [:box] do |t,args| - system("puppet apply -v --debug --modulepath=#{base_dir}/modules recipe/site.pp") -end - -desc 'List Boxes' -task :list do - - subdirs=Dir.glob("#{box_definition_dir}/*") - subdirs.each do |sub| - if File.directory?("#{sub}") - run_box=Dir.glob("#{sub}/run.rb") - clean_box=Dir.glob("#{sub}/clean.rb") - if run_box.length!=0 - name=sub.sub(/#{box_dir}\//,'') - puts "rake run['#{name}']" - end - if clean_box.length!=0 - name=sub.sub(/#{box_dir}\//,'') - puts "rake clean['#{name}']" - end - end - end +task :build, [:boxname] do |t,args| + if args.to_hash.size!=1 + puts "needs one arguments: rake build['boxname']" + exit + end + Veewee::Session.build(args.boxname) +end + +desc 'List boxes' +task :boxes do + Veewee::Session.list_boxes +end +desc 'Remove box' +task :remove_box, [:boxname] do |t,args| + Veewee::Session.remove_box(args.boxname) end +desc 'Clean all unfinished builds' +task :clean do + Veewee::Session.clean +end \ No newline at end of file diff --git a/lib/args.rb b/lib/args.rb deleted file mode 100644 index 1620a5eb..00000000 --- a/lib/args.rb +++ /dev/null @@ -1,12 +0,0 @@ -# quit unless our script gets two command line arguments -unless ARGV.length == 2 - puts "Dude, not the right number of arguments." - puts "Usage: ruby MyScript.rb InputFile.csv SortedOutputFile.csv\n" - - - # our input file should be the first command line arg - input_file = ARGV[0] - # - # # our output file should be the second command line arg - output_file = ARGV[1] -end diff --git a/lib/sendkeystrokes.rb b/lib/sendkeystrokes.rb deleted file mode 100644 index 135363de..00000000 --- a/lib/sendkeystrokes.rb +++ /dev/null @@ -1,79 +0,0 @@ -def send_sequence(vboxcmd,vname,sequence) - cmd=""; - sequence.each { |s| - keycodes=string_to_keycode(s) - puts keycodes - # VBox seems to have issues with sending the scancodes as one big - # .join()-ed string. It seems to get them out or order or ignore some. - # A workaround is to send the scancodes one-by-one. - codes="" - for keycode in keycodes.split(' ') do - codes=codes+send_keycode(vboxcmd,vname,keycode) - end - cmd=cmd+codes+" sleep 1;" - } - return cmd; -end - -def send_keycode(vboxcmd,vname,keycode) - - return "#{vboxcmd} controlvm '#{vname}' keyboardputscancode #{keycode} ;" -end - -def string_to_keycode(thestring) - - #http://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html - - k=Hash.new - k['1'] = '02' ; k['2'] = '03' ; k['3'] = '04'; k['4']= '05' ;k['5']='06'; k['6'] = '07' ; k['7'] = '08'; k['8'] = '09'; k['9']= '0a'; k['0']='0b'; k['-'] = '0c'; k['='] = '0d' ; - k['Tab'] = '0f'; k['q'] = '10' ; k['w'] = '11' ; k['e'] = '12'; k['r'] = '13' ; k['t'] = '14' ; k['y'] = '15'; k['u']= '16' ; k['i']='17'; k['o'] = '18' ; k['p'] = '19' ; k['[']='1a'; k[']']='1b' - k['Q'] = '2a 10 aa' ; k['W'] = '2a 11 aa' ; k['E'] = '2a 12 aa'; k['R'] = '2a 13 aa' ; k['t'] = '14' ; k['y'] = '15'; k['U']= '2a 16 aa' ; k['i']='17'; k['o'] = '18' ; k['p'] = '19' ; - - k['a'] = '1e'; k['s'] = '1f' ; k['d'] = '20' ; k['f'] = '21'; k['g'] = '22' ; k['h'] = '23' ; k['j'] = '24'; k['k']= '25' ; k['l']='26'; k[';'] = '27' ;k['"']='28'; - k['a'] = '1e'; k['S'] = '2a 1f aa' ; k['d'] = '20' ; k['f'] = '21'; k['g'] = '22' ; k['h'] = '23' ; k['j'] = '24'; k['k']= '25' ; k['l']='26'; k[';'] = '27' ;k['"']='28'; - - k['z'] = '2c'; k['x'] = '2d' ; k['c'] = '2e' ; k['v'] = '2f'; k['b'] = '30' ; k['n'] = '31' ; k['m'] = '32'; k[',']= '33' ; k['.']='34'; k['/'] = '35' ;k[':'] = '2a 27 aa' - k['_'] = '2a 0c aa'; - - special=Hash.new; - special[''] = '1c'; - special[''] = '0e'; - special[''] = '39'; - special[''] = '1c' - special[''] = '01'; - - keycodes='' - thestring.gsub!(/ /,"") - - until thestring.length == 0 - nospecial=true; - special.keys.each { |key| - if thestring.start_with?(key) - #take thestring - #check if it starts with a special key + pop special string - keycodes=keycodes+special[key]+' '; - thestring=thestring.slice(key.length,thestring.length-key.length) - nospecial=false; - break; - end - } - if nospecial - keycodes=keycodes+k[thestring.slice(0,1)]+' '; - thestring=thestring.slice(1,thestring.length-1) - end - #else take the character + pop 1 character - end - - return keycodes -end - - -module Puppet::Parser::Functions - newfunction(:sendkeystrokes, :type => :rvalue) do |args| - vboxcmd= args[0] - vname = args[1] - keystrokes = args[2] - cmd=send_sequence(vboxcmd,vname,keystrokes) - return cmd - end -end diff --git a/lib/veewee.rb b/lib/veewee.rb deleted file mode 100644 index 2446c173..00000000 --- a/lib/veewee.rb +++ /dev/null @@ -1,140 +0,0 @@ -ENV['GEM_PATH']=File.dirname(__FILE__) -ENV['GEM_HOME']=File.dirname(__FILE__) -ENV['VBOX_USER_HOME']=File.dirname(__FILE__)+"/tmp" -#PATH=$GEM_HOME/bin:$PATH - -require 'webrick' -include WEBrick - -exit - -class Veewee - - #:vostype -> this is the virtualbox type - # - def self.contract(options={:vcpu => '1', :vmemory=> '348', :vdisksize => '10140', :isodst => "", :isosrc => "", :isomd5 => "", :bootwait => "30", - :vostype => "Ubuntu", :bootcmd => "", :kickport => "", :kickip => "", :vmname => "ubuntu", :hostsshport => "2222", :guestsshport => "22"}) - puts "it works" - - #Download iso file is not existing - - #Verify the md5 - if [ options[:isomd5] != ""] - puts "we go an isomd5" - verify_md5(options[:isodst],options[:isomd5]) - end - - #Check if exists (remove if wanted) - #Create VM unless exits - #Add IDE unless exists - #Add SATA unless exists - #Create Disk unless exists - #Add Disk to SATA unless already linked - #Add ISO to IDE unless already mounted - #Boot VM unless already booted - #Wait some time - #Send some keystrokes unless ssh exists - #Wait for SSH to become alive - #Login to the box with username, password - #sudo install a minimal chef thing (rvm?) - #or example a script as root to care of the minimal fixing - #If installed and checks are running - #export the box - - end - - def self.verify_md5(filename,checksum) - puts "verifying md5 sum" - end - - def self.checkiso_exists(filename) - puts "verifying if iso exists" - puts "potentional ask it to download iso, if ask" - end - - def self.install_gems - #install vagrant gem - #install md5sum? gem - #install virtualbox gem - end - - def self.find_vbox_cmd - #vboxheadless="VBoxHeadless" - return "VBoxManage" - end - - def self.create_vm(options) - #command => "${vboxcmd} createvm --name ${vmname} --ostype ${vostype} --register", - #unless => "${vboxcmd} list vms|grep ${vname}" - end - - def self.create_disk(options) - #command => "${vboxcmd} createhd --filename '${vname}.vdi' --size ${vdisksize}", - #unless => "${vboxcmd} showhdinfo '${vname}.vdi'" - end - - def self.create_ide(vmname) - #command => "${vboxcmd} storagectl '${vname}' --name 'IDE Controller' --add ide", - #unless => "${vboxcmd} showvminfo '${vname}' | grep 'IDE Controller' " - end - - def self.attach_disk(vmname) - #command => "${vboxcmd} storageattach '${vname}' --storagectl 'SATA Controller' --port 0 --device 0 --type hdd --medium '${vname}.vdi'", - end - - def self.mount_iso(vmname,isofile) - #command => "${vboxcmd} storageattach '${vname}' --storagectl 'IDE Controller' --type dvddrive --port 1 --device 0 --medium '${isodst}' "; - end - - def self.create_sata - #command => "${vboxcmd} storagectl '${vname}' --name 'SATA Controller' --add sata", - #unless => "${vboxcmd} showvminfo '${vname}' | grep 'SATA Controller' "; - end - - def self.suppress - # command => "${vboxcmd} setextradata global 'GUI/RegistrationData' 'triesLeft=0'; - # ${vboxcmd} setextradata global 'GUI/UpdateDate' '1 d, 2009-09-20'; - # ${vboxcmd} setextradata global 'GUI/SuppressMessages' 'confirmInputCapture,remindAboutAutoCapture,remindAboutMouseIntegrationOff'; - - end - - def self.set_ssh_port - # exec { - # "set ssh port": - # command => "${vboxcmd} modifyvm '${vname}' --natpf1 'guestssh,tcp,,${hostsshport},,${guestsshport}'", - # unless => "${vboxcmd} showvminfo '${vname}'|grep State|grep running" - # } - end - - def self.wait_for_http(filename,options => {:port => 7777}) - end - - def self.wait_for_ssh - end - -end - -Veewee.contract - -exit - - - -class FileServlet < WEBrick::HTTPServlet::AbstractServlet - def do_GET(request,response) - response['Content-Type']='text/plain' - response.status = 200 - displayfile=File.open("/Users/patrick/vagrantbox/files/preseed.cfg",'r') - content=displayfile.read() - response.body=content - sleep 4 - @@s.shutdown - end -end - -@@s= HTTPServer.new(:Port => 7125) -@@s.mount("/preseed.cfg", FileServlet) -trap("INT"){@@s.shutdown} -@@s.start - - diff --git a/lib/veewee/scancode.rb b/lib/veewee/scancode.rb new file mode 100644 index 00000000..f2dd47bd --- /dev/null +++ b/lib/veewee/scancode.rb @@ -0,0 +1,101 @@ +module Veewee + class Scancode + + def self.send_sequence(vboxcmd,vname,sequence) + + sequence.each { |s| + s.gsub!(/%IP%/,Veewee::Session.local_ip); + s.gsub!(/%PORT%/,'7122'); + s.gsub!(/%NAME%/, vname); + keycodes=string_to_keycode(s) + + # VBox seems to have issues with sending the scancodes as one big + # .join()-ed string. It seems to get them out or order or ignore some. + # A workaround is to send the scancodes one-by-one. + codes="" + for keycode in keycodes.split(' ') do + send_keycode(vboxcmd,vname,keycode) + sleep 0.01 + end + #sleep after each sequence (needs to be param) + sleep 1 + } + + + end + + def self.send_keycode(vboxcmd,vname,keycode) + command= "#{vboxcmd} controlvm '#{vname}' keyboardputscancode #{keycode}" + #puts "#{command}" + IO.popen("#{command}") { |f| print '.' } + end + + def self.string_to_keycode(thestring) + + #http://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html + + k=Hash.new + k['1'] = '02' ; k['2'] = '03' ; k['3'] = '04'; k['4']= '05' ;k['5']='06'; k['6'] = '07' ; k['7'] = '08'; k['8'] = '09'; k['9']= '0a'; k['0']='0b'; k['-'] = '0c'; k['='] = '0d' ; + k['Tab'] = '0f'; + k['q'] = '10' ; k['w'] = '11' ; k['e'] = '12'; k['r'] = '13' ; k['t'] = '14' ; k['y'] = '15'; k['u']= '16' ; k['i']='17'; k['o'] = '18' ; k['p'] = '19' ; + + k['Q'] = '2a 10 aa' ; k['W'] = '2a 11 aa' ; k['E'] = '2a 12 aa'; k['R'] = '2a 13 aa' ; k['T'] = '2a 14 aa' ; k['Y'] = '2a 15 aa'; k['U']= '2a 16 aa' ; k['I']='2a 17 aa'; k['O'] = '2a 18 aa' ; k['P'] = '2a 19 aa' ; + + k['a'] = '1e'; k['s'] = '1f' ; k['d'] = '20' ; k['f'] = '21'; k['g'] = '22' ; k['h'] = '23' ; k['j'] = '24'; k['k']= '25' ; k['l']='26'; k[';'] = '27' + k['A'] = '2a 1e aa'; k['S'] = '2a 1f aa' ; k['D'] = '2a 20 aa' ; k['F'] = '2a 21 aa'; k['G'] = '2a 22 aa' ; k['H'] = '2a 23 aa' ; k['J'] = '2a 24 aa'; k['K']= '2a 25 aa' ; k['L']='2a 26 aa'; + + k[';'] = '27' ;k['"']='28'; + + k['[']='1a'; k[']']='1b' + + k['z'] = '2c'; k['x'] = '2d' ; k['c'] = '2e' ; k['v'] = '2f'; k['b'] = '30' ; k['n'] = '31' ; k['m'] = '32'; + k['Z'] = '2a 2c aa'; k['X'] = '2a 2d aa' ; k['C'] = '2a 2e aa' ; k['V'] = '2a 2f aa'; k['B'] = '2a 30 aa' ; k['N'] = '2a 31 aa' ; k['M'] = '2a 32 aa'; + + k[',']= '33' ; k['.']='34'; k['/'] = '35' ;k[':'] = '2a 27 aa'; + k['%'] = '2a 06 aa'; k['_'] = '2a 0c aa'; + + special=Hash.new; + special[''] = '1c'; + special[''] = '0e'; + special[''] = '39'; + special[''] = '1c' + special[''] = '01'; + #special[''] = '01'; + #special[''] = '01'; + #special[''] = '01'; + #special[''] = '01'; + + keycodes='' + thestring.gsub!(/ /,"") + + until thestring.length == 0 + nospecial=true; + special.keys.each { |key| + if thestring.start_with?(key) + #take thestring + #check if it starts with a special key + pop special string + keycodes=keycodes+special[key]+' '; + thestring=thestring.slice(key.length,thestring.length-key.length) + nospecial=false; + break; + end + } + if nospecial + code=k[thestring.slice(0,1)] + if !code.nil? + keycodes=keycodes+code+' ' + else + puts "no scan code for #{thestring.slice(0,1)}" + end + #pop one + thestring=thestring.slice(1,thestring.length-1) + end + end + + return keycodes + end + + end +end + + diff --git a/lib/veewee/session.rb b/lib/veewee/session.rb new file mode 100644 index 00000000..a2e3e099 --- /dev/null +++ b/lib/veewee/session.rb @@ -0,0 +1,300 @@ +require 'socket' +require 'net/scp' + +module Veewee + class Session + + attr_accessor :veewee_dir + attr_accessor :definition_dir + attr_accessor :template_dir + attr_accessor :iso_dir + attr_accessor :name + attr_accessor :definition + + def self.setenv(env) + @veewee_dir=env[:veewee_dir] + @definition_dir=env[:definition_dir] + @template_dir=env[:template_dir] + @box_dir=env[:box_dir] + @iso_dir=env[:iso_dir] + end + + def self.declare(options) + defaults={ + :cpu_count => '1', :memory_size=> '256', + :disk_size => '10140', :disk_format => 'VDI',:disk_size => '10240' , + :os_type_id => 'Ubuntu', + :iso_file => "ubuntu-10.10-server-i386.iso", :iso_src => "", :iso_md5 => "", :iso_download_timeout => 1000, + :boot_wait => "10", :boot_cmd_sequence => [ "boot"], + :kickstart_port => "7122", :kickstart_ip => self.local_ip, :kickstart_timeout => 10000,:kickstart_file => "preseed.cfg", + :ssh_login_timeout => "100",:ssh_user => "vagrant", :ssh_password => "vagrant",:ssh_key => "", + :ssh_host_port => "2222", :ssh_guest_port => "22", + :postinstall_files => [ "postinstall.sh"],:postinstall_timeout => 10000} + + @definition=defaults.merge(options) + + end + + def self.define(boxname,template_name) + #Check if template_name exists + #puts @veewee_dir + if File.directory?(File.join(@template_dir,template_name)) + else + puts "this template can not be found, use rake templates to list all templates" + end + if File.directory?(File.join(@definition_dir,boxname)) + puts "this definition already exists, use rake undefine['#{name}'] to remove this definition" + else + FileUtils.mkdir(File.join(@definition_dir,boxname)) + FileUtils.cp_r(File.join(@template_dir,template_name,'.'),File.join(@definition_dir,boxname)) + puts "template succesfully copied" + end + end + + + def self.definition_exists?(boxname) + if File.directory?(File.join(@definition_dir,boxname)) + if File.exists?(File.join(@definition_dir,boxname,'definition.rb')) + return true + else + return false + end + else + return false + end + + end + + def self.undefine(boxname) + name_dir=File.join(@definition_dir,boxname) + if File.directory?(name_dir) + #TODO: Needs to be more defensive!! + FileUtils.rm_rf(name_dir) + else + puts "Can not undefine , definition #{boxname} does not exist" + exit + end + end + + def self.list_templates + puts "the following templates are available:" + subdirs=Dir.glob("#{@template_dir}/*") + subdirs.each do |sub| + if File.directory?("#{sub}") + definition=Dir.glob("#{sub}/definition.rb") + if definition.length!=0 + name=sub.sub(/#{@template_dir}\//,'') + puts "use rake define['','#{name}']" + end + end + end + end + + def self.list_boxes + puts "Not yet implemented" + end + + def self.list_definitions + puts "Not yet implemented" + end + + def self.clean + puts "Not yet implemented" + end + + def self.remove_box(boxname) + puts "Not yet implemented" + end + + def self.build(boxname) + #Now we have to load the definition + + + + if definition_exists?(boxname) + definition_file=File.join(@definition_dir,boxname,"definition.rb") + begin + require definition_file + rescue LoadError + puts "Error loading definition of #{boxname}" + exit + end + + #Command to execute locally + vboxcmd="VboxManage" + + + #TODO Check all parameters for correctness + + vm=VirtualBox::VM.find(boxname) + if vm.nil? + + #TODO One day ruby-virtualbox will be able to handle this creation + #Box does not exist, we can start to create it + command="#{vboxcmd} createvm --name '#{boxname}' --ostype '#{@definition[:os_type_id]}' --register" + + #Exec and system stop the execution here + IO.popen("#{command}") { |f| puts f.gets } + vm=VirtualBox::VM.find(boxname) + else + puts "box already exists" + end + + if (!vm.nil? && !(vm.powered_off?)) + puts "shutting down box" + #We force it here, maybe vm.shutdown is cleaner + vm.stop + end + + #Set all params we know + vm.memory_size=@definition[:memory_size] + vm.os_type_id=@definition[:os_type_id] + vm.cpu_count=@definition[:cpu_count] + vm.name=boxname + + vm.validate + vm.save + + #Now check the disks + #Maybe one day we can use the name, now we have to check location + #disk=VirtualBox::HardDrive.find(boxname) + disk=nil + location=boxname+"."+@definition[:disk_format].downcase + + VirtualBox::HardDrive.all.each do |d| + if !d.location.match(/#{location}/).nil? + disk=d + end + end + + puts "hea" + if disk.nil? + puts "creating new harddrive" + newdisk=VirtualBox::HardDrive.new + newdisk.format=@definition[:disk_format] + newdisk.logical_size=@definition[:disk_size].to_i + + newdisk.location=location + newdisk.save + disk=newdisk + puts disk + end + + #unless => "${vboxcmd} showvminfo '${vname}' | grep 'IDE Controller' " + command ="#{vboxcmd} storagectl '#{boxname}' --name 'IDE Controller' --add ide" + IO.popen("#{command}") { |f| puts f.gets } + + #unless => "${vboxcmd} showvminfo '${vname}' | grep 'SATA Controller' "; + command ="#{vboxcmd} storagectl '#{boxname}' --name 'SATA Controller' --add sata" + IO.popen("#{command}") { |f| puts f.gets } + + puts "here" + #command => "${vboxcmd} storageattach '${vname}' --storagectl 'SATA Controller' --port 0 --device 0 --type hdd --medium '${vname}.vdi'", + command ="#{vboxcmd} storageattach '#{boxname}' --storagectl 'SATA Controller' --port 0 --device 0 --type hdd --medium '#{location}'" + IO.popen("#{command}") { |f| puts f.gets } + + puts "la" + full_iso_file=File.join(@iso_dir,@definition[:iso_file]) + puts "#{full_iso_file}" + #command => "${vboxcmd} storageattach '${vname}' --storagectl 'IDE Controller' --type dvddrive --port 1 --device 0 --medium '${isodst}' "; + command ="#{vboxcmd} storageattach '#{boxname}' --storagectl 'IDE Controller' --type dvddrive --port 1 --device 0 --medium '#{full_iso_file}'" + puts command + IO.popen("#{command}") { |f| puts f.gets } + + + #Setting this annoying messages to register + VirtualBox::ExtraData.global["GUI/RegistrationData"]="triesLeft=0" + VirtualBox::ExtraData.global["GUI/UpdateDate"]="1 d, 2009-09-20" + VirtualBox::ExtraData.global["GUI/SuppressMessages"]="confirmInputCapture,remindAboutAutoCapture,remindAboutMouseIntegrationOff" + VirtualBox::ExtraData.global.save + + #Map SSH Ports + # command => "${vboxcmd} modifyvm '${vname}' --natpf1 'guestssh,tcp,,${hostsshport},,${guestsshport}'", + port = VirtualBox::NATForwardedPort.new + port.name = "guestssh" + port.guestport = @definition[:ssh_guest_port].to_i + port.hostport = @definition[:ssh_host_port].to_i + vm.network_adapters[0].nat_driver.forwarded_ports << port + port.save + vm.save + + #Starting machine + #vm.start("vrdp") + vm.start("gui") + + #waiting for it to boot + sleep @definition[:boot_wait].to_i + + puts "sending keys" + Veewee::Scancode.send_sequence("#{vboxcmd}","#{boxname}",@definition[:boot_cmd_sequence]) + + #:kickstart_port => "7122", :kickstart_ip => self.local_ip, :kickstart_timeout => 1000,:kickstart_file => "preseed.cfg", + Veewee::Web.wait_for_request(@definition[:kickstart_file],{:port => @definition[:kickstart_port], + :host => @definition[:kickstart_ip], :timeout => @definition[:kickstart_timeout], + :web_dir => File.join(@definition_dir,boxname)}) + + + Veewee::Ssh.when_ssh_login_works("localhost",{:port => @definition[:ssh_host_port], :user => @definition[:ssh_user],:password => @definition[:ssh_password]}) do + + postinstall_file=File.join(@definition_dir,boxname,@definition[:postinstall_files][0]) + Net::SSH.start( "localhost", @definition[:ssh_user], {:port => @definition[:ssh_host_port], :password => @definition[:ssh_password]} ) do |ssh| + puts "Transferring #{postinstall_file} " + ssh.scp.upload!( postinstall_file, '.' ) do |ch, name, sent, total| + print "\r#{postinstall_file}: #{(sent.to_f * 100 / total.to_f).to_i}%" + end + end + + Net::SSH.start( "localhost", @definition[:ssh_user], {:port => @definition[:ssh_host_port], :password => @definition[:ssh_password]} ) do |session| + + + session.open_channel do |channel| + + channel.request_pty do |ch, success| + raise "Error requesting pty" unless success + + ch.send_channel_request("shell") do |ch, success| + raise "Error opening shell" unless success + end + end + + channel.on_data do |ch, data| + STDOUT.print data + + end + + channel.on_extended_data do |ch, type, data| + STDOUT.print "Error: #{data}\n" + end + + channel.send_data( "echo \"vagrant\"|sudo -S sh #{@definition[:postinstall_files][0]}\n" ) + + end + + end + + end + + end + end + + def self.set_ssh_port + # exec { + # "set ssh port": + # command => "${vboxcmd} modifyvm '${vname}' --natpf1 'guestssh,tcp,,${hostsshport},,${guestsshport}'", + # unless => "${vboxcmd} showvminfo '${vname}'|grep State|grep running" + # } + end + + def self.local_ip + orig, Socket.do_not_reverse_lookup = Socket.do_not_reverse_lookup, true # turn off reverse DNS resolution temporarily + + UDPSocket.open do |s| + s.connect '64.233.187.99', 1 + s.addr.last + end + ensure + Socket.do_not_reverse_lookup = orig + end + + end +end \ No newline at end of file diff --git a/lib/ssh.rb b/lib/veewee/ssh.rb similarity index 61% rename from lib/ssh.rb rename to lib/veewee/ssh.rb index ae35cca1..5d4330f3 100644 --- a/lib/ssh.rb +++ b/lib/veewee/ssh.rb @@ -1,18 +1,13 @@ -def when_ssh_login_works(sshparams= {},&block) - Shellutil.execute_when_ssh_available(ip="localhost", sshparams) do - yield - end -end - +module Veewee + class Ssh -def execute_when_ssh_available(ip="localhost", options = { } , &block) + def self.when_ssh_login_works(ip="localhost", options = { } , &block) - defaults={ :port => '22', :timeout => 2 , :gw_machine => '' , :gw_port => '22' , :gw_user => 'root' , :user => 'root', :password => ''} + defaults={ :port => '22', :timeout => 200 , :user => 'vagrant', :password => 'vagrant'} print "sshing to => #{options[:port]}" options=defaults.merge(options) - configfile="#{ENV['VM_STATE']}/.ssh/ssh_config.systr" begin Timeout::timeout(options[:timeout]) do @@ -37,8 +32,5 @@ def execute_when_ssh_available(ip="localhost", options = { } , &block) return false end -def self.execute(command, options = { :progress => "off"} ) - - Net::SSH.start(options[:host], options[:user], { :port => options[:port], :password => options[:password], :paranoid => false }) do |ssh| - end +end end diff --git a/lib/veewee/web.rb b/lib/veewee/web.rb new file mode 100644 index 00000000..9cf696ac --- /dev/null +++ b/lib/veewee/web.rb @@ -0,0 +1,41 @@ +module Veewee + class Web + + @@filename="" + @@web_dir="" + require 'webrick' + include WEBrick + + class FileServlet < WEBrick::HTTPServlet::AbstractServlet + + def initialize(server,localfile) + super(server) + @server=server + @localfile=localfile + end + def do_GET(request,response) + response['Content-Type']='text/plain' + response.status = 200 + displayfile=File.open(@localfile,'r') + content=displayfile.read() + response.body=content + #If we shut too fast it might not get the complete file + sleep 2 + @server.shutdown + end + end + + def self.wait_for_request(filename,options={:timeout => 10, :web_dir => "", :port => 7125}) + + web_dir=options[:web_dir] + filename=filename + + s= HTTPServer.new(:Port => options[:port]) + s.mount("/#{filename}", FileServlet,File.join(web_dir,filename)) + trap("INT"){s.shutdown} + s.start + end + end +end + + diff --git a/lib/web.rb b/lib/web.rb deleted file mode 100644 index 700c7b22..00000000 --- a/lib/web.rb +++ /dev/null @@ -1,19 +0,0 @@ -require 'webrick' -include WEBrick - -class FileServlet < WEBrick::HTTPServlet::AbstractServlet - def do_GET(request,response) - response['Content-Type']='text/plain' - response.status = 200 - displayfile=File.open("/Users/patrick/vagrantbox/files/preseed.cfg",'r') - content=displayfile.read() - response.body=content - sleep 4 - @@s.shutdown - end -end - -@@s= HTTPServer.new(:Port => 7125) -@@s.mount("/preseed.cfg", FileServlet) -trap("INT"){@@s.shutdown} -@@s.start diff --git a/templates/centos-5-4-32bit/installer.rb b/templates/centos-5-4-32bit/definition.rb similarity index 100% rename from templates/centos-5-4-32bit/installer.rb rename to templates/centos-5-4-32bit/definition.rb diff --git a/templates/ubuntu-10-10-64bit/installer.rb b/templates/ubuntu-10-10-64bit/definition.rb similarity index 100% rename from templates/ubuntu-10-10-64bit/installer.rb rename to templates/ubuntu-10-10-64bit/definition.rb diff --git a/trials/docu-vbox.txt b/trials/docu-vbox.txt new file mode 100644 index 00000000..c54dbcb2 --- /dev/null +++ b/trials/docu-vbox.txt @@ -0,0 +1,83 @@ +>> vm.interface.methods +=> ["teleporter_password", "get_guest_property_value", "pointing_hid_type=", "call_function", "get_serial_port", "teleporter_password=", "current_snapshot", "vram_size", "get_cpu_status", "methods", "send", "delete_settings", "settings_modified", "members", "access_error", "keyboard_hid_type", "vram_size=", "taint", "get_cpu_id_leaf", "instance_variable_defined?", "set_boot_order", "medium_attachments", "get_guest_property_timestamp", "keyboard_hid_type=", "state", "snapshot_count", "accelerate_3d_enabled", "query_log_filename", "singleton_methods", "instance_eval", "export", "get_medium_attachment", "session_state", "accelerate_3d_enabled=", "set_cpu_id_leaf", "hpet_enabled", "nil?", "get_boot_order", "memory_size", "set_guest_property", "read_property", "get_parallel_port", "hpet_enabled=", "current_state_modified", "protected_methods", "instance_exec", "get_snapshot", "display", "memory_size=", "accelerate_2d_video_enabled", "read_log", "tainted?", "method", "get_network_adapter", "untaint", "remove_cpu_id_leaf", "instance_of?", "os_type_id", "rtc_use_utc", "accelerate_2d_video_enabled=", "attach_device", "equal?", "name", "set_guest_propetty_value", "usb_controller", "os_type_id=", "rtc_use_utc=", "write_property", "clipboard_mode", "hash", "name=", "private_methods", "find_snapshot", "monitor_count", "clipboard_mode=", "session_type", "kind_of?", "hardware_version", "io_cache_enabled", "monitor_count=", "freeze", "remove_all_cpu_id_leafs", "detach_device", "eql?", "enumerate_guest_properties", "hardware_version=", "io_cache_enabled=", "id", "get_extra_data_keys", "guest_property_notification_patterns", "bios_settings", "public_methods", "set_current_snapshot", "implementer", "add_storage_controller", "has_function?", "session_pid", "object_id", "guest_property_notification_patterns=", "is_a?", "hardware_uuid", "io_cache_size", "get_hw_virt_ex_property", "passthrough_device", "query_saved_thumbnail_size", "audio_adapter", "tap", "hardware_uuid=", "io_cache_size=", "member", "type", "get_extra_data", "teleporter_enabled", "firmware_type", "instance_variables", "can_show_console_window", "__id__", "lib", "get_storage_controller_by_name", "has_property?", "frozen?", "last_state_change", "to_enum", "teleporter_enabled=", "io_bandwidth_max", "firmware_type=", "to_a", "set_hw_virt_ex_property", "cpu_count", "respond_to?", "mount_medium", "storage_controllers", "read_saved_thumbnail_to_array", "class", "set_extra_data", "cpu_hot_plug_enabled", "cpu_count=", "io_bandwidth_max=", "teleporter_port", "snapshot_folder", "instance_variable_get", "show_console_window", "==", "cpu_hot_plug_enabled=", "__send__", "get_storage_controller_by_instance", "===", "create_shared_folder", "state_file_path", "enum_for", "teleporter_port=", "extend", "to_s", "save_settings", "memory_balloon_size", "hot_plug_cpu", "snapshot_folder=", "get_medium", "query_saved_screenshot_png_size", "parent", "page_fusion_enabled", "memory_balloon_size=", "clone", "get_cpu_property", "teleporter_address", "=~", "instance_variable_set", "get_guest_property", "vrdp_server", "page_fusion_enabled=", "remove_storage_controller", "remove_shared_folder", "log_folder", "teleporter_address=", "discard_settings", "shared_folders", "hot_unplug_cpu", "description", "inspect", "get_medium_attachments_of_controller", "read_saved_png_screenshot_to_array", "settings_file_path", "accessible", "pointing_hid_type", "dup", "set_cpu_property", "description="] + + +patricks-iMac:virtualbox-0.7.5 patrick$ vi lib/virtualbox/com/ffi/interfaces.rb + create_interface(:Keyboard, :NSISupports) + + + +#http://www.virtualbox.org/sdkref/_virtual_box_8idl-source.html +#http://www.virtualbox.org/sdkref/interface_i_keyboard.html + + +vi lib/virtualbox/com/interface/3.2.x/keyboard.rb + +module VirtualBox + module COM + module Interface + module Version_3_2_X + class Keyboard < AbstractInterface + IID = "2D1A531B-4C6E-49CC-8AF6-5C857B78B5D7" + + function :put_cad, nil, [] + function :put_scancode, nil, [T_INT64] + function :put_scancodes, nil, [ [:scancode,T_INT64], T_UINT64 ] + + #function :detach_usb_device, :USBDevice, [WSTRING] + #function :find_usb_device_by_address, :USBDevice, [WSTRING] + #function :find_usb_device_by_id, :USBDevice, [WSTRING] + #function :create_shared_folder, nil, [WSTRING, WSTRING, T_BOOL] + #function :remove_shared_folder, nil, [WSTRING] + #function :take_snapshot, :Progress, [WSTRING, WSTRING] + #function :delete_snapshot, :Progress, [WSTRING] + #function :restore_snapshot, :Progress, [:Snapshot] + #function :teleport, :Progress, [WSTRING, T_UINT32, WSTRING, T_UINT32] + #function :register_callback, nil, [:ConsoleCallback] + #function :unregister_callback, nil, [:ConsoleCallback] + end + end + end + end +end + + + + +>> session=VirtualBox::Lib.lib.session +=> # +>> session.state +get_state +[#] +FFI call: get_state [] [#]0 +=> :closed + + +vm.interface.parent.open_remote_session(session,"c5429061-8f1c-4a9d-aea6-0d2d6a4a4ebc","gui","") + + +VirtualBox::Exceptions::FFIException: Error in API call to open_session: 2147942487 + from /Users/patrick/veewee/gems/gems/virtualbox-0.7.5/lib/virtualbox/com/implementer/ffi.rb:99:in `call_and_check' + from /Users/patrick/veewee/gems/gems/virtualbox-0.7.5/lib/virtualbox/com/implementer/ffi.rb:72:in `call_vtbl_function' + from /Users/patrick/veewee/gems/gems/virtualbox-0.7.5/lib/virtualbox/com/implementer/ffi.rb:51:in `call_function' + from /Users/patrick/veewee/gems/gems/virtualbox-0.7.5/lib/virtualbox/com/abstract_interface.rb:135:in `call_function' + from /Users/patrick/veewee/gems/gems/virtualbox-0.7.5/lib/virtualbox/com/abstract_interface.rb:51:in `open_session' + from (irb):33 + + + +BUG +https://github.com/mitchellh/virtualbox/issuesearch?state=closed&q=session#issue/25 + + + +***open_remote_session**** +open_remote_session +open_remote_session +[#, + #, + #, + #, + #] +FFI call: open_remote_session [#, "c5429061-8f1c-4a9d-aea6-0d2d6a4a4ebc", "gui", ""] [#, #, #, #, #]0 + diff --git a/lib/f.rb b/trials/f.rb similarity index 100% rename from lib/f.rb rename to trials/f.rb diff --git a/trials/t.rb b/trials/t.rb new file mode 100644 index 00000000..21858258 --- /dev/null +++ b/trials/t.rb @@ -0,0 +1,15 @@ +require 'rubygems' +require 'pp' +require 'virtualbox' +vm=VirtualBox::VM.find("blub") +#vm.start +vm.state +#session = VirtualBox::Lib.lib.session + +vm.with_open_session do |session| + pp session + pp session.console + pp session.console.keyboard + pp session.console.keyboard.methods + session.console.keyboard.put_scancode(20) +end