vagrant-libvirt 0.0.45 → 0.4.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.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +542 -167
  3. data/lib/vagrant-libvirt/action.rb +2 -2
  4. data/lib/vagrant-libvirt/action/create_domain.rb +112 -42
  5. data/lib/vagrant-libvirt/action/create_domain_volume.rb +14 -10
  6. data/lib/vagrant-libvirt/action/create_network_interfaces.rb +8 -5
  7. data/lib/vagrant-libvirt/action/create_networks.rb +2 -2
  8. data/lib/vagrant-libvirt/action/destroy_domain.rb +1 -1
  9. data/lib/vagrant-libvirt/action/forward_ports.rb +10 -8
  10. data/lib/vagrant-libvirt/action/halt_domain.rb +1 -1
  11. data/lib/vagrant-libvirt/action/handle_box_image.rb +28 -60
  12. data/lib/vagrant-libvirt/action/handle_storage_pool.rb +4 -4
  13. data/lib/vagrant-libvirt/action/package_domain.rb +64 -12
  14. data/lib/vagrant-libvirt/action/prepare_nfs_settings.rb +3 -9
  15. data/lib/vagrant-libvirt/action/prune_nfs_exports.rb +19 -9
  16. data/lib/vagrant-libvirt/action/remove_libvirt_image.rb +2 -2
  17. data/lib/vagrant-libvirt/action/remove_stale_volume.rb +17 -11
  18. data/lib/vagrant-libvirt/action/set_boot_order.rb +2 -2
  19. data/lib/vagrant-libvirt/action/set_name_of_domain.rb +6 -9
  20. data/lib/vagrant-libvirt/action/start_domain.rb +87 -30
  21. data/lib/vagrant-libvirt/action/wait_till_up.rb +10 -32
  22. data/lib/vagrant-libvirt/cap/public_address.rb +16 -0
  23. data/lib/vagrant-libvirt/cap/synced_folder.rb +3 -3
  24. data/lib/vagrant-libvirt/config.rb +294 -42
  25. data/lib/vagrant-libvirt/driver.rb +49 -34
  26. data/lib/vagrant-libvirt/errors.rb +5 -5
  27. data/lib/vagrant-libvirt/plugin.rb +7 -2
  28. data/lib/vagrant-libvirt/provider.rb +2 -9
  29. data/lib/vagrant-libvirt/templates/domain.xml.erb +52 -10
  30. data/lib/vagrant-libvirt/templates/public_interface.xml.erb +5 -1
  31. data/lib/vagrant-libvirt/util.rb +1 -0
  32. data/lib/vagrant-libvirt/util/erb_template.rb +6 -7
  33. data/lib/vagrant-libvirt/util/network_util.rb +6 -1
  34. data/lib/vagrant-libvirt/util/nfs.rb +17 -0
  35. data/lib/vagrant-libvirt/util/ui.rb +23 -0
  36. data/lib/vagrant-libvirt/version +1 -0
  37. data/lib/vagrant-libvirt/version.rb +72 -1
  38. data/locales/en.yml +6 -6
  39. data/spec/spec_helper.rb +28 -2
  40. data/spec/support/libvirt_context.rb +3 -1
  41. data/spec/support/sharedcontext.rb +7 -3
  42. data/spec/unit/action/create_domain_spec.rb +160 -0
  43. data/spec/unit/action/create_domain_spec/default_system_storage_pool.xml +17 -0
  44. data/spec/unit/action/create_domain_spec/default_user_storage_pool.xml +17 -0
  45. data/spec/unit/action/destroy_domain_spec.rb +2 -2
  46. data/spec/unit/action/set_name_of_domain_spec.rb +3 -3
  47. data/spec/unit/action/start_domain_spec.rb +231 -0
  48. data/spec/unit/action/start_domain_spec/clock_timer_rtc.xml +50 -0
  49. data/spec/unit/action/start_domain_spec/default.xml +48 -0
  50. data/spec/unit/action/start_domain_spec/default_added_tpm_path.xml +48 -0
  51. data/spec/unit/action/start_domain_spec/default_added_tpm_version.xml +48 -0
  52. data/spec/unit/action/wait_till_up_spec.rb +14 -9
  53. data/spec/unit/config_spec.rb +438 -0
  54. data/spec/unit/provider_spec.rb +11 -0
  55. data/spec/unit/templates/domain_all_settings.xml +20 -5
  56. data/spec/unit/templates/domain_custom_cpu_model.xml +4 -1
  57. data/spec/unit/templates/domain_defaults.xml +4 -1
  58. data/spec/unit/templates/domain_spec.rb +92 -4
  59. data/spec/unit/templates/tpm/version_1.2.xml +54 -0
  60. data/spec/unit/templates/tpm/version_2.0.xml +53 -0
  61. metadata +91 -36
  62. data/.coveralls.yml +0 -1
  63. data/.github/issue_template.md +0 -37
  64. data/.gitignore +0 -21
  65. data/.travis.yml +0 -24
  66. data/Gemfile +0 -26
  67. data/Rakefile +0 -8
  68. data/example_box/README.md +0 -29
  69. data/example_box/Vagrantfile +0 -60
  70. data/example_box/metadata.json +0 -5
  71. data/lib/vagrant-libvirt/templates/default_storage_volume.xml.erb +0 -14
  72. data/tools/create_box.sh +0 -130
  73. data/tools/prepare_redhat_for_box.sh +0 -119
  74. data/vagrant-libvirt.gemspec +0 -51
@@ -23,7 +23,7 @@ module VagrantPlugins
23
23
 
24
24
  libvirt_domain = env[:machine].provider.driver.connection.client.lookup_domain_by_uuid(env[:machine].id)
25
25
 
26
- # libvirt API doesn't support modifying memory on NUMA enabled CPUs
26
+ # Libvirt API doesn't support modifying memory on NUMA enabled CPUs
27
27
  # http://libvirt.org/git/?p=libvirt.git;a=commit;h=d174394105cf00ed266bf729ddf461c21637c736
28
28
  if config.numa_nodes == nil
29
29
  if config.memory.to_i * 1024 != libvirt_domain.max_memory
@@ -37,12 +37,16 @@ module VagrantPlugins
37
37
  xml_descr = REXML::Document.new descr
38
38
  descr_changed = false
39
39
 
40
+ # For outputting XML for comparison
41
+ formatter = REXML::Formatters::Pretty.new
42
+
40
43
  # additional disk bus
41
44
  config.disks.each do |disk|
42
45
  device = disk[:device]
43
46
  bus = disk[:bus]
44
47
  REXML::XPath.each(xml_descr, '/domain/devices/disk[@device="disk"]/target[@dev="' + device + '"]') do |disk_target|
45
48
  next unless disk_target.attributes['bus'] != bus
