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.
- checksums.yaml +8 -8
- data/.travis.yml +8 -0
- data/README.md +6 -6
- data/beaker.gemspec +6 -2
- data/lib/beaker.rb +1 -1
- data/lib/beaker/answers.rb +34 -7
- data/lib/beaker/answers/version20.rb +124 -0
- data/lib/beaker/answers/version28.rb +21 -0
- data/lib/beaker/answers/version30.rb +24 -5
- data/lib/beaker/cli.rb +55 -41
- data/lib/beaker/command.rb +2 -2
- data/lib/beaker/dsl/helpers.rb +320 -106
- data/lib/beaker/dsl/install_utils.rb +202 -81
- data/lib/beaker/dsl/roles.rb +40 -0
- data/lib/beaker/host.rb +28 -20
- data/lib/beaker/host/unix.rb +7 -4
- data/lib/beaker/host/unix/pkg.rb +42 -12
- data/lib/beaker/host/windows.rb +9 -5
- data/lib/beaker/host/windows/group.rb +1 -1
- data/lib/beaker/host/windows/pkg.rb +41 -8
- data/lib/beaker/hypervisor.rb +23 -10
- data/lib/beaker/hypervisor/aixer.rb +15 -19
- data/lib/beaker/hypervisor/blimper.rb +71 -72
- data/lib/beaker/hypervisor/fusion.rb +11 -10
- data/lib/beaker/hypervisor/solaris.rb +17 -23
- data/lib/beaker/hypervisor/vagrant.rb +27 -12
- data/lib/beaker/hypervisor/vcloud.rb +154 -138
- data/lib/beaker/hypervisor/vcloud_pooled.rb +97 -0
- data/lib/beaker/hypervisor/vsphere.rb +8 -5
- data/lib/beaker/hypervisor/vsphere_helper.rb +43 -33
- data/lib/beaker/network_manager.rb +16 -12
- data/lib/beaker/options/command_line_parser.rb +199 -0
- data/lib/beaker/options/hosts_file_parser.rb +39 -0
- data/lib/beaker/options/options_file_parser.rb +45 -0
- data/lib/beaker/options/options_hash.rb +294 -0
- data/lib/beaker/options/parser.rb +288 -0
- data/lib/beaker/options/pe_version_scraper.rb +35 -0
- data/lib/beaker/options/presets.rb +70 -0
- data/lib/beaker/shared.rb +2 -1
- data/lib/beaker/shared/host_handler.rb +7 -2
- data/lib/beaker/shared/repetition.rb +1 -0
- data/lib/beaker/shared/timed.rb +14 -0
- data/lib/beaker/test_case.rb +2 -38
- data/lib/beaker/test_suite.rb +11 -25
- data/lib/beaker/utils/repo_control.rb +6 -8
- data/lib/beaker/utils/setup_helper.rb +9 -20
- data/spec/beaker/answers_spec.rb +109 -0
- data/spec/beaker/command_spec.rb +2 -2
- data/spec/beaker/dsl/assertions_spec.rb +1 -3
- data/spec/beaker/dsl/helpers_spec.rb +519 -84
- data/spec/beaker/dsl/install_utils_spec.rb +265 -16
- data/spec/beaker/dsl/roles_spec.rb +31 -10
- data/spec/beaker/host/windows/group_spec.rb +55 -0
- data/spec/beaker/host_spec.rb +130 -40
- data/spec/beaker/hypervisor/aixer_spec.rb +34 -0
- data/spec/beaker/hypervisor/blimper_spec.rb +77 -0
- data/spec/beaker/hypervisor/fusion_spec.rb +26 -0
- data/spec/beaker/hypervisor/hypervisor_spec.rb +66 -0
- data/spec/beaker/hypervisor/solaris_spec.rb +39 -0
- data/spec/beaker/hypervisor/vagrant_spec.rb +105 -0
- data/spec/beaker/hypervisor/vcloud_pooled_spec.rb +60 -0
- data/spec/beaker/hypervisor/vcloud_spec.rb +70 -0
- data/spec/beaker/hypervisor/vsphere_helper_spec.rb +162 -0
- data/spec/beaker/hypervisor/vsphere_spec.rb +76 -0
- data/spec/beaker/options/command_line_parser_spec.rb +25 -0
- data/spec/beaker/options/data/LATEST +1 -0
- data/spec/beaker/options/data/badyaml.cfg +21 -0
- data/spec/beaker/options/data/hosts.cfg +21 -0
- data/spec/beaker/options/data/opts.txt +6 -0
- data/spec/beaker/options/hosts_file_parser_spec.rb +30 -0
- data/spec/beaker/options/options_file_parser_spec.rb +23 -0
- data/spec/beaker/options/options_hash_spec.rb +111 -0
- data/spec/beaker/options/parser_spec.rb +172 -0
- data/spec/beaker/options/pe_version_scaper_spec.rb +15 -0
- data/spec/beaker/options/presets_spec.rb +24 -0
- data/spec/beaker/puppet_command_spec.rb +54 -21
- data/spec/beaker/shared/error_handler_spec.rb +40 -0
- data/spec/beaker/shared/host_handler_spec.rb +104 -0
- data/spec/beaker/shared/repetition_spec.rb +72 -0
- data/spec/beaker/test_suite_spec.rb +3 -16
- data/spec/beaker/utils/ntp_control_spec.rb +42 -0
- data/spec/beaker/utils/repo_control_spec.rb +168 -0
- data/spec/beaker/utils/setup_helper_spec.rb +82 -0
- data/spec/beaker/utils/validator_spec.rb +58 -0
- data/spec/helpers.rb +97 -0
- data/spec/matchers.rb +39 -0
- data/spec/mock_blimpy.rb +48 -0
- data/spec/mock_fission.rb +60 -0
- data/spec/mock_vsphere.rb +310 -0
- data/spec/mock_vsphere_helper.rb +183 -0
- data/spec/mocks.rb +83 -0
- data/spec/spec_helper.rb +8 -1
- metadata +106 -13
- data/beaker.rb +0 -10
- data/lib/beaker/options_parsing.rb +0 -323
- data/lib/beaker/test_config.rb +0 -148
- data/spec/beaker/options_parsing_spec.rb +0 -37
- 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
|
-
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
50
|
+
end #revert_fusion
|
|
50
51
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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
|
|
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?(
|
|
11
|
-
fog_file = YAML.load_file(
|
|
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
|
|
12
|
+
raise "Cant load #{@options[:dot_fog]} config" unless @fog_file
|
|
14
13
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
|
|
20
|
-
|
|
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,
|
|
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
|
-
(
|
|
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
|
-
"
|
|
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
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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 =
|
|
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
|
|
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
|
-
|
|
89
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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
|
-
|
|
22
|
+
@vsphere_helper = VsphereHelper.new( @vsphere_credentials )
|
|
23
|
+
end
|
|
37
24
|
|
|
38
|
-
|
|
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
|
-
|
|
41
|
-
vm[h['template']] = vsphere_helper.find_folder(templatefolders.join('/')).find(h['template'])
|
|
34
|
+
retry
|
|
42
35
|
else
|
|
43
|
-
|
|
36
|
+
raise "DNS resolution failed after #{@options[:timeout].to_i} seconds"
|
|
44
37
|
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
45
40
|
|
|
46
|
-
|
|
47
|
-
|
|
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
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
:
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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
|
-
|
|
95
|
-
|
|
96
|
-
@
|
|
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
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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
|
-
|
|
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
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
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
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
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
|
-
|
|
167
|
-
|
|
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
|