vagrant-libvirt 0.6.3 → 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +65 -13
  3. data/lib/vagrant-libvirt/action/cleanup_on_failure.rb +76 -0
  4. data/lib/vagrant-libvirt/action/create_domain.rb +56 -10
  5. data/lib/vagrant-libvirt/action/create_network_interfaces.rb +5 -1
  6. data/lib/vagrant-libvirt/action/create_networks.rb +24 -0
  7. data/lib/vagrant-libvirt/action/destroy_domain.rb +106 -21
  8. data/lib/vagrant-libvirt/action/destroy_networks.rb +1 -1
  9. data/lib/vagrant-libvirt/action/forward_ports.rb +12 -11
  10. data/lib/vagrant-libvirt/action/prepare_nfs_settings.rb +1 -1
  11. data/lib/vagrant-libvirt/action/start_domain.rb +36 -0
  12. data/lib/vagrant-libvirt/action/wait_till_up.rb +6 -32
  13. data/lib/vagrant-libvirt/action.rb +72 -83
  14. data/lib/vagrant-libvirt/config.rb +85 -30
  15. data/lib/vagrant-libvirt/driver.rb +11 -9
  16. data/lib/vagrant-libvirt/errors.rb +12 -0
  17. data/lib/vagrant-libvirt/templates/domain.xml.erb +228 -218
  18. data/lib/vagrant-libvirt/templates/private_network.xml.erb +4 -1
  19. data/lib/vagrant-libvirt/util/network_util.rb +15 -3
  20. data/lib/vagrant-libvirt/util/nfs.rb +2 -0
  21. data/lib/vagrant-libvirt/util/resolvers.rb +80 -0
  22. data/lib/vagrant-libvirt/version +1 -1
  23. data/locales/en.yml +17 -0
  24. data/spec/spec_helper.rb +36 -23
  25. data/spec/support/libvirt_context.rb +7 -4
  26. data/spec/support/sharedcontext.rb +1 -1
  27. data/spec/unit/action/cleanup_on_failure_spec.rb +131 -0
  28. data/spec/unit/action/create_domain_spec/additional_disks_domain.xml +6 -18
  29. data/spec/unit/action/create_domain_spec/custom_disk_settings.xml +43 -0
  30. data/spec/unit/action/create_domain_spec/default_domain.xml +6 -18
  31. data/spec/unit/action/create_domain_spec/two_disk_settings.xml +49 -0
  32. data/spec/unit/action/create_domain_spec.rb +51 -7
  33. data/spec/unit/action/create_domain_volume_spec.rb +5 -3
  34. data/spec/unit/action/destroy_domain_spec/additional_disks_domain.xml +47 -0
  35. data/spec/unit/action/destroy_domain_spec/box_multiple_disks.xml +55 -0
  36. data/spec/unit/action/destroy_domain_spec/box_multiple_disks_and_additional_and_custom_disks.xml +72 -0
  37. data/spec/unit/action/destroy_domain_spec/box_multiple_disks_and_additional_and_custom_disks_no_aliases.xml +67 -0
  38. data/spec/unit/action/destroy_domain_spec/box_multiple_disks_and_additional_disks.xml +67 -0
  39. data/spec/unit/action/destroy_domain_spec/cdrom_domain.xml +48 -0
  40. data/spec/unit/action/destroy_domain_spec.rb +134 -30
  41. data/spec/unit/action/forward_ports_spec.rb +10 -2
  42. data/spec/unit/action/prepare_nfs_settings_spec.rb +59 -0
  43. data/spec/unit/action/shutdown_domain_spec.rb +1 -1
  44. data/spec/unit/action/start_domain_spec/clock_timer_rtc.xml +6 -18
  45. data/spec/unit/action/start_domain_spec/default.xml +6 -18
  46. data/spec/unit/action/start_domain_spec/default_added_tpm_path.xml +6 -18
  47. data/spec/unit/action/start_domain_spec/default_added_tpm_version.xml +6 -18
  48. data/spec/unit/action/start_domain_spec/existing.xml +1 -1
  49. data/spec/unit/action/wait_till_up_spec.rb +4 -43
  50. data/spec/unit/action_spec.rb +2 -0
  51. data/spec/unit/config_spec.rb +133 -26
  52. data/spec/unit/driver_spec.rb +154 -10
  53. data/spec/unit/templates/domain_all_settings.xml +56 -77
  54. data/spec/unit/templates/domain_cpu_mode_passthrough.xml +39 -0
  55. data/spec/unit/templates/domain_custom_cpu_model.xml +6 -18
  56. data/spec/unit/templates/domain_defaults.xml +6 -18
  57. data/spec/unit/templates/domain_spec.rb +39 -13
  58. data/spec/unit/templates/tpm/version_1.2.xml +6 -18
  59. data/spec/unit/templates/tpm/version_2.0.xml +6 -18
  60. data/spec/unit/util/resolvers_spec.rb +116 -0
  61. metadata +40 -41
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9cdcf747d5d28e485d660d025beefdd8c3f58c107816ce719bcb0ba14559913a
4
- data.tar.gz: 71026dbb9ada779894dd0d5136f91e0da2c986ee279c320919817aaea511bdce
3
+ metadata.gz: 222341781630e6677eb79c302c0d658e9684ff55c9ebc596de959e32186de2d7
4
+ data.tar.gz: ae974712832e934acf1d696365db7c42b5efb53521f8ebd7227bf9be3891f8cd
5
5
  SHA512:
