beaker 0.0.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. checksums.yaml +8 -8
  2. data/.travis.yml +8 -0
  3. data/README.md +6 -6
  4. data/beaker.gemspec +6 -2
  5. data/lib/beaker.rb +1 -1
  6. data/lib/beaker/answers.rb +34 -7
  7. data/lib/beaker/answers/version20.rb +124 -0
  8. data/lib/beaker/answers/version28.rb +21 -0
  9. data/lib/beaker/answers/version30.rb +24 -5
  10. data/lib/beaker/cli.rb +55 -41
  11. data/lib/beaker/command.rb +2 -2
  12. data/lib/beaker/dsl/helpers.rb +320 -106
  13. data/lib/beaker/dsl/install_utils.rb +202 -81
  14. data/lib/beaker/dsl/roles.rb +40 -0
  15. data/lib/beaker/host.rb +28 -20
  16. data/lib/beaker/host/unix.rb +7 -4
  17. data/lib/beaker/host/unix/pkg.rb +42 -12
  18. data/lib/beaker/host/windows.rb +9 -5
  19. data/lib/beaker/host/windows/group.rb +1 -1
  20. data/lib/beaker/host/windows/pkg.rb +41 -8
  21. data/lib/beaker/hypervisor.rb +23 -10
  22. data/lib/beaker/hypervisor/aixer.rb +15 -19
  23. data/lib/beaker/hypervisor/blimper.rb +71 -72
  24. data/lib/beaker/hypervisor/fusion.rb +11 -10
  25. data/lib/beaker/hypervisor/solaris.rb +17 -23
  26. data/lib/beaker/hypervisor/vagrant.rb +27 -12
  27. data/lib/beaker/hypervisor/vcloud.rb +154 -138
  28. data/lib/beaker/hypervisor/vcloud_pooled.rb +97 -0
  29. data/lib/beaker/hypervisor/vsphere.rb +8 -5
  30. data/lib/beaker/hypervisor/vsphere_helper.rb +43 -33
  31. data/lib/beaker/network_manager.rb +16 -12
  32. data/lib/beaker/options/command_line_parser.rb +199 -0
  33. data/lib/beaker/options/hosts_file_parser.rb +39 -0
  34. data/lib/beaker/options/options_file_parser.rb +45 -0
  35. data/lib/beaker/options/options_hash.rb +294 -0
  36. data/lib/beaker/options/parser.rb +288 -0
  37. data/lib/beaker/options/pe_version_scraper.rb +35 -0
  38. data/lib/beaker/options/presets.rb +70 -0
  39. data/lib/beaker/shared.rb +2 -1
  40. data/lib/beaker/shared/host_handler.rb +7 -2
  41. data/lib/beaker/shared/repetition.rb +1 -0
  42. data/lib/beaker/shared/timed.rb +14 -0
  43. data/lib/beaker/test_case.rb +2 -38
  44. data/lib/beaker/test_suite.rb +11 -25
  45. data/lib/beaker/utils/repo_control.rb +6 -8
  46. data/lib/beaker/utils/setup_helper.rb +9 -20
  47. data/spec/beaker/answers_spec.rb +109 -0
  48. data/spec/beaker/command_spec.rb +2 -2
  49. data/spec/beaker/dsl/assertions_spec.rb +1 -3
  50. data/spec/beaker/dsl/helpers_spec.rb +519 -84
  51. data/spec/beaker/dsl/install_utils_spec.rb +265 -16
  52. data/spec/beaker/dsl/roles_spec.rb +31 -10
  53. data/spec/beaker/host/windows/group_spec.rb +55 -0
  54. data/spec/beaker/host_spec.rb +130 -40
  55. data/spec/beaker/hypervisor/aixer_spec.rb +34 -0
  56. data/spec/beaker/hypervisor/blimper_spec.rb +77 -0
  57. data/spec/beaker/hypervisor/fusion_spec.rb +26 -0
  58. data/spec/beaker/hypervisor/hypervisor_spec.rb +66 -0
  59. data/spec/beaker/hypervisor/solaris_spec.rb +39 -0
  60. data/spec/beaker/hypervisor/vagrant_spec.rb +105 -0
  61. data/spec/beaker/hypervisor/vcloud_pooled_spec.rb +60 -0
  62. data/spec/beaker/hypervisor/vcloud_spec.rb +70 -0
  63. data/spec/beaker/hypervisor/vsphere_helper_spec.rb +162 -0
  64. data/spec/beaker/hypervisor/vsphere_spec.rb +76 -0
  65. data/spec/beaker/options/command_line_parser_spec.rb +25 -0
  66. data/spec/beaker/options/data/LATEST +1 -0
  67. data/spec/beaker/options/data/badyaml.cfg +21 -0
  68. data/spec/beaker/options/data/hosts.cfg +21 -0
  69. data/spec/beaker/options/data/opts.txt +6 -0
  70. data/spec/beaker/options/hosts_file_parser_spec.rb +30 -0
  71. data/spec/beaker/options/options_file_parser_spec.rb +23 -0
  72. data/spec/beaker/options/options_hash_spec.rb +111 -0
  73. data/spec/beaker/options/parser_spec.rb +172 -0
  74. data/spec/beaker/options/pe_version_scaper_spec.rb +15 -0
  75. data/spec/beaker/options/presets_spec.rb +24 -0
  76. data/spec/beaker/puppet_command_spec.rb +54 -21
  77. data/spec/beaker/shared/error_handler_spec.rb +40 -0
  78. data/spec/beaker/shared/host_handler_spec.rb +104 -0
  79. data/spec/beaker/shared/repetition_spec.rb +72 -0
  80. data/spec/beaker/test_suite_spec.rb +3 -16
  81. data/spec/beaker/utils/ntp_control_spec.rb +42 -0
  82. data/spec/beaker/utils/repo_control_spec.rb +168 -0
  83. data/spec/beaker/utils/setup_helper_spec.rb +82 -0
  84. data/spec/beaker/utils/validator_spec.rb +58 -0
  85. data/spec/helpers.rb +97 -0
  86. data/spec/matchers.rb +39 -0
  87. data/spec/mock_blimpy.rb +48 -0
  88. data/spec/mock_fission.rb +60 -0
  89. data/spec/mock_vsphere.rb +310 -0
  90. data/spec/mock_vsphere_helper.rb +183 -0
  91. data/spec/mocks.rb +83 -0
  92. data/spec/spec_helper.rb +8 -1
  93. metadata +106 -13
  94. data/beaker.rb +0 -10
  95. data/lib/beaker/options_parsing.rb +0 -323
  96. data/lib/beaker/test_config.rb +0 -148
  97. data/spec/beaker/options_parsing_spec.rb +0 -37
  98. data/spec/mocks_and_helpers.rb +0 -34
