vagrant-qemu 0.6.3 → 0.6.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f81dd5d072fb839f4c777404103ebdd5ec5054d485ac1e03333cffe30f928757
4
- data.tar.gz: 11eb4c9827ec804c3de383404c8249c0b9f5b02ac2d52a1e304c7b4719acc87d
3
+ metadata.gz: 275a26aad79e641534b4c9ea0bb7a9824f964b61c66dbbe9e3bf0d7075f23081
4
+ data.tar.gz: f4afe41ed386785952534fff85e7030030fab8b4defdd7438ce37cee649b1a50
5
5
  SHA512:
6
- metadata.gz: '0906a95866bb2bd8206dc602242e58c21ef966fe71c428ff5eebea455065fee57c6e1b7c06ff516d1b4d54bb42b23e9e821480e096ea6f8625d477355267dcdb'
7
- data.tar.gz: abbfa2aae80e76d9ce268db53657deaa468ab125b7b0aa2e5934c2b3cb4917ac2ff54662ea49b8f4a428815161414b9560439801845b7ac09b6479b0ead4a7b2
6
+ metadata.gz: b05b9827dc708cf7dab8a417caae11eeed6fda22380e6d80d8eb3fd8a08c974b70f26b32ee0a10ceb06699a69ed59f1dcbfb42b856bed00ddb5bdeefa04acd37
7
+ data.tar.gz: dd55d31e14d55305e1c7714d74eb5d273fed56ba3b4ea927fb37ff305d337dbfd752f913f3b509562c395d8734950079d155e59950138c601041d29b0f10f744
data/CHANGELOG.md CHANGED
@@ -205,3 +205,21 @@
205
205
  arguments for the private network NIC and the command line assembly blew up
