beaker 0.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 +15 -0
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/.simplecov +14 -0
- data/DOCUMENTING.md +167 -0
- data/Gemfile +3 -0
- data/LICENSE +17 -0
- data/README.md +332 -0
- data/Rakefile +121 -0
- data/beaker.gemspec +42 -0
- data/beaker.rb +10 -0
- data/bin/beaker +9 -0
- data/lib/beaker.rb +36 -0
- data/lib/beaker/answers.rb +29 -0
- data/lib/beaker/answers/version28.rb +104 -0
- data/lib/beaker/answers/version30.rb +194 -0
- data/lib/beaker/cli.rb +113 -0
- data/lib/beaker/command.rb +241 -0
- data/lib/beaker/command_factory.rb +21 -0
- data/lib/beaker/dsl.rb +85 -0
- data/lib/beaker/dsl/assertions.rb +87 -0
- data/lib/beaker/dsl/helpers.rb +625 -0
- data/lib/beaker/dsl/install_utils.rb +299 -0
- data/lib/beaker/dsl/outcomes.rb +99 -0
- data/lib/beaker/dsl/roles.rb +97 -0
- data/lib/beaker/dsl/structure.rb +63 -0
- data/lib/beaker/dsl/wrappers.rb +100 -0
- data/lib/beaker/host.rb +193 -0
- data/lib/beaker/host/aix.rb +15 -0
- data/lib/beaker/host/aix/file.rb +16 -0
- data/lib/beaker/host/aix/group.rb +35 -0
- data/lib/beaker/host/aix/user.rb +32 -0
- data/lib/beaker/host/unix.rb +54 -0
- data/lib/beaker/host/unix/exec.rb +15 -0
- data/lib/beaker/host/unix/file.rb +16 -0
- data/lib/beaker/host/unix/group.rb +40 -0
- data/lib/beaker/host/unix/pkg.rb +22 -0
- data/lib/beaker/host/unix/user.rb +32 -0
- data/lib/beaker/host/windows.rb +44 -0
- data/lib/beaker/host/windows/exec.rb +18 -0
- data/lib/beaker/host/windows/file.rb +15 -0
- data/lib/beaker/host/windows/group.rb +36 -0
- data/lib/beaker/host/windows/pkg.rb +26 -0
- data/lib/beaker/host/windows/user.rb +32 -0
- data/lib/beaker/hypervisor.rb +37 -0
- data/lib/beaker/hypervisor/aixer.rb +52 -0
- data/lib/beaker/hypervisor/blimper.rb +123 -0
- data/lib/beaker/hypervisor/fusion.rb +56 -0
- data/lib/beaker/hypervisor/solaris.rb +65 -0
- data/lib/beaker/hypervisor/vagrant.rb +118 -0
- data/lib/beaker/hypervisor/vcloud.rb +175 -0
- data/lib/beaker/hypervisor/vsphere.rb +80 -0
- data/lib/beaker/hypervisor/vsphere_helper.rb +200 -0
- data/lib/beaker/logger.rb +167 -0
- data/lib/beaker/network_manager.rb +73 -0
- data/lib/beaker/options_parsing.rb +323 -0
- data/lib/beaker/result.rb +55 -0
- data/lib/beaker/shared.rb +15 -0
- data/lib/beaker/shared/error_handler.rb +17 -0
- data/lib/beaker/shared/host_handler.rb +46 -0
- data/lib/beaker/shared/repetition.rb +28 -0
- data/lib/beaker/ssh_connection.rb +198 -0
- data/lib/beaker/test_case.rb +225 -0
- data/lib/beaker/test_config.rb +148 -0
- data/lib/beaker/test_suite.rb +288 -0
- data/lib/beaker/utils.rb +7 -0
- data/lib/beaker/utils/ntp_control.rb +42 -0
- data/lib/beaker/utils/repo_control.rb +92 -0
- data/lib/beaker/utils/setup_helper.rb +77 -0
- data/lib/beaker/utils/validator.rb +27 -0
- data/spec/beaker/command_spec.rb +94 -0
- data/spec/beaker/dsl/assertions_spec.rb +104 -0
- data/spec/beaker/dsl/helpers_spec.rb +230 -0
- data/spec/beaker/dsl/install_utils_spec.rb +70 -0
- data/spec/beaker/dsl/outcomes_spec.rb +43 -0
- data/spec/beaker/dsl/roles_spec.rb +86 -0
- data/spec/beaker/dsl/structure_spec.rb +60 -0
- data/spec/beaker/dsl/wrappers_spec.rb +52 -0
- data/spec/beaker/host_spec.rb +95 -0
- data/spec/beaker/logger_spec.rb +117 -0
- data/spec/beaker/options_parsing_spec.rb +37 -0
- data/spec/beaker/puppet_command_spec.rb +128 -0
- data/spec/beaker/ssh_connection_spec.rb +39 -0
- data/spec/beaker/test_case_spec.rb +6 -0
- data/spec/beaker/test_suite_spec.rb +44 -0
- data/spec/mocks_and_helpers.rb +34 -0
- data/spec/spec_helper.rb +15 -0
- metadata +359 -0
@@ -0,0 +1,80 @@
|
|
1
|
+
module Beaker
|
2
|
+
class Vsphere < Beaker::Hypervisor
|
3
|
+
|
4
|
+
def initialize(vsphere_hosts, options, config)
|
5
|
+
@options = options
|
6
|
+
@@config = config['CONFIG'].dup
|
7
|
+
@logger = options[:logger]
|
8
|
+
@vsphere_hosts = vsphere_hosts
|
9
|
+
require 'yaml' unless defined?(YAML)
|
10
|
+
vsphere_credentials = VsphereHelper.load_config
|
11
|
+
|
12
|
+
@logger.notify "Connecting to vSphere at #{vsphere_credentials[:server]}" +
|
13
|
+
" with credentials for #{vsphere_credentials[:user]}"
|
14
|
+
|
15
|
+
vsphere_helper = VsphereHelper.new( vsphere_credentials )
|
16
|
+
|
17
|
+
vsphere_vms = {}
|
18
|
+
@vsphere_hosts.each do |h|
|
19
|
+
name = h["vmname"] || h.name
|
20
|
+
vsphere_vms[name] = h["snapshot"]
|
21
|
+
end
|
22
|
+
vms = vsphere_helper.find_vms(vsphere_vms.keys)
|
23
|
+
vsphere_vms.each_pair do |name, snap|
|
24
|
+
unless vm = vms[name]
|
25
|
+
raise "Couldn't find VM #{name} in vSphere!"
|
26
|
+
end
|
27
|
+
|
28
|
+
snapshot = vsphere_helper.find_snapshot(vm, snap) or
|
29
|
+
raise "Could not find snapshot '#{snap}' for VM #{vm.name}!"
|
30
|
+
|
31
|
+
@logger.notify "Reverting #{vm.name} to snapshot '#{snap}'"
|
32
|
+
start = Time.now
|
33
|
+
# This will block for each snapshot...
|
34
|
+
# The code to issue them all and then wait until they are all done sucks
|
35
|
+
snapshot.RevertToSnapshot_Task.wait_for_completion
|
36
|
+
|
37
|
+
time = Time.now - start
|
38
|
+
@logger.notify "Spent %.2f seconds reverting" % time
|
39
|
+
|
40
|
+
unless vm.runtime.powerState == "poweredOn"
|
41
|
+
@logger.notify "Booting #{vm.name}"
|
42
|
+
start = Time.now
|
43
|
+
vm.PowerOnVM_Task.wait_for_completion
|
44
|
+
@logger.notify "Spent %.2f seconds booting #{vm.name}" % (Time.now - start)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
vsphere_helper.close
|
49
|
+
end
|
50
|
+
|
51
|
+
def cleanup
|
52
|
+
@logger.notify "Destroying vsphere boxes"
|
53
|
+
vsphere_credentials = VsphereHelper.load_config
|
54
|
+
|
55
|
+
@logger.notify "Connecting to vSphere at #{vsphere_credentials[:server]}" +
|
56
|
+
" with credentials for #{vsphere_credentials[:user]}"
|
57
|
+
|
58
|
+
vsphere_helper = VsphereHelper.new( vsphere_credentials )
|
59
|
+
|
60
|
+
vm_names = @vsphere_hosts.map {|h| h['vmname'] || h.name }
|
61
|
+
vms = vsphere_helper.find_vms vm_names
|
62
|
+
vm_names.each do |name|
|
63
|
+
unless vm = vms[name]
|
64
|
+
raise "Couldn't find VM #{name} in vSphere!"
|
65
|
+
end
|
66
|
+
|
67
|
+
if vm.runtime.powerState == "poweredOn"
|
68
|
+
@logger.notify "Shutting down #{vm.name}"
|
69
|
+
start = Time.now
|
70
|
+
vm.PowerOffVM_Task.wait_for_completion
|
71
|
+
@logger.notify(
|
72
|
+
"Spent %.2f seconds halting #{vm.name}" % (Time.now - start) )
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
vsphere_helper.close
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,200 @@
|
|
1
|
+
require 'yaml' unless defined?(YAML)
|
2
|
+
require 'rubygems' unless defined?(Gem)
|
3
|
+
begin
|
4
|
+
require 'beaker/logger'
|
5
|
+
rescue LoadError
|
6
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'logger.rb'))
|
7
|
+
end
|
8
|
+
|
9
|
+
class VsphereHelper
|
10
|
+
def initialize vInfo = {}
|
11
|
+
@logger = vInfo[:logger] || Beaker::Logger.new
|
12
|
+
begin
|
13
|
+
require 'rbvmomi'
|
14
|
+
rescue LoadError
|
15
|
+
raise "Unable to load RbVmomi, please ensure its installed"
|
16
|
+
end
|
17
|
+
@connection = RbVmomi::VIM.connect :host => vInfo[:server],
|
18
|
+
:user => vInfo[:user],
|
19
|
+
:password => vInfo[:pass],
|
20
|
+
:insecure => true
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.load_config
|
24
|
+
# support Fog/Cloud Provisioner layout
|
25
|
+
# (ie, someplace besides my made up conf)
|
26
|
+
vsphere_credentials = nil
|
27
|
+
if File.exists? '/etc/plharness/vsphere'
|
28
|
+
vsphere_credentials = load_legacy_credentials
|
29
|
+
|
30
|
+
elsif File.exists?( File.join(ENV['HOME'], '.fog') )
|
31
|
+
vsphere_credentials = load_fog_credentials
|
32
|
+
end
|
33
|
+
|
34
|
+
return vsphere_credentials
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.load_fog_credentials
|
38
|
+
vInfo = YAML.load_file( File.join(ENV['HOME'], '.fog') )
|
39
|
+
|
40
|
+
vsphere_credentials = {}
|
41
|
+
vsphere_credentials[:server] = vInfo[:default][:vsphere_server]
|
42
|
+
vsphere_credentials[:user] = vInfo[:default][:vsphere_username]
|
43
|
+
vsphere_credentials[:pass] = vInfo[:default][:vsphere_password]
|
44
|
+
|
45
|
+
return vsphere_credentials
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.load_legacy_credentials
|
49
|
+
vInfo = YAML.load_file '/etc/plharness/vsphere'
|
50
|
+
|
51
|
+
puts(
|
52
|
+
"Use of /etc/plharness/vsphere as a config file is deprecated.\n" +
|
53
|
+
"Please use ~/.fog instead\n" +
|
54
|
+
"See http://docs.puppetlabs.com/pe/2.0/" +
|
55
|
+
"cloudprovisioner_configuring.html for format"
|
56
|
+
)
|
57
|
+
|
58
|
+
vsphere_credentials = {}
|
59
|
+
vsphere_credentials[:server] = vInfo['location']
|
60
|
+
vsphere_credentials[:user] = vInfo['user']
|
61
|
+
vsphere_credentials[:pass] = vInfo['pass']
|
62
|
+
|
63
|
+
return vsphere_credentials
|
64
|
+
end
|
65
|
+
|
66
|
+
def find_snapshot vm, snapname
|
67
|
+
search_child_snaps vm.snapshot.rootSnapshotList, snapname
|
68
|
+
end
|
69
|
+
|
70
|
+
def search_child_snaps tree, snapname
|
71
|
+
snapshot = nil
|
72
|
+
tree.each do |child|
|
73
|
+
if child.name == snapname
|
74
|
+
snapshot ||= child.snapshot
|
75
|
+
else
|
76
|
+
snapshot ||= search_child_snaps child.childSnapshotList, snapname
|
77
|
+
end
|
78
|
+
end
|
79
|
+
snapshot
|
80
|
+
end
|
81
|
+
|
82
|
+
def find_customization name
|
83
|
+
csm = @connection.serviceContent.customizationSpecManager
|
84
|
+
|
85
|
+
begin
|
86
|
+
customizationSpec = csm.GetCustomizationSpec({:name => name}).spec
|
87
|
+
rescue
|
88
|
+
customizationSpec = nil
|
89
|
+
end
|
90
|
+
|
91
|
+
return customizationSpec
|
92
|
+
end
|
93
|
+
|
94
|
+
# an easier wrapper around the horrid PropertyCollector interface,
|
95
|
+
# necessary for searching VMs in all Datacenters that may be nested
|
96
|
+
# within folders of arbitrary depth
|
97
|
+
# returns a hash array of <name> => <VirtualMachine ManagedObjects>
|
98
|
+
def find_vms names, connection = @connection
|
99
|
+
names = names.is_a?(Array) ? names : [ names ]
|
100
|
+
containerView = get_base_vm_container_from connection
|
101
|
+
propertyCollector = connection.propertyCollector
|
102
|
+
|
103
|
+
objectSet = [{
|
104
|
+
:obj => containerView,
|
105
|
+
:skip => true,
|
106
|
+
:selectSet => [ RbVmomi::VIM::TraversalSpec.new({
|
107
|
+
:name => 'gettingTheVMs',
|
108
|
+
:path => 'view',
|
109
|
+
:skip => false,
|
110
|
+
:type => 'ContainerView'
|
111
|
+
}) ]
|
112
|
+
}]
|
113
|
+
|
114
|
+
propSet = [{
|
115
|
+
:pathSet => [ 'name' ],
|
116
|
+
:type => 'VirtualMachine'
|
117
|
+
}]
|
118
|
+
|
119
|
+
results = propertyCollector.RetrievePropertiesEx({
|
120
|
+
:specSet => [{
|
121
|
+
:objectSet => objectSet,
|
122
|
+
:propSet => propSet
|
123
|
+
}],
|
124
|
+
:options => { :maxObjects => nil }
|
125
|
+
})
|
126
|
+
|
127
|
+
vms = {}
|
128
|
+
results.objects.each do |result|
|
129
|
+
name = result.propSet.first.val
|
130
|
+
next unless names.include? name
|
131
|
+
vms[name] = result.obj
|
132
|
+
end
|
133
|
+
|
134
|
+
while results.token do
|
135
|
+
results = propertyCollector.ContinueRetrievePropertiesEx({:token => results.token})
|
136
|
+
results.objects.each do |result|
|
137
|
+
name = result.propSet.first.val
|
138
|
+
next unless names.include? name
|
139
|
+
vms[name] = result.obj
|
140
|
+
end
|
141
|
+
end
|
142
|
+
vms
|
143
|
+
end
|
144
|
+
|
145
|
+
def find_datastore datastorename
|
146
|
+
datacenter = @connection.serviceInstance.find_datacenter
|
147
|
+
datacenter.find_datastore(datastorename)
|
148
|
+
end
|
149
|
+
|
150
|
+
def find_folder foldername
|
151
|
+
datacenter = @connection.serviceInstance.find_datacenter
|
152
|
+
base = datacenter.vmFolder
|
153
|
+
folders = foldername.split('/')
|
154
|
+
folders.each do |folder|
|
155
|
+
case base
|
156
|
+
when RbVmomi::VIM::Folder
|
157
|
+
base = base.childEntity.find { |f| f.name == folder }
|
158
|
+
else
|
159
|
+
abort "Unexpected object type encountered (#{base.class}) while finding folder"
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
base
|
164
|
+
end
|
165
|
+
|
166
|
+
def find_pool poolname
|
167
|
+
datacenter = @connection.serviceInstance.find_datacenter
|
168
|
+
base = datacenter.hostFolder
|
169
|
+
pools = poolname.split('/')
|
170
|
+
pools.each do |pool|
|
171
|
+
case base
|
172
|
+
when RbVmomi::VIM::Folder
|
173
|
+
base = base.childEntity.find { |f| f.name == pool }
|
174
|
+
when RbVmomi::VIM::ClusterComputeResource
|
175
|
+
base = base.resourcePool.resourcePool.find { |f| f.name == pool }
|
176
|
+
when RbVmomi::VIM::ResourcePool
|
177
|
+
base = base.resourcePool.find { |f| f.name == pool }
|
178
|
+
else
|
179
|
+
abort "Unexpected object type encountered (#{base.class}) while finding resource pool"
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
base = base.resourcePool unless base.is_a?(RbVmomi::VIM::ResourcePool) and base.respond_to?(:resourcePool)
|
184
|
+
base
|
185
|
+
end
|
186
|
+
|
187
|
+
def get_base_vm_container_from connection
|
188
|
+
viewManager = connection.serviceContent.viewManager
|
189
|
+
viewManager.CreateContainerView({
|
190
|
+
:container => connection.serviceContent.rootFolder,
|
191
|
+
:recursive => true,
|
192
|
+
:type => [ 'VirtualMachine' ]
|
193
|
+
})
|
194
|
+
end
|
195
|
+
|
196
|
+
def close
|
197
|
+
@connection.close
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
@@ -0,0 +1,167 @@
|
|
1
|
+
module Beaker
|
2
|
+
class Logger
|
3
|
+
NORMAL = "\e[00;00m"
|
4
|
+
BRIGHT_NORMAL = "\e[00;01m"
|
5
|
+
BLACK = "\e[00;30m"
|
6
|
+
RED = "\e[00;31m"
|
7
|
+
GREEN = "\e[00;32m"
|
8
|
+
YELLOW = "\e[00;33m"
|
9
|
+
BLUE = "\e[00;34m"
|
10
|
+
MAGENTA = "\e[00;35m"
|
11
|
+
CYAN = "\e[00;36m"
|
12
|
+
WHITE = "\e[00;37m"
|
13
|
+
GREY = "\e[01;30m"
|
14
|
+
BRIGHT_RED = "\e[01;31m"
|
15
|
+
BRIGHT_GREEN = "\e[01;32m"
|
16
|
+
BRIGHT_YELLOW = "\e[01;33m"
|
17
|
+
BRIGHT_BLUE = "\e[01;34m"
|
18
|
+
BRIGHT_MAGENTA = "\e[01;35m"
|
19
|
+
BRIGHT_CYAN = "\e[01;36m"
|
20
|
+
BRIGHT_WHITE = "\e[01;37m"
|
21
|
+
|
22
|
+
LOG_LEVELS = {
|
23
|
+
:debug => 1,
|
24
|
+
:warn => 2,
|
25
|
+
:normal => 3,
|
26
|
+
:info => 4
|
27
|
+
}
|
28
|
+
|
29
|
+
attr_accessor :color, :log_level, :destinations
|
30
|
+
|
31
|
+
def initialize(*args)
|
32
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
33
|
+
@color = options[:color]
|
34
|
+
@log_level = options[:debug] ? :debug : :normal
|
35
|
+
@destinations = []
|
36
|
+
|
37
|
+
dests = args
|
38
|
+
dests << STDOUT unless options[:quiet]
|
39
|
+
dests.uniq!
|
40
|
+
dests.each {|dest| add_destination(dest)}
|
41
|
+
end
|
42
|
+
|
43
|
+
def add_destination(dest)
|
44
|
+
case dest
|
45
|
+
when IO
|
46
|
+
@destinations << dest
|
47
|
+
when String
|
48
|
+
@destinations << File.open(dest, 'w')
|
49
|
+
else
|
50
|
+
raise "Unsuitable log destination #{dest.inspect}"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def remove_destination(dest)
|
55
|
+
case dest
|
56
|
+
when IO
|
57
|
+
@destinations.delete(dest)
|
58
|
+
when String
|
59
|
+
@destinations.delete_if {|d| d.respond_to?(:path) and d.path == dest}
|
60
|
+
else
|
61
|
+
raise "Unsuitable log destination #{dest.inspect}"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def is_debug?
|
66
|
+
LOG_LEVELS[@log_level] <= LOG_LEVELS[:debug]
|
67
|
+
end
|
68
|
+
|
69
|
+
def is_warn?
|
70
|
+
LOG_LEVELS[@log_level] <= LOG_LEVELS[:warn]
|
71
|
+
end
|
72
|
+
|
73
|
+
def host_output *args
|
74
|
+
return unless is_debug?
|
75
|
+
strings = strip_colors_from args
|
76
|
+
string = strings.join
|
77
|
+
optionally_color GREY, string, false
|
78
|
+
end
|
79
|
+
|
80
|
+
def debug *args
|
81
|
+
return unless is_debug?
|
82
|
+
optionally_color WHITE, args
|
83
|
+
end
|
84
|
+
|
85
|
+
def warn *args
|
86
|
+
return unless is_warn?
|
87
|
+
strings = args.map {|msg| "Warning: #{msg}" }
|
88
|
+
optionally_color YELLOW, strings
|
89
|
+
end
|
90
|
+
|
91
|
+
def success *args
|
92
|
+
optionally_color GREEN, args
|
93
|
+
end
|
94
|
+
|
95
|
+
def notify *args
|
96
|
+
optionally_color BRIGHT_WHITE, args
|
97
|
+
end
|
98
|
+
|
99
|
+
def error *args
|
100
|
+
optionally_color BRIGHT_RED, args
|
101
|
+
end
|
102
|
+
|
103
|
+
def strip_colors_from lines
|
104
|
+
Array(lines).map do |line|
|
105
|
+
line.gsub /\e\[(\d+;)?\d+m/, ''
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def optionally_color color_code, msg, add_newline = true
|
110
|
+
print_statement = add_newline ? :puts : :print
|
111
|
+
@destinations.each do |to|
|
112
|
+
to.print color_code if @color
|
113
|
+
to.send print_statement, msg
|
114
|
+
to.print NORMAL if @color
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# utility method to get the current call stack and format it
|
119
|
+
# to a human-readable string (which some IDEs/editors
|
120
|
+
# will recognize as links to the line numbers in the trace)
|
121
|
+
def pretty_backtrace backtrace = caller(1)
|
122
|
+
trace = purge_harness_files_from( Array( backtrace ) )
|
123
|
+
expand_symlinks( trace ).join "\n"
|
124
|
+
end
|
125
|
+
|
126
|
+
private
|
127
|
+
def expand_symlinks backtrace
|
128
|
+
backtrace.collect do |line|
|
129
|
+
file_path, line_num = line.split( ":" )
|
130
|
+
expanded_path = expand_symlink File.expand_path( file_path )
|
131
|
+
expanded_path.to_s + ":" + line_num.to_s
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def purge_harness_files_from backtrace
|
136
|
+
mostly_purged = backtrace.reject do |line|
|
137
|
+
# LOADED_FEATURES is an array of anything `require`d, i.e. everything
|
138
|
+
# but the test in question
|
139
|
+
$LOADED_FEATURES.any? do |require_path|
|
140
|
+
line.include? require_path
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# And remove lines that contain our program name in them
|
145
|
+
completely_purged = mostly_purged.reject {|line| line.include? $0 }
|
146
|
+
end
|
147
|
+
|
148
|
+
# utility method that takes a path as input, checks each component
|
149
|
+
# of the path to see if it is a symlink, and expands
|
150
|
+
# it if it is. returns the expanded path.
|
151
|
+
def expand_symlink file_path
|
152
|
+
file_path.split( "/" ).inject do |full_path, next_dir|
|
153
|
+
next_path = full_path + "/" + next_dir
|
154
|
+
if File.symlink? next_path
|
155
|
+
link = File.readlink next_path
|
156
|
+
next_path =
|
157
|
+
case link
|
158
|
+
when /^\// then link
|
159
|
+
else
|
160
|
+
File.expand_path( full_path + "/" + link )
|
161
|
+
end
|
162
|
+
end
|
163
|
+
next_path
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
%w(hypervisor).each do |lib|
|
2
|
+
begin
|
3
|
+
require "beaker/#{lib}"
|
4
|
+
rescue LoadError
|
5
|
+
require File.expand_path(File.join(File.dirname(__FILE__), lib))
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
module Beaker
|
10
|
+
class NetworkManager
|
11
|
+
HYPERVISOR_TYPES = ['solaris', 'blimpy', 'vsphere', 'fusion', 'aix', 'vcloud', 'vagrant']
|
12
|
+
|
13
|
+
def initialize(config, options, logger)
|
14
|
+
@logger = logger
|
15
|
+
@options = options
|
16
|
+
@hosts = []
|
17
|
+
@config = config
|
18
|
+
@virtual_machines = {}
|
19
|
+
@noprovision_machines = []
|
20
|
+
@config['HOSTS'].each_key do |name|
|
21
|
+
host_info = @config['HOSTS'][name]
|
22
|
+
#check to see if this host has a hypervisor
|
23
|
+
hypervisor = host_info['hypervisor']
|
24
|
+
#provision this box
|
25
|
+
# - only if we are running with --provision
|
26
|
+
# - only if we have a hypervisor
|
27
|
+
# - only if either the specific hosts has no specification or has 'provision' in its config
|
28
|
+
if @options[:provision] && hypervisor && (host_info.has_key?('provision') ? host_info['provision'] : true) #obey config file provision, defaults to provisioning vms
|
29
|
+
raise "Invalid hypervisor: #{hypervisor} (#{name})" unless HYPERVISOR_TYPES.include? hypervisor
|
30
|
+
@logger.debug "Hypervisor for #{name} is #{host_info['hypervisor'] || 'default' }, and I'm going to use #{hypervisor}"
|
31
|
+
@virtual_machines[hypervisor] = [] unless @virtual_machines[hypervisor]
|
32
|
+
@virtual_machines[hypervisor] << name
|
33
|
+
else #this is a non-provisioned machine, deal with it without hypervisors
|
34
|
+
@logger.debug "No hypervisor for #{name}, connecting to host without provisioning"
|
35
|
+
@noprovision_machines << name
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def provision
|
42
|
+
@provisioned_set = {}
|
43
|
+
@virtual_machines.each do |type, names|
|
44
|
+
hosts_for_type = []
|
45
|
+
#set up host objects for provisioned provisioned_set
|
46
|
+
names.each do |name|
|
47
|
+
host = Beaker::Host.create(name, @options, @config)
|
48
|
+
hosts_for_type << host
|
49
|
+
end
|
50
|
+
@provisioned_set[type] = Beaker::Hypervisor.create(type, hosts_for_type, @options, @config)
|
51
|
+
@hosts << hosts_for_type
|
52
|
+
end
|
53
|
+
@noprovision_machines.each do |name|
|
54
|
+
@hosts << Beaker::Host.create(name, @options, @config)
|
55
|
+
end
|
56
|
+
@hosts = @hosts.flatten
|
57
|
+
@hosts
|
58
|
+
end
|
59
|
+
|
60
|
+
def cleanup
|
61
|
+
#only cleanup if we aren't preserving hosts
|
62
|
+
#shut down connections
|
63
|
+
@hosts.each {|host| host.close }
|
64
|
+
|
65
|
+
if not @options[:preserve_hosts]
|
66
|
+
@provisioned_set.each_key do |type|
|
67
|
+
@provisioned_set[type].cleanup
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|