49
+ @logger.debug "disk #{device} bus updated from '#{disk_target.attributes['bus']}' to '#{bus}'"
46
50
  descr_changed = true
47
51
  disk_target.attributes['bus'] = bus
48
52
  disk_target.parent.delete_element("#{disk_target.parent.xpath}/address")
@@ -52,6 +56,7 @@ module VagrantPlugins
52
56
  # disk_bus
53
57
  REXML::XPath.each(xml_descr, '/domain/devices/disk[@device="disk"]/target[@dev="vda"]') do |disk_target|
54
58
  next unless disk_target.attributes['bus'] != config.disk_bus
59
+ @logger.debug "domain disk bus updated from '#{disk_target.attributes['bus']}' to '#{bus}'"
55
60
  descr_changed = true
56
61
  disk_target.attributes['bus'] = config.disk_bus
57
62
  disk_target.parent.delete_element("#{disk_target.parent.xpath}/address")
@@ -61,6 +66,7 @@ module VagrantPlugins
61
66
  unless config.nic_model_type.nil?
62
67
  REXML::XPath.each(xml_descr, '/domain/devices/interface/model') do |iface_model|
63
68
  if iface_model.attributes['type'] != config.nic_model_type
69
+ @logger.debug "network type updated from '#{iface_model.attributes['type']}' to '#{config.nic_model_type}'"
64
70
  descr_changed = true
65
71
  iface_model.attributes['type'] = config.nic_model_type
66
72
  end
@@ -68,7 +74,9 @@ module VagrantPlugins
68
74
  end
69
75
 
70
76
  # vCpu count
71
- if config.cpus.to_i != libvirt_domain.vcpus.length
77
+ vcpus_count = libvirt_domain.num_vcpus(0)
78
+ if config.cpus.to_i != vcpus_count
79
+ @logger.debug "cpu count updated from '#{vcpus_count}' to '#{config.cpus}'"
72
80
  descr_changed = true
73
81
  REXML::XPath.first(xml_descr, '/domain/vcpu').text = config.cpus
74
82
  end
@@ -76,11 +84,13 @@ module VagrantPlugins
76
84
  # cpu_mode
77
85
  cpu = REXML::XPath.first(xml_descr, '/domain/cpu')
78
86
  if cpu.nil?
87
+ @logger.debug "cpu_mode updated from not set to '#{config.cpu_mode}'"
79
88
  descr_changed = true
80
89
  cpu = REXML::Element.new('cpu', REXML::XPath.first(xml_descr, '/domain'))
81
90
  cpu.attributes['mode'] = config.cpu_mode
82
91
  else
83
92
  if cpu.attributes['mode'] != config.cpu_mode
93
+ @logger.debug "cpu_mode updated from '#{cpu.attributes['mode']}' to '#{config.cpu_mode}'"
84
94
  descr_changed = true
85
95
  cpu.attributes['mode'] = config.cpu_mode
86
96
  end
@@ -89,16 +99,19 @@ module VagrantPlugins
89
99
  if config.cpu_mode != 'host-passthrough'
90
100
  cpu_model = REXML::XPath.first(xml_descr, '/domain/cpu/model')
91
101
  if cpu_model.nil?
102
+ @logger.debug "cpu_model updated from not set to '#{config.cpu_model}'"
92
103
  descr_changed = true
93
104
  cpu_model = REXML::Element.new('model', REXML::XPath.first(xml_descr, '/domain/cpu'))
94
105
  cpu_model.attributes['fallback'] = 'allow'
95
106
  cpu_model.text = config.cpu_model
96
107
  else
97
- if cpu_model.text != config.cpu_model
108
+ if (cpu_model.text or '').strip != config.cpu_model.strip
109
+ @logger.debug "cpu_model text updated from #{cpu_model.text} to '#{config.cpu_model}'"
98
110
  descr_changed = true
99
111
  cpu_model.text = config.cpu_model
100
112
  end
101
113
  if cpu_model.attributes['fallback'] != config.cpu_fallback
114
+ @logger.debug "cpu_model fallback attribute updated from #{cpu_model.attributes['fallback']} to '#{config.cpu_fallback}'"
102
115
  descr_changed = true
103
116
  cpu_model.attributes['fallback'] = config.cpu_fallback
104
117
  end
@@ -107,12 +120,14 @@ module VagrantPlugins
107
120
  svm_feature = REXML::XPath.first(xml_descr, '/domain/cpu/feature[@name="svm"]')
108
121
  if config.nested
109
122
  if vmx_feature.nil?
123
+ @logger.debug "nested mode enabled from unset by setting cpu vmx feature"
110
124
  descr_changed = true
111
125
  vmx_feature = REXML::Element.new('feature', REXML::XPath.first(xml_descr, '/domain/cpu'))
112
126
  vmx_feature.attributes['policy'] = 'optional'
113
127
  vmx_feature.attributes['name'] = 'vmx'
114
128
  end
115
129
  if svm_feature.nil?
130
+ @logger.debug "nested mode enabled from unset by setting cpu svm feature"
116
131
  descr_changed = true
117
132
  svm_feature = REXML::Element.new('feature', REXML::XPath.first(xml_descr, '/domain/cpu'))
118
133
  svm_feature.attributes['policy'] = 'optional'
@@ -120,16 +135,19 @@ module VagrantPlugins
120
135
  end
121
136
  else
122
137
  unless vmx_feature.nil?
138
+ @logger.debug "nested mode disabled for cpu by removing vmx feature"
123
139
  descr_changed = true
124
140
  cpu.delete_element(vmx_feature)
125
141
  end
126
142
  unless svm_feature.nil?
143
+ @logger.debug "nested mode disabled for cpu by removing svm feature"
127
144
  descr_changed = true
128
145
  cpu.delete_element(svm_feature)
129
146
  end
130
147
  end
131
148
  elsif config.numa_nodes == nil
132
149
  unless cpu.elements.to_a.empty?
150
+ @logger.debug "switching cpu_mode to host-passthrough and removing emulated cpu features"
133
151
  descr_changed = true
134
152
  cpu.elements.each do |elem|
135
153
  cpu.delete_element(elem)
@@ -137,6 +155,34 @@ module VagrantPlugins
137
155
  end
138
156
  end
139
157
 
