clc-chef-metal-vsphere 0.3.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 +7 -0
- data/README.md +90 -0
- data/Rakefile +30 -0
- data/lib/chef_metal/driver_init/vsphere.rb +3 -0
- data/lib/chef_metal_vsphere.rb +13 -0
- data/lib/chef_metal_vsphere/version.rb +3 -0
- data/lib/chef_metal_vsphere/vsphere_driver.rb +464 -0
- data/lib/chef_metal_vsphere/vsphere_helpers.rb +250 -0
- data/lib/chef_metal_vsphere/vsphere_url.rb +31 -0
- data/spec/integration_tests/.gitignore +1 -0
- data/spec/integration_tests/vsphere_driver_spec.rb +123 -0
- data/spec/unit_tests/VsphereDriver_spec.rb +206 -0
- data/spec/unit_tests/VsphereUrl_spec.rb +60 -0
- metadata +128 -0
@@ -0,0 +1,250 @@
|
|
1
|
+
require 'rbvmomi'
|
2
|
+
|
3
|
+
module ChefMetalVsphere
|
4
|
+
module Helpers
|
5
|
+
|
6
|
+
def vim(options = connect_options)
|
7
|
+
# reconnect on every call - connections may silently timeout during long operations (e.g. cloning)
|
8
|
+
RbVmomi::VIM.connect options
|
9
|
+
end
|
10
|
+
|
11
|
+
def find_vm(dc_name, vm_folder, vm_name)
|
12
|
+
folder = find_folder(dc_name, vm_folder) or raise("vSphere Folder not found [#{vm_folder}] for vm #{vm_name}")
|
13
|
+
vm = folder.find(vm_name, RbVmomi::VIM::VirtualMachine)
|
14
|
+
end
|
15
|
+
|
16
|
+
def find_vm_by_id(uuid, connection = vim)
|
17
|
+
vm = connection.searchIndex.FindByUuid({:uuid => uuid, :vmSearch => true, :instanceUuid => true})
|
18
|
+
end
|
19
|
+
|
20
|
+
def vm_started?(vm, wait_on_port = 22)
|
21
|
+
return false if vm.nil?
|
22
|
+
state = vm.runtime.powerState
|
23
|
+
return false unless state == 'poweredOn'
|
24
|
+
return false unless port_ready?(vm, wait_on_port)
|
25
|
+
return true
|
26
|
+
end
|
27
|
+
|
28
|
+
def vm_stopped?(vm)
|
29
|
+
return true if vm.nil?
|
30
|
+
state = vm.runtime.powerState
|
31
|
+
return false unless state == 'poweredOff'
|
32
|
+
return false
|
33
|
+
end
|
34
|
+
|
35
|
+
def start_vm(vm, wait_on_port = 22)
|
36
|
+
state = vm.runtime.powerState
|
37
|
+
unless state == 'poweredOn'
|
38
|
+
vm.PowerOnVM_Task.wait_for_completion
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def stop_vm(vm)
|
43
|
+
begin
|
44
|
+
vm.ShutdownGuest
|
45
|
+
sleep 2 until vm.runtime.powerState == 'poweredOff'
|
46
|
+
rescue
|
47
|
+
vm.PowerOffVM_Task.wait_for_completion
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def port_ready?(vm, port)
|
52
|
+
vm_ip = vm.guest.ipAddress
|
53
|
+
return false if vm_ip.nil?
|
54
|
+
|
55
|
+
begin
|
56
|
+
tcp_socket = TCPSocket.new(vm_ip, port)
|
57
|
+
readable = IO.select([tcp_socket], nil, nil, 5)
|
58
|
+
if readable
|
59
|
+
true
|
60
|
+
else
|
61
|
+
false
|
62
|
+
end
|
63
|
+
rescue Errno::ETIMEDOUT
|
64
|
+
false
|
65
|
+
rescue Errno::EPERM
|
66
|
+
false
|
67
|
+
rescue Errno::ECONNREFUSED
|
68
|
+
false
|
69
|
+
rescue Errno::EHOSTUNREACH, Errno::ENETUNREACH
|
70
|
+
false
|
71
|
+
ensure
|
72
|
+
tcp_socket && tcp_socket.close
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
#folder could be like: /Level1/Level2/folder_name
|
77
|
+
def find_folder(dc_name, folder_name)
|
78
|
+
#dc(dc_name).vmFolder.childEntity.grep(RbVmomi::VIM::Folder).find { |x| x.name == folder_name }
|
79
|
+
baseEntity = dc(dc_name).vmFolder
|
80
|
+
if folder_name && folder_name.length > 0
|
81
|
+
entityArray = folder_name.split('/')
|
82
|
+
entityArray.each do |entityArrItem|
|
83
|
+
if entityArrItem != ''
|
84
|
+
baseEntity = baseEntity.childEntity.grep(RbVmomi::VIM::Folder).find { |f| f.name == entityArrItem }
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
baseEntity
|
89
|
+
end
|
90
|
+
|
91
|
+
def dc(dc_name)
|
92
|
+
vim.serviceInstance.find_datacenter(dc_name) or raise("vSphere Datacenter not found [#{datacenter}]")
|
93
|
+
end
|
94
|
+
|
95
|
+
def do_vm_clone(dc_name, vm_template, vm_name, options)
|
96
|
+
datacenter = dc(dc_name)
|
97
|
+
pool = options[:resource_pool] ? find_pool(datacenter, options[:resource_pool]) : vm_template.resourcePool
|
98
|
+
rspec = RbVmomi::VIM.VirtualMachineRelocateSpec(pool: pool)
|
99
|
+
raise ':resource_pool must be specified when cloning from a VM Template' if pool.nil?
|
100
|
+
|
101
|
+
unless options[:datastore].to_s.empty?
|
102
|
+
rspec.datastore = find_datastore(datacenter, options[:datastore])
|
103
|
+
end
|
104
|
+
|
105
|
+
clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec(
|
106
|
+
location: rspec,
|
107
|
+
powerOn: false,
|
108
|
+
template: false
|
109
|
+
)
|
110
|
+
|
111
|
+
clone_spec.config = RbVmomi::VIM.VirtualMachineConfigSpec(:deviceChange => Array.new)
|
112
|
+
|
113
|
+
if options.has_key?(:customization_spec)
|
114
|
+
if(options[:customization_spec].is_a?(Hash))
|
115
|
+
cust_options = options[:customization_spec]
|
116
|
+
raise ArgumentError, "domain is required" unless cust_options.key?(:domain)
|
117
|
+
if cust_options.key?(:ipsettings)
|
118
|
+
raise ArgumentError, "ip and subnetMask is required for static ip" unless cust_options[:ipsettings].key?(:ip) and
|
119
|
+
cust_options[:ipsettings].key?(:subnetMask)
|
120
|
+
cust_ip_settings = RbVmomi::VIM::CustomizationIPSettings.new(cust_options[:ipsettings])
|
121
|
+
cust_ip_settings.ip = RbVmomi::VIM::CustomizationFixedIp(:ipAddress => cust_options[:ipsettings][:ip])
|
122
|
+
end
|
123
|
+
cust_domain = cust_options[:domain]
|
124
|
+
cust_ip_settings ||= RbVmomi::VIM::CustomizationIPSettings.new(:ip => RbVmomi::VIM::CustomizationDhcpIpGenerator.new())
|
125
|
+
cust_ip_settings.dnsDomain = cust_domain
|
126
|
+
cust_global_ip_settings = RbVmomi::VIM::CustomizationGlobalIPSettings.new
|
127
|
+
cust_global_ip_settings.dnsServerList = cust_ip_settings.dnsServerList
|
128
|
+
cust_global_ip_settings.dnsSuffixList = [cust_domain]
|
129
|
+
cust_hostname = RbVmomi::VIM::CustomizationFixedName.new(:name => cust_options[:hostname]) if cust_options.key?(:hostname)
|
130
|
+
cust_hostname ||= RbVmomi::VIM::CustomizationFixedName.new(:name => vm_name)
|
131
|
+
cust_hwclockutc = cust_options[:hw_clock_utc]
|
132
|
+
cust_timezone = cust_options[:time_zone]
|
133
|
+
cust_prep = RbVmomi::VIM::CustomizationLinuxPrep.new(
|
134
|
+
:domain => cust_domain,
|
135
|
+
:hostName => cust_hostname,
|
136
|
+
:hwClockUTC => cust_hwclockutc,
|
137
|
+
:timeZone => cust_timezone)
|
138
|
+
cust_adapter_mapping = [RbVmomi::VIM::CustomizationAdapterMapping.new(:adapter => cust_ip_settings)]
|
139
|
+
cust_spec = RbVmomi::VIM::CustomizationSpec.new(
|
140
|
+
:identity => cust_prep,
|
141
|
+
:globalIPSettings => cust_global_ip_settings,
|
142
|
+
:nicSettingMap => cust_adapter_mapping)
|
143
|
+
else
|
144
|
+
cust_spec = find_customization_spec(options[:customization_spec])
|
145
|
+
end
|
146
|
+
clone_spec.customization = cust_spec
|
147
|
+
end
|
148
|
+
|
149
|
+
unless options[:annotation].to_s.nil?
|
150
|
+
clone_spec.config.annotation = options[:annotation]
|
151
|
+
end
|
152
|
+
|
153
|
+
unless options[:num_cpus].to_s.nil?
|
154
|
+
clone_spec.config.numCPUs = options[:num_cpus]
|
155
|
+
end
|
156
|
+
|
157
|
+
unless options[:memory_mb].to_s.nil?
|
158
|
+
clone_spec.config.memoryMB = options[:memory_mb]
|
159
|
+
end
|
160
|
+
|
161
|
+
unless options[:network_name].to_s.nil?
|
162
|
+
network = find_network(datacenter, options[:network_name])
|
163
|
+
card = vm_template.config.hardware.device.grep(RbVmomi::VIM::VirtualEthernetCard).first
|
164
|
+
begin
|
165
|
+
switch_port = RbVmomi::VIM.DistributedVirtualSwitchPortConnection(:switchUuid => network.config.distributedVirtualSwitch.uuid, :portgroupKey => network.key)
|
166
|
+
card.backing.port = switch_port
|
167
|
+
rescue
|
168
|
+
# not connected to a distibuted switch?
|
169
|
+
card.backing.deviceName = options[:network_name]
|
170
|
+
end
|
171
|
+
dev_spec = RbVmomi::VIM.VirtualDeviceConfigSpec(:device => card, :operation => "edit")
|
172
|
+
clone_spec.config.deviceChange.push dev_spec
|
173
|
+
end
|
174
|
+
|
175
|
+
vm_template.CloneVM_Task(
|
176
|
+
name: vm_name,
|
177
|
+
folder: find_folder(dc_name, options[:vm_folder]),
|
178
|
+
spec: clone_spec
|
179
|
+
).wait_for_completion
|
180
|
+
|
181
|
+
vm = find_vm(dc_name, options[:vm_folder], vm_name)
|
182
|
+
|
183
|
+
unless options[:additional_disk_size_gb].to_s.nil?
|
184
|
+
if options[:datastore].to_s.empty?
|
185
|
+
raise ":datastore must be specified when adding a disk to a cloned vm"
|
186
|
+
end
|
187
|
+
idx = vm.disks.count
|
188
|
+
task = vm.ReconfigVM_Task(:spec => RbVmomi::VIM.VirtualMachineConfigSpec(:deviceChange =>[RbVmomi::VIM::VirtualDeviceConfigSpec(
|
189
|
+
:operation => :add,
|
190
|
+
:fileOperation => :create,
|
191
|
+
:device => RbVmomi::VIM.VirtualDisk(
|
192
|
+
:key => idx,
|
193
|
+
:backing => RbVmomi::VIM.VirtualDiskFlatVer2BackingInfo(
|
194
|
+
:fileName => "[#{options[:datastore]}]",
|
195
|
+
:diskMode => 'persistent',
|
196
|
+
:thinProvisioned => true
|
197
|
+
),
|
198
|
+
:capacityInKB => options[:additional_disk_size_gb] * 1024 * 1024,
|
199
|
+
:controllerKey => 1000,
|
200
|
+
:unitNumber => idx
|
201
|
+
)
|
202
|
+
)]))
|
203
|
+
task.wait_for_completion
|
204
|
+
end
|
205
|
+
|
206
|
+
vm
|
207
|
+
end
|
208
|
+
|
209
|
+
def find_network(dc, network_name)
|
210
|
+
baseEntity = dc.network
|
211
|
+
baseEntity.find { |f| f.name == network_name } or raise "no such network #{network_name}"
|
212
|
+
end
|
213
|
+
|
214
|
+
def find_datastore(dc, datastore_name)
|
215
|
+
baseEntity = dc.datastore
|
216
|
+
baseEntity.find { |f| f.info.name == datastore_name } or raise "no such datastore #{datastore_name}"
|
217
|
+
end
|
218
|
+
|
219
|
+
def find_pool(dc, pool_name)
|
220
|
+
baseEntity = dc.hostFolder
|
221
|
+
entityArray = pool_name.split('/')
|
222
|
+
entityArray.each do |entityArrItem|
|
223
|
+
if entityArrItem != ''
|
224
|
+
if baseEntity.is_a? RbVmomi::VIM::Folder
|
225
|
+
baseEntity = baseEntity.childEntity.find { |f| f.name == entityArrItem } or nil
|
226
|
+
elsif baseEntity.is_a? RbVmomi::VIM::ClusterComputeResource or baseEntity.is_a? RbVmomi::VIM::ComputeResource
|
227
|
+
baseEntity = baseEntity.resourcePool.resourcePool.find { |f| f.name == entityArrItem } or nil
|
228
|
+
elsif baseEntity.is_a? RbVmomi::VIM::ResourcePool
|
229
|
+
baseEntity = baseEntity.resourcePool.find { |f| f.name == entityArrItem } or nil
|
230
|
+
else
|
231
|
+
baseEntity = nil
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
raise "vSphere ResourcePool not found [#{pool_name}]" if baseEntity.nil?
|
237
|
+
|
238
|
+
baseEntity = baseEntity.resourcePool if not baseEntity.is_a?(RbVmomi::VIM::ResourcePool) and baseEntity.respond_to?(:resourcePool)
|
239
|
+
baseEntity
|
240
|
+
end
|
241
|
+
|
242
|
+
def find_customization_spec(customization_spec)
|
243
|
+
csm = vim.serviceContent.customizationSpecManager
|
244
|
+
csi = csm.GetCustomizationSpec(:name => customization_spec)
|
245
|
+
spec = csi.spec
|
246
|
+
raise "Customization Spec not found [#{customization_spec}]" if spec.nil?
|
247
|
+
spec
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
module URI
|
4
|
+
class VsphereUrl < Generic
|
5
|
+
DEFAULT_PORT = 443
|
6
|
+
DEFAULT_PATH = '/sdk'
|
7
|
+
|
8
|
+
def self.from_config(options)
|
9
|
+
URI("vsphere://#{options[:host]}:#{options[:port]}#{options[:path]}?use_ssl=#{options[:use_ssl]}&insecure=#{options[:insecure]}")
|
10
|
+
end
|
11
|
+
|
12
|
+
def use_ssl
|
13
|
+
if query
|
14
|
+
ssl_query = query.split('&').each.select{|q| q.start_with?('use_ssl=')}.first
|
15
|
+
ssl_query == 'use_ssl=true'
|
16
|
+
else
|
17
|
+
true
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def insecure
|
22
|
+
if query
|
23
|
+
insecure_query = query.split('&').each.select{|q| q.start_with?('insecure=')}.first
|
24
|
+
insecure_query == 'insecure=true'
|
25
|
+
else
|
26
|
+
false
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
@@schemes['VSPHERE'] = VsphereUrl
|
31
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
config.rb
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'chef_metal_vsphere/vsphere_driver'
|
2
|
+
#require 'chef_metal_vsphere/ubuntu_patch'
|
3
|
+
require 'chef_metal/chef_machine_spec'
|
4
|
+
|
5
|
+
# A file named config.rb in the same directory as this spec file
|
6
|
+
# must exist containing the driver options to use for the test.
|
7
|
+
# Here is an example:
|
8
|
+
# {
|
9
|
+
# :driver_options => {
|
10
|
+
# :host => '213.45.67.88',
|
11
|
+
# :user => 'vmapi',
|
12
|
+
# :password => 'SuperSecureP@ssw0rd',
|
13
|
+
# :insecure => true
|
14
|
+
# },
|
15
|
+
# :machine_options => {
|
16
|
+
# :start_timeout => 600,
|
17
|
+
# :create_timeout => 600,
|
18
|
+
# :bootstrap_options => {
|
19
|
+
# :datacenter => 'QA1',
|
20
|
+
# :template_name => 'UBUNTU-12-64-TEMPLATE',
|
21
|
+
# :vm_folder => 'DLAB',
|
22
|
+
# :num_cpus => 2,
|
23
|
+
# :network_name => 'vlan152_172.21.152',
|
24
|
+
# :memory_mb => 4096,
|
25
|
+
# :resource_pool => 'CLSTR02/DLAB',
|
26
|
+
# :ssh => {
|
27
|
+
# :user => 'root',
|
28
|
+
# :password => 'SuperSecureP@ssw0rd',
|
29
|
+
# :paranoid => false,
|
30
|
+
# :port => 22
|
31
|
+
# },
|
32
|
+
# :convergence_options => {}
|
33
|
+
# }
|
34
|
+
# }
|
35
|
+
# }
|
36
|
+
|
37
|
+
describe "vsphere_driver" do
|
38
|
+
include ChefMetalVsphere::Helpers
|
39
|
+
|
40
|
+
before :all do
|
41
|
+
@vm_name = "cmvd-test-#{SecureRandom.hex}"
|
42
|
+
@metal_config = eval File.read(File.expand_path('../config.rb', __FILE__))
|
43
|
+
Cheffish.honor_local_mode do
|
44
|
+
chef_server = Cheffish.default_chef_server(@metal_config)
|
45
|
+
puts "chef server:#{chef_server}"
|
46
|
+
@machine_spec = ChefMetal::ChefMachineSpec.new({'name' => @vm_name}, chef_server)
|
47
|
+
@driver = ChefMetal.driver_for_url("vsphere://#{@metal_config[:driver_options][:host]}", @metal_config)
|
48
|
+
action_handler = ChefMetal::ActionHandler.new
|
49
|
+
@driver.allocate_machine(action_handler, @machine_spec, @metal_config[:machine_options])
|
50
|
+
@metal_config[:machine_options][:convergence_options] = {:chef_server => chef_server}
|
51
|
+
@driver.ready_machine(action_handler, @machine_spec, @metal_config[:machine_options])
|
52
|
+
@server_id = @machine_spec.location['server_id']
|
53
|
+
@connection = vim(@metal_config[:driver_options])
|
54
|
+
@vm = find_vm_by_id(@server_id, @connection)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
context 'when allocating a machine' do
|
60
|
+
|
61
|
+
it "adds machine to the correct folder" do
|
62
|
+
expect(@vm.parent.name).to eq(@metal_config[:machine_options][:bootstrap_options][:vm_folder])
|
63
|
+
end
|
64
|
+
it "has a matching id with the machine_spec" do
|
65
|
+
expect(@vm.config.instanceUuid).to eq(@machine_spec.location['server_id'])
|
66
|
+
end
|
67
|
+
it "has the correct name" do
|
68
|
+
expect(@vm.config.name).to eq(@vm_name)
|
69
|
+
end
|
70
|
+
it "has the correct number of CPUs" do
|
71
|
+
expect(@vm.config.hardware.numCPU).to eq(@metal_config[:machine_options][:bootstrap_options][:num_cpus])
|
72
|
+
end
|
73
|
+
it "has the correct amount of memory" do
|
74
|
+
expect(@vm.config.hardware.memoryMB).to eq(@metal_config[:machine_options][:bootstrap_options][:memory_mb])
|
75
|
+
end
|
76
|
+
it "is on the correct network" do
|
77
|
+
expect(@vm.network[0].name).to eq(@metal_config[:machine_options][:bootstrap_options][:network_name])
|
78
|
+
end
|
79
|
+
it "is on the correct datastore" do
|
80
|
+
expect(@vm.datastore[0].name).to eq(@metal_config[:machine_options][:bootstrap_options][:datastore])
|
81
|
+
end
|
82
|
+
it "is in the correct resource pool" do
|
83
|
+
expect(@vm.resourcePool.name).to eq(@metal_config[:machine_options][:bootstrap_options][:resource_pool].split('/')[1])
|
84
|
+
end
|
85
|
+
it "is in the correct cluster" do
|
86
|
+
expect(@vm.resourcePool.owner.name).to eq(@metal_config[:machine_options][:bootstrap_options][:resource_pool].split('/')[0])
|
87
|
+
end
|
88
|
+
it "is in the correct datacenter" do
|
89
|
+
expect(@connection.serviceInstance.find_datacenter(@metal_config[:machine_options][:bootstrap_options][:datacenter]).find_vm("#{@vm.parent.name}/#{@vm_name}")).not_to eq(nil)
|
90
|
+
end
|
91
|
+
it "has an added disk of the correct size" do
|
92
|
+
disk_count = @vm.disks.count
|
93
|
+
expect(@vm.disks[disk_count-1].capacityInKB).to eq(@metal_config[:machine_options][:bootstrap_options][:additional_disk_size_gb] * 1024 * 1024)
|
94
|
+
end
|
95
|
+
it "has the correct IP address" do
|
96
|
+
if @vm.guest.toolsRunningStatus != "guestToolsRunning"
|
97
|
+
now = Time.now.utc
|
98
|
+
until (Time.now.utc - now) > 30 || (@vm.guest.toolsRunningStatus == "guestToolsRunning" && !@vm.guest.ipAddress.nil? && @vm.guest.ipAddress.length > 0) do
|
99
|
+
print "."
|
100
|
+
sleep 5
|
101
|
+
end
|
102
|
+
end
|
103
|
+
expect(@vm.guest.ipAddress).to eq(@metal_config[:machine_options][:bootstrap_options][:customization_spec][:ipsettings][:ip])
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
context "destroy_machine" do
|
108
|
+
|
109
|
+
it "removes the machine" do
|
110
|
+
Cheffish.honor_local_mode do
|
111
|
+
chef_server = Cheffish.default_chef_server(@metal_config)
|
112
|
+
driver = ChefMetal.driver_for_url("vsphere://#{@metal_config[:driver_options][:host]}", @metal_config)
|
113
|
+
action_handler = ChefMetal::ActionHandler.new
|
114
|
+
machine_spec = ChefMetal::ChefMachineSpec.new({'name' => @vm_name}, chef_server)
|
115
|
+
machine_spec.location = { 'driver_url' => driver.driver_url,
|
116
|
+
'server_id' => @server_id}
|
117
|
+
driver.destroy_machine(action_handler, machine_spec, @metal_config[:machine_options])
|
118
|
+
end
|
119
|
+
vm = find_vm_by_id(@server_id, @connection)
|
120
|
+
expect(vm).to eq(nil)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,206 @@
|
|
1
|
+
require 'chef_metal_vsphere/vsphere_driver'
|
2
|
+
|
3
|
+
describe "canonicalize_url" do
|
4
|
+
|
5
|
+
context "when config does not include the properties included in the url" do
|
6
|
+
metal_config = {
|
7
|
+
:driver_options => {
|
8
|
+
:user => 'vmapi',
|
9
|
+
:password => '<password>'
|
10
|
+
},
|
11
|
+
:machine_options => {
|
12
|
+
:ssh => {
|
13
|
+
:password => '<password>',
|
14
|
+
:paranoid => false
|
15
|
+
},
|
16
|
+
:bootstrap_options => {
|
17
|
+
:datacenter => 'QA1',
|
18
|
+
:template_name => 'UBUNTU-12-64-TEMPLATE',
|
19
|
+
:vm_folder => 'DLAB',
|
20
|
+
:num_cpus => 2,
|
21
|
+
:memory_mb => 4096,
|
22
|
+
:resource_pool => 'CLSTR02/DLAB'
|
23
|
+
}
|
24
|
+
},
|
25
|
+
:log_level => :debug
|
26
|
+
}
|
27
|
+
|
28
|
+
let(:results) {
|
29
|
+
ChefMetalVsphere::VsphereDriver.canonicalize_url('vsphere://3.3.3.3:999/crazyapi?use_ssl=false&insecure=true', metal_config)
|
30
|
+
}
|
31
|
+
|
32
|
+
it "populates the config with correct host from the driver url" do
|
33
|
+
expect(results[1][:driver_options][:connect_options][:host]).to eq('3.3.3.3')
|
34
|
+
end
|
35
|
+
it "populates the config with correct port from the driver url" do
|
36
|
+
expect(results[1][:driver_options][:connect_options][:port]).to eq(999)
|
37
|
+
end
|
38
|
+
it "populates the config with correct path from the driver url" do
|
39
|
+
expect(results[1][:driver_options][:connect_options][:path]).to eq('/crazyapi')
|
40
|
+
end
|
41
|
+
it "populates the config with correct use_ssl setting from the driver url" do
|
42
|
+
expect(results[1][:driver_options][:connect_options][:use_ssl]).to eq(false)
|
43
|
+
end
|
44
|
+
it "populates the config with correct insecure setting from the driver url" do
|
45
|
+
expect(results[1][:driver_options][:connect_options][:insecure]).to eq(true)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context "when config keys are stringified" do
|
50
|
+
metal_config = {
|
51
|
+
'driver_options' => {
|
52
|
+
'user' => 'vmapi',
|
53
|
+
'password' => '<password>'
|
54
|
+
},
|
55
|
+
'machine_options' => {
|
56
|
+
'ssh' => {
|
57
|
+
'password' => '<password>'
|
58
|
+
},
|
59
|
+
'bootstrap_options' => {
|
60
|
+
'datacenter' => 'QA1'
|
61
|
+
}
|
62
|
+
}
|
63
|
+
}
|
64
|
+
|
65
|
+
let(:results) {
|
66
|
+
ChefMetalVsphere::VsphereDriver.canonicalize_url('vsphere://3.3.3.3:999/crazyapi?use_ssl=false&insecure=true', metal_config)
|
67
|
+
}
|
68
|
+
|
69
|
+
it "will symbolize user" do
|
70
|
+
expect(results[1][:driver_options][:connect_options][:user]).to eq('vmapi')
|
71
|
+
end
|
72
|
+
it "will symbolize password" do
|
73
|
+
expect(results[1][:driver_options][:connect_options][:password]).to eq('<password>')
|
74
|
+
end
|
75
|
+
it "will symbolize ssh password" do
|
76
|
+
expect(results[1][:machine_options][:ssh][:password]).to eq('<password>')
|
77
|
+
end
|
78
|
+
it "will symbolize ssh bootstrap options" do
|
79
|
+
expect(results[1][:machine_options][:bootstrap_options][:datacenter]).to eq('QA1')
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context "when no url is in the config" do
|
84
|
+
metal_config = {
|
85
|
+
:driver_options => {
|
86
|
+
:user => 'vmapi',
|
87
|
+
:password => '<password>',
|
88
|
+
:host => '4.4.4.4',
|
89
|
+
:port => 888,
|
90
|
+
:path => '/yoda',
|
91
|
+
:use_ssl => 'false',
|
92
|
+
:insecure => 'true'
|
93
|
+
},
|
94
|
+
:machine_options => {
|
95
|
+
:ssh => {
|
96
|
+
:password => '<password>',
|
97
|
+
:paranoid => false
|
98
|
+
},
|
99
|
+
:bootstrap_options => {
|
100
|
+
:datacenter => 'QA1',
|
101
|
+
:template_name => 'UBUNTU-12-64-TEMPLATE',
|
102
|
+
:vm_folder => 'DLAB',
|
103
|
+
:num_cpus => 2,
|
104
|
+
:memory_mb => 4096,
|
105
|
+
:resource_pool => 'CLSTR02/DLAB'
|
106
|
+
}
|
107
|
+
},
|
108
|
+
:log_level => :debug
|
109
|
+
}
|
110
|
+
|
111
|
+
let(:results) {
|
112
|
+
ChefMetalVsphere::VsphereDriver.canonicalize_url(nil, metal_config)
|
113
|
+
}
|
114
|
+
|
115
|
+
it "creates the correct driver url from config settings" do
|
116
|
+
expect(results[0]).to eq('vsphere://4.4.4.4:888/yoda?use_ssl=false&insecure=true')
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
context "when no url is in the config and config is missing defaulted values" do
|
121
|
+
metal_config = {
|
122
|
+
:driver_options => {
|
123
|
+
:user => 'vmapi',
|
124
|
+
:password => '<password>',
|
125
|
+
:host => '4.4.4.4'
|
126
|
+
},
|
127
|
+
:machine_options => {
|
128
|
+
:bootstrap_options => {
|
129
|
+
:datacenter => 'QA1',
|
130
|
+
:template_name => 'UBUNTU-12-64-TEMPLATE',
|
131
|
+
:vm_folder => 'DLAB',
|
132
|
+
:num_cpus => 2,
|
133
|
+
:memory_mb => 4096,
|
134
|
+
:resource_pool => 'CLSTR02/DLAB',
|
135
|
+
:ssh => {
|
136
|
+
:password => '<password>',
|
137
|
+
:paranoid => false
|
138
|
+
}
|
139
|
+
}
|
140
|
+
},
|
141
|
+
:log_level => :debug
|
142
|
+
}
|
143
|
+
|
144
|
+
let(:results) {
|
145
|
+
ChefMetalVsphere::VsphereDriver.canonicalize_url(nil, metal_config)
|
146
|
+
}
|
147
|
+
|
148
|
+
it "creates the correct driver url from default settings" do
|
149
|
+
expect(results[0]).to eq('vsphere://4.4.4.4/sdk?use_ssl=true&insecure=false')
|
150
|
+
end
|
151
|
+
it "populates the config with correct port from default settings" do
|
152
|
+
expect(results[1][:driver_options][:connect_options][:port]).to eq(443)
|
153
|
+
end
|
154
|
+
it "populates the config with correct path from default settings" do
|
155
|
+
expect(results[1][:driver_options][:connect_options][:path]).to eq('/sdk')
|
156
|
+
end
|
157
|
+
it "populates the config with correct use_ssl setting from default settings" do
|
158
|
+
expect(results[1][:driver_options][:connect_options][:use_ssl]).to eq(true)
|
159
|
+
end
|
160
|
+
it "populates the config with correct insecure setting from default settings" do
|
161
|
+
expect(results[1][:driver_options][:connect_options][:insecure]).to eq(false)
|
162
|
+
end
|
163
|
+
it "populates the config with correct ssh port from default settings" do
|
164
|
+
expect(results[1][:machine_options][:bootstrap_options][:ssh][:port]).to eq(22)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
context "when missing host" do
|
169
|
+
metal_config = {
|
170
|
+
:driver_options => {
|
171
|
+
:user => 'vmapi',
|
172
|
+
:password => '<password>',
|
173
|
+
}
|
174
|
+
}
|
175
|
+
|
176
|
+
it "should raise an error" do
|
177
|
+
expect{ChefMetalVsphere::VsphereDriver.canonicalize_url(nil,metal_config)}.to raise_error(RuntimeError)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
context "when missing user" do
|
182
|
+
metal_config = {
|
183
|
+
:driver_options => {
|
184
|
+
:host => 'host',
|
185
|
+
:password => '<password>',
|
186
|
+
}
|
187
|
+
}
|
188
|
+
|
189
|
+
it "should raise an error" do
|
190
|
+
expect{ChefMetalVsphere::VsphereDriver.canonicalize_url(nil,metal_config)}.to raise_error(RuntimeError)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
context "when missing password" do
|
195
|
+
metal_config = {
|
196
|
+
:driver_options => {
|
197
|
+
:host => 'host',
|
198
|
+
:user => 'user',
|
199
|
+
}
|
200
|
+
}
|
201
|
+
|
202
|
+
it "should raise an error" do
|
203
|
+
expect{ChefMetalVsphere::VsphereDriver.canonicalize_url(nil,metal_config)}.to raise_error(RuntimeError)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|