@@ -1,7 +1,7 @@
1
1
  module Beaker
2
2
  class Fusion < Beaker::Hypervisor
3
3
 
4
- def initialize(fusion_hosts, options, config)
4
+ def initialize(fusion_hosts, options)
5
5
  require 'rubygems' unless defined?(Gem)
6
6
  begin
7
7
  require 'fission'
@@ -10,16 +10,17 @@ module Beaker
10
10
  end
11
11
  @logger = options[:logger]
12
12
  @options = options
13
- @config = config['CONFIG'].dup
14
13
  @fusion_hosts = fusion_hosts
14
+ @fission = Fission::VM
15
+ end
15
16
 
16
-
17
- available = Fission::VM.all.data.collect{|vm| vm.name}.sort.join(", ")
17
+ def provision
18
+ available = @fission.all.data.collect{|vm| vm.name}.sort.join(", ")
18
19
  @logger.notify "Available VM names: #{available}"
19
20
 
20
21
  @fusion_hosts.each do |host|
21
22
  vm_name = host["vmname"] || host.name
22
- vm = Fission::VM.new vm_name
23
+ vm = @fission.new vm_name
23
24
  raise "Could not find VM '#{vm_name}' for #{host.name}!" unless vm.exists?
24
25
 
25
26
  available_snapshots = vm.snapshots.data.sort.join(", ")