158
+ # Clock
159
+ clock = REXML::XPath.first(xml_descr, '/domain/clock')
160
+ if clock.attributes['offset'] != config.clock_offset
161
+ @logger.debug "clock offset changed"
162
+ descr_changed = true
163
+ clock.attributes['offset'] = config.clock_offset
164
+ end
165
+
166
+ # clock timers - because timers can be added/removed, just rebuild and then compare
167
+ if !config.clock_timers.empty? || clock.has_elements?
168
+ oldclock = ''
169
+ formatter.write(REXML::XPath.first(xml_descr, '/domain/clock'), oldclock)
170
+ clock.delete_element('//timer')
171
+ config.clock_timers.each do |clock_timer|
172
+ timer = REXML::Element.new('timer', clock)
173
+ clock_timer.each do |attr, value|
174
+ timer.attributes[attr.to_s] = value
175
+ end
176
+ end
177
+
178
+ newclock = ''
179
+ formatter.write(clock, newclock)
180
+ unless newclock.eql? oldclock
181
+ @logger.debug "clock timers config changed"
182
+ descr_changed = true
183
+ end
184
+ end
185
+
140
186
  # Graphics
141
187
  graphics = REXML::XPath.first(xml_descr, '/domain/devices/graphics')
142
188
  if config.graphics_type != 'none'
@@ -178,31 +224,31 @@ module VagrantPlugins
178
224
  end
179
225
 
180
226
  # TPM
181
- if config.tpm_path
182
- raise Errors::FogCreateServerError, 'The TPM Path must be fully qualified' unless config.tpm_path[0].chr == '/'
227
+ if [config.tpm_path, config.tpm_version].any?
228
+ if config.tpm_path
229
+ raise Errors::FogCreateServerError, 'The TPM Path must be fully qualified' unless config.tpm_path[0].chr == '/'
230
+ end
183
231
 
184
- tpm = REXML::XPath.first(xml_descr, '/domain/devices/tpm')
185
- if tpm.nil?
232
+ # just build the tpm element every time
233
+ # check at the end if it is different
234
+ oldtpm = REXML::XPath.first(xml_descr, '/domain/devices/tpm')
235
+ REXML::XPath.first(xml_descr, '/domain/devices').delete_element("tpm")
236
+ newtpm = REXML::Element.new('tpm', REXML::XPath.first(xml_descr, '/domain/devices'))
237
+
238
+ newtpm.attributes['model'] = config.tpm_model
239
+ backend = newtpm.add_element('backend')
240
+ backend.attributes['type'] = config.tpm_type
241
+
242
+ case config.tpm_type
243
+ when 'emulator'
244
+ backend.attributes['version'] = config.tpm_version
245
+ when 'passthrough'
246
+ backend.add_element('device').attributes['path'] = config.tpm_path
247
+ end
248
+
249
+ unless "'#{newtpm}'".eql? "'#{oldtpm}'"
250
+ @logger.debug "tpm config changed"
186
251
  descr_changed = true
187
- tpm = REXML::Element.new('tpm', REXML::XPath.first(xml_descr, '/domain/devices/tpm/model'))
188
- tpm.attributes['model'] = config.tpm_model
189
- tpm_backend_type = tpm.add_element('backend')
190
- tpm_backend_type.attributes['type'] = config.tpm_type
191
- tpm_device_path = tpm_backend_type.add_element('device')
192
- tpm_device_path.attributes['path'] = config.tpm_path
193
- else
194
- if tpm.attributes['model'] != config.tpm_model
195
- descr_changed = true
196
- tpm.attributes['model'] = config.tpm_model
197
- end
198
- if tpm.elements['backend'].attributes['type'] != config.tpm_type
199
- descr_changed = true
200
- tpm.elements['backend'].attributes['type'] = config.tpm_type
201
- end
202
- if tpm.elements['backend'].elements['device'].attributes['path'] != config.tpm_path
203
- descr_changed = true
204
- tpm.elements['backend'].elements['device'].attributes['path'] = config.tpm_path
205
- end
206
252
  end
207
253
  end
208
254
 
@@ -210,16 +256,21 @@ module VagrantPlugins
210
256
  video = REXML::XPath.first(xml_descr, '/domain/devices/video')
211
257
  if !video.nil? && (config.graphics_type == 'none')
212
258
  # graphics_type = none, video devices are removed since there is no possible output
259
+ @logger.debug "deleting video elements as config.graphics_type is none"
213
260
  descr_changed = true
214
261
  video.parent.delete_element(video)
215
262
  else
216
263
  video_model = REXML::XPath.first(xml_descr, '/domain/devices/video/model')
217
264
  if video_model.nil?
265
+ @logger.debug "video updated from not set to type '#{config.video_type}' and vram '#{config.video_vram}'"
266
+ descr_changed = true
218
267
  video_model = REXML::Element.new('model', REXML::XPath.first(xml_descr, '/domain/devices/video'))
219
268
  video_model.attributes['type'] = config.video_type
220
269
  video_model.attributes['vram'] = config.video_vram
221
270
  else
222
- if video_model.attributes['type'] != config.video_type || video_model.attributes['vram'] != config.video_vram
271
+ if video_model.attributes['type'] != config.video_type || video_model.attributes['vram'] != config.video_vram.to_s
272
+ @logger.debug "video type updated from '#{video_model.attributes['type']}' to '#{config.video_type}'"
273
+ @logger.debug "video vram updated from '#{video_model.attributes['vram']}' to '#{config.video_vram}'"
223
274
  descr_changed = true
224
275
  video_model.attributes['type'] = config.video_type
225
276
  video_model.attributes['vram'] = config.video_vram
@@ -237,11 +288,13 @@ module VagrantPlugins
237
288
  if config.dtb
238
289
  dtb = REXML::XPath.first(xml_descr, '/domain/os/dtb')
239
290
  if dtb.nil?
291
+ @logger.debug "dtb updated from not set to '#{config.dtb}'"
240
292
  descr_changed = true
241
293
  dtb = REXML::Element.new('dtb', REXML::XPath.first(xml_descr, '/domain/os'))
242
294
  dtb.text = config.dtb
243
295
  else
244
- if dtb.text != config.dtb
296
+ if (dtb.text or '') != config.dtb
297
+ @logger.debug "dtb updated from '#{dtb.text}' to '#{config.dtb}'"
245
298
  descr_changed = true
246
299
  dtb.text = config.dtb
247
300
  end
@@ -252,11 +305,13 @@ module VagrantPlugins
252
305
  if config.kernel
253
306
  kernel = REXML::XPath.first(xml_descr, '/domain/os/kernel')
254
307
  if kernel.nil?
308
+ @logger.debug "kernel updated from not set to '#{config.kernel}'"
255
309
  descr_changed = true
256
310
  kernel = REXML::Element.new('kernel', REXML::XPath.first(xml_descr, '/domain/os'))
257
311
  kernel.text = config.kernel
258
312
  else
259
- if kernel.text != config.kernel
313
+ if (kernel.text or '').strip != config.kernel
314
+ @logger.debug "kernel updated from '#{kernel.text}' to '#{config.kernel}'"
260
315
  descr_changed = true
261
316
  kernel.text = config.kernel
262
317
  end
@@ -265,11 +320,13 @@ module VagrantPlugins
265
320
  if config.initrd