206
206
  before QEMU was launched. Setting `net_mode` explicitly (e.g.
207
207
  `:vmnet_shared`) was the workaround. (#40)
208
+
209
+ # 0.6.4 (2026-10-09)
210
+
211
+ * Fix `vagrant up` failing with `ForwardPortCollision` ("The forwarded port
212
+ to 50022 is already in use") on macOS 27 even when nothing listens on the
213
+ port. A non-blocking connect to a closed local port there reports success
214
+ on the retry, so Vagrant's port check treated every port as in use. The
215
+ provider now supplies a port check that confirms the connection; results on
216
+ other systems are unchanged, and Windows keeps Vagrant's own check.
217
+ * Quote MAC addresses in the generated cloud-init `network-config`. cloud-init
218
+ reads it as YAML 1.1, where an unquoted MAC whose octets are all decimal and
219
+ below 60 (e.g. `52:54:00:26:47:05`) is a base-60 integer. With
220
+ `advanced_network`, about 1.3% of generated MACs hit this, and the guest's
221
+ network config was rejected, which could leave the VM unreachable over SSH
222
+ on first boot. (#82, thanks @SamuelBoerlin)
223
+ * README: bring a `socket_opts` `listen=`/`connect=` pair up with
224
+ `vagrant up --no-parallel`. A plain `vagrant up` boots both machines in
225
+ parallel, and if the connector starts first the link never comes up.
data/CLAUDE.md CHANGED
@@ -23,7 +23,43 @@ vagrant plugin install ./pkg/vagrant-qemu-<version>.gem
23
23
  vagrant plugin list | grep vagrant-qemu
24
24
  ```
25
25
 
26
- Tests (rspec) are defined in the Gemfile but currently commented out in the Rakefile. There is no active test suite.
26
+ ## Testing
27
+
28
+ ```bash
29
+ bundle exec rake spec:unit # unit specs
30
+ bundle exec rake spec:acceptance # acceptance specs
31
+ bundle exec rake spec # unit + acceptance
32
+ ```
33
+
34
+ Heavy suites are tag-gated in `spec/spec_helper.rb` and excluded unless the matching env var is set: `TEST_QEMU` (`:requires_qemu`), `TEST_VMNET` (`:requires_vmnet`), `TEST_SOCKET_VMNET` (`:requires_socket_vmnet`). rspec prints the excluded tags in its `Run options:` line — check it to confirm the suite you wanted actually ran. The vmnet e2e suite needs root:
35
+
36
+ ```bash
37
+ TEST_VMNET=1 sudo -E bundle exec rspec spec/e2e/advanced_network_spec.rb
38
+ ```
39
+
40
+ **e2e exercises the *installed* plugin, not the source tree.** `spec/e2e/helper.rb` compares the installed plugin version against `lib/vagrant-qemu/version.rb` and aborts on a mismatch, so rebuild and reinstall first:
41
+
42
+ ```bash
43
+ bundle exec rake build && vagrant plugin install ./pkg/vagrant-qemu-<version>.gem
44
+ ```
45
+
46
+ That guard compares version *numbers* only. Reinstalling after a source change without bumping the version passes the check while still testing stale code — and produces a local gem whose version collides with a published one.
47
+
48
+ ## Releasing
49
+
50
+ `bundle exec rake release` handles the mechanics: tags `v<version>`, pushes the tag, builds, and pushes the gem to rubygems.org. Bump `lib/vagrant-qemu/version.rb` and add the CHANGELOG entry in a separate `Release <version>` commit first (see git history for the shape).
51
+
52
+ A release is complete only when all four have landed:
53
+
54
+ 1. gem published on rubygems.org
55
+ 2. `master` pushed
56
+ 3. tag `v<version>` pushed
57
+ 4. GitHub release created **with the built gem attached as an asset** — a repo convention every prior release follows:
58
+ ```bash
59
+ gh release create v<version> --title v<version> --notes-file <notes> pkg/vagrant-qemu-<version>.gem
60
+ ```
61
+
62
+ `rake release` tags before pushing the gem, so a mid-way failure can leave a pushed tag with no published gem; verify all four rather than assuming the command got through.
27
63
 
28
64
  ## Architecture
29
65
 
data/README.md CHANGED
@@ -329,7 +329,7 @@ For VM-to-VM networking on macOS without sudo, use `:socket` with a `listen`/`co
329
329
  ```ruby
330
330
  Vagrant.configure("2") do |config|
331
331
  PORT = 12399
332
- # vm1 listens; define it first so it is up before vm2 connects.
332
+ # vm1 listens, vm2 connects to it.
333
333
  config.vm.define "vm1" do |c|
334
334
  c.vm.box = "perk/ubuntu-2204-arm64" # an aarch64 cloud-init box
335
335
  c.vm.network "private_network", ip: "192.168.105.51"
@@ -354,6 +354,8 @@ Vagrant.configure("2") do |config|
354
354
  end
355
355
  ```
356
356
 
357
+ Bring it up with `vagrant up --no-parallel`. The provider boots machines in parallel by default, so a plain `vagrant up` can start vm2 before vm1 is listening, and the link never comes up.
358
+
357
359
  A single VM with a static IP (vmnet is the default backend on macOS when `net_mode` is `:auto`):
358
360
 
359
361
  ```ruby
@@ -415,7 +417,7 @@ Notes:
415
417
  * The Linux `:tap` backend expects a pre-created tap device attached to a bridge, e.g.:
416
418
  `sudo ip tuntap add tap0 mode tap && sudo ip link set tap0 master br0 && sudo ip link set tap0 up`
417
419
  * `socket_opts = "mcast=..."` gives N-way VM-to-VM on Linux/Windows, but does **not** work on macOS: QEMU binds the netdev socket to the multicast group address, which the Darwin socket stack refuses to send from (`EADDRNOTAVAIL`). On macOS use a `listen`/`connect` pair (no root) or vmnet (sudo).
418
- * `socket_opts = "listen=..."` / `"connect=..."` is a point-to-point QEMU TCP link and connects **exactly two** VMs (QEMU's listening socket accepts a single connection — it is not a hub). You choose which VM listens and which connects. The listener must be running before the connector starts, so define the listener first and bring the environment up together (`vagrant up`); starting a connector alone, or reloading the listener, drops the link.
420
+ * `socket_opts = "listen=..."` / `"connect=..."` is a point-to-point QEMU TCP link and connects **exactly two** VMs (QEMU's listening socket accepts a single connection — it is not a hub). You choose which VM listens and which connects. The listener must be running before the connector starts, so define the listener first and bring the environment up with `vagrant up --no-parallel` (a plain `vagrant up` boots both in parallel and may start the connector first: both VMs come up with their IPs, but no traffic passes). Starting a connector alone, or reloading the listener, drops the link.
419
421
 
420
422
  Platform support:
421
423
 
@@ -1,3 +1,5 @@
1
+ require "socket"
2
+
1
3
  module VagrantPlugins
2
4
  module QEMU
3
5
  module Action
@@ -17,6 +19,13 @@ module VagrantPlugins
17
19
  remap = {}
18
20
  env[:port_collision_remap] = remap
19
21
 
22
+ # Windows keeps Vagrant's per-interface check for 0.0.0.0.
23
+ if !Vagrant::Util::Platform.windows?
24
+ env[:port_collision_port_check] = lambda do |host_ip, host_port|
25
+ self.class.port_in_use?(host_ip || "0.0.0.0", host_port)
26
+ end
27
+ end
28
+
20
29
  has_ssh_forward = false
21
30
  machine.config.vm.networks.each do |type, options|
22
31
  next if type != :forwarded_port
@@ -42,6 +51,20 @@ module VagrantPlugins
42
51
 
43
52
  @app.call(env)
44
53
  end
54
+
55
+ # Vagrant's IsPortOpen with an extra getpeername: on macOS 27 a refused
56
+ # non-blocking connect reports EISCONN on the retry, so Socket.tcp
57
+ # returns an unconnected socket and every port looks in use.
58
+ def self.port_in_use?(host, port)
59
+ Socket.tcp(host, port, connect_timeout: 0.1) do |sock|
60
+ sock.remote_address
61
+ true
62
+ end
63
+ rescue Errno::ETIMEDOUT, Errno::ECONNREFUSED, Errno::EHOSTUNREACH,
64
+ Errno::ENETUNREACH, Errno::EACCES, Errno::ENOTCONN, Errno::EALREADY,
65
+ Errno::EINVAL
66
+ false
67
+ end
45
68
  end
46
69
  end
47
70
  end
@@ -100,10 +100,15 @@ module VagrantPlugins
100
100
  # @param mac1 [String] MAC of advanced network NIC
101
101
  # @param ip [String] static IP for the advanced NIC (e.g. "192.168.105.10")
102
102
  # @param netmask [String] netmask (e.g. "255.255.255.0")
103
- # @return [String] YAML string
103
+ # Emitted as JSON, which is valid YAML: cloud-init parses network-config
104
+ # as YAML 1.1, where an unquoted MAC whose octets are all decimal and
105
+ # below 60 (e.g. 52:54:00:26:47:05) is a base-60 integer. Psych's
106
+ # to_yaml leaves such a MAC unquoted; JSON always quotes strings.
107
+ #
108
+ # @return [String] YAML (JSON) string
104
109
  def self.build_network_config(mac0:, mac1:, ip:, netmask: "255.255.255.0")
105
110
  require 'ipaddr'
106
- require 'yaml'
111
+ require 'json'
107
112
 
108
113
  prefix = IPAddr.new(netmask).to_i.to_s(2).count("1")
109
114
 
@@ -123,7 +128,7 @@ module VagrantPlugins
123
128
  }
124
129
  }
125
130
 
126
- config.to_yaml
131
+ JSON.pretty_generate(config)
127
132
  end
128
133
  end
129
134
  end
@@ -1,5 +1,5 @@
1
1
  module VagrantPlugins
2
2
  module QEMU
3
- VERSION = '0.6.3'
3
+ VERSION = '0.6.4'
4
4
  end
5
5
  end
@@ -16,6 +16,7 @@ describe "advanced networking end-to-end", :requires_vmnet do
16
16
  it "VM gets the configured static IP with the default net_mode" do
17
17
  File.write(@work_dir.join("Vagrantfile"), <<~RUBY)
18
18
  Vagrant.configure("2") do |config|
19
+ #{snapd_fast_stop}
19
20
  config.vm.box = "#{test_box_cloudinit}"
20
21
  config.vm.box_check_update = false
21
22
  config.vm.synced_folder ".", "/vagrant", disabled: true
@@ -35,6 +36,7 @@ describe "advanced networking end-to-end", :requires_vmnet do
35
36
  it "host can ping the VM IP" do
36
37
  File.write(@work_dir.join("Vagrantfile"), <<~RUBY)
37
38
  Vagrant.configure("2") do |config|
39
+ #{snapd_fast_stop}
38
40
  config.vm.box = "#{test_box_cloudinit}"
39
41
  config.vm.box_check_update = false
40
42
  config.vm.synced_folder ".", "/vagrant", disabled: true
@@ -58,6 +60,7 @@ describe "advanced networking end-to-end", :requires_vmnet do
58
60
  user_mac = "52:54:00:aa:bb:cc"
59
61
  File.write(@work_dir.join("Vagrantfile"), <<~RUBY)
60
62
  Vagrant.configure("2") do |config|
63
+ #{snapd_fast_stop}
61
64
  config.vm.box = "#{test_box_cloudinit}"
62
65
  config.vm.box_check_update = false
63
66
  config.vm.synced_folder ".", "/vagrant", disabled: true
@@ -80,6 +83,7 @@ describe "advanced networking end-to-end", :requires_vmnet do
80
83
  it "two VMs can communicate via private network" do
81
84
  File.write(@work_dir.join("Vagrantfile"), <<~RUBY)
82
85
  Vagrant.configure("2") do |config|
86
+ #{snapd_fast_stop}
83
87
  config.vm.define "vm1" do |c|
84
88
  c.vm.box = "#{test_box_cloudinit}"
85
89
  c.vm.box_check_update = false
data/spec/e2e/helper.rb CHANGED
@@ -46,6 +46,15 @@ module E2EHelper
46
46
  TEST_BOX_CLOUDINIT
47
47
  end
48
48
 
49
+ # The cloud-init box starts a snapd auto-refresh on first boot, and stopping
50
+ # snapd mid-refresh can hold guest shutdown for up to 90s. Destroy follows
51
+ # right after, so don't wait for it.
52
+ def snapd_fast_stop
53
+ <<~RUBY.chomp
54
+ config.vm.provision "shell", inline: "mkdir -p /etc/systemd/system/snapd.service.d && printf '[Service]\\\\nTimeoutStopSec=5s\\\\n' > /etc/systemd/system/snapd.service.d/e2e-fast-stop.conf && systemctl daemon-reload"
55
+ RUBY
56
+ end
57
+
49
58
  def vagrant_up(cwd, provider: "qemu", timeout: 300)
50
59
  run_vagrant_cmd("up", "--provider=#{provider}", cwd: cwd, timeout: timeout)
51
60
  end
@@ -65,7 +74,10 @@ module E2EHelper
65
74
  run_vagrant_cmd("reload", cwd: cwd, timeout: timeout)
66
75
  end
67
76
 
68
- def vagrant_destroy(cwd, timeout: 60)
77
+ # Longer than the driver's own escalation (powerdown, then quit, each up to
78
+ # graceful_timeout) for two machines: killing vagrant mid-stop leaves the
79
+ # daemonized QEMU running and holding its ports for the next example.
80
+ def vagrant_destroy(cwd, timeout: 300)
69
81
  run_vagrant_cmd("destroy", "-f", cwd: cwd, timeout: timeout)
70
82
  end
71
83
 
@@ -36,6 +36,7 @@ describe "advanced networking over socket multicast (no root)", :requires_qemu d
36
36
  # assignment or cross-VM traffic broke.
37
37
  File.write(@work_dir.join("Vagrantfile"), <<~RUBY)
38
38
  Vagrant.configure("2") do |config|
39
+ #{snapd_fast_stop}
39
40
  config.vm.box = "#{test_box_cloudinit}"
40
41
  config.vm.box_check_update = false
41
42
  config.vm.synced_folder ".", "/vagrant", disabled: true
@@ -57,6 +58,37 @@ describe "advanced networking over socket multicast (no root)", :requires_qemu d
57
58
  expect(ssh[:stdout]).to include("192.168.105.40")
58
59
  end
59
60
 
61
+ it "a MAC that YAML 1.1 reads as an integer reaches netplan as a string" do
62
+ # All octets decimal and below 60: an unquoted MAC in network-config is a
63
+ # base-60 integer to cloud-init, and netplan then rejects the rendered
64
+ # config. Generated MACs hit this ~1.3% of the time, so pin one.
65
+ mac = "52:54:00:26:47:05"
66
+ File.write(@work_dir.join("Vagrantfile"), <<~RUBY)
67
+ Vagrant.configure("2") do |config|
68
+ #{snapd_fast_stop}
69
+ config.vm.box = "#{test_box_cloudinit}"
70
+ config.vm.box_check_update = false
71
+ config.vm.synced_folder ".", "/vagrant", disabled: true
72
+ config.vm.network "private_network", ip: "192.168.105.42", mac: "#{mac}"
73
+ config.vm.provider "qemu" do |qe|
74
+ qe.memory = "2G"
75
+ qe.advanced_network = true
76
+ qe.net_mode = :socket
77
+ qe.mcast_addr = "#{MCAST}"
78
+ end
79
+ end
80
+ RUBY
81
+
82
+ result = vagrant_up(@work_dir, timeout: 600)
83
+ expect(result[:exit_code]).to eq 0
84
+
85
+ ssh = vagrant_ssh(@work_dir, command: "ip addr show")
86
+ expect(ssh[:stdout]).to include("192.168.105.42")
87
+
88
+ ssh = vagrant_ssh(@work_dir, command: "sudo netplan generate")
89
+ expect(ssh[:exit_code]).to eq(0), ssh[:stderr]
90
+ end
91
+
60
92
  it "two VMs communicate over the socket multicast private network" do
61
93
  # QEMU's socket-multicast netdev binds its UDP socket to the multicast
62
94
  # group address (net/socket.c net_socket_mcast_create). Darwin's socket
@@ -73,6 +105,7 @@ describe "advanced networking over socket multicast (no root)", :requires_qemu d
73
105
 
74
106
  File.write(@work_dir.join("Vagrantfile"), <<~RUBY)
75
107
  Vagrant.configure("2") do |config|
108
+ #{snapd_fast_stop}
76
109
  config.vm.define "vm1" do |c|
77
110
  c.vm.box = "#{test_box_cloudinit}"
78
111
  c.vm.box_check_update = false
@@ -135,8 +168,8 @@ describe "advanced networking over socket listen/connect (no root)", :requires_q
135
168
  it "two VMs communicate over a user-defined listen/connect socket" do
136
169
  File.write(@work_dir.join("Vagrantfile"), <<~RUBY)
137
170
  Vagrant.configure("2") do |config|
138
- # The user picks the roles: vm1 listens, vm2 connects. vm1 is defined
139
- # first so it boots first and is listening before vm2 dials in.
171
+ #{snapd_fast_stop}
172
+ # The user picks the roles: vm1 listens, vm2 connects.
140
173
  config.vm.define "vm1" do |c|
141
174
  c.vm.box = "#{test_box_cloudinit}"
142
175
  c.vm.box_check_update = false
@@ -167,7 +200,10 @@ describe "advanced networking over socket listen/connect (no root)", :requires_q
167
200
  end
168
201
  RUBY
169
202
 
170
- vagrant_up(@work_dir, timeout: 600)
203
+ # The provider boots machines in parallel; --no-parallel follows the
204
+ # definition order, so vm1 is listening before vm2 connects.
205
+ result = run_vagrant_cmd("up", "--provider=qemu", "--no-parallel", cwd: @work_dir, timeout: 600)
206
+ expect(result[:exit_code]).to eq(0), result[:stderr]
171
207
 
172
208
  # vm1 (listener) pings vm2 (connector) over the link. Assert on the ping
173
209
  # output itself, not just an exit code that can pass vacuously.
@@ -16,6 +16,7 @@ describe "socket_vmnet advanced networking end-to-end", :requires_socket_vmnet d
16
16
  it "VM gets the configured static IP (no sudo)" do
17
17
  File.write(@work_dir.join("Vagrantfile"), <<~RUBY)
18
18
  Vagrant.configure("2") do |config|
19
+ #{snapd_fast_stop}
19
20
  config.vm.box = "#{test_box_cloudinit}"
20
21
  config.vm.box_check_update = false
21
22
  config.vm.synced_folder ".", "/vagrant", disabled: true
@@ -36,6 +37,7 @@ describe "socket_vmnet advanced networking end-to-end", :requires_socket_vmnet d
36
37
  it "host can ping the VM IP" do
37
38
  File.write(@work_dir.join("Vagrantfile"), <<~RUBY)
38
39
  Vagrant.configure("2") do |config|
40
+ #{snapd_fast_stop}
39
41
  config.vm.box = "#{test_box_cloudinit}"
40
42
  config.vm.box_check_update = false
41
43
  config.vm.synced_folder ".", "/vagrant", disabled: true
@@ -56,6 +58,7 @@ describe "socket_vmnet advanced networking end-to-end", :requires_socket_vmnet d
56
58
  it "two VMs can communicate via the socket_vmnet private network" do
57
59
  File.write(@work_dir.join("Vagrantfile"), <<~RUBY)
58
60
  Vagrant.configure("2") do |config|
61
+ #{snapd_fast_stop}
59
62
  config.vm.define "vm1" do |c|
60
63
  c.vm.box = "#{test_box_cloudinit}"
61
64
  c.vm.box_check_update = false
@@ -100,6 +103,7 @@ describe "socket_vmnet advanced networking end-to-end", :requires_socket_vmnet d
100
103
  shim = File.expand_path("support/qemu_no_stream_shim.sh", __dir__)
101
104
  File.write(@work_dir.join("Vagrantfile"), <<~RUBY)
102
105
  Vagrant.configure("2") do |config|
106
+ #{snapd_fast_stop}
103
107
  config.vm.box = "#{test_box_cloudinit}"
104
108
  config.vm.box_check_update = false
105
109
  config.vm.synced_folder ".", "/vagrant", disabled: true
@@ -69,4 +69,36 @@ describe VagrantPlugins::QEMU::Action::PrepareForwardedPortCollisionParams do
69
69
 
70
70
  expect(ssh_entry[:host]).to eq 60022
71
71
  end
72
+
73
+ describe "port collision check" do
74
+ def port_check(windows: false)
75
+ allow(Vagrant::Util::Platform).to receive(:windows?).and_return(windows)
76
+ ctx = mock_vagrant_env(networks: [])
77
+ described_class.new(app, ctx[:env]).call(ctx[:env])
78
+ ctx[:env][:port_collision_port_check]
79
+ end
80
+
81
+ it "reports a listening port as in use" do
82
+ server = TCPServer.new("127.0.0.1", 0)
83
+ expect(port_check.call("127.0.0.1", server.addr[1])).to eq true
84
+ ensure
85
+ server&.close
86
+ end
87
+
88
+ it "reports a closed port as free" do
89
+ server = TCPServer.new("127.0.0.1", 0)
90
+ port = server.addr[1]
91
+ server.close
92
+ expect(port_check.call("127.0.0.1", port)).to eq false
93
+ end
94
+
95
+ it "checks 0.0.0.0 when no host_ip is given" do
96
+ expect(described_class).to receive(:port_in_use?).with("0.0.0.0", 50022).and_return(false)
97
+ port_check.call(nil, 50022)
98
+ end
99
+
100
+ it "keeps Vagrant's own check on Windows" do
101
+ expect(port_check(windows: true)).to be_nil
102
+ end
103
+ end
72
104
  end
@@ -29,6 +29,15 @@ describe VagrantPlugins::QEMU::Network, ".build_network_config" do
29
29
  expect(priv_nic["addresses"]).to eq ["192.168.105.10/24"]
30
30
  end
31
31
 
32
+ context "with MACs that YAML 1.1 reads as base-60 integers" do
33
+ let(:mac0) { "52:54:00:26:47:05" }
34
+ let(:mac1) { "52:54:00:12:34:56" }
35
+
36
+ it "quotes the MACs" do
37
+ expect(subject).to include("\"#{mac0}\"", "\"#{mac1}\"")
38
+ end
39
+ end
40
+
32
41
  it "calculates /16 prefix for 255.255.0.0 netmask" do
33
42
  result = described_class.build_network_config(
34
43
  mac0: mac0, mac1: mac1,
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vagrant-qemu
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.3
4
+ version: 0.6.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - ppggff
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-08-12 00:00:00.000000000 Z
11
+ date: 2026-10-09 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Enables Vagrant to manage machines with QEMU.
14
14
  email: pgf00a@gmail.com