@@ -46,11 +47,11 @@ module Beaker
46
47
  time = Time.now - start
47
48
  @logger.notify "Spent %.2f seconds resuming VM" % time
48
49
  end
49
- end #revert_fusion
50
+ end #revert_fusion
50
51
 
51
- def cleanup
52
- @logger.notify "No cleanup for fusion boxes"
53
- end
52
+ def cleanup
53
+ @logger.notify "No cleanup for fusion boxes"
54
+ end
54
55
 
55
- end
56
+ end
56
57
  end
@@ -1,44 +1,38 @@
1
- module Beaker
1
+ module Beaker
2
2
  class Solaris < Beaker::Hypervisor
3
3
 
4
- def initialize(solaris_hosts, options, config)
4
+ def initialize(solaris_hosts, options)
5
5
  @options = options
6
- @config = config['CONFIG'].dup
7
6
  @logger = options[:logger]
8
7
  @solaris_hosts = solaris_hosts
9
- fog_file = nil
10
- if File.exists?( File.join(ENV['HOME'], '.fog') )
11
- fog_file = YAML.load_file( File.join(ENV['HOME'], '.fog') )
8
+ @fog_file = nil
9
+ if File.exists?( @options[:dot_fog] )
10
+ @fog_file = YAML.load_file( @options[:dot_fog] )
12
11
  end
13
- raise "Cant load ~/.fog config" unless fog_file
12
+ raise "Cant load #{@options[:dot_fog]} config" unless @fog_file
14
13
 
15
- hypername = fog_file[:default][:solaris_hypervisor_server]
16
- vmpath = fog_file[:default][:solaris_hypervisor_vmpath]
17
- snappaths = fog_file[:default][:solaris_hypervisor_snappaths]
14
+ end
15
+
16
+ def provision
17
+ hypername = @fog_file[:default][:solaris_hypervisor_server]
18
+ vmpath = @fog_file[:default][:solaris_hypervisor_vmpath]
19
+ snappaths = @fog_file[:default][:solaris_hypervisor_snappaths]
18
20
 