266
321
  initrd = REXML::XPath.first(xml_descr, '/domain/os/initrd')
267
322
  if initrd.nil?
323
+ @logger.debug "initrd updated from not set to '#{config.initrd}'"
268
324
  descr_changed = true
269
325
  initrd = REXML::Element.new('initrd', REXML::XPath.first(xml_descr, '/domain/os'))
270
326
  initrd.text = config.initrd
271
327
  else
272
- if initrd.text != config.initrd
328
+ if (initrd.text or '').strip != config.initrd
329
+ @logger.debug "initrd updated from '#{initrd.text}' to '#{config.initrd}'"
273
330
  descr_changed = true
274
331
  initrd.text = config.initrd
275
332
  end
@@ -21,46 +21,26 @@ module VagrantPlugins
21
21
  env[:metrics] ||= {}
22
22
 
23
23
  # Get domain object
24
- domain = env[:machine].provider.driver.get_domain(env[:machine].id.to_s)
24
+ domain = env[:machine].provider.driver.get_domain(env[:machine])
25
25
  if domain.nil?
26
26
  raise Errors::NoDomainError,
27
27
  error_message: "Domain #{env[:machine].id} not found"
28
28
  end
29
29
 
30
30
  # Wait for domain to obtain an ip address. Ip address is searched
31
- # from arp table, either localy or remotely via ssh, if libvirt
31
+ # from arp table, either locally or remotely via ssh, if Libvirt
32
32
  # connection was done via ssh.
33
33
  env[:ip_address] = nil
34
34
  @logger.debug("Searching for IP for MAC address: #{domain.mac}")
35
35
  env[:ui].info(I18n.t('vagrant_libvirt.waiting_for_ip'))
36
36
 
37
- if env[:machine].provider_config.qemu_use_session
38
- env[:metrics]['instance_ip_time'] = Util::Timer.time do
39
- retryable(on: Fog::Errors::TimeoutError, tries: 300) do
40
- # If we're interrupted don't worry about waiting
41
- return terminate(env) if env[:interrupted]
37
+ env[:metrics]['instance_ip_time'] = Util::Timer.time do
38
+ retryable(on: Fog::Errors::TimeoutError, tries: 300) do
39
+ # just return if interrupted and let the warden call recover
40
+ return if env[:interrupted]
42
41
 
43
- # Wait for domain to obtain an ip address
44
- domain.wait_for(2) do
45
- env[:ip_address] = env[:machine].provider.driver.get_ipaddress_system(domain.mac)
46
- !env[:ip_address].nil?
47
- end
48
- end
49
- end
50
- else
51
- env[:metrics]['instance_ip_time'] = Util::Timer.time do
52
- retryable(on: Fog::Errors::TimeoutError, tries: 300) do
53
- # If we're interrupted don't worry about waiting
54
- return terminate(env) if env[:interrupted]
55
-
56
- # Wait for domain to obtain an ip address
57
- domain.wait_for(2) do
58
- addresses.each_pair do |_type, ip|
59
- env[:ip_address] = ip[0] unless ip[0].nil?
60
- end
61
- !env[:ip_address].nil?
62
- end
63
- end
42
+ # Wait for domain to obtain an ip address
43
+ env[:ip_address] = env[:machine].provider.driver.get_domain_ipaddress(env[:machine], domain)
64
44
  end
65
45
  end
66
46
 
@@ -84,8 +64,8 @@ module VagrantPlugins
84
64
  end
85
65
  end
86
66
  end
87
- # if interrupted above, just terminate immediately
88
- return terminate(env) if env[:interrupted]
67
+ # just return if interrupted and let the warden call recover
68
+ return if env[:interrupted]
89
69
  @logger.info("Time for SSH ready: #{env[:metrics]['instance_ssh_time']}")
90
70
 
91
71
  # Booted and ready for use.
@@ -95,8 +75,6 @@ module VagrantPlugins
95
75
  end
96
76
 
97
77
  def recover(env)
98
- return if env['vagrant.error'].is_a?(Vagrant::Errors::VagrantError)
99
-
100
78
  # Undo the import
101
79
  terminate(env)
102
80
  end
@@ -0,0 +1,16 @@
1
+ module VagrantPlugins
2
+ module ProviderLibvirt
3
+ module Cap
4
+ class PublicAddress
5
+ def self.public_address(machine)
6
+ # This does not need to be a globally routable address, it
7
+ # only needs to be accessible from the machine running
8
+ # Vagrant.
9
+ ssh_info = machine.ssh_info
10
+ return nil if !ssh_info
11
+ ssh_info[:host]
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -20,7 +20,7 @@ module VagrantPlugins
20
20
  end
21
21
 
22
22
  def usable?(machine, _raise_error = false)
23
- # bail now if not using libvirt since checking version would throw error
23
+ # bail now if not using Libvirt since checking version would throw error
24
24
  return false unless machine.provider_name == :libvirt
25
25
 
26
26
  # <filesystem/> support in device attach/detach introduced in 1.2.2
@@ -30,7 +30,7 @@ module VagrantPlugins
30
30
  end
31
31
 
32
32
  def prepare(machine, folders, _opts)
33
- raise Vagrant::Errors::Error('No libvirt connection') if machine.provider.driver.connection.nil?
33
+ raise Vagrant::Errors::Error('No Libvirt connection') if machine.provider.driver.connection.nil?
34
34
  @conn = machine.provider.driver.connection.client
35
35
 
36
36
  begin
@@ -89,7 +89,7 @@ module VagrantPlugins
89
89
 
90
90
  def cleanup(machine, _opts)
91
91
  if machine.provider.driver.connection.nil?
92
- raise Vagrant::Errors::Error('No libvirt connection')
92
+ raise Vagrant::Errors::Error('No Libvirt connection')
93
93
  end
94
94
  @conn = machine.provider.driver.connection.client
95
95
  begin
@@ -20,12 +20,12 @@ module VagrantPlugins
20
20
  # A hypervisor name to access via Libvirt.
21
21
  attr_accessor :driver
22
22
 
23
- # The name of the server, where libvirtd is running.
23
+ # The name of the server, where Libvirtd is running.
24
24
  attr_accessor :host
25
25
 
26
26
  # If use ssh tunnel to connect to Libvirt.
27
27
  attr_accessor :connect_via_ssh
28
- # Path towards the libvirt socket
28
+ # Path towards the Libvirt socket
29
29
  attr_accessor :socket
30
30
 
31
31
  # The username to access Libvirt.
@@ -37,11 +37,16 @@ module VagrantPlugins
37
37
  # ID SSH key file
38
38
  attr_accessor :id_ssh_key_file
39
39
 
40
+ attr_accessor :proxy_command
41
+
40
42
  # Libvirt storage pool name, where box image and instance snapshots will
