vagrant-libvirt 0.6.2 → 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.
Files changed (64) 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/handle_box_image.rb +19 -10
  11. data/lib/vagrant-libvirt/action/prepare_nfs_settings.rb +1 -1
  12. data/lib/vagrant-libvirt/action/start_domain.rb +36 -0
  13. data/lib/vagrant-libvirt/action/wait_till_up.rb +6 -32
  14. data/lib/vagrant-libvirt/action.rb +67 -80
  15. data/lib/vagrant-libvirt/config.rb +85 -30
  16. data/lib/vagrant-libvirt/driver.rb +11 -9
  17. data/lib/vagrant-libvirt/errors.rb +12 -0
  18. data/lib/vagrant-libvirt/templates/domain.xml.erb +228 -218
  19. data/lib/vagrant-libvirt/templates/private_network.xml.erb +4 -1
  20. data/lib/vagrant-libvirt/util/network_util.rb +15 -3
  21. data/lib/vagrant-libvirt/util/nfs.rb +2 -0
  22. data/lib/vagrant-libvirt/util/resolvers.rb +80 -0
  23. data/lib/vagrant-libvirt/version +1 -1
  24. data/locales/en.yml +21 -0
  25. data/spec/spec_helper.rb +36 -23
  26. data/spec/support/libvirt_context.rb +7 -4
  27. data/spec/support/sharedcontext.rb +1 -1
  28. data/spec/unit/action/cleanup_on_failure_spec.rb +131 -0
  29. data/spec/unit/action/create_domain_spec/additional_disks_domain.xml +6 -18
  30. data/spec/unit/action/create_domain_spec/custom_disk_settings.xml +43 -0
  31. data/spec/unit/action/create_domain_spec/default_domain.xml +6 -18
  32. data/spec/unit/action/create_domain_spec/two_disk_settings.xml +49 -0
  33. data/spec/unit/action/create_domain_spec.rb +51 -7
  34. data/spec/unit/action/create_domain_volume_spec.rb +5 -3
  35. data/spec/unit/action/destroy_domain_spec/additional_disks_domain.xml +47 -0
  36. data/spec/unit/action/destroy_domain_spec/box_multiple_disks.xml +55 -0
  37. data/spec/unit/action/destroy_domain_spec/box_multiple_disks_and_additional_and_custom_disks.xml +72 -0
  38. data/spec/unit/action/destroy_domain_spec/box_multiple_disks_and_additional_and_custom_disks_no_aliases.xml +67 -0
  39. data/spec/unit/action/destroy_domain_spec/box_multiple_disks_and_additional_disks.xml +67 -0
  40. data/spec/unit/action/destroy_domain_spec/cdrom_domain.xml +48 -0
  41. data/spec/unit/action/destroy_domain_spec.rb +134 -30
  42. data/spec/unit/action/forward_ports_spec.rb +10 -2
  43. data/spec/unit/action/handle_box_image_spec.rb +30 -0
  44. data/spec/unit/action/prepare_nfs_settings_spec.rb +59 -0
  45. data/spec/unit/action/shutdown_domain_spec.rb +1 -1
  46. data/spec/unit/action/start_domain_spec/clock_timer_rtc.xml +6 -18
  47. data/spec/unit/action/start_domain_spec/default.xml +6 -18
  48. data/spec/unit/action/start_domain_spec/default_added_tpm_path.xml +6 -18
  49. data/spec/unit/action/start_domain_spec/default_added_tpm_version.xml +6 -18
  50. data/spec/unit/action/start_domain_spec/existing.xml +1 -1
  51. data/spec/unit/action/wait_till_up_spec.rb +4 -43
  52. data/spec/unit/action_spec.rb +2 -0
  53. data/spec/unit/config_spec.rb +133 -26
  54. data/spec/unit/driver_spec.rb +154 -10
  55. data/spec/unit/provider_spec.rb +11 -0
  56. data/spec/unit/templates/domain_all_settings.xml +56 -77
  57. data/spec/unit/templates/domain_cpu_mode_passthrough.xml +39 -0
  58. data/spec/unit/templates/domain_custom_cpu_model.xml +6 -18
  59. data/spec/unit/templates/domain_defaults.xml +6 -18
  60. data/spec/unit/templates/domain_spec.rb +39 -13
  61. data/spec/unit/templates/tpm/version_1.2.xml +6 -18
  62. data/spec/unit/templates/tpm/version_2.0.xml +6 -18
  63. data/spec/unit/util/resolvers_spec.rb +116 -0
  64. metadata +65 -64
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3e9e48f76c74f80aa79c260ab558d0a72ec8dd3ecc667731ff05bd0a54d8ab8b
4
- data.tar.gz: 8144733ea9d0f2a0a3152d481ab690120017a6767dcee783de8d5ba86d320d62
3
+ metadata.gz: b1bfaefd1dab7cbdb1293e867e29fef05a9eb101fae5226a38203593de84e717
4
+ data.tar.gz: d36d4f487ed2ad0b4f00ba09c263a5cd8deda6c268eef50974376e2796b7e64d
5
5
  SHA512:
6
- metadata.gz: a4a81d5cacbee89973ae0dee7eedcc28ccee0a66d9d1139cef7a91ade87b16ca85a91f0cf22e7d8659450114691fc3079b7beef5cb002621683881cc99ca634a
7
- data.tar.gz: 418ed72a453ba03aca7c0cb67d15adc431d37ab5de7c7f0f2d9f9a987f90ad7a88e923249eaf0a324ebc57886dc1b4d9eb23bcf3258254970dc8cdc8ba9a6f90
6
+ metadata.gz: 510c1b6ffd2fb4eea02ede8d7612c3a41a89e5c50b630370bec6fd70b79986caa222e6ce1cc0f4c2732b310f7c134866aa2283ee449441c92078b148c4734503
7
+ data.tar.gz: cb6ab754dcff508ec150c6ff67cf82b603243596b35ab6a5ef79d4dfe36042a933dde8eebc3630d5a2473c8fcd398111a98d12a64a66950ad0abe942c15bce40
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