vagrant-libvirt 0.7.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +25 -9
- data/lib/vagrant-libvirt/action/cleanup_on_failure.rb +76 -0
- data/lib/vagrant-libvirt/action/create_domain.rb +45 -23
- data/lib/vagrant-libvirt/action/create_network_interfaces.rb +5 -1
- data/lib/vagrant-libvirt/action/create_networks.rb +13 -0
- data/lib/vagrant-libvirt/action/destroy_domain.rb +106 -21
- data/lib/vagrant-libvirt/action/destroy_networks.rb +1 -1
- data/lib/vagrant-libvirt/action/forward_ports.rb +12 -11
- data/lib/vagrant-libvirt/action/wait_till_up.rb +6 -32
- data/lib/vagrant-libvirt/action.rb +67 -80
- data/lib/vagrant-libvirt/config.rb +45 -33
- data/lib/vagrant-libvirt/driver.rb +3 -1
- data/lib/vagrant-libvirt/errors.rb +8 -0
- data/lib/vagrant-libvirt/templates/domain.xml.erb +223 -226
- data/lib/vagrant-libvirt/templates/private_network.xml.erb +4 -1
- data/lib/vagrant-libvirt/util/network_util.rb +13 -2
- data/lib/vagrant-libvirt/util/resolvers.rb +80 -0
- data/lib/vagrant-libvirt/version +1 -1
- data/locales/en.yml +13 -0
- data/spec/spec_helper.rb +33 -28
- data/spec/support/libvirt_context.rb +3 -3
- data/spec/unit/action/cleanup_on_failure_spec.rb +131 -0
- data/spec/unit/action/create_domain_spec/additional_disks_domain.xml +6 -18
- data/spec/unit/action/create_domain_spec/custom_disk_settings.xml +43 -0
- data/spec/unit/action/create_domain_spec/default_domain.xml +6 -18
- data/spec/unit/action/create_domain_spec/two_disk_settings.xml +49 -0
- data/spec/unit/action/create_domain_spec.rb +51 -7
- data/spec/unit/action/create_domain_volume_spec.rb +5 -3
- data/spec/unit/action/destroy_domain_spec/additional_disks_domain.xml +47 -0
- data/spec/unit/action/destroy_domain_spec/box_multiple_disks.xml +55 -0
- data/spec/unit/action/destroy_domain_spec/box_multiple_disks_and_additional_and_custom_disks.xml +72 -0
- data/spec/unit/action/destroy_domain_spec/box_multiple_disks_and_additional_and_custom_disks_no_aliases.xml +67 -0
- data/spec/unit/action/destroy_domain_spec/box_multiple_disks_and_additional_disks.xml +67 -0
- data/spec/unit/action/destroy_domain_spec/cdrom_domain.xml +48 -0
- data/spec/unit/action/destroy_domain_spec.rb +134 -30
- data/spec/unit/action/forward_ports_spec.rb +10 -2
- data/spec/unit/action/prepare_nfs_settings_spec.rb +4 -0
- data/spec/unit/action/start_domain_spec/clock_timer_rtc.xml +6 -18
- data/spec/unit/action/start_domain_spec/default.xml +6 -18
- data/spec/unit/action/start_domain_spec/default_added_tpm_path.xml +6 -18
- data/spec/unit/action/start_domain_spec/default_added_tpm_version.xml +6 -18
- data/spec/unit/action/start_domain_spec/existing.xml +1 -1
- data/spec/unit/action/wait_till_up_spec.rb +2 -42
- data/spec/unit/action_spec.rb +2 -0
- data/spec/unit/config_spec.rb +85 -26
- data/spec/unit/driver_spec.rb +17 -8
- data/spec/unit/provider_spec.rb +11 -0
- data/spec/unit/templates/domain_all_settings.xml +52 -79
- data/spec/unit/templates/domain_cpu_mode_passthrough.xml +39 -0
- data/spec/unit/templates/domain_custom_cpu_model.xml +6 -18
- data/spec/unit/templates/domain_defaults.xml +6 -18
- data/spec/unit/templates/domain_spec.rb +36 -13
- data/spec/unit/templates/tpm/version_1.2.xml +6 -18
- data/spec/unit/templates/tpm/version_2.0.xml +6 -18
- data/spec/unit/util/resolvers_spec.rb +116 -0
- metadata +62 -64
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b1bfaefd1dab7cbdb1293e867e29fef05a9eb101fae5226a38203593de84e717
|
4
|
+
data.tar.gz: d36d4f487ed2ad0b4f00ba09c263a5cd8deda6c268eef50974376e2796b7e64d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 510c1b6ffd2fb4eea02ede8d7612c3a41a89e5c50b630370bec6fd70b79986caa222e6ce1cc0f4c2732b310f7c134866aa2283ee449441c92078b148c4734503
|
7
|
+
data.tar.gz: cb6ab754dcff508ec150c6ff67cf82b603243596b35ab6a5ef79d4dfe36042a933dde8eebc3630d5a2473c8fcd398111a98d12a64a66950ad0abe942c15bce40
|
data/README.md
CHANGED
@@ -49,8 +49,8 @@ can help a lot :-)
|
|
49
49
|
* [USB Device Passthrough](#usb-device-passthrough)
|
50
50
|
* [USB Redirector Devices](#usb-redirector-devices)
|
51
51
|
* [Filter for USB Redirector Devices](#filter-for-usb-redirector-devices)
|
52
|
-
* [Random number generator passthrough](#random-number-generator-passthrough)
|
53
52
|
* [Serial Console Devices](#serial-console-devices)
|
53
|
+
* [Random number generator passthrough](#random-number-generator-passthrough)
|
54
54
|
* [Watchdog device](#watchdog-device)
|
55
55
|
* [Smartcard device](#smartcard-device)
|
56
56
|
* [Hypervisor Features](#hypervisor-features)
|
@@ -141,7 +141,7 @@ docker pull vagrantlibvirt/vagrant-libvirt:edge
|
|
141
141
|
|
142
142
|
Running the image:
|
143
143
|
```bash
|
144
|
-
docker run -
|
144
|
+
docker run -i --rm \
|
145
145
|
-e LIBVIRT_DEFAULT_URI \
|
146
146
|
-v /var/run/libvirt/:/var/run/libvirt/ \
|
147
147
|
-v ~/.vagrant.d:/.vagrant.d \
|
@@ -155,7 +155,7 @@ docker run -it --rm \
|
|
155
155
|
It's possible to define a function in `~/.bashrc`, for example:
|
156
156
|
```bash
|
157
157
|
vagrant(){
|
158
|
-
docker run -
|
158
|
+
docker run -i --rm \
|
159
159
|
-e LIBVIRT_DEFAULT_URI \
|
160
160
|
-v /var/run/libvirt/:/var/run/libvirt/ \
|
161
161
|
-v ~/.vagrant.d:/.vagrant.d \
|
@@ -184,7 +184,7 @@ To run with Podman you need to include
|
|
184
184
|
--security-opt label=disable \
|
185
185
|
-v ~/.vagrant.d/boxes:/vagrant/boxes \
|
186
186
|
-v ~/.vagrant.d/data:/vagrant/data \
|
187
|
-
-v ~/.vagrant.d/
|
187
|
+
-v ~/.vagrant.d/tmp:/vagrant/tmp \
|
188
188
|
```
|
189
189
|
|
190
190
|
for example:
|
@@ -196,7 +196,7 @@ vagrant(){
|
|
196
196
|
-v /var/run/libvirt/:/var/run/libvirt/ \
|
197
197
|
-v ~/.vagrant.d/boxes:/vagrant/boxes \
|
198
198
|
-v ~/.vagrant.d/data:/vagrant/data \
|
199
|
-
-v ~/.vagrant.d/
|
199
|
+
-v ~/.vagrant.d/tmp:/vagrant/tmp \
|
200
200
|
-v $(realpath "${PWD}"):${PWD} \
|
201
201
|
-w $(realpath "${PWD}") \
|
202
202
|
--network host \
|
@@ -610,7 +610,7 @@ end
|
|
610
610
|
values](http://libvirt.org/formatdomain.html#elementsVideo) are "vga",
|
611
611
|
"cirrus", "vmvga", "xen", "vbox", or "qxl".
|
612
612
|
* `video_vram` - Used by some graphics card types to vary the amount of RAM
|
613
|
-
dedicated to video. Defaults to
|
613
|
+
dedicated to video. Defaults to 16384.
|
614
614
|
* `video_accel3d` - Set to `true` to enable 3D acceleration. Defaults to
|
615
615
|
`false`.
|
616
616
|
* `sound_type` - [Set the virtual sound card](https://libvirt.org/formatdomain.html#elementsSound)
|
@@ -859,6 +859,7 @@ starts with `libvirt__` string. Here is a list of those options:
|
|
859
859
|
* `:libvirt__dhcp_bootp_server` - The server that runs the DHCP server. Used
|
860
860
|
only when dhcp is enabled.By default is the same host that runs the DHCP
|
861
861
|
server.
|
862
|
+
* `:libvirt__tftp_root` - Path to the root directory served via TFTP.
|
862
863
|
* `:libvirt__adapter` - Number specifiyng sequence number of interface.
|
863
864
|
* `:libvirt__forward_mode` - Specify one of `veryisolated`, `none`, `open`, `nat`
|
864
865
|
or `route` options. This option is used only when creating new network. Mode
|
@@ -977,6 +978,8 @@ used by this network are configurable at the provider level.
|
|
977
978
|
* `management_network_domain` - Domain name assigned to the management network.
|
978
979
|
* `management_network_mtu` - MTU size of management network. If not specified,
|
979
980
|
the Libvirt default (1500) will be used.
|
981
|
+
* `management_network_keep` - Starting from version *0.7.0*, *always_destroy* is set to *true* by default for any network.
|
982
|
+
This option allows to change this behaviour for the management network.
|
980
983
|
|
981
984
|
You may wonder how vagrant-libvirt knows the IP address a VM received. Libvirt
|
982
985
|
doesn't provide a standard way to find out the IP address of a running domain.
|
@@ -999,6 +1002,19 @@ if it detects an attached channel during boot.
|
|
999
1002
|
* `qemu_use_agent` - false by default, if set to true, attempt to extract configured
|
1000
1003
|
ip address via qemu agent.
|
1001
1004
|
|
1005
|
+
By default if `qemu_use_agent` is set to `true` the code will automatically
|
1006
|
+
inject a suitable channel unless there already exists an entry with a
|
1007
|
+
`:target_name` matching `'org.qemu.guest_agent.'`.
|
1008
|
+
Alternatively if setting `qemu_use_agent` but, needing to disable the addition
|
1009
|
+
of the channel, simply use a disabled flag as follows:
|
1010
|
+
```ruby
|
1011
|
+
Vagrant.configure(2) do |config|
|
1012
|
+
config.vm.provider :libvirt do |libvirt|
|
1013
|
+
libvirt.channel :type => 'unix', :target_name => 'org.qemu.guest_agent.0', :disabled => true
|
1014
|
+
end
|
1015
|
+
end
|
1016
|
+
```
|
1017
|
+
|
1002
1018
|
To use the management network interface with an external dhcp service you need
|
1003
1019
|
to setup a bridged host network manually and define it via
|
1004
1020
|
`management_network_name` in your Vagrantfile.
|
@@ -1196,9 +1212,9 @@ Bus 001 Device 002: ID 1234:abcd Example device
|
|
1196
1212
|
Vagrant.configure("2") do |config|
|
1197
1213
|
config.vm.provider :libvirt do |libvirt|
|
1198
1214
|
# pass through specific device based on identifying it
|
1199
|
-
libvirt.
|
1215
|
+
libvirt.usb :vendor => '0x1234', :product => '0xabcd'
|
1200
1216
|
# pass through a host device where multiple of the same vendor/product exist
|
1201
|
-
libvirt.
|
1217
|
+
libvirt.usb :bus => '1', :device => '1'
|
1202
1218
|
end
|
1203
1219
|
end
|
1204
1220
|
```
|
@@ -1279,7 +1295,7 @@ Currently only redirecting to a file is supported.
|
|
1279
1295
|
Vagrant.configure("2") do |config|
|
1280
1296
|
config.vm.define :test do |test|
|
1281
1297
|
test.vm.provider :libvirt do |domain|
|
1282
|
-
domain.serial :type => "file", :source => {:path => "/var/log/vm_consoles/test.log}
|
1298
|
+
domain.serial :type => "file", :source => {:path => "/var/log/vm_consoles/test.log"}
|
1283
1299
|
end
|
1284
1300
|
end
|
1285
1301
|
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
|
4
|
+
module VagrantPlugins
|
5
|
+
module ProviderLibvirt
|
6
|
+
module Action
|
7
|
+
class CleanupOnFailure
|
8
|
+
def initialize(app, _env)
|
9
|
+
@logger = Log4r::Logger.new('vagrant_libvirt::action::cleanup_on_failure')
|
10
|
+
@app = app
|
11
|
+
@cleanup = true
|
12
|
+
end
|
13
|
+
|
14
|
+
def call(env)
|
15
|
+
# passing a value doesn't work as the env that is updated may be dupped from
|
16
|
+
# the original meaning the latter action's update is discarded. Instead pass
|
17
|
+
# a reference to the method on this class that will toggle the instance
|
18
|
+
# variable indicating whether cleanup is needed or not.
|
19
|
+
env['vagrant-libvirt.complete'] = method(:completed)
|
20
|
+
|
21
|
+
@app.call(env)
|
22
|
+
end
|
23
|
+
|
24
|
+
def recover(env)
|
25
|
+
return unless env[:machine] && env[:machine].state.id != :not_created
|
26
|
+
|
27
|
+
# only destroy if failed to complete bring up
|
28
|
+
unless @cleanup
|
29
|
+
@logger.debug('VM provider setup was completed, no need to halt/destroy')
|
30
|
+
return
|
31
|
+
end
|
32
|
+
|
33
|
+
# If we're not supposed to destroy on error then just return
|
34
|
+
return unless env[:destroy_on_error]
|
35
|
+
|
36
|
+
if env[:halt_on_error]
|
37
|
+
halt_env = env.dup
|
38
|
+
halt_env.delete(:interrupted)
|
39
|
+
halt_env[:config_validate] = false
|
40
|
+
env[:action_runner].run(Action.action_halt, halt_env)
|
41
|
+
else
|
42
|
+
destroy_env = env.dup
|
43
|
+
destroy_env.delete(:interrupted)
|
44
|
+
destroy_env[:config_validate] = false
|
45
|
+
destroy_env[:force_confirm_destroy] = true
|
46
|
+
env[:action_runner].run(Action.action_destroy, destroy_env)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def completed
|
51
|
+
@cleanup = false
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class SetupComplete
|
56
|
+
def initialize(app, _env)
|
57
|
+
@logger = Log4r::Logger.new('vagrant_libvirt::action::setup_complete')
|
58
|
+
@app = app
|
59
|
+
end
|
60
|
+
|
61
|
+
def call(env)
|
62
|
+
if env['vagrant-libvirt.complete'].nil? or !env['vagrant-libvirt.complete'].respond_to? :call
|
63
|
+
raise Errors::CallChainError, require_action: CleanupOnFailure.name, current_action: SetupComplete.name
|
64
|
+
end
|
65
|
+
|
66
|
+
@logger.debug('Marking provider setup as completed')
|
67
|
+
# mark provider as finished setup so that any failure after this
|
68
|
+
# point doesn't result in destroying or shutting down the VM
|
69
|
+
env['vagrant-libvirt.complete'].call
|
70
|
+
|
71
|
+
@app.call(env)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
require 'log4r'
|
4
4
|
|
5
|
+
require 'vagrant-libvirt/util/resolvers'
|
6
|
+
|
5
7
|
module VagrantPlugins
|
6
8
|
module ProviderLibvirt
|
7
9
|
module Action
|
@@ -20,7 +22,7 @@ module VagrantPlugins
|
|
20
22
|
|
21
23
|
def _disks_print(disks)
|
22
24
|
disks.collect do |x|
|
23
|
-
"#{x[:device]}(#{x[:type]}
|
25
|
+
"#{x[:device]}(#{x[:type]}, #{x[:bus]}, #{x[:size]})"
|
24
26
|
end.join(', ')
|
25
27
|
end
|
26
28
|
|
@@ -73,11 +75,7 @@ module VagrantPlugins
|
|
73
75
|
@graphics_autoport = config.graphics_autoport
|
74
76
|
@graphics_port = config.graphics_port
|
75
77
|
@graphics_ip = config.graphics_ip
|
76
|
-
@graphics_passwd =
|
77
|
-
''
|
78
|
-
else
|
79
|
-
"passwd='#{config.graphics_passwd}'"
|
80
|
-
end
|
78
|
+
@graphics_passwd = config.graphics_passwd
|
81
79
|
@graphics_gl = config.graphics_gl
|
82
80
|
@video_type = config.video_type
|
83
81
|
@sound_type = config.sound_type
|
@@ -135,11 +133,19 @@ module VagrantPlugins
|
|
135
133
|
# RNG device passthrough
|
136
134
|
@rng = config.rng
|
137
135
|
|
136
|
+
# Memballoon
|
137
|
+
@memballoon_enabled = config.memballoon_enabled
|
138
|
+
@memballoon_model = config.memballoon_model
|
139
|
+
@memballoon_pci_bus = config.memballoon_pci_bus
|
140
|
+
@memballoon_pci_slot = config.memballoon_pci_slot
|
141
|
+
|
138
142
|
config = env[:machine].provider_config
|
139
143
|
@domain_type = config.driver
|
140
144
|
|
141
145
|
@os_type = 'hvm'
|
142
146
|
|
147
|
+
resolver = ::VagrantPlugins::ProviderLibvirt::Util::DiskDeviceResolver.new(prefix=@disk_device[0..1])
|
148
|
+
|
143
149
|
# Get path to domain image from the storage pool selected if we have a box.
|
144
150
|
if env[:machine].config.vm.box
|
145
151
|
if @snapshot_pool_name != @storage_pool_name
|
@@ -147,6 +153,12 @@ module VagrantPlugins
|
|
147
153
|
else
|
148
154
|
pool_name = @storage_pool_name
|
149
155
|
end
|
156
|
+
|
157
|
+
# special handling for domain volume
|
158
|
+
env[:box_volumes][0][:device] = env[:box_volumes][0].fetch(:device, @disk_device)
|
159
|
+
|
160
|
+
resolver.resolve!(env[:box_volumes])
|
161
|
+
|
150
162
|
@logger.debug "Search for volumes in pool: #{pool_name}"
|
151
163
|
env[:box_volumes].each_index do |index|
|
152
164
|
suffix_index = index > 0 ? "_#{index}" : ''
|
@@ -154,14 +166,16 @@ module VagrantPlugins
|
|
154
166
|
name: "#{@name}#{suffix_index}.img"
|
155
167
|
).find { |x| x.pool_name == pool_name }
|
156
168
|
raise Errors::DomainVolumeExists if domain_volume.nil?
|
169
|
+
|
157
170
|
@domain_volumes.push({
|
158
|
-
:dev =>
|
171
|
+
:dev => env[:box_volumes][index][:device],
|
159
172
|
:cache => @domain_volume_cache,
|
160
173
|
:bus => @disk_bus,
|
161
174
|
:path => domain_volume.path,
|
162
175
|
:virtual_size => env[:box_volumes][index][:virtual_size]
|
163
176
|
})
|
164
|
-
|
177
|
+
end
|
178
|
+
|
165
179
|
end
|
166
180
|
|
167
181
|
# If we have a box, take the path from the domain volume and set our storage_prefix.
|
@@ -173,19 +187,7 @@ module VagrantPlugins
|
|
173
187
|
storage_prefix = get_disk_storage_prefix(env, @storage_pool_name)
|
174
188
|
end
|
175
189
|
|
176
|
-
@
|
177
|
-
|
178
|
-
@serials.each do |serial|
|
179
|
-
next unless serial[:source] && serial[:source][:path]
|
180
|
-
|
181
|
-
dir = File.dirname(serial[:source][:path])
|
182
|
-
begin
|
183
|
-
FileUtils.mkdir_p(dir)
|
184
|
-
rescue ::Errno::EACCES
|
185
|
-
raise Errors::SerialCannotCreatePathError,
|
186
|
-
path: dir
|
187
|
-
end
|
188
|
-
end
|
190
|
+
resolver.resolve!(@disks)
|
189
191
|
|
190
192
|
@disks.each do |disk|
|
191
193
|
disk[:path] ||= _disk_name(@name, disk)
|
@@ -235,6 +237,20 @@ module VagrantPlugins
|
|
235
237
|
end
|
236
238
|
end
|
237
239
|
|
240
|
+
@serials = config.serials
|
241
|
+
|
242
|
+
@serials.each do |serial|
|
243
|
+
next unless serial[:source] && serial[:source][:path]
|
244
|
+
|
245
|
+
dir = File.dirname(serial[:source][:path])
|
246
|
+
begin
|
247
|
+
FileUtils.mkdir_p(dir)
|
248
|
+
rescue ::Errno::EACCES
|
249
|
+
raise Errors::SerialCannotCreatePathError,
|
250
|
+
path: dir
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
238
254
|
# Output the settings we're going to use to the user
|
239
255
|
env[:ui].info(I18n.t('vagrant_libvirt.creating_domain'))
|
240
256
|
env[:ui].info(" -- Name: #{@name}")
|
@@ -284,7 +300,7 @@ module VagrantPlugins
|
|
284
300
|
end
|
285
301
|
env[:ui].info(" -- Storage pool: #{@storage_pool_name}")
|
286
302
|
@domain_volumes.each do |volume|
|
287
|
-
env[:ui].info(" -- Image(#{volume[:
|
303
|
+
env[:ui].info(" -- Image(#{volume[:dev]}): #{volume[:path]}, #{volume[:bus]}, #{volume[:virtual_size].to_GB}G")
|
288
304
|
end
|
289
305
|
|
290
306
|
if not @disk_driver_opts.empty?
|
@@ -298,7 +314,7 @@ module VagrantPlugins
|
|
298
314
|
env[:ui].info(" -- Graphics Type: #{@graphics_type}")
|
299
315
|
env[:ui].info(" -- Graphics Port: #{@graphics_port}")
|
300
316
|
env[:ui].info(" -- Graphics IP: #{@graphics_ip}")
|
301
|
-
env[:ui].info(" -- Graphics Password: #{@graphics_passwd.
|
317
|
+
env[:ui].info(" -- Graphics Password: #{@graphics_passwd.nil? ? 'Not defined' : 'Defined'}")
|
302
318
|
env[:ui].info(" -- Video Type: #{@video_type}")
|
303
319
|
env[:ui].info(" -- Video VRAM: #{@video_vram}")
|
304
320
|
env[:ui].info(" -- Video 3D accel: #{@video_accel3d}")
|
@@ -312,6 +328,12 @@ module VagrantPlugins
|
|
312
328
|
env[:ui].info(" -- TPM Path: #{@tpm_path}")
|
313
329
|
end
|
314
330
|
|
331
|
+
if @memballoon_enabled
|
332
|
+
env[:ui].info(" -- Memballoon model: #{@memballoon_model}")
|
333
|
+
env[:ui].info(" -- Memballoon bus: #{@memballoon_pci_bus}")
|
334
|
+
env[:ui].info(" -- Memballoon slot: #{@memballoon_pci_slot}")
|
335
|
+
end
|
336
|
+
|
315
337
|
@boot_order.each do |device|
|
316
338
|
env[:ui].info(" -- Boot device: #{device}")
|
317
339
|
end
|
@@ -213,8 +213,12 @@ module VagrantPlugins
|
|
213
213
|
type: :static,
|
214
214
|
ip: options[:ip],
|
215
215
|
netmask: options[:netmask],
|
216
|
-
gateway: options[:gateway]
|
216
|
+
gateway: options[:gateway],
|
217
|
+
route: options[:route]
|
217
218
|
}.merge(network)
|
219
|
+
if IPAddr.new(options[:ip]).ipv6?
|
220
|
+
network[:type] = :static6
|
221
|
+
end
|
218
222
|
else
|
219
223
|
network[:type] = :dhcp
|
220
224
|
end
|
@@ -30,6 +30,15 @@ module VagrantPlugins
|
|
30
30
|
|
31
31
|
def call(env)
|
32
32
|
if env[:machine].provider_config.qemu_use_session
|
33
|
+
# Get a list of all (active and inactive) Libvirt networks. This
|
34
|
+
# triggers a side effect to ensure networking is fully available
|
35
|
+
# for VMs using sessions. It is likely that this should be done
|
36
|
+
# to determine the correct virtual device for the management
|
37
|
+
# network for sessions instead of assuming the default of virbr0.
|
38
|
+
@available_networks = libvirt_networks(
|
39
|
+
env[:machine].provider.driver.system_connection
|
40
|
+
)
|
41
|
+
|
33
42
|
@app.call(env)
|
34
43
|
return
|
35
44
|
end
|
@@ -343,6 +352,10 @@ module VagrantPlugins
|
|
343
352
|
@network_dhcp_enabled = false
|
344
353
|
end
|
345
354
|
|
355
|
+
if @options[:tftp_root]
|
356
|
+
@tftp_root = @options[:tftp_root]
|
357
|
+
end
|
358
|
+
|
346
359
|
@network_domain_name = @options[:domain_name]
|
347
360
|
|
348
361
|
begin
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'log4r'
|
4
|
+
require 'rexml'
|
4
5
|
|
5
6
|
module VagrantPlugins
|
6
7
|
module ProviderLibvirt
|
@@ -48,37 +49,121 @@ module VagrantPlugins
|
|
48
49
|
# cdroms are consider volumes, but cannot be destroyed
|
49
50
|
domain.destroy(destroy_volumes: true)
|
50
51
|
else
|
52
|
+
domain_xml = libvirt_domain.xml_desc(1)
|
53
|
+
xml_descr = REXML::Document.new(domain_xml)
|
54
|
+
disks_xml = REXML::XPath.match(xml_descr, '/domain/devices/disk[@device="disk"]')
|
55
|
+
have_aliases = !(REXML::XPath.match(disks_xml, './alias[@name="ua-box-volume-0"]').first).nil?
|
56
|
+
if !have_aliases
|
57
|
+
env[:ui].warn(I18n.t('vagrant_libvirt.destroy.obsolete_method'))
|
58
|
+
end
|
59
|
+
|
51
60
|
domain.destroy(destroy_volumes: false)
|
52
61
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
62
|
+
volumes = domain.volumes
|
63
|
+
|
64
|
+
# Remove root storage. If no aliases available, perform the removal by name and keep track
|
65
|
+
# of how many matches there are in the volumes. This will provide a fallback offset to where
|
66
|
+
# the additional storage devices are.
|
67
|
+
detected_box_volumes = 0
|
68
|
+
if have_aliases
|
69
|
+
REXML::XPath.match(disks_xml, './alias[contains(@name, "ua-box-volume-")]').each do |box_disk|
|
70
|
+
diskname = box_disk.parent.elements['source'].attributes['file'].rpartition('/').last
|
71
|
+
detected_box_volumes += 1
|
72
|
+
|
73
|
+
destroy_volume(volumes, diskname, env)
|
74
|
+
end
|
75
|
+
else
|
76
|
+
# fallback to try and infer which boxes are box images, as they are listed first
|
77
|
+
# as soon as there is no match, can exit
|
78
|
+
disks_xml.each_with_index do |box_disk, idx|
|
79
|
+
name = libvirt_domain.name + (idx == 0 ? '.img' : "_#{idx}.img")
|
80
|
+
diskname = box_disk.elements['source'].attributes['file'].rpartition('/').last
|
81
|
+
|
82
|
+
break if name != diskname
|
83
|
+
detected_box_volumes += 1
|
84
|
+
|
85
|
+
root_disk = volumes.select do |x|
|
86
|
+
x.name == name if x
|
68
87
|
end.first
|
69
|
-
|
88
|
+
if root_disk
|
89
|
+
root_disk.destroy
|
90
|
+
end
|
70
91
|
end
|
71
92
|
end
|
72
93
|
|
73
|
-
#
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
94
|
+
# work out if there are any custom disks attached that wasn't done by vagrant-libvirt,
|
95
|
+
# and warn there might be unexpected behaviour
|
96
|
+
total_disks = disks_xml.length
|
97
|
+
offset = total_disks - env[:machine].provider_config.disks.length
|
98
|
+
if offset != detected_box_volumes
|
99
|
+
env[:ui].warn(I18n.t('vagrant_libvirt.destroy.unexpected_volumes'))
|
100
|
+
end
|
101
|
+
|
102
|
+
if !have_aliases
|
103
|
+
# if no aliases found, see if it's possible to check the number of box disks
|
104
|
+
# otherwise the destroy could remove the wrong disk by accident.
|
105
|
+
if env[:machine].box != nil
|
106
|
+
box_disks = env[:machine].box.metadata.fetch('disks', [1])
|
107
|
+
offset = box_disks.length
|
108
|
+
if offset != detected_box_volumes
|
109
|
+
env[:ui].warn(I18n.t('vagrant_libvirt.destroy.expected_removal_mismatch'))
|
110
|
+
end
|
111
|
+
else
|
112
|
+
env[:ui].warn(I18n.t('vagrant_libvirt.destroy.box_metadata_unavailable'))
|
113
|
+
end
|
114
|
+
|
115
|
+
# offset only used when no aliases available
|
116
|
+
offset = detected_box_volumes
|
117
|
+
end
|
118
|
+
|
119
|
+
env[:machine].provider_config.disks.each_with_index.each do |disk, index|
|
120
|
+
# shared disks remove only manually or ???
|
121
|
+
next if disk[:allow_existing]
|
122
|
+
|
123
|
+
# look for exact match using aliases which will be used
|
124
|
+
# for subsequent domain creations
|
125
|
+
if have_aliases
|
126
|
+
domain_disk = REXML::XPath.match(disks_xml, './alias[@name="ua-disk-volume-' + index.to_s + '"]').first
|
127
|
+
domain_disk = domain_disk.parent if !domain_disk.nil?
|
128
|
+
else
|
129
|
+
# otherwise fallback to find the disk by device if specified by user
|
130
|
+
# and finally index counting with offset and hope the match is correct
|
131
|
+
if !disk[:device].nil?
|
132
|
+
domain_disk = REXML::XPath.match(disks_xml, './target[@dev="' + disk[:device] + '"]').first
|
133
|
+
domain_disk = domain_disk.parent if !domain_disk.nil?
|
134
|
+
else
|
135
|
+
domain_disk = disks_xml[offset + index]
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
next if domain_disk.nil?
|
140
|
+
|
141
|
+
diskname = domain_disk.elements['source'].attributes['file'].rpartition('/').last
|
142
|
+
destroy_volume(volumes, diskname, env)
|
143
|
+
end
|
78
144
|
end
|
79
145
|
|
80
146
|
@app.call(env)
|
81
147
|
end
|
148
|
+
|
149
|
+
protected
|
150
|
+
|
151
|
+
def destroy_volume(volumes, diskname, env)
|
152
|
+
# diskname is unique
|
153
|
+
libvirt_disk = volumes.select do |x|
|
154
|
+
x.name == diskname if x
|
155
|
+
end.first
|
156
|
+
if libvirt_disk
|
157
|
+
libvirt_disk.destroy
|
158
|
+
elsif disk[:path]
|
159
|
+
poolname = env[:machine].provider_config.storage_pool_name
|
160
|
+
libvirt_disk = volumes.select do |x|
|
161
|
+
# FIXME: can remove pool/target.img and pool/123/target.img
|
162
|
+
x.path =~ /\/#{disk[:path]}$/ && x.pool_name == poolname
|
163
|
+
end.first
|
164
|
+
libvirt_disk.destroy if libvirt_disk
|
165
|
+
end
|
166
|
+
end
|
82
167
|
end
|
83
168
|
end
|
84
169
|
end
|
@@ -47,7 +47,7 @@ module VagrantPlugins
|
|
47
47
|
)
|
48
48
|
rescue Libvirt::RetrieveError => e
|
49
49
|
# this network is already destroyed, so move on
|
50
|
-
if e.
|
50
|
+
if e.libvirt_code == ProviderLibvirt::Util::ErrorCodes::VIR_ERR_NO_NETWORK
|
51
51
|
@logger.info 'It is already undefined'
|
52
52
|
next
|
53
53
|
# some other error occured, so raise it again
|
@@ -87,12 +87,13 @@ module VagrantPlugins
|
|
87
87
|
gateway_ports)
|
88
88
|
ssh_info = machine.ssh_info
|
89
89
|
params = %W(
|
90
|
+
-n
|
90
91
|
-L
|
91
92
|
#{host_ip}:#{host_port}:#{guest_ip}:#{guest_port}
|
92
93
|
-N
|
93
94
|
#{ssh_info[:host]}
|
94
|
-
)
|
95
|
-
params += '
|
95
|
+
)
|
96
|
+
params += '-g' if gateway_ports
|
96
97
|
|
97
98
|
options = (%W(
|
98
99
|
User=#{ssh_info[:username]}
|
@@ -105,32 +106,32 @@ module VagrantPlugins
|
|
105
106
|
ForwardX11=#{ssh_info[:forward_x11] ? 'yes' : 'no'}
|
106
107
|
IdentitiesOnly=#{ssh_info[:keys_only] ? 'yes' : 'no'}
|
107
108
|
) + ssh_info[:private_key_path].map do |pk|
|
108
|
-
"IdentityFile
|
109
|
-
end
|
109
|
+
"IdentityFile=\"#{pk}\""
|
110
|
+
end
|
111
|
+
).map { |s| ['-o', s] }.flatten
|
110
112
|
|
111
|
-
options +=
|
113
|
+
options += ['-o', "ProxyCommand=\"#{ssh_info[:proxy_command]}\""] if machine.provider_config.proxy_command
|
114
|
+
|
115
|
+
ssh_cmd = ['ssh'] + options + params
|
112
116
|
|
113
117
|
# TODO: instead of this, try and lock and get the stdin from spawn...
|
114
|
-
ssh_cmd = ''
|
115
118
|
if host_port <= 1024
|
116
119
|
@@lock.synchronize do
|
117
120
|
# TODO: add i18n
|
118
121
|
env[:ui].info 'Requesting sudo for host port(s) <= 1024'
|
119
122
|
r = system('sudo -v')
|
120
123
|
if r
|
121
|
-
ssh_cmd
|
124
|
+
ssh_cmd.unshift('sudo') # add sudo prefix
|
122
125
|
end
|
123
126
|
end
|
124
127
|
end
|
125
128
|
|
126
|
-
|
127
|
-
|
128
|
-
@logger.debug "Forwarding port with `#{ssh_cmd}`"
|
129
|
+
@logger.debug "Forwarding port with `#{ssh_cmd.join(' ')}`"
|
129
130
|
log_file = ssh_forward_log_file(
|
130
131
|
env[:machine], host_ip, host_port, guest_ip, guest_port,
|
131
132
|
)
|
132
133
|
@logger.info "Logging to #{log_file}"
|
133
|
-
spawn(ssh_cmd, [:out, :err] => [log_file, 'w'], :pgroup => true)
|
134
|
+
spawn(*ssh_cmd, [:out, :err] => [log_file, 'w'], :pgroup => true)
|
134
135
|
end
|
135
136
|
|
136
137
|
def ssh_forward_log_file(machine, host_ip, host_port, guest_ip, guest_port)
|