41
43
  # be stored.
42
44
  attr_accessor :storage_pool_name
43
45
  attr_accessor :storage_pool_path
44
46
 
47
+ # Libvirt storage pool where the base image snapshot shall be stored
48
+ attr_accessor :snapshot_pool_name
49
+
45
50
  # Turn on to prevent hostname conflicts
46
51
  attr_accessor :random_hostname
47
52
 
@@ -55,6 +60,7 @@ module VagrantPlugins
55
60
  attr_accessor :management_network_autostart
56
61
  attr_accessor :management_network_pci_bus
57
62
  attr_accessor :management_network_pci_slot
63
+ attr_accessor :management_network_domain
58
64
 
59
65
  # System connection information
60
66
  attr_accessor :system_uri
@@ -63,18 +69,25 @@ module VagrantPlugins
63
69
  attr_accessor :default_prefix
64
70
 
65
71
  # Domain specific settings used while creating new domain.
72
+ attr_accessor :title
73
+ attr_accessor :description
66
74
  attr_accessor :uuid
67
75
  attr_accessor :memory
76
+ attr_accessor :nodeset
68
77
  attr_accessor :memory_backing
69
78
  attr_accessor :channel
70
79
  attr_accessor :cpus
80
+ attr_accessor :cpuset
71
81
  attr_accessor :cpu_mode
72
82
  attr_accessor :cpu_model
73
83
  attr_accessor :cpu_fallback
74
84
  attr_accessor :cpu_features
75
85
  attr_accessor :cpu_topology
86
+ attr_accessor :shares
76
87
  attr_accessor :features
77
88
  attr_accessor :features_hyperv
89
+ attr_accessor :clock_offset
90
+ attr_accessor :clock_timers
78
91
  attr_accessor :numa_nodes
79
92
  attr_accessor :loader
80
93
  attr_accessor :nvram
@@ -84,9 +97,10 @@ module VagrantPlugins
84
97
  attr_accessor :machine_virtual_size
85
98
  attr_accessor :disk_bus
86
99
  attr_accessor :disk_device
100
+ attr_accessor :disk_driver_opts
87
101
  attr_accessor :nic_model_type
88
102
  attr_accessor :nested
89
- attr_accessor :volume_cache
103
+ attr_accessor :volume_cache # deprecated, kept for backwards compatibility; use disk_driver
90
104
  attr_accessor :kernel
91
105
  attr_accessor :cmd_line
92
106
  attr_accessor :initrd
@@ -108,6 +122,13 @@ module VagrantPlugins
108
122
  attr_accessor :tpm_model
109
123
  attr_accessor :tpm_type
110
124
  attr_accessor :tpm_path
125
+ attr_accessor :tpm_version
126
+
127
+ # Configure the memballoon
128
+ attr_accessor :memballoon_enabled
129
+ attr_accessor :memballoon_model
130
+ attr_accessor :memballoon_pci_bus
131
+ attr_accessor :memballoon_pci_slot
111
132
 
112
133
  # Sets the max number of NICs that can be created
113
134
  # Default set to 8. Don't change the default unless you know
@@ -158,7 +179,10 @@ module VagrantPlugins
158
179
  # Additional qemuargs arguments
159
180
  attr_accessor :qemu_args
160
181
 
161
- # Use qemu session instead of system
182
+ # Additional qemuenv arguments
183
+ attr_accessor :qemu_env
184
+
185
+ # Use QEMU session instead of system
162
186
  attr_accessor :qemu_use_session
163
187
 
164
188
  def initialize
@@ -169,7 +193,10 @@ module VagrantPlugins
169
193
  @username = UNSET_VALUE
170
194
  @password = UNSET_VALUE
171
195
  @id_ssh_key_file = UNSET_VALUE
196
+ @socket = UNSET_VALUE
197
+ @proxy_command = UNSET_VALUE
172
198
  @storage_pool_name = UNSET_VALUE
199
+ @snapshot_pool_name = UNSET_VALUE
173
200
  @random_hostname = UNSET_VALUE
174
201
  @management_network_device = UNSET_VALUE
175
202
  @management_network_name = UNSET_VALUE
@@ -180,22 +207,30 @@ module VagrantPlugins
180
207
  @management_network_autostart = UNSET_VALUE
181
208
  @management_network_pci_slot = UNSET_VALUE
182
209
  @management_network_pci_bus = UNSET_VALUE
210
+ @management_network_domain = UNSET_VALUE
183
211
 
184
212
  # System connection information
185
213
  @system_uri = UNSET_VALUE
186
214
 
187
215
  # Domain specific settings.
216
+ @title = UNSET_VALUE
217
+ @description = UNSET_VALUE
188
218
  @uuid = UNSET_VALUE
189
219
  @memory = UNSET_VALUE
220
+ @nodeset = UNSET_VALUE
190
221
  @memory_backing = UNSET_VALUE
191
222
  @cpus = UNSET_VALUE
223
+ @cpuset = UNSET_VALUE
192
224
  @cpu_mode = UNSET_VALUE
193
225
  @cpu_model = UNSET_VALUE
194
226
  @cpu_fallback = UNSET_VALUE
195
227
  @cpu_features = UNSET_VALUE
196
228
  @cpu_topology = UNSET_VALUE
229
+ @shares = UNSET_VALUE
197
230
  @features = UNSET_VALUE
198
231
  @features_hyperv = UNSET_VALUE
232
+ @clock_offset = UNSET_VALUE
233
+ @clock_timers = []
199
234
  @numa_nodes = UNSET_VALUE
200
235
  @loader = UNSET_VALUE
201
236
  @nvram = UNSET_VALUE
@@ -204,6 +239,7 @@ module VagrantPlugins
204
239
  @machine_virtual_size = UNSET_VALUE
205
240
  @disk_bus = UNSET_VALUE
206
241
  @disk_device = UNSET_VALUE
242
+ @disk_driver_opts = {}
207
243
  @nic_model_type = UNSET_VALUE
208
244
  @nested = UNSET_VALUE
209
245
  @volume_cache = UNSET_VALUE
@@ -226,6 +262,12 @@ module VagrantPlugins
226
262
  @tpm_model = UNSET_VALUE
227
263
  @tpm_type = UNSET_VALUE
228
264
  @tpm_path = UNSET_VALUE
265
+ @tpm_version = UNSET_VALUE
266
+
267
+ @memballoon_enabled = UNSET_VALUE
268
+ @memballoon_model = UNSET_VALUE
269
+ @memballoon_pci_bus = UNSET_VALUE
270
+ @memballoon_pci_slot = UNSET_VALUE
229
271
 
230
272
  @nic_adapter_count = UNSET_VALUE
231
273
 
