vagrant-libvirt 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +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)
|