vagrant-libvirt 0.3.0 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +421 -50
  3. data/lib/vagrant-libvirt/action.rb +7 -1
  4. data/lib/vagrant-libvirt/action/clean_machine_folder.rb +30 -0
  5. data/lib/vagrant-libvirt/action/create_domain.rb +56 -18
  6. data/lib/vagrant-libvirt/action/create_domain_volume.rb +57 -55
  7. data/lib/vagrant-libvirt/action/create_network_interfaces.rb +0 -3
  8. data/lib/vagrant-libvirt/action/create_networks.rb +11 -4
  9. data/lib/vagrant-libvirt/action/destroy_domain.rb +1 -1
  10. data/lib/vagrant-libvirt/action/forward_ports.rb +37 -38
  11. data/lib/vagrant-libvirt/action/halt_domain.rb +25 -9
  12. data/lib/vagrant-libvirt/action/handle_box_image.rb +163 -74
  13. data/lib/vagrant-libvirt/action/is_running.rb +1 -3
  14. data/lib/vagrant-libvirt/action/is_suspended.rb +4 -4
  15. data/lib/vagrant-libvirt/action/package_domain.rb +2 -1
  16. data/lib/vagrant-libvirt/action/set_boot_order.rb +6 -2
  17. data/lib/vagrant-libvirt/action/start_domain.rb +86 -29
  18. data/lib/vagrant-libvirt/action/wait_till_up.rb +8 -52
  19. data/lib/vagrant-libvirt/cap/{mount_p9.rb → mount_9p.rb} +2 -2
  20. data/lib/vagrant-libvirt/cap/mount_virtiofs.rb +37 -0
  21. data/lib/vagrant-libvirt/cap/{synced_folder.rb → synced_folder_9p.rb} +4 -5
  22. data/lib/vagrant-libvirt/cap/synced_folder_virtiofs.rb +109 -0
  23. data/lib/vagrant-libvirt/config.rb +236 -43
  24. data/lib/vagrant-libvirt/driver.rb +49 -32
  25. data/lib/vagrant-libvirt/errors.rb +24 -1
  26. data/lib/vagrant-libvirt/plugin.rb +14 -5
  27. data/lib/vagrant-libvirt/provider.rb +2 -9
  28. data/lib/vagrant-libvirt/templates/domain.xml.erb +35 -10
  29. data/lib/vagrant-libvirt/templates/private_network.xml.erb +1 -1
  30. data/lib/vagrant-libvirt/util/network_util.rb +21 -3
  31. data/lib/vagrant-libvirt/version +1 -1
  32. data/lib/vagrant-libvirt/version.rb +57 -9
  33. data/locales/en.yml +12 -0
  34. data/spec/spec_helper.rb +37 -3
  35. data/spec/support/binding_proc.rb +24 -0
  36. data/spec/support/libvirt_context.rb +2 -0
  37. data/spec/support/matchers/have_file_content.rb +63 -0
  38. data/spec/support/sharedcontext.rb +4 -0
  39. data/spec/unit/action/clean_machine_folder_spec.rb +58 -0
  40. data/spec/unit/action/create_domain_spec.rb +121 -36
  41. data/spec/unit/action/create_domain_spec/additional_disks_domain.xml +54 -0
  42. data/spec/unit/action/create_domain_spec/default_domain.xml +49 -0
  43. data/spec/unit/action/create_domain_spec/{default_storage_pool.xml → default_system_storage_pool.xml} +0 -0
  44. data/spec/unit/action/create_domain_spec/default_user_storage_pool.xml +17 -0
  45. data/spec/unit/action/create_domain_volume_spec.rb +102 -0
  46. data/spec/unit/action/create_domain_volume_spec/one_disk_in_storage.xml +21 -0
  47. data/spec/unit/action/create_domain_volume_spec/three_disks_in_storage_disk_0.xml +21 -0
  48. data/spec/unit/action/create_domain_volume_spec/three_disks_in_storage_disk_1.xml +21 -0
  49. data/spec/unit/action/create_domain_volume_spec/three_disks_in_storage_disk_2.xml +21 -0
  50. data/spec/unit/action/destroy_domain_spec.rb +1 -1
  51. data/spec/unit/action/forward_ports_spec.rb +202 -0
  52. data/spec/unit/action/halt_domain_spec.rb +90 -0
  53. data/spec/unit/action/handle_box_image_spec.rb +363 -0
  54. data/spec/unit/action/start_domain_spec.rb +183 -1
  55. data/spec/unit/action/start_domain_spec/clock_timer_rtc.xml +50 -0
  56. data/spec/unit/action/start_domain_spec/default.xml +2 -2
  57. data/spec/unit/action/start_domain_spec/default_added_tpm_path.xml +48 -0
  58. data/spec/unit/action/start_domain_spec/default_added_tpm_version.xml +48 -0
  59. data/spec/unit/action/wait_till_up_spec.rb +22 -21
  60. data/spec/unit/config_spec.rb +395 -127
  61. data/spec/unit/templates/domain_all_settings.xml +14 -3
  62. data/spec/unit/templates/domain_custom_cpu_model.xml +2 -1
  63. data/spec/unit/templates/domain_defaults.xml +2 -1
  64. data/spec/unit/templates/domain_spec.rb +100 -3
  65. data/spec/unit/templates/tpm/version_1.2.xml +54 -0
  66. data/spec/unit/templates/tpm/version_2.0.xml +53 -0
  67. metadata +105 -19