@@ -272,7 +314,12 @@ module VagrantPlugins
272
314
  # Attach mgmt network
273
315
  @mgmt_attach = UNSET_VALUE
274
316
 
275
- @qemu_args = []
317
+ # Additional QEMU commandline arguments
318
+ @qemu_args = UNSET_VALUE
319
+
320
+ # Additional QEMU commandline environment variables
321
+ @qemu_env = UNSET_VALUE
322
+
276
323
  @qemu_use_session = UNSET_VALUE
277
324
  end
278
325
 
@@ -305,7 +352,7 @@ module VagrantPlugins
305
352
  end
306
353
  end
307
354
 
308
- # is it better to raise our own error, or let libvirt cause the exception?
355
+ # is it better to raise our own error, or let Libvirt cause the exception?
309
356
  raise 'Only four cdroms may be attached at a time'
310
357
  end
311
358
 
@@ -349,7 +396,29 @@ module VagrantPlugins
349
396
  raise 'Feature name AND state must be specified'
350
397
  end
351
398
 
352
- @features_hyperv = [{name: options[:name], state: options[:state]}] if @features_hyperv == UNSET_VALUE
399
+ @features_hyperv = [] if @features_hyperv == UNSET_VALUE
400
+
401
+ @features_hyperv.push(name: options[:name],
402
+ state: options[:state])
403
+ end
404
+
405
+ def clock_timer(options = {})
406
+ if options[:name].nil?
407
+ raise 'Clock timer name must be specified'
408
+ end
409
+
410
+ options.each do |key, value|
411
+ case key
412
+ when :name, :track, :tickpolicy, :frequency, :mode, :present
413
+ if value.nil?
414
+ raise "Value of timer option #{key} is nil"
415
+ end
416
+ else
417
+ raise "Unknown clock timer option: #{key}"
418
+ end
419
+ end
420
+
421
+ @clock_timers.push(options.dup)
353
422
  end
354
423
 
355
424
  def cputopology(options = {})
@@ -431,7 +500,14 @@ module VagrantPlugins
431
500
 
432
501
  @pcis = [] if @pcis == UNSET_VALUE
433
502
 
434
- @pcis.push(bus: options[:bus],
503
+ if options[:domain].nil?
504
+ pci_domain = '0x0000'
505
+ else
506
+ pci_domain = options[:domain]
507
+ end
508
+
509
+ @pcis.push(domain: pci_domain,
510
+ bus: options[:bus],
435
511
  slot: options[:slot],
436
512
  function: options[:function])
437
513
  end
@@ -517,6 +593,12 @@ module VagrantPlugins
517
593
  @smartcard_dev[:source_service] = options[:source_service] if @smartcard_dev[:type] == 'tcp'
518
594
  end
519
595
 
596
+ # Disk driver options for primary disk
597
+ def disk_driver(options = {})
598
+ supported_opts = [:cache, :io, :copy_on_read, :discard, :detect_zeroes]
599
+ @disk_driver_opts = options.select { |k,_| supported_opts.include? k }
600
+ end
601
+
520
602
  # NOTE: this will run twice for each time it's needed- keep it idempotent
521
603
  def storage(storage_type, options = {})
522
604
  if storage_type == :file
@@ -570,24 +652,55 @@ module VagrantPlugins
570
652
  cache: options[:cache] || 'default',
571
653
  allow_existing: options[:allow_existing],
572
654
  shareable: options[:shareable],
573
- serial: options[:serial]
655
+ serial: options[:serial],
656
+ io: options[:io],
657
+ copy_on_read: options[:copy_on_read],
658
+ discard: options[:discard],
659
+ detect_zeroes: options[:detect_zeroes],
660
+ pool: options[:pool], # overrides storage_pool setting for additional disks
661
+ wwn: options[:wwn],
574
662
  }
575
663
 
576
664
  @disks << disk # append
577
665
  end
578
666
 
579
667
  def qemuargs(options = {})
668
+ @qemu_args = [] if @qemu_args == UNSET_VALUE
669
+
580
670
  @qemu_args << options if options[:value]
581
671
  end
582
672
 
583
- # code to generate URI from a config moved out of the connect action
584
- def _generate_uri
585
- # builds the libvirt connection URI from the given driver config
673
+ def qemuenv(options = {})
674
+ @qemu_env = {} if @qemu_env == UNSET_VALUE
675
+
676
+ @qemu_env.merge!(options)
677
+ end
678
+
679
+ def _default_uri
680
+ # Determine if any settings except driver provided explicitly, if not
681
+ # and the LIBVIRT_DEFAULT_URI var is set, use that.
682
+ #
683
+ # Skipping driver because that may be set on individual boxes rather
684
+ # than by the user.
685
+ if [
686
+ @connect_via_ssh, @host, @username, @password,
687
+ @id_ssh_key_file, @qemu_use_session, @socket,
688
+ ].none?{ |v| v != UNSET_VALUE }
689
+ if ENV.fetch('LIBVIRT_DEFAULT_URI', '') != ""
690
+ @uri = ENV['LIBVIRT_DEFAULT_URI']
691
+ end
692
+ end
693
+ end
694
+
695
+ # code to generate URI from from either the LIBVIRT_URI environment
696
+ # variable or a config moved out of the connect action
697
+ def _generate_uri(qemu_use_session)
698
+ # builds the Libvirt connection URI from the given driver config
586
699
  # Setup connection uri.
587
700
  uri = @driver.dup
588
701
  virt_path = case uri
589
702
  when 'qemu', 'kvm'
590
- @qemu_use_session ? '/session' : '/system'
703
+ qemu_use_session ? '/session' : '/system'
591
704
  when 'openvz', 'uml', 'phyp', 'parallels'
592
705
  '/system'
593
706
  when '@en', 'esx'
@@ -598,46 +711,67 @@ module VagrantPlugins
598
711
  raise "Require specify driver #{uri}"
599
712
  end
600
713
  if uri == 'kvm'
601
- uri = 'qemu' # use qemu uri for kvm domain type
714
+ uri = 'qemu' # use QEMU uri for KVM domain type
602
715
  end
603
716
 
604
- if @connect_via_ssh
717
+ # turn on ssh if an ssh key file is explicitly provided
718
+ if @connect_via_ssh == UNSET_VALUE && @id_ssh_key_file && @id_ssh_key_file != UNSET_VALUE
719
+ @connect_via_ssh = true
720
+ end
721
+
722
+ params = {}
723
+
724
+ if @connect_via_ssh == true
725
+ finalize_id_ssh_key_file
726
+
605
727
  uri << '+ssh://'
606
- uri << @username + '@' if @username
728
+ uri << @username + '@' if @username && @username != UNSET_VALUE
729
+
730
+ uri << ( @host && @host != UNSET_VALUE ? @host : 'localhost' )
607
731
 
