clc-chef-metal-vsphere 0.3.0

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