@@ -49,6 +49,7 @@ module VagrantPlugins
49
49
 
50
50
  b2.use StartDomain
51
51
  b2.use WaitTillUp
52
+ b2.use WaitForCommunicator, [:running]
52
53
 
53
54
  b2.use ForwardPorts
54
55
  b2.use SetHostname
@@ -107,6 +108,7 @@ module VagrantPlugins
107
108
  # Machine should gain IP address when comming up,
108
109
  # so wait for dhcp lease and store IP into machines data_dir.
109
110
  b3.use WaitTillUp
111
+ b3.use WaitForCommunicator, [:running]
110
112
 
111
113
  b3.use ForwardPorts
112
114
  b3.use PrepareNFSSettings
@@ -179,6 +181,7 @@ module VagrantPlugins
179
181
  # Try to remove stale volumes anyway
180
182
  b2.use SetNameOfDomain
181
183
  b2.use RemoveStaleVolume if env[:machine].config.vm.box
184
+ b2.use CleanMachineFolder, quiet: true
182
185
  b2.use MessageNotCreated unless env[:result]
183
186
 
184
187
  next
@@ -186,11 +189,12 @@ module VagrantPlugins
186
189
 
187
190
  b2.use Call, DestroyConfirm do |env2, b3|
188
191
  if env2[:result]
192
+ b3.use ProvisionerCleanup, :before
189
193
  b3.use ClearForwardedPorts
190
194
  b3.use PruneNFSExports
191
195
  b3.use DestroyDomain
192
196
  b3.use DestroyNetworks
193
- b3.use ProvisionerCleanup
197
+ b3.use CleanMachineFolder
194
198
  else
195
199
  b3.use MessageWillNotDestroy
196
200
  end
@@ -324,6 +328,7 @@ module VagrantPlugins
324
328
  autoload :CreateDomainVolume, action_root.join('create_domain_volume')
325
329
  autoload :CreateNetworkInterfaces, action_root.join('create_network_interfaces')
326
330
  autoload :CreateNetworks, action_root.join('create_networks')
331
+ autoload :CleanMachineFolder, action_root.join('clean_machine_folder')
327
332
  autoload :DestroyDomain, action_root.join('destroy_domain')
328
333
  autoload :DestroyNetworks, action_root.join('destroy_networks')
329
334
  autoload :ForwardPorts, action_root.join('forward_ports')
@@ -366,6 +371,7 @@ module VagrantPlugins
366
371
  autoload :SyncedFolders, 'vagrant/action/builtin/synced_folders'
367
372
  autoload :SyncedFolderCleanup, 'vagrant/action/builtin/synced_folder_cleanup'
368
373
  autoload :ProvisionerCleanup, 'vagrant/action/builtin/provisioner_cleanup'
374
+ autoload :WaitForCommunicator, 'vagrant/action/builtin/wait_for_communicator'
369
375
  end
370
376
  end
371
377
  end