608
- uri << if @host
609
- @host
610
- else
611
- 'localhost'
612
- end
732
+ params['no_verify'] = '1'
733
+ params['keyfile'] = @id_ssh_key_file if @id_ssh_key_file
613
734
  else
614
735
  uri << '://'
615
- uri << @host if @host
736
+ uri << @host if @host && @host != UNSET_VALUE
616
737
  end
617
738
 
618
739
  uri << virt_path
619
- uri << '?no_verify=1'
620
740
 
621
- if @id_ssh_key_file
622
- # set ssh key for access to libvirt host
623
- uri << "\&keyfile="
624
- # if no slash, prepend $HOME/.ssh/
625
- @id_ssh_key_file.prepend("#{`echo ${HOME}`.chomp}/.ssh/") if @id_ssh_key_file !~ /\A\//
626
- uri << @id_ssh_key_file
627
- end
628
- # set path to libvirt socket
629
- uri << "\&socket=" + @socket if @socket
741
+ # set path to Libvirt socket
742
+ params['socket'] = @socket if @socket
743
+
744
+ uri << "?" + params.map{|pair| pair.join('=')}.join('&') if !params.empty?
630
745
  uri
631
746
  end
632
747
 
748
+ def _parse_uri(uri)
749
+ begin
750
+ URI.parse(uri)
751
+ rescue
752
+ raise "@uri set to invalid uri '#{uri}'"
753
+ end
754
+ end
755
+
633
756
  def finalize!
757
+ _default_uri if @uri == UNSET_VALUE
758
+
759
+ # settings which _generate_uri
634
760
  @driver = 'kvm' if @driver == UNSET_VALUE
635
- @host = nil if @host == UNSET_VALUE
636
- @connect_via_ssh = false if @connect_via_ssh == UNSET_VALUE
637
- @username = nil if @username == UNSET_VALUE
638
761
  @password = nil if @password == UNSET_VALUE
639
- @id_ssh_key_file = 'id_rsa' if @id_ssh_key_file == UNSET_VALUE
762
+ @socket = nil if @socket == UNSET_VALUE
763
+
764
+ # If uri isn't set then let's build one from various sources.
765
+ # Default to passing false for qemu_use_session if it's not set.
766
+ if @uri == UNSET_VALUE
767
+ @uri = _generate_uri(@qemu_use_session == UNSET_VALUE ? false : @qemu_use_session)
768
+ end
769
+
770
+ finalize_from_uri
771
+ finalize_proxy_command
772
+
640
773
  @storage_pool_name = 'default' if @storage_pool_name == UNSET_VALUE
774
+ @snapshot_pool_name = @storage_pool_name if @snapshot_pool_name == UNSET_VALUE
641
775
  @storage_pool_path = nil if @storage_pool_path == UNSET_VALUE
642
776
  @random_hostname = false if @random_hostname == UNSET_VALUE
643
777
  @management_network_device = 'virbr0' if @management_network_device == UNSET_VALUE
@@ -649,18 +783,18 @@ module VagrantPlugins
649
783
  @management_network_autostart = false if @management_network_autostart == UNSET_VALUE
650
784
  @management_network_pci_bus = nil if @management_network_pci_bus == UNSET_VALUE
651
785
  @management_network_pci_slot = nil if @management_network_pci_slot == UNSET_VALUE
786
+ @management_network_domain = nil if @management_network_domain == UNSET_VALUE
652
787
  @system_uri = 'qemu:///system' if @system_uri == UNSET_VALUE
653
788
 
654
- @qemu_use_session = false if @qemu_use_session == UNSET_VALUE
655
-
656
- # generate a URI if none is supplied
657
- @uri = _generate_uri if @uri == UNSET_VALUE
658
-
659
789
  # Domain specific settings.
790
+ @title = '' if @title == UNSET_VALUE
791
+ @description = '' if @description == UNSET_VALUE
660
792
  @uuid = '' if @uuid == UNSET_VALUE
661
793
  @memory = 512 if @memory == UNSET_VALUE
794
+ @nodeset = nil if @nodeset == UNSET_VALUE
662
795
  @memory_backing = [] if @memory_backing == UNSET_VALUE
663
796
  @cpus = 1 if @cpus == UNSET_VALUE
797
+ @cpuset = nil if @cpuset == UNSET_VALUE
664
798
  @cpu_mode = 'host-model' if @cpu_mode == UNSET_VALUE
665
799
  @cpu_model = if (@cpu_model == UNSET_VALUE) && (@cpu_mode == 'custom')
666
800
  'qemu64'
@@ -672,8 +806,11 @@ module VagrantPlugins
672
806
  @cpu_topology = {} if @cpu_topology == UNSET_VALUE
673
807
  @cpu_fallback = 'allow' if @cpu_fallback == UNSET_VALUE
674
808
  @cpu_features = [] if @cpu_features == UNSET_VALUE
809
+ @shares = nil if @shares == UNSET_VALUE
675
810
  @features = ['acpi','apic','pae'] if @features == UNSET_VALUE
676
811
  @features_hyperv = [] if @features_hyperv == UNSET_VALUE
812
+ @clock_offset = 'utc' if @clock_offset == UNSET_VALUE
813
+ @clock_timers = [] if @clock_timers == UNSET_VALUE
677
814
  @numa_nodes = @numa_nodes == UNSET_VALUE ? nil : _generate_numa
678
815
  @loader = nil if @loader == UNSET_VALUE
679
816
  @nvram = nil if @nvram == UNSET_VALUE
@@ -682,9 +819,10 @@ module VagrantPlugins
682
819
  @machine_virtual_size = nil if @machine_virtual_size == UNSET_VALUE
683
820
  @disk_bus = 'virtio' if @disk_bus == UNSET_VALUE
684
821
  @disk_device = 'vda' if @disk_device == UNSET_VALUE
822
+ @disk_driver_opts = {} if @disk_driver_opts == UNSET_VALUE
685
823
  @nic_model_type = nil if @nic_model_type == UNSET_VALUE
686
824
  @nested = false if @nested == UNSET_VALUE
687
- @volume_cache = 'default' if @volume_cache == UNSET_VALUE
825
+ @volume_cache = nil if @volume_cache == UNSET_VALUE
688
826
  @kernel = nil if @kernel == UNSET_VALUE
689
827
  @cmd_line = '' if @cmd_line == UNSET_VALUE
690
828
  @initrd = '' if @initrd == UNSET_VALUE
@@ -706,6 +844,11 @@ module VagrantPlugins
706
844
  @tpm_model = 'tpm-tis' if @tpm_model == UNSET_VALUE
707
845
  @tpm_type = 'passthrough' if @tpm_type == UNSET_VALUE
708
846
  @tpm_path = nil if @tpm_path == UNSET_VALUE