6
- metadata.gz: 7dc8d355a72f309322630617dbb3be94536969637bc3f6d7c9fa907aebbbd1b96bcc49aad3501dd5dd3a1220d17d5d12a14f7cd87d57e43c2790238e5099622d
7
- data.tar.gz: ded86b4e49bfb44e3d257936373b804d918a1eb34b956e2a02c9d99e60a7f5140cdc5241740720461a505897b74690589e0ba8c9a4656ce430be9164b86541c3
6
+ metadata.gz: 7d839a81423674ae57497e45265d839b19477988074f86f98c421fc7da182f5fdfd8f5314fc6282f27a4454bab0979fd0b4b118d660ab6a92a26ad0ee40707a2
7
+ data.tar.gz: 2c424318fd5c566512f0237a5b00eae03ff0a89dd8186188870a89f82afd0989640f7367fdad3ee45e1d97f331cab20618a27c4bf019c7e7a84cb4f7e628aba9
data/README.md CHANGED
@@ -1,8 +1,9 @@
1
1
  # Vagrant Libvirt Provider
2
2
 
3
3
  [![Join the chat at https://gitter.im/vagrant-libvirt/vagrant-libvirt](https://badges.gitter.im/vagrant-libvirt/vagrant-libvirt.svg)](https://gitter.im/vagrant-libvirt/vagrant-libvirt?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
4
- [![Build Status](https://travis-ci.org/vagrant-libvirt/vagrant-libvirt.svg)](https://travis-ci.org/vagrant-libvirt/vagrant-libvirt)
4
+ [![Build Status](https://github.com/vagrant-libvirt/vagrant-libvirt/actions/workflows/unit-tests.yml/badge.svg)](https://github.com/vagrant-libvirt/vagrant-libvirt/actions/workflows/unit-tests.yml)
5
5
  [![Coverage Status](https://coveralls.io/repos/github/vagrant-libvirt/vagrant-libvirt/badge.svg?branch=master)](https://coveralls.io/github/vagrant-libvirt/vagrant-libvirt?branch=master)
6
+ [![Gem Version](https://badge.fury.io/rb/vagrant-libvirt.svg)](https://badge.fury.io/rb/vagrant-libvirt)
6
7
 
7
8
  This is a [Vagrant](http://www.vagrantup.com) plugin that adds a
8
9
  [Libvirt](http://libvirt.org) provider to Vagrant, allowing Vagrant to
@@ -48,6 +49,7 @@ can help a lot :-)
48
49
  * [USB Device Passthrough](#usb-device-passthrough)
49
50
  * [USB Redirector Devices](#usb-redirector-devices)
50
51
  * [Filter for USB Redirector Devices](#filter-for-usb-redirector-devices)
52
+ * [Serial Console Devices](#serial-console-devices)
51
53
  * [Random number generator passthrough](#random-number-generator-passthrough)
52
54
  * [Watchdog device](#watchdog-device)
53
55
  * [Smartcard device](#smartcard-device)
@@ -137,15 +139,9 @@ docker pull vagrantlibvirt/vagrant-libvirt:edge
137
139
  ```
138
140
  ---
139
141
 
140
- Preparing the docker run, only once:
141
-
142
- ```bash
143
- mkdir -p ~/.vagrant.d/{boxes,data,tmp}
144
- ```
145
-
146
142
  Running the image:
147
143
  ```bash
148
- docker run -it --rm \
144
+ docker run -i --rm \
149
145
  -e LIBVIRT_DEFAULT_URI \
150
146
  -v /var/run/libvirt/:/var/run/libvirt/ \
151
147
  -v ~/.vagrant.d:/.vagrant.d \
@@ -159,7 +155,7 @@ docker run -it --rm \
159
155
  It's possible to define a function in `~/.bashrc`, for example:
160
156
  ```bash
161
157
  vagrant(){
162
- docker run -it --rm \
158
+ docker run -i --rm \
163
159
  -e LIBVIRT_DEFAULT_URI \
164
160
  -v /var/run/libvirt/:/var/run/libvirt/ \
165
161
  -v ~/.vagrant.d:/.vagrant.d \
@@ -173,6 +169,14 @@ vagrant(){
173
169
  ```
174
170
 
175
171
  ### Using Podman
172
+
173
+ Preparing the podman run, only once:
174
+
175
+ ```bash
176
+ mkdir -p ~/.vagrant.d/{boxes,data,tmp}
177
+ ```
178
+ _N.B. This is needed until the entrypoint works for podman to only mount the `~/.vagrant.d` directory_
179
+
176
180
  To run with Podman you need to include
177
181
 
178
182
  ```bash
@@ -180,6 +184,7 @@ To run with Podman you need to include
180
184
  --security-opt label=disable \
181
185
  -v ~/.vagrant.d/boxes:/vagrant/boxes \
182
186
  -v ~/.vagrant.d/data:/vagrant/data \
187
+ -v ~/.vagrant.d/tmp:/vagrant/tmp \
183
188
  ```
184
189
 
185
190
  for example:
@@ -191,6 +196,7 @@ vagrant(){
191
196
  -v /var/run/libvirt/:/var/run/libvirt/ \
192
197
  -v ~/.vagrant.d/boxes:/vagrant/boxes \
193
198
  -v ~/.vagrant.d/data:/vagrant/data \
199
+ -v ~/.vagrant.d/tmp:/vagrant/tmp \
194
200
  -v $(realpath "${PWD}"):${PWD} \
195
201
  -w $(realpath "${PWD}") \
196
202
  --network host \
@@ -232,7 +238,7 @@ installed](http://docs.vagrantup.com/v2/installation/index.html).
232
238
  Vagrant-libvirt supports Vagrant 2.0, 2.1 & 2.2. It should also work with earlier
233
239
  releases from 1.5 onwards but they are not actively tested.
234
240
 
235
- Check the [.travis.yml](https://github.com/vagrant-libvirt/vagrant-libvirt/blob/master/.travis.yml)
241
+ Check the [unit tests](https://github.com/vagrant-libvirt/vagrant-libvirt/blob/master/.github/workflows/unit-tests.yml)
236
242
  for the current list of tested versions.
237
243
 
238
244
  *We only test with the upstream version!* If you decide to install your distro's
@@ -593,6 +599,8 @@ end
593
599
  * `graphics_autoport` - Sets autoport for graphics, Libvirt in this case
594
600
  ignores graphics_port value, Defaults to 'yes'. Possible value are "yes" and
595
601
  "no"
602
+ * `graphics_gl` - Set to `true` to enable OpenGL. Defaults to `true` if
603
+ `video_accel3d` is `true`.
596
604
  * `keymap` - Set keymap for vm. default: en-us
597
605
  * `kvm_hidden` - [Hide the hypervisor from the
598
606
  guest](https://libvirt.org/formatdomain.html#elementsFeatures). Useful for
@@ -602,7 +610,9 @@ end
602
610
  values](http://libvirt.org/formatdomain.html#elementsVideo) are "vga",
603
611
  "cirrus", "vmvga", "xen", "vbox", or "qxl".
604
612
  * `video_vram` - Used by some graphics card types to vary the amount of RAM
605
- dedicated to video. Defaults to 9216.
613
+ dedicated to video. Defaults to 16384.
614
+ * `video_accel3d` - Set to `true` to enable 3D acceleration. Defaults to
615
+ `false`.
606
616
  * `sound_type` - [Set the virtual sound card](https://libvirt.org/formatdomain.html#elementsSound)
607
617
  Defaults to "ich6".
608
618
  * `machine_type` - Sets machine type. Equivalent to qemu `-machine`. Use
@@ -657,6 +667,9 @@ end
657
667
  it is not possible to communicate with VM through `vagrant ssh` or run
658
668
  provisioning. Setting to 'false' is only possible when VM doesn't use box.
659
669
  Defaults set to 'true'.
670
+ * `serial` - [libvirt serial devices](https://libvirt.org/formatdomain.html#elementsConsole).
671
+ Configure a serial/console port to communicate with the guest. Can be used
672
+ to log to file boot time messages sent to ttyS0 console by the guest.
660
673
 
661
674
  Specific domain settings can be set for each domain separately in multi-VM
662
675
  environment. Example below shows a part of Vagrantfile, where specific options
@@ -846,6 +859,7 @@ starts with `libvirt__` string. Here is a list of those options:
846
859
  * `:libvirt__dhcp_bootp_server` - The server that runs the DHCP server. Used
847
860
  only when dhcp is enabled.By default is the same host that runs the DHCP
848
861
  server.
862
+ * `:libvirt__tftp_root` - Path to the root directory served via TFTP.
849
863
  * `:libvirt__adapter` - Number specifiyng sequence number of interface.
850
864
  * `:libvirt__forward_mode` - Specify one of `veryisolated`, `none`, `open`, `nat`
851
865
  or `route` options. This option is used only when creating new network. Mode
@@ -906,6 +920,9 @@ starts with `libvirt__` string. Here is a list of those options:
906
920
  If not specified the default is 'false'.
907
921
  * `:bus` - The bus of the PCI device. Both :bus and :slot have to be defined.
908
922
  * `:slot` - The slot of the PCI device. Both :bus and :slot have to be defined.
923
+ * `:libvirt__always_destroy` - Allow domains that use but did not create a
924
+ network to destroy it when the domain is destroyed (default: `true`). Set to
925
+ `false` to only allow the domain that created the network to destroy it.
909
926
 
910
927
  When the option `:libvirt__dhcp_enabled` is to to 'false' it shouldn't matter
911
928
  whether the virtual network contains a DHCP server or not and vagrant-libvirt
@@ -961,6 +978,8 @@ used by this network are configurable at the provider level.
961
978
  * `management_network_domain` - Domain name assigned to the management network.
962
979
  * `management_network_mtu` - MTU size of management network. If not specified,
963
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.
964
983
 
965
984
  You may wonder how vagrant-libvirt knows the IP address a VM received. Libvirt
966
985
  doesn't provide a standard way to find out the IP address of a running domain.
@@ -983,6 +1002,19 @@ if it detects an attached channel during boot.
983
1002
  * `qemu_use_agent` - false by default, if set to true, attempt to extract configured
984
1003
  ip address via qemu agent.
985
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
+
986
1018
  To use the management network interface with an external dhcp service you need
987
1019
  to setup a bridged host network manually and define it via
988
1020
  `management_network_name` in your Vagrantfile.
@@ -1180,9 +1212,9 @@ Bus 001 Device 002: ID 1234:abcd Example device
1180
1212
  Vagrant.configure("2") do |config|
1181
1213
  config.vm.provider :libvirt do |libvirt|
1182
1214
  # pass through specific device based on identifying it
1183
- libvirt.usbdev :vendor => '0x1234', :product => '0xabcd'
1215
+ libvirt.usb :vendor => '0x1234', :product => '0xabcd'
1184
1216
  # pass through a host device where multiple of the same vendor/product exist
1185
- libvirt.usbdev :bus => '1', :device => '1'
1217
+ libvirt.usb :bus => '1', :device => '1'
1186
1218
  end
1187
1219
  end
1188
1220
  ```
@@ -1249,6 +1281,26 @@ Vagrant.configure("2") do |config|
1249
1281
  end
1250
1282
  ```
1251
1283
 
1284
+ ## Serial Console Devices
1285
+ You can define settings to redirect output from the serial console of any VM brought up with libvirt to a file or other devices that are listening. [See libvirt documentation](https://libvirt.org/formatdomain.html#elementCharSerial).
1286
+
1287
+ Currently only redirecting to a file is supported.
1288
+
1289
+ * `type` - only value that has an effect is file, in the future support may be added for virtual console, pty, dev, pipe, tcp, udp, unix socket, spiceport & nmdm.
1290
+ * `source` - options pertaining to how the connection attaches to the host, contains sub-settings dependent on `type`.
1291
+ `source` options for type `file`
1292
+ * `path` - file on host to connect to the serial port to record all output. May be created by qemu system user causing some permissions issues.
1293
+
1294
+ ```ruby
1295
+ Vagrant.configure("2") do |config|
1296
+ config.vm.define :test do |test|
1297
+ test.vm.provider :libvirt do |domain|
1298
+ domain.serial :type => "file", :source => {:path => "/var/log/vm_consoles/test.log"}
1299
+ end
1300
+ end
1301
+ end
1302
+ ```
1303
+
1252
1304
  ## Random number generator passthrough
1253
1305
 
1254
1306
  You can pass through `/dev/random` to your VM by configuring the domain like this:
@@ -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]},#{x[:size]})"
25
+ "#{x[:device]}(#{x[:type]}, #{x[:bus]}, #{x[:size]})"
24
26
  end.join(', ')
25
27
  end
26
28
 
@@ -73,14 +75,12 @@ 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 = if config.graphics_passwd.to_s.empty?
77
- ''
78
- else
79
- "passwd='#{config.graphics_passwd}'"
80
- end
78
+ @graphics_passwd = config.graphics_passwd
79
+ @graphics_gl = config.graphics_gl
81
80
  @video_type = config.video_type
82
81
  @sound_type = config.sound_type
83
82
  @video_vram = config.video_vram
83
+ @video_accel3d = config.video_accel3d
84
84
  @keymap = config.keymap
85
85
  @kvm_hidden = config.kvm_hidden
86
86
 
@@ -133,11 +133,19 @@ module VagrantPlugins
133
133
  # RNG device passthrough
134
134
  @rng = config.rng
135
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
+
136
142
  config = env[:machine].provider_config
137
143
  @domain_type = config.driver
138
144
 
139
145
  @os_type = 'hvm'
140
146
 
147
+ resolver = ::VagrantPlugins::ProviderLibvirt::Util::DiskDeviceResolver.new(prefix=@disk_device[0..1])
148
+
141
149
  # Get path to domain image from the storage pool selected if we have a box.
142
150
  if env[:machine].config.vm.box
143
151
  if @snapshot_pool_name != @storage_pool_name
@@ -145,6 +153,12 @@ module VagrantPlugins
145
153
  else
146
154
  pool_name = @storage_pool_name
147
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
+
148
162
  @logger.debug "Search for volumes in pool: #{pool_name}"
149
163
  env[:box_volumes].each_index do |index|
150
164
  suffix_index = index > 0 ? "_#{index}" : ''
@@ -152,14 +166,16 @@ module VagrantPlugins
152
166
  name: "#{@name}#{suffix_index}.img"
153
167
  ).find { |x| x.pool_name == pool_name }
154
168
  raise Errors::DomainVolumeExists if domain_volume.nil?
169
+
155
170
  @domain_volumes.push({
156
- :dev => (index+1).vdev.to_s,
171
+ :dev => env[:box_volumes][index][:device],
157
172
  :cache => @domain_volume_cache,
158
173
  :bus => @disk_bus,
159
174
  :path => domain_volume.path,
160
175
  :virtual_size => env[:box_volumes][index][:virtual_size]
161
176
  })
162
- end
177
+ end
178
+
163
179
  end
164
180
 
165
181
  # If we have a box, take the path from the domain volume and set our storage_prefix.
@@ -171,6 +187,8 @@ module VagrantPlugins
171
187
  storage_prefix = get_disk_storage_prefix(env, @storage_pool_name)
172
188
  end
173
189
 
190
+ resolver.resolve!(@disks)
191
+
174
192
  @disks.each do |disk|
175
193
  disk[:path] ||= _disk_name(@name, disk)
176
194
 
@@ -219,6 +237,20 @@ module VagrantPlugins
219
237
  end
220
238
  end
221
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
+
222
254
  # Output the settings we're going to use to the user
223
255
  env[:ui].info(I18n.t('vagrant_libvirt.creating_domain'))
224
256
  env[:ui].info(" -- Name: #{@name}")
@@ -268,7 +300,7 @@ module VagrantPlugins
268
300
  end
269
301
  env[:ui].info(" -- Storage pool: #{@storage_pool_name}")
270
302
  @domain_volumes.each do |volume|
271
- env[:ui].info(" -- Image(#{volume[:device]}): #{volume[:path]}, #{volume[:virtual_size].to_GB}G")
303
+ env[:ui].info(" -- Image(#{volume[:dev]}): #{volume[:path]}, #{volume[:bus]}, #{volume[:virtual_size].to_GB}G")
272
304
  end
273
305
 
274
306
  if not @disk_driver_opts.empty?
@@ -282,9 +314,10 @@ module VagrantPlugins
282
314
  env[:ui].info(" -- Graphics Type: #{@graphics_type}")
283
315
  env[:ui].info(" -- Graphics Port: #{@graphics_port}")
284
316
  env[:ui].info(" -- Graphics IP: #{@graphics_ip}")
285
- env[:ui].info(" -- Graphics Password: #{@graphics_passwd.empty? ? 'Not defined' : 'Defined'}")
317
+ env[:ui].info(" -- Graphics Password: #{@graphics_passwd.nil? ? 'Not defined' : 'Defined'}")
286
318
  env[:ui].info(" -- Video Type: #{@video_type}")
287
319
  env[:ui].info(" -- Video VRAM: #{@video_vram}")
320
+ env[:ui].info(" -- Video 3D accel: #{@video_accel3d}")
288
321
  env[:ui].info(" -- Sound Type: #{@sound_type}")
289
322
  env[:ui].info(" -- Keymap: #{@keymap}")
290
323
  env[:ui].info(" -- TPM Backend: #{@tpm_type}")
@@ -295,6 +328,12 @@ module VagrantPlugins
295
328
  env[:ui].info(" -- TPM Path: #{@tpm_path}")
296
329
  end
297
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
+
298
337
  @boot_order.each do |device|
299
338
  env[:ui].info(" -- Boot device: #{device}")
300
339
  end
@@ -379,6 +418,13 @@ module VagrantPlugins
379
418
  env[:ui].info(" -- smartcard device: mode=#{@smartcard_dev[:mode]}, type=#{@smartcard_dev[:type]}")
380
419
  end
381
420
 
421
+ @serials.each_with_index do |serial, port|
422
+ if serial[:source]
423
+ env[:ui].info(" -- SERIAL(COM#{port}: redirect to #{serial[:source][:path]}")
424
+ env[:ui].warn(I18n.t('vagrant_libvirt.warnings.creating_domain_console_access_disabled'))
425
+ end
426
+ end
427
+
382
428
  unless @qemu_args.empty?
383
429
  env[:ui].info(' -- Command line args: ')
384
430
  @qemu_args.each do |arg|
@@ -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
@@ -208,6 +217,9 @@ module VagrantPlugins
208
217
 
209
218
  # Create a private network.
210
219
  create_private_network(env)
220
+ write_created_network(env)
221
+ else
222
+ write_created_network(env) unless @options[:always_destroy] == false
211
223
  end
212
224
  end
213
225
 
@@ -247,6 +259,9 @@ module VagrantPlugins
247
259
 
248
260
  # Create a private network.
249
261
  create_private_network(env)
262
+ write_created_network(env)
263
+ else
264
+ write_created_network(env) unless @options[:always_destroy] == false
250
265
  end
251
266
  end
252
267
 
@@ -273,6 +288,9 @@ module VagrantPlugins
273
288
 
274
289
  # Create a private network.
275
290
  create_private_network(env)
291
+ write_created_network(env)
292
+ else
293
+ write_created_network(env) unless @options[:always_destroy] == false
276
294
  end
277
295
  end
278
296
 
@@ -334,6 +352,10 @@ module VagrantPlugins
334
352
  @network_dhcp_enabled = false
335
353
  end
336
354
 
355
+ if @options[:tftp_root]
356
+ @tftp_root = @options[:tftp_root]
357
+ end
358
+
337
359
  @network_domain_name = @options[:domain_name]
338
360
 
339
361
  begin
@@ -347,7 +369,9 @@ module VagrantPlugins
347
369
  rescue => e
348
370
  raise Errors::CreateNetworkError, error_message: e.message
349
371
  end
372
+ end
350
373
 
374
+ def write_created_network(env)
351
375
  created_networks_file = env[:machine].data_dir + 'created_networks'
352
376
 
353
377
  message = 'Saving information about created network ' \
@@ -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
- env[:machine].provider_config.disks.each do |disk|
54
- # shared disks remove only manually or ???
55
- next if disk[:allow_existing]
56
- diskname = libvirt_domain.name + '-' + disk[:device] + '.' + disk[:type].to_s
57
- # diskname is unique
58
- libvirt_disk = domain.volumes.select do |x|
59
- x.name == diskname
60
- end.first
61
- if libvirt_disk
62
- libvirt_disk.destroy
63
- elsif disk[:path]
64
- poolname = env[:machine].provider_config.storage_pool_name
65
- libvirt_disk = domain.volumes.select do |x|
66
- # FIXME: can remove pool/target.img and pool/123/target.img
67
- x.path =~ /\/#{disk[:path]}$/ && x.pool_name == poolname
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
- libvirt_disk.destroy if libvirt_disk
88
+ if root_disk
89
+ root_disk.destroy
90
+ end
70
91
  end
71
92
  end
72
93
 
73
- # remove root storage
74
- root_disk = domain.volumes.select do |x|
75
- x.name == libvirt_domain.name + '.img' if x
76
- end.first
77
- root_disk.destroy if root_disk
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