@@ -0,0 +1,30 @@
1
+ require 'log4r'
2
+
3
+ module VagrantPlugins
4
+ module ProviderLibvirt
5
+ module Action
6
+ class CleanMachineFolder
7
+
8
+ def initialize(app, env, options=nil)
9
+ @logger = Log4r::Logger.new('vagrant_libvirt::action::create_domain')
10
+ @app = app
11
+ @ui = env[:ui]
12
+ @quiet = (options || {}).fetch(:quiet, false)
13
+ end
14
+
15
+ def call(env)
16
+ machine_folder = env[:machine].data_dir
17
+
18
+ @ui.info("Deleting the machine folder") unless @quiet
19
+
20
+ @logger.debug("Recursively removing: #{machine_folder}")
21
+ FileUtils.rm_rf(machine_folder, :secure => true)
22
+ # need to recreate to prevent exception during a cancelled up
23
+ FileUtils.mkdir_p(machine_folder)
24
+
25
+ @app.call(env)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -5,6 +5,7 @@ module VagrantPlugins
5
5
  module Action
6
6
  class CreateDomain
7
7
  include VagrantPlugins::ProviderLibvirt::Util::ErbTemplate
8
+ include VagrantPlugins::ProviderLibvirt::Util::StorageUtil
8
9
 
9
10
  def initialize(app, _env)
10
11
  @logger = Log4r::Logger.new('vagrant_libvirt::action::create_domain')
@@ -32,7 +33,8 @@ module VagrantPlugins
32
33
  # Gather some info about domain
33
34
  @name = env[:domain_name]
34
35
  @title = config.title
35
- @description = config.description
36
+ vagrantfile = File.join(env[:root_path], (env[:vagrantfile_name] || "Vagrantfile"))
37
+ @description = !config.description.empty? ? config.description : "Source: #{vagrantfile}"
36
38
  @uuid = config.uuid
37
39
  @cpus = config.cpus.to_i
38
40
  @cpuset = config.cpuset
@@ -41,6 +43,8 @@ module VagrantPlugins
41
43
  @nodeset = config.nodeset
42
44
  @features = config.features
43
45
  @features_hyperv = config.features_hyperv
46
+ @clock_offset = config.clock_offset
47
+ @clock_timers = config.clock_timers
44
48
  @shares = config.shares
45
49
  @cpu_mode = config.cpu_mode
46
50
  @cpu_model = config.cpu_model
@@ -52,11 +56,12 @@ module VagrantPlugins
52
56
  @machine_arch = config.machine_arch
53
57
  @disk_bus = config.disk_bus
54
58
  @disk_device = config.disk_device
59
+ @disk_driver_opts = config.disk_driver_opts
55
60
  @nested = config.nested
56
61
  @memory_size = config.memory.to_i * 1024
57
62
  @memory_backing = config.memory_backing
58
63
  @management_network_mac = config.management_network_mac
59
- @domain_volume_cache = config.volume_cache
64
+ @domain_volume_cache = config.volume_cache || 'default'
60
65
  @kernel = config.kernel
61
66
  @cmd_line = config.cmd_line
62
67
  @emulator_path = config.emulator_path
@@ -80,6 +85,7 @@ module VagrantPlugins
80
85
  @tpm_model = config.tpm_model
81
86
  @tpm_type = config.tpm_type
82
87
  @tpm_path = config.tpm_path
88
+ @tpm_version = config.tpm_version
83
89
 
84
90
  # Boot order
85
91
  @boot_order = config.boot_order
@@ -87,6 +93,7 @@ module VagrantPlugins
87
93
  # Storage
88
94
  @storage_pool_name = config.storage_pool_name
89
95
  @snapshot_pool_name = config.snapshot_pool_name
96
+ @domain_volumes = []
90
97
  @disks = config.disks
91
98
  @cdroms = config.cdroms
92
99
 
@@ -136,23 +143,30 @@ module VagrantPlugins
136
143
  else
137
144
  pool_name = @storage_pool_name
138
145
  end
139
- @logger.debug "Search for volume in pool: #{pool_name}"
140
- domain_volume = env[:machine].provider.driver.connection.volumes.all(
141
- name: "#{@name}.img"
142
- ).find { |x| x.pool_name == pool_name }
143
- raise Errors::DomainVolumeExists if domain_volume.nil?
144
- @domain_volume_path = domain_volume.path
146
+ @logger.debug "Search for volumes in pool: #{pool_name}"
147
+ env[:box_volumes].each_index do |index|
148
+ suffix_index = index > 0 ? "_#{index}" : ''
149
+ domain_volume = env[:machine].provider.driver.connection.volumes.all(
150
+ name: "#{@name}#{suffix_index}.img"
151
+ ).find { |x| x.pool_name == pool_name }
152
+ raise Errors::DomainVolumeExists if domain_volume.nil?
153
+ @domain_volumes.push({
154
+ :dev => (index+1).vdev.to_s,
155
+ :cache => @domain_volume_cache,
156
+ :bus => @disk_bus,
157
+ :path => domain_volume.path,
158
+ :virtual_size => env[:box_volumes][index][:virtual_size]
159
+ })
160
+ end
145
161
  end