847
+ @tpm_version = nil if @tpm_version == UNSET_VALUE
848
+ @memballoon_enabled = nil if @memballoon_enabled == UNSET_VALUE
849
+ @memballoon_model = 'virtio' if @memballoon_model == UNSET_VALUE
850
+ @memballoon_pci_bus = '0x00' if @memballoon_pci_bus == UNSET_VALUE
851
+ @memballoon_pci_slot = '0x0f' if @memballoon_pci_slot == UNSET_VALUE
709
852
  @nic_adapter_count = 8 if @nic_adapter_count == UNSET_VALUE
710
853
  @emulator_path = nil if @emulator_path == UNSET_VALUE
711
854
 
@@ -761,12 +904,24 @@ module VagrantPlugins
761
904
  # Attach mgmt network
762
905
  @mgmt_attach = true if @mgmt_attach == UNSET_VALUE
763
906
 
907
+ # Additional QEMU commandline arguments
764
908
  @qemu_args = [] if @qemu_args == UNSET_VALUE
909
+
910
+ # Additional QEMU commandline environment variables
911
+ @qemu_env = {} if @qemu_env == UNSET_VALUE
765
912
  end
766
913
 
767
914
  def validate(machine)
768
915
  errors = _detected_errors
769
916
 
917
+ # The @uri and @qemu_use_session should not conflict
918
+ uri = _parse_uri(@uri)
919
+ if (uri.scheme.start_with? "qemu") && (uri.path.include? "session")
920
+ if @qemu_use_session != true
921
+ errors << "the URI and qemu_use_session configuration conflict: uri:'#{@uri}' qemu_use_session:'#{@qemu_use_session}'"
922
+ end
923
+ end
924
+
770
925
  machine.provider_config.disks.each do |disk|
771
926
  if disk[:path] && (disk[:path][0] == '/')
772
927
  errors << "absolute volume paths like '#{disk[:path]}' not yet supported"
@@ -785,6 +940,14 @@ module VagrantPlugins
785
940
  end
786
941
  end
787
942
 
943
+ if !machine.provider_config.volume_cache.nil? and machine.provider_config.volume_cache != UNSET_VALUE
944
+ machine.ui.warn("Libvirt Provider: volume_cache is deprecated. Use disk_driver :cache => '#{machine.provider_config.volume_cache}' instead.")
945
+
946
+ if !machine.provider_config.disk_driver_opts.empty?
947
+ machine.ui.warn("Libvirt Provider: volume_cache has no effect when disk_driver is defined.")
948
+ end
949
+ end
950
+
788
951
  { 'Libvirt Provider' => errors }
789
952
  end
790
953
 
@@ -797,6 +960,95 @@ module VagrantPlugins
797
960
  c = cdroms.dup
798
961
  c += other.cdroms
799
962
  result.cdroms = c
963
+
964
+ result.disk_driver_opts = disk_driver_opts.merge(other.disk_driver_opts)
965
+
966
+ c = clock_timers.dup
967
+ c += other.clock_timers
968
+ result.clock_timers = c
969
+
970
+ c = qemu_env != UNSET_VALUE ? qemu_env.dup : {}
971
+ c.merge!(other.qemu_env) if other.qemu_env != UNSET_VALUE
972
+ result.qemu_env = c
973
+ end
974
+ end
975
+
976
+ private
977
+
978
+ def finalize_from_uri
979
+ # Parse uri to extract individual components
980
+ uri = _parse_uri(@uri)
981
+
982
+ # only set @connect_via_ssh if not explicitly to avoid overriding
983
+ # and allow an error to occur if the @uri and @connect_via_ssh disagree
984
+ @connect_via_ssh = uri.scheme.include? "ssh" if @connect_via_ssh == UNSET_VALUE
985
+
986
+ # Set qemu_use_session based on the URI if it wasn't set by the user
987
+ if @qemu_use_session == UNSET_VALUE
988
+ if (uri.scheme.start_with? "qemu") && (uri.path.include? "session")
989
+ @qemu_use_session = true
990
+ else
991
+ @qemu_use_session = false
992
+ end
993
+ end
994
+
995
+ # Extract host and username values from uri if provided, otherwise nil
996
+ @host = uri.host
997
+ @username = uri.user
998
+
999
+ finalize_id_ssh_key_file
1000
+ end
1001
+
1002
+ def resolve_ssh_key_file(key_file)
1003
+ # set ssh key for access to Libvirt host
1004
+ # if no slash, prepend $HOME/.ssh/
1005
+ key_file.prepend("#{ENV['HOME']}/.ssh/") if key_file && key_file !~ /\A\//
1006
+
1007
+ key_file
1008
+ end
1009
+
1010
+ def finalize_id_ssh_key_file
1011
+ # resolve based on the following roles
1012
+ # 1) if @connect_via_ssh is set to true, and id_ssh_key_file not current set,
1013
+ # set default if the file exists
1014
+ # 2) if supplied the key name, attempt to expand based on user home
1015
+ # 3) otherwise set to nil
1016
+
1017
+ if @connect_via_ssh == true && @id_ssh_key_file == UNSET_VALUE
1018
+ # set default if using ssh while allowing a user using nil to disable this
1019
+ id_ssh_key_file = resolve_ssh_key_file('id_rsa')
1020
+ id_ssh_key_file = nil if !File.file?(id_ssh_key_file)
1021
+ elsif @id_ssh_key_file != UNSET_VALUE
1022
+ id_ssh_key_file = resolve_ssh_key_file(@id_ssh_key_file)
1023
+ else
1024
+ id_ssh_key_file = nil
1025
+ end
1026
+
1027
+ @id_ssh_key_file = id_ssh_key_file
1028
+ end
1029
+
1030
+ def finalize_proxy_command
1031
+ if @connect_via_ssh
1032
+ if @proxy_command == UNSET_VALUE
1033
+ proxy_command = "ssh '#{@host}' "
1034
+ proxy_command << "-l '#{@username}' " if @username
1035
+ proxy_command << "-i '#{@id_ssh_key_file}' " if @id_ssh_key_file
1036
+ proxy_command << '-W %h:%p'
1037
+ else
1038
+ inputs = { host: @host }
1039
+ inputs[:username] = @username if @username
1040
+ inputs[:id_ssh_key_file] = @id_ssh_key_file if @id_ssh_key_file
1041
+
1042
+ proxy_command = @proxy_command
1043
+ # avoid needing to escape '%' symbols
1044
+ inputs.each do |key, value|
1045
+ proxy_command.gsub!("{#{key}}", value)
1046
+ end
1047
+ end
1048
+
1049
+ @proxy_command = proxy_command
1050
+ else
1051
+ @proxy_command = nil
800
1052
  end
801
1053
  end
802
1054
  end