19
- hyperconf = {
20
- 'HOSTS' => {
21
+ hyperopts = @options.dup
22
+ hyperopts['HOSTS'] = {
21
23
  hypername => { 'platform' => 'solaris-11-sparc' }
22
- },
23
- 'CONFIG' => {
24
- 'user' => fog_file[:default][:solaris_hypervisor_username] || ENV['USER'],
25
- 'ssh' => {
26
- :keys => fog_file[:default][:solaris_hypervisor_keyfile] || "#{ENV['HOME']}/.ssh/id_rsa"
27
- }
28
- }
29
24
  }
30
25
 
31
- hyperconfig = Beaker::TestConfig.new( hyperconf, @options )
32
-
33
26
  @logger.notify "Connecting to hypervisor at #{hypername}"
34
- hypervisor = Beaker::Host.create( hypername, @options, hyperconfig )
27
+ hypervisor = Beaker::Host.create( hypername, hyperopts )
28
+ hypervisor[:user] = @fog_file[:default][:solaris_hypervisor_username] || hypervisor[:user]
29
+ hypervisor[:ssh][:keys] = [@fog_file[:default][:solaris_hypervisor_keyfile]] || hypervisor[:ssh][:keys]
35
30
 
36
31
  @solaris_hosts.each do |host|
37
32
  vm_name = host['vmname'] || host.name
38
33
  #use the snapshot provided for this host
39
34
  snapshot = host['snapshot']
40
35
 
41
-
42
36
  @logger.notify "Reverting #{vm_name} to snapshot #{snapshot}"
43
37
  start = Time.now
44
38
  hypervisor.exec(Command.new("sudo /sbin/zfs rollback -Rf #{vmpath}/#{vm_name}@#{snapshot}"))
@@ -1,3 +1,5 @@
1
+ require 'open3'
2
+
1
3
  module Beaker
2
4
  class Vagrant < Beaker::Hypervisor
3
5
 
@@ -9,11 +11,11 @@ module Beaker
9
11
  end
10
12
 
11
13
  def rand_chunk
12
- (1 + rand(253)).to_s #don't want a 0 or a 255
14
+ (2 + rand(252)).to_s #don't want a 0, 1, or a 255
13
15
  end
14
16
 
15
17
  def randip
16
- "192.168.#{rand_chunk}.#{rand_chunk}"
18
+ "10.255.#{rand_chunk}.#{rand_chunk}"
17
19
  end
18
20
 
19
21
  def make_vfile hosts
@@ -27,7 +29,7 @@ module Beaker
27
29
  vagrant_file << " v.vm.box = '#{host['box']}'\n"
28
30
  vagrant_file << " v.vm.box_url = '#{host['box_url']}'\n" unless host['box_url'].nil?
29
31
  vagrant_file << " v.vm.base_mac = '#{randmac}'\n"
30
- vagrant_file << " v.vm.network :private_network, ip: \"#{host['ip'].to_s}\"\n"
32
+ vagrant_file << " v.vm.network :private_network, ip: \"#{host['ip'].to_s}\", :netmask => \"255.255.0.0\"\n"
31
33
  vagrant_file << " end\n"
32
34
  @logger.debug "created Vagrantfile for VagrantHost #{host.name}"
33
35
  end
@@ -35,9 +37,10 @@ module Beaker
35
37
  vagrant_file << " vb.customize [\"modifyvm\", :id, \"--memory\", \"1024\"]\n"
36
38
  vagrant_file << " end\n"
37
39
  vagrant_file << "end\n"
38
- f = File.open("Vagrantfile", 'w')
39
- f.write(vagrant_file)
40
- f.close()
40
+ FileUtils.mkdir_p(@vagrant_path)
41
+ File.open(File.expand_path(File.join(@vagrant_path, "Vagrantfile")), 'w') do |f|
42
+ f.write(vagrant_file)
43
+ end
41
44
  end
42
45
 
43
46
  def hack_etc_hosts hosts
@@ -62,7 +65,10 @@ module Beaker
62
65
 
63
66
  def set_ssh_config host, user
64
67
  f = Tempfile.new("#{host.name}")
65
- ssh_config = `vagrant ssh-config #{host.name}`
68
+ ssh_config = Dir.chdir(@vagrant_path) do
69
+ stdin, stdout = Open3.popen3('vagrant', 'ssh-config', host.name)
70
+ stdout.read
71
+ end
66
72
  #replace hostname with ip
67
73
  ssh_config = ssh_config.gsub(/#{host.name}/, host['ip'])
68
74
  #set the user
@@ -74,19 +80,22 @@ module Beaker
74
80
  @temp_files << f
75
81
  end
76
82
 
77
- def initialize(vagrant_hosts, options, config)
83
+ def initialize(vagrant_hosts, options)
78
84
  require 'tempfile'
79
85
  @options = options
80
- @config = config['CONFIG'].dup
81
86
  @logger = options[:logger]
82
87
  @temp_files = []
83
88
  @vagrant_hosts = vagrant_hosts
89
+ @vagrant_path = File.expand_path(File.join(File.basename(__FILE__), '..', 'vagrant_files', options[:hosts_file]))
90
+
91
+ end
84
92
 
93
+ def provision
85
94
  make_vfile @vagrant_hosts
86
95
 
87
96
  #stop anything currently running, that way vagrant up will re-do networking on existing boxes
88
- system("vagrant halt")
89
- system("vagrant up")
97
+ vagrant_cmd("halt")
98
+ vagrant_cmd("up")
90
99
 
91
100
  @logger.debug "configure vagrant boxes (set ssh-config, switch to root user, hack etc/hosts)"
92
101
  @vagrant_hosts.each do |host|
@@ -111,7 +120,13 @@ module Beaker
111
120
  f.close()
112
121
  end
113
122
  @logger.notify "Destroying vagrant boxes"
114
- system("vagrant destroy --force")
123
+ vagrant_cmd("destroy --force")
124
+ end
125
+
126
+ def vagrant_cmd(args)
127
+ Dir.chdir(@vagrant_path) do
128
+ system("vagrant #{args}")
129
+ end
115
130
  end
116
131
 
117
132
  end
@@ -1,174 +1,190 @@
1
+ require 'yaml' unless defined?(YAML)
2
+
1
3
  module Beaker
2
4
  class Vcloud < Beaker::Hypervisor
5
+ CHARMAP = [('a'..'z'),('0'..'9')].map{|r| r.to_a}.flatten
3
6
 
4
- def initialize(vcloud_hosts, options, config)
7
+ def initialize(vcloud_hosts, options)
5
8
  @options = options
6
- @config = config['CONFIG'].dup
7
9
  @logger = options[:logger]
8
10
  @vcloud_hosts = vcloud_hosts
9
- require 'yaml' unless defined?(YAML)
10
-
11
- raise 'You must specify a datastore for vCloud instances!' unless @config['datastore']
12
- raise 'You must specify a resource pool for vCloud instances!' unless @config['resourcepool']
13
- raise 'You must specify a folder for vCloud instances!' unless @config['folder']
14
-
15
- vsphere_credentials = VsphereHelper.load_config
16
-
17
- @logger.notify "Connecting to vSphere at #{vsphere_credentials[:server]}" +
18
- " with credentials for #{vsphere_credentials[:user]}"
19
-
20
- vsphere_helper = VsphereHelper.new( vsphere_credentials )
21
- vsphere_vms = {}
22
-
23
- attempts = 10
24
11
 
25
- start = Time.now
26
- @vcloud_hosts.each_with_index do |h, i|
27
- # Generate a randomized hostname
28
- o = [('a'..'z'),('0'..'9')].map{|r| r.to_a}.flatten
29
- h['vmhostname'] = o[rand(25)] + (0...14).map{o[rand(o.length)]}.join
12
+ raise 'You must specify a datastore for vCloud instances!' unless @options['datastore']
13
+ raise 'You must specify a resource pool for vCloud instances!' unless @options['resourcepool']
14
+ raise 'You must specify a folder for vCloud instances!' unless @options['folder']
15
+ @vsphere_credentials = VsphereHelper.load_config(@options[:dot_fog])
16
+ end
30
17
 
31
- if h['template'] =~ /\//
32
- templatefolders = h['template'].split('/')
33
- h['template'] = templatefolders.pop
34
- end
18
+ def connect_to_vsphere
19
+ @logger.notify "Connecting to vSphere at #{@vsphere_credentials[:server]}" +
20
+ " with credentials for #{@vsphere_credentials[:user]}"
35
21
 
36
- @logger.notify "Deploying #{h['vmhostname']} (#{h.name}) to #{@config['folder']} from template '#{h['template']}'"
22
+ @vsphere_helper = VsphereHelper.new( @vsphere_credentials )
23
+ end
37
24
 
38
- vm = {}
25
+ def wait_for_dns_resolution host, try, attempts
26
+ @logger.notify "Waiting for #{host['vmhostname']} DNS resolution"
27
+ begin
28
+ Socket.getaddrinfo(host['vmhostname'], nil)
29
+ rescue
30
+ if try <= attempts
31
+ sleep 5
32
+ try += 1
39
33
 
40
- if templatefolders
41
- vm[h['template']] = vsphere_helper.find_folder(templatefolders.join('/')).find(h['template'])
34
+ retry
42
35
  else
43
- vm = vsphere_helper.find_vms(h['template'])
36
+ raise "DNS resolution failed after #{@options[:timeout].to_i} seconds"
44
37
  end
38
+ end
39
+ end
45
40
 
46
- if vm.length == 0
47
- raise "Unable to find template '#{h['template']}'!"
41
+ def booting_host host, try, attempts
42
+ @logger.notify "Booting #{host['vmhostname']} (#{host.name}) and waiting for it to register with vSphere"
43
+ until
44
+ @vsphere_helper.find_vms(host['vmhostname'])[host['vmhostname']].summary.guest.toolsRunningStatus == 'guestToolsRunning' and
45
+ @vsphere_helper.find_vms(host['vmhostname'])[host['vmhostname']].summary.guest.ipAddress != nil
46
+ if try <= attempts
47
+ sleep 5
48
+ try += 1
49
+ else
50
+ raise "vSphere registration failed after #{@options[:timeout].to_i} seconds"
48
51
  end
52
+ end
53
+ end
49
54
 
50
- # Add VM annotation
51
- configSpec = RbVmomi::VIM.VirtualMachineConfigSpec(
52
- :annotation =>
53
- 'Base template: ' + h['template'] + "\n" +
54
- 'Creation time: ' + Time.now.strftime("%Y-%m-%d %H:%M") + "\n\n" +
55
- 'CI build link: ' + ( ENV['BUILD_URL'] || 'Deployed independently of CI' )
56
- )
57
-
58
- # Are we using a customization spec?
59
- customizationSpec = vsphere_helper.find_customization( h['template'] )
60
-
61
- if customizationSpec
62
- # Print a logger message if using a customization spec
63
- @logger.notify "Found customization spec for '#{h['template']}', will apply after boot"
64
-
65
- # Using a customization spec takes longer, set a longer timeout
66
- attempts = attempts * 2
67
- end
55
+ def generate_host_name
56
+ CHARMAP[rand(25)] + (0...14).map{CHARMAP[rand(CHARMAP.length)]}.join
57
+ end
68
58
 
69
- # Put the VM in the specified folder and resource pool
70
- relocateSpec = RbVmomi::VIM.VirtualMachineRelocateSpec(
71
- :datastore => vsphere_helper.find_datastore(@config['datastore']),
72
- :pool => vsphere_helper.find_pool(@config['resourcepool']),
73
- :diskMoveType => :moveChildMostDiskBacking
74
- )
75
-
76
- # Create a clone spec
77
- spec = RbVmomi::VIM.VirtualMachineCloneSpec(
78
- :config => configSpec,
79
- :location => relocateSpec,
80
- :customization => customizationSpec,
81
- :powerOn => true,
82
- :template => false
83
- )
84
-
85
- # Deploy from specified template
86
- if (@vcloud_hosts.length == 1) or (i == @vcloud_hosts.length - 1)
87
- vm[h['template']].CloneVM_Task( :folder => vsphere_helper.find_folder(@config['folder']), :name => h['vmhostname'], :spec => spec ).wait_for_completion
88
- else
89
- vm[h['template']].CloneVM_Task( :folder => vsphere_helper.find_folder(@config['folder']), :name => h['vmhostname'], :spec => spec )
90
- end
59
+ def create_clone_spec host
60
+ # Add VM annotation
61
+ configSpec = RbVmomi::VIM.VirtualMachineConfigSpec(
62
+ :annotation =>
63
+ 'Base template: ' + host['template'] + "\n" +
64
+ 'Creation time: ' + Time.now.strftime("%Y-%m-%d %H:%M") + "\n\n" +
65
+ 'CI build link: ' + ( ENV['BUILD_URL'] || 'Deployed independently of CI' )
66
+ )
67
+
68
+ # Are we using a customization spec?
69
+ customizationSpec = @vsphere_helper.find_customization( host['template'] )
70
+
71
+ if customizationSpec
72
+ # Print a logger message if using a customization spec
73
+ @logger.notify "Found customization spec for '#{host['template']}', will apply after boot"
91
74
  end
92
- @logger.notify 'Spent %.2f seconds deploying VMs' % (Time.now - start)
93
75
 
94
- start = Time.now
95
- @vcloud_hosts.each_with_index do |h, i|
96
- @logger.notify "Booting #{h['vmhostname']} (#{h.name}) and waiting for it to register with vSphere"
76
+ # Put the VM in the specified folder and resource pool
77
+ relocateSpec = RbVmomi::VIM.VirtualMachineRelocateSpec(
78
+ :datastore => @vsphere_helper.find_datastore(@options['datastore']),
79
+ :pool => @vsphere_helper.find_pool(@options['resourcepool']),
80
+ :diskMoveType => :moveChildMostDiskBacking
81
+ )
82
+
83
+ # Create a clone spec
84
+ spec = RbVmomi::VIM.VirtualMachineCloneSpec(
85
+ :config => configSpec,
86
+ :location => relocateSpec,
87
+ :customization => customizationSpec,
88
+ :powerOn => true,
89
+ :template => false
90
+ )
91
+ spec
92
+ end
93
+
94
+ def provision
95
+ connect_to_vsphere
96
+ begin
97
+ vsphere_vms = {}
98
+
97
99
  try = 1
98
- last_wait = 0
99
- wait = 1
100
- until
101
- vsphere_helper.find_vms(h['vmhostname'])[h['vmhostname']].summary.guest.toolsRunningStatus == 'guestToolsRunning' and
102
- vsphere_helper.find_vms(h['vmhostname'])[h['vmhostname']].summary.guest.ipAddress != nil
103
- if try <= attempts
104
- sleep wait
105
- (last_wait, wait) = wait, last_wait + wait
106
- try += 1
100
+ attempts = @options[:timeout].to_i / 5
101
+
102
+ start = Time.now
103
+ tasks = []
104
+ @vcloud_hosts.each_with_index do |h, i|
105
+ # Generate a randomized hostname
106
+ h['vmhostname'] = generate_host_name
107
+
108
+ if h['template'] =~ /\//
109
+ templatefolders = h['template'].split('/')
110
+ h['template'] = templatefolders.pop
111
+ end
112
+
113
+ @logger.notify "Deploying #{h['vmhostname']} (#{h.name}) to #{@options['folder']} from template '#{h['template']}'"
114
+
115
+ vm = {}
116
+
117
+ if templatefolders
118
+ vm[h['template']] = @vsphere_helper.find_folder(templatefolders.join('/')).find(h['template'])
107
119
  else
108
- raise "vSphere registration failed after #{wait} seconds"
120
+ vm = @vsphere_helper.find_vms(h['template'])
109
121
  end
122
+
123
+ if vm.length == 0
124
+ raise "Unable to find template '#{h['template']}'!"
125
+ end
126
+
127
+ spec = create_clone_spec(h)
128
+
129
+ # Deploy from specified template
130
+ tasks << vm[h['template']].CloneVM_Task( :folder => @vsphere_helper.find_folder(@options['folder']), :name => h['vmhostname'], :spec => spec )
110
131
  end
111
- end
112
- @logger.notify "Spent %.2f seconds booting and waiting for vSphere registration" % (Time.now - start)
113
-
114
- start = Time.now
115
- @vcloud_hosts.each_with_index do |h, i|
116
- @logger.notify "Waiting for #{h['vmhostname']} DNS resolution"
117
- try = 1
118
- last_wait = 0
119
- wait = 3
120
-
121
- begin
122
- Socket.getaddrinfo(h['vmhostname'], nil)
123
- rescue
124
- if try <= attempts
125
- sleep wait
126
- (last_wait, wait) = wait, last_wait + wait
127
- try += 1
128
-
129
- retry
130
- else
131
- raise "DNS resolution failed after #{wait} seconds"
132
+ try = (Time.now - start) / 5
133
+ @vsphere_helper.wait_for_tasks(tasks, try, attempts)
134
+ @logger.notify 'Spent %.2f seconds deploying VMs' % (Time.now - start)
135
+
136
+ try = (Time.now - start) / 5
137
+ duration = run_and_report_duration do
138
+ @vcloud_hosts.each_with_index do |h, i|
139
+ booting_host(h, try, attempts)
132
140
  end
133
141
  end
142
+ @logger.notify "Spent %.2f seconds booting and waiting for vSphere registration" % duration
143
+
144
+ try = (Time.now - start) / 5
145
+ duration = run_and_report_duration do
146
+ @vcloud_hosts.each_with_index do |h, i|
147
+ wait_for_dns_resolution(h, try, attempts)
148
+ end
149
+ end
150
+ @logger.notify "Spent %.2f seconds waiting for DNS resolution" % duration
151
+ rescue => e
152
+ @vsphere_helper.close
153
+ report_and_raise(@logger, e, "Vcloud.provision")
134
154
  end
135
- @logger.notify "Spent %.2f seconds waiting for DNS resolution" % (Time.now - start)
136
-
137
- vsphere_helper.close
138
155
  end
139
156
 
140
157
  def cleanup
141
158
  @logger.notify "Destroying vCloud boxes"
142
- vsphere_credentials = VsphereHelper.load_config
143
-
144
- @logger.notify "Connecting to vSphere at #{vsphere_credentials[:server]}" +
145
- " with credentials for #{vsphere_credentials[:user]}"
146
-
147
- vsphere_helper = VsphereHelper.new( vsphere_credentials )
148
-
149
- vm_names = @vcloud_hosts.map {|h| h['vmhostname'] }.compact
150
- if @vcloud_hosts.length != vm_names.length
151
- @logger.warn "Some hosts did not have vmhostname set correctly! This likely means VM provisioning was not successful"
152
- end
153
- vms = vsphere_helper.find_vms vm_names
154
- vm_names.each do |name|
155
- unless vm = vms[name]
156
- raise "Couldn't find VM #{name} in vSphere!"
159
+ connect_to_vsphere
160
+ begin
161
+ vm_names = @vcloud_hosts.map {|h| h['vmhostname'] }.compact
162
+ if @vcloud_hosts.length != vm_names.length
163
+ @logger.warn "Some hosts did not have vmhostname set correctly! This likely means VM provisioning was not successful"
157
164
  end
158
-
159
- if vm.runtime.powerState == 'poweredOn'
160
- @logger.notify "Shutting down #{vm.name}"
161
- start = Time.now
162
- vm.PowerOffVM_Task.wait_for_completion
163
- @logger.notify "Spent %.2f seconds halting #{vm.name}" % (Time.now - start)
165
+ vms = @vsphere_helper.find_vms vm_names
166
+ vm_names.each do |name|
167
+ unless vm = vms[name]
168
+ raise "Couldn't find VM #{name} in vSphere!"
169
+ end
170
+
171
+ if vm.runtime.powerState == 'poweredOn'
172
+ @logger.notify "Shutting down #{vm.name}"
173
+ duration = run_and_report_duration do
174
+ vm.PowerOffVM_Task.wait_for_completion
175
+ end
176
+ @logger.notify "Spent %.2f seconds halting #{vm.name}" % duration
177
+ end
178
+
179
+ duration = run_and_report_duration do
180
+ vm.Destroy_Task
181
+ end
182
+ @logger.notify "Spent %.2f seconds destroying #{vm.name}" % duration
164
183
  end
165
-
166
- start = Time.now
167
- vm.Destroy_Task
168
- @logger.notify "Spent %.2f seconds destroying #{vm.name}" % (Time.now - start)
184
+ rescue => e
185
+ @vsphere_helper.close
186
+ report_and_raise(@logger, e, "Vcloud.cleanup")
169
187
  end
170
-
171
- vsphere_helper.close
172
188
  end
173
189
 
174
190
  end