146
162
 
147
163
  # If we have a box, take the path from the domain volume and set our storage_prefix.
148
164
  # If not, we dump the storage pool xml to get its defined path.
149
165
  # the default storage prefix is typically: /var/lib/libvirt/images/
150
- if !config.qemu_use_session
151
- if env[:machine].config.vm.box
152
- storage_prefix = File.dirname(@domain_volume_path) + '/' # steal
153
- else
154
- storage_prefix = get_disk_storage_prefix(env, @storage_pool_name)
155
- end
166
+ if env[:machine].config.vm.box
167
+ storage_prefix = File.dirname(@domain_volumes[0][:path]) + '/' # steal
168
+ else
169
+ storage_prefix = get_disk_storage_prefix(env, @storage_pool_name)
156
170
  end
157
171
 
158
172
  @disks.each do |disk|
@@ -184,6 +198,8 @@ module VagrantPlugins
184
198
  format_type: disk[:type],
185
199
  path: disk[:absolute_path],
186
200
  capacity: disk[:size],
201
+ owner: storage_uid(env),
202
+ group: storage_gid(env),
187
203
  #:allocation => ?,
188
204
  pool_name: disk_pool_name
189
205
  )
@@ -222,7 +238,15 @@ module VagrantPlugins
222
238
  env[:ui].info(" -- Feature: #{feature}")
223
239
  end
224
240
  @features_hyperv.each do |feature|
