beaker 0.0.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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