225
- env[:ui].info(" -- Feature (HyperV): name=#{feature[:name]}, state=#{feature[:state]}")
241
+ if feature[:name] == 'spinlocks'
242
+ env[:ui].info(" -- Feature (HyperV): name=#{feature[:name]}, state=#{feature[:state]}, retries=#{feature[:retries]}")
243
+ else
244
+ env[:ui].info(" -- Feature (HyperV): name=#{feature[:name]}, state=#{feature[:state]}")
245
+ end
246
+ end
247
+ env[:ui].info(" -- Clock offset: #{@clock_offset}")
248
+ @clock_timers.each do |timer|
249
+ env[:ui].info(" -- Clock timer: #{timer.map { |k,v| "#{k}=#{v}"}.join(', ')}")
226
250
  end
227
251
  env[:ui].info(" -- Memory: #{@memory_size / 1024}M")
228
252
  unless @nodeset.nil?
@@ -241,8 +265,16 @@ module VagrantPlugins
241
265
  env[:ui].info(" -- Base box: #{env[:machine].box.name}")
242
266
  end
243
267
  env[:ui].info(" -- Storage pool: #{@storage_pool_name}")
244
- env[:ui].info(" -- Image: #{@domain_volume_path} (#{env[:box_virtual_size]}G)")
245
- env[:ui].info(" -- Volume Cache: #{@domain_volume_cache}")
268
+ @domain_volumes.each do |volume|
269
+ env[:ui].info(" -- Image(#{volume[:device]}): #{volume[:path]}, #{volume[:virtual_size]}G")
270
+ end
271
+
272
+ if not @disk_driver_opts.empty?
273
+ env[:ui].info(" -- Disk driver opts: #{@disk_driver_opts.reject { |k,v| v.nil? }.map { |k,v| "#{k}='#{v}'"}.join(' ')}")
274
+ else
275
+ env[:ui].info(" -- Disk driver opts: cache='#{@domain_volume_cache}'")
276
+ end
277
+
246
278
  env[:ui].info(" -- Kernel: #{@kernel}")
247
279
  env[:ui].info(" -- Initrd: #{@initrd}")
248
280
  env[:ui].info(" -- Graphics Type: #{@graphics_type}")
@@ -253,7 +285,13 @@ module VagrantPlugins
253
285
  env[:ui].info(" -- Video VRAM: #{@video_vram}")
254
286
  env[:ui].info(" -- Sound Type: #{@sound_type}")
255
287
  env[:ui].info(" -- Keymap: #{@keymap}")
256
- env[:ui].info(" -- TPM Path: #{@tpm_path}")
288
+ env[:ui].info(" -- TPM Backend: #{@tpm_type}")
289
+ if @tpm_type == 'emulator'
290
+ env[:ui].info(" -- TPM Model: #{@tpm_model}")
291
+ env[:ui].info(" -- TPM Version: #{@tpm_version}")
292
+ else
293
+ env[:ui].info(" -- TPM Path: #{@tpm_path}")
294
+ end
257
295
 
258
296
  @boot_order.each do |device|
259
297
  env[:ui].info(" -- Boot device: #{device}")
@@ -18,72 +18,74 @@ module VagrantPlugins
18
18
  def call(env)
19
19
  env[:ui].info(I18n.t('vagrant_libvirt.creating_domain_volume'))
20
20
 
21
- # Get config options.
22
- config = env[:machine].provider_config
21
+ env[:box_volumes].each_index do |index|
22
+ suffix_index = index > 0 ? "_#{index}" : ''
23
+ # Get config options.
24
+ config = env[:machine].provider_config
23
25
 
24
- # This is name of newly created image for vm.
25
- @name = "#{env[:domain_name]}.img"
26
+ # This is name of newly created image for vm.
27
+ @name = "#{env[:domain_name]}#{suffix_index}.img"
26
28
 
27
- # Verify the volume doesn't exist already.
28
- domain_volume = env[:machine].provider.driver.connection.volumes.all(
29
- name: @name
30
- ).first
31
- raise Errors::DomainVolumeExists if domain_volume && domain_volume.id
29
+ # Verify the volume doesn't exist already.
30
+ domain_volume = env[:machine].provider.driver.connection.volumes.all(
31
+ name: @name
32
+ ).first
33
+ raise Errors::DomainVolumeExists if domain_volume && domain_volume.id
32
34
 
33
- # Get path to backing image - box volume.
34
- box_volume = env[:machine].provider.driver.connection.volumes.all(
35
- name: env[:box_volume_name]
36
- ).first
37
- @backing_file = box_volume.path
35
+ # Get path to backing image - box volume.
36
+ box_volume = env[:machine].provider.driver.connection.volumes.all(
37
+ name: env[:box_volumes][index][:name]
38
+ ).first
39
+ @backing_file = box_volume.path
38
40
 
39
- # Virtual size of image. Take value worked out by HandleBoxImage
40
- @capacity = env[:box_virtual_size] # G
41
+ # Virtual size of image. Take value worked out by HandleBoxImage
42
+ @capacity = env[:box_volumes][index][:virtual_size] # G
41
43
 
42
- # Create new volume from xml template. Fog currently doesn't support
43
- # volume snapshots directly.
44
- begin
45
- xml = Nokogiri::XML::Builder.new do |xml|
46
- xml.volume do
47
- xml.name(@name)
48
- xml.capacity(@capacity, unit: 'G')
49
- xml.target do
50
- xml.format(type: 'qcow2')
51
- xml.permissions do
52
- xml.owner storage_uid(env)
53
- xml.group storage_gid(env)
54
- xml.label 'virt_image_t'
44
+ # Create new volume from xml template. Fog currently doesn't support
45
+ # volume snapshots directly.
46
+ begin
47
+ xml = Nokogiri::XML::Builder.new do |xml|
48
+ xml.volume do
49
+ xml.name(@name)
50
+ xml.capacity(@capacity, unit: 'G')
51
+ xml.target do
52
+ xml.format(type: 'qcow2')
53
+ xml.permissions do
54
+ xml.owner storage_uid(env)
55
+ xml.group storage_gid(env)
56
+ xml.label 'virt_image_t'
57
+ end
55
58
  end
56
- end
57
- xml.backingStore do
58
- xml.path(@backing_file)
59
- xml.format(type: 'qcow2')
60
- xml.permissions do
61
- xml.owner storage_uid(env)
62
- xml.group storage_gid(env)
63
- xml.label 'virt_image_t'
59
+ xml.backingStore do
60
+ xml.path(@backing_file)
61
+ xml.format(type: 'qcow2')
62
+ xml.permissions do
63
+ xml.owner storage_uid(env)
64
+ xml.group storage_gid(env)
65
+ xml.label 'virt_image_t'
66
+ end
64
67
  end
65
68
  end
69
+ end.to_xml(
70
+ save_with: Nokogiri::XML::Node::SaveOptions::NO_DECLARATION |
71
+ Nokogiri::XML::Node::SaveOptions::NO_EMPTY_TAGS |
72
+ Nokogiri::XML::Node::SaveOptions::FORMAT
73
+ )
74
+ if config.snapshot_pool_name != config.storage_pool_name
75
+ pool_name = config.snapshot_pool_name
76
+ else
77
+ pool_name = config.storage_pool_name
66
78
  end
67
- end.to_xml(
68
- save_with: Nokogiri::XML::Node::SaveOptions::NO_DECLARATION |
69
- Nokogiri::XML::Node::SaveOptions::NO_EMPTY_TAGS |
70
- Nokogiri::XML::Node::SaveOptions::FORMAT
71
- )
72
- if config.snapshot_pool_name != config.storage_pool_name
73
- pool_name = config.snapshot_pool_name
74
- else
75
- pool_name = config.storage_pool_name
79
+ @logger.debug "Using pool #{pool_name} for base box snapshot"
80
+ domain_volume = env[:machine].provider.driver.connection.volumes.create(
81
+ xml: xml,
82
+ pool_name: pool_name
83
+ )
84
+ rescue Fog::Errors::Error => e
85
+ raise Errors::FogDomainVolumeCreateError,
86
+ error_message: e.message
76
87
  end
77
- @logger.debug "Using pool #{pool_name} for base box snapshot"
78
- domain_volume = env[:machine].provider.driver.connection.volumes.create(
79
- xml: xml,
80
- pool_name: pool_name
81
- )
82
- rescue Fog::Errors::Error => e
83
- raise Errors::FogDomainVolumeCreateError,
84
- error_message: e.message
85
88
  end
86
-
87
89
  @app.call(env)
88
90
  end
89
91
  end
@@ -214,9 +214,6 @@ module VagrantPlugins
214
214
  network[:type] = :dhcp
215
215
  end
216
216
 
217
- # do not run configure_networks for tcp tunnel interfaces
218
- next if options.fetch(:tunnel_type, nil)
219
-
220
217
  networks_to_configure << network
221
218
  end
222
219
 
@@ -54,6 +54,8 @@ module VagrantPlugins
54
54
  env[:machine].provider.driver.connection.client
55
55
  )
56
56
 
57
+ current_network = @available_networks.detect { |network| network[:name] == @options[:network_name] }
58
+
57
59
  # Prepare a hash describing network for this specific interface.
58
60
  @interface_network = {
59
61
  name: nil,
@@ -64,11 +66,11 @@ module VagrantPlugins
64
66
  domain_name: nil,
65
67
  ipv6_address: options[:ipv6_address] || nil,
66
68
  ipv6_prefix: options[:ipv6_prefix] || nil,
67
- created: false,
68
- active: false,
69
+ created: current_network.nil? ? false : true,
70
+ active: current_network.nil? ? false : current_network[:active],
69
71
  autostart: options[:autostart] || false,
70
72
  guest_ipv6: @options[:guest_ipv6] || 'yes',
71
- libvirt_network: nil
73
+ libvirt_network: current_network.nil? ? nil : current_network[:libvirt_network]
72
74
  }
73
75
 
74
76
  if @options[:ip]
@@ -255,7 +257,9 @@ module VagrantPlugins
255
257
 
256
258
  # Do we need to create new network?
257
259
  unless @interface_network[:created]
258
- @interface_network[:name] = 'vagrant-private-dhcp'
260
+ @interface_network[:name] = @options[:network_name] ?
261
+ @options[:network_name] :
262
+ 'vagrant-private-dhcp'
259
263
  @interface_network[:network_address] = net_address
260
264
 
261
265
  # Set IP address of network (actually bridge). It will be used as
@@ -297,6 +301,9 @@ module VagrantPlugins
297
301
 
298
302
  @network_ipv6_address = @interface_network[:ipv6_address]
299
303
  @network_ipv6_prefix = @interface_network[:ipv6_prefix]
304
+
305
+ @network_bridge_stp = @options[:bridge_stp].nil? || @options[:bridge_stp] ? 'on' : 'off'
306
+ @network_bridge_delay = @options[:bridge_delay] ? @options[:bridge_delay] : 0
300
307
 
301
308
  @network_forward_mode = @options[:forward_mode]
302
309
  if @options[:forward_device]
@@ -70,7 +70,7 @@ module VagrantPlugins
70
70
 
71
71
  # remove root storage
72
72
  root_disk = domain.volumes.select do |x|
73
- x.name == libvirt_domain.name + '.img'
73
+ x.name == libvirt_domain.name + '.img' if x
74
74
  end.first
75
75
  root_disk.destroy if root_disk
76
76
  end
@@ -11,10 +11,8 @@ module VagrantPlugins
11
11
  end
12
12
 
13
13
  def call(env)
14
- @env = env
15
-
16
14
  # Get the ports we're forwarding
17
- env[:forwarded_ports] = compile_forwarded_ports(env[:machine].config)
15
+ env[:forwarded_ports] = compile_forwarded_ports(env, env[:machine].config)
18
16
 
19
17
  # Warn if we're port forwarding to any privileged ports
20
18
  env[:forwarded_ports].each do |fp|
@@ -28,51 +26,52 @@ module VagrantPlugins
28
26
  # Continue, we need the VM to be booted in order to grab its IP
29
27
  @app.call env
30
28
 
31
- if @env[:forwarded_ports].any?
29
+ if env[:forwarded_ports].any?
32
30
  env[:ui].info I18n.t('vagrant.actions.vm.forward_ports.forwarding')
33
- forward_ports
31
+ forward_ports(env)
34
32
  end
35
33
  end
36
34
 
37
- def forward_ports
38
- @env[:forwarded_ports].each do |fp|
35
+ def forward_ports(env)
36
+ env[:forwarded_ports].each do |fp|
39
37
  message_attributes = {
40
38
  adapter: fp[:adapter] || 'eth0',
41
39
  guest_port: fp[:guest],
42
40
  host_port: fp[:host]
43
41
  }
44
42
 
45
- @env[:ui].info(I18n.t(
43
+ env[:ui].info(I18n.t(
46
44
  'vagrant.actions.vm.forward_ports.forwarding_entry',
47
- message_attributes
45
+ **message_attributes
48
46
  ))
49
47
 
50
- if fp[:protocol] == 'udp'
51
- @env[:ui].warn I18n.t('vagrant_libvirt.warnings.forwarding_udp')
52
- next
53
- end
54
-
55
48
  ssh_pid = redirect_port(
56
- @env[:machine],
49
+ env,
50
+ env[:machine],
57
51
  fp[:host_ip] || '*',
58
52
  fp[:host],
59
- fp[:guest_ip] || @env[:machine].provider.ssh_info[:host],
53
+ fp[:guest_ip] || env[:machine].provider.ssh_info[:host],
60
54
  fp[:guest],
61
55
  fp[:gateway_ports] || false
62
56
  )
63
- store_ssh_pid(fp[:host], ssh_pid)
57
+ store_ssh_pid(env[:machine], fp[:host], ssh_pid)
64
58
  end
65
59
  end
66
60
 
67
61
  private
68
62
 
69
- def compile_forwarded_ports(config)
63
+ def compile_forwarded_ports(env, config)
70
64
  mappings = {}
71
65
 
72
66
  config.vm.networks.each do |type, options|
73
67
  next if options[:disabled]
74
68
 
75
- next unless type == :forwarded_port && options[:id] != 'ssh'
69
+ if options[:protocol] == 'udp'
70
+ env[:ui].warn I18n.t('vagrant_libvirt.warnings.forwarding_udp')
71
+ next
72
+ end
73
+
74
+ next if type != :forwarded_port || ( options[:id] == 'ssh' && !env[:machine].provider_config.forward_ssh_port )
76
75
  if options.fetch(:host_ip, '').to_s.strip.empty?
77
76
  options.delete(:host_ip)
78
77
  end
@@ -82,7 +81,7 @@ module VagrantPlugins
82
81
  mappings.values
83
82
  end
84
83
 
85
- def redirect_port(machine, host_ip, host_port, guest_ip, guest_port,
84
+ def redirect_port(env, machine, host_ip, host_port, guest_ip, guest_port,
86
85
  gateway_ports)
87
86
  ssh_info = machine.ssh_info
88
87
  params = %W(
@@ -107,14 +106,14 @@ module VagrantPlugins
107
106
  "IdentityFile='\"#{pk}\"'"
108
107
  end).map { |s| s.prepend('-o ') }.join(' ')
109
108
 
110
- options += " -o ProxyCommand=\"#{ssh_info[:proxy_command]}\"" if machine.provider_config.connect_via_ssh
109
+ options += " -o ProxyCommand=\"#{ssh_info[:proxy_command]}\"" if machine.provider_config.proxy_command
111
110
 
112
111
  # TODO: instead of this, try and lock and get the stdin from spawn...
113
112
  ssh_cmd = ''
114
113
  if host_port <= 1024
115
114
  @@lock.synchronize do
116
115
  # TODO: add i18n
117
- @env[:ui].info 'Requesting sudo for host port(s) <= 1024'
116
+ env[:ui].info 'Requesting sudo for host port(s) <= 1024'
118
117
  r = system('sudo -v')
119
118
  if r
120
119
  ssh_cmd << 'sudo ' # add sudo prefix
@@ -125,14 +124,15 @@ module VagrantPlugins
125
124
  ssh_cmd << "ssh -n #{options} #{params}"
126
125
 
127
126
  @logger.debug "Forwarding port with `#{ssh_cmd}`"
128
- log_file = ssh_forward_log_file(host_ip, host_port,
129
- guest_ip, guest_port)
127
+ log_file = ssh_forward_log_file(
128
+ env[:machine], host_ip, host_port, guest_ip, guest_port,
129
+ )
130
130
  @logger.info "Logging to #{log_file}"
131
131
  spawn(ssh_cmd, [:out, :err] => [log_file, 'w'], :pgroup => true)
132
132
  end
133
133
 
134
- def ssh_forward_log_file(host_ip, host_port, guest_ip, guest_port)
135
- log_dir = @env[:machine].data_dir.join('logs')
134
+ def ssh_forward_log_file(machine, host_ip, host_port, guest_ip, guest_port)
135
+ log_dir = machine.data_dir.join('logs')
136
136
  log_dir.mkdir unless log_dir.directory?
137
137
  File.join(
138
138
  log_dir,
@@ -141,8 +141,8 @@ module VagrantPlugins
141
141
  )
142
142
  end
143
143
 
144
- def store_ssh_pid(host_port, ssh_pid)
145
- data_dir = @env[:machine].data_dir.join('pids')
144
+ def store_ssh_pid(machine, host_port, ssh_pid)
145
+ data_dir = machine.data_dir.join('pids')
146
146
  data_dir.mkdir unless data_dir.directory?
147
147
 
148
148
  data_dir.join("ssh_#{host_port}.pid").open('w') do |pid_file|
@@ -169,13 +169,12 @@ module VagrantPlugins
169
169
  end
170
170
 
171
171
  def call(env)
172
- @env = env
173
-
174
- if ssh_pids.any?
172
+ pids = ssh_pids(env[:machine])
173
+ if pids.any?
175
174
  env[:ui].info I18n.t(
176
175
  'vagrant.actions.vm.clear_forward_ports.deleting'
177
176
  )
178
- ssh_pids.each do |tag|
177
+ pids.each do |tag|
179
178
  next unless ssh_pid?(tag[:pid])
180
179
  @logger.debug "Killing pid #{tag[:pid]}"
181
180
  kill_cmd = ''
@@ -191,7 +190,7 @@ module VagrantPlugins
191
190
  end
192
191
 
193
192
  @logger.info 'Removing ssh pid files'
194
- remove_ssh_pids
193
+ remove_ssh_pids(env[:machine])
195
194
  else
196
195
  @logger.info 'No ssh pids found'
197
196
  end
@@ -201,9 +200,9 @@ module VagrantPlugins
201
200
 
202
201
  protected
203
202
 
204
- def ssh_pids
205
- glob = @env[:machine].data_dir.join('pids').to_s + '/ssh_*.pid'
206
- @ssh_pids = Dir[glob].map do |file|
203
+ def ssh_pids(machine)
204
+ glob = machine.data_dir.join('pids').to_s + '/ssh_*.pid'
205
+ ssh_pids = Dir[glob].map do |file|
207
206
  {
208
207
  pid: File.read(file).strip.chomp,
209
208
  port: File.basename(file)['ssh_'.length..-1 * ('.pid'.length + 1)].to_i
@@ -217,8 +216,8 @@ module VagrantPlugins
217
216
  `ps -o command= #{pid}`.strip.chomp =~ /ssh/
218
217
  end
219
218
 
220
- def remove_ssh_pids
221
- glob = @env[:machine].data_dir.join('pids').to_s + '/ssh_*.pid'
219
+ def remove_ssh_pids(machine)
220
+ glob = machine.data_dir.join('pids').to_s + '/ssh_*.pid'
222
221
  Dir[glob].each do |file|
223
222
  File.delete file
224
223
  end