vagrant-qemu 0.3.5 → 0.3.7

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: c30b268793fc83d9e8f8e87c6a8f4bcee6b918bc93e290fca5d7fa5bbf997fb8
4
- data.tar.gz: 0f4601e7634001be4f8073587dd695dacac7c5ff6822c06530d8b09cae4f19e2
3
+ metadata.gz: aa6a7877a0f30cbe820b09bfb481863f115758c542c92f02570641c3057983de
4
+ data.tar.gz: 74151d323890fcf318b74af5c251ae9413f8089429a700ac51e1e3f57d0e693f
5
5
  SHA512:
6
- metadata.gz: c0799387634f0395de31a58e7e94b2e5668527b4a1f02e793d7bc0efdfc8b44879146a6e5a714866e99a8447ffd4ac23985efac9ca3d4d05462a217d3ae88a6b
7
- data.tar.gz: 9ca32661b5d7078e9e4641d2acb3c131686b9e52458405618bfe0074abc77829d36f9b858c24202f9cd01fe96793a4e5595e39dc8eecb6678c1ad38f8cfcd2e4
6
+ metadata.gz: e0bc88d099f46ce974eb217025108e86d6ab14ca7efe199450e7ddf1e9364ebe24d466175067f3cf30f470864981251cecb46b3bffdfa070f6e7caf67906249b
7
+ data.tar.gz: 3d7e6b3486b69cf0a7ff5ebdcd536bda37ea5f733e6eb89677746d27b3e6169f12e369ce31d6b02dfacb7e6145719c656afed238796bba8338b8f11fc69deacb
data/CHANGELOG.md CHANGED
@@ -66,3 +66,14 @@
66
66
  * Allow no cpu for riscv64.
67
67
  * Allow more config options to be nil.
68
68
  * Let id start with "vq_".
69
+
70
+ # 0.3.6 (2024-02-27)
71
+
72
+ * Config 'image_path' support array type
73
+ * Try to support libvirt box v2 format
74
+
75
+ # 0.3.7 (2025-02-02)
76
+
77
+ * Ignore exception after sending 'system_powerdown' cmd, fix windows halt error
78
+ * Move pid file to tmp dir
79
+ * Be able to auto correct ssh port collisions, new config: ssh_auto_correct
data/README.md CHANGED
@@ -30,6 +30,7 @@ Others:
30
30
 
31
31
  * Import from a Libvirt vagrant box or qcow2 image
32
32
  * To use box for **Paralles or VMware Fusion**, see [Wiki](https://github.com/ppggff/vagrant-qemu/wiki) for details
33
+ * Libvirt box v2 format support is experimental
33
34
  * Start VM without GUI
34
35
  * SSH into VM
35
36
  * Provision the instances with any built-in Vagrant provisioner
@@ -85,9 +86,10 @@ This provider exposes a few provider-specific configuration options:
85
86
  * `memory` - The memory setting of VM, default: `4G`
86
87
  * debug/expert
87
88
  * `ssh_host` - The SSH IP used to access VM, default: `127.0.0.1`
89
+ * `ssh_auto_correct` - Auto correct port collisions for ssh port, default: `false`
88
90
  * `net_device` - The network device, default: `virtio-net-device`
89
91
  * `drive_interface` - The interface type for the main drive, default `virtio`
90
- * `image_path` - The path to qcow2 image for box-less VM, default is nil value
92
+ * `image_path` - The path (or array of paths) to qcow2 image for box-less VM, default is nil value
91
93
  * `qemu_dir` - The path to QEMU's install dir, default: `/opt/homebrew/share/qemu`
92
94
  * `extra_qemu_args` - The raw list of additional arguments to pass to QEMU. Use with extreme caution. (see "Force Multicore" below as example)
93
95
  * `extra_netdev_args` - extra, comma-separated arguments to pass to the -netdev parameter. Use with caution. (see "Force Local IP" below as example)
@@ -225,7 +227,6 @@ end
225
227
  8. Windows host
226
228
 
227
229
  Windows version QEMU doesn't support `daemonize` mode and unix socket
228
- (Notes: not tested)
229
230
 
230
231
  ```
231
232
  Vagrant.configure("2") do |config|
@@ -239,6 +240,32 @@ Vagrant.configure("2") do |config|
239
240
  end
240
241
  ```
241
242
 
243
+ 9. Auto port collisions for ssh port (multiple machine)
244
+
245
+ ```
246
+ Vagrant.configure("2") do |config|
247
+
248
+ config.vm.define "vm1" do |c|
249
+ c.vm.box = "ppggff/centos-7-aarch64-2009-4K"
250
+ c.vm.provider "qemu" do |qe|
251
+ qe.memory = "2G"
252
+ qe.ssh_auto_correct = true
253
+ end
254
+ c.vm.synced_folder ".", "/vagrant", disabled: true
255
+ end
256
+
257
+ config.vm.define "vm2" do |c|
258
+ c.vm.box = "ppggff/centos-7-aarch64-2009-4K"
259
+ c.vm.provider "qemu" do |qe|
260
+ qe.memory = "2G"
261
+ qe.ssh_auto_correct = true
262
+ end
263
+ c.vm.synced_folder ".", "/vagrant", disabled: true
264
+ end
265
+
266
+ end
267
+ ```
268
+
242
269
  ## Debug
243
270
 
244
271
  Serial port is exported to unix socket: `<user_home>/.vagrant.d/tmp/vagrant-qemu/<id>/qemu_socket_serial`, or `debug_port`.
@@ -298,6 +325,21 @@ Vagrant.configure("2") do |config|
298
325
  end
299
326
  ```
300
327
 
328
+ As an alternative solution(helpful for macOS) it is possible to use 9p file system via virtio.
329
+
330
+ ```
331
+ config.vm.synced_folder ".", "/vagrant", disabled: true
332
+ config.vm.provider "qemu" do |qe|
333
+ qe.extra_qemu_args = %w(-virtfs local,path=.,mount_tag=shared,security_model=mapped)
334
+ end
335
+ ```
336
+ This will pass "current directory" to mount point tagged "shared"
337
+ Use the following /etc/fstab entry on the vagrant vm to mount the shared directory into /home/vagrant/shared
338
+ ```
339
+ shared /home/vagrant/shared 9p _netdev,trans=virtio,msize=524288 0
340
+ ```
341
+ Please keep in mind that the guest OS will need to install 9p dependencies to handle the 9p filestystem.
342
+
301
343
  ### 2. netcat does not support the -U parameter
302
344
 
303
345
  I had netcat installed through home brew and it does not support the -U parameter.
@@ -1,4 +1,5 @@
1
1
  require "log4r"
2
+ require "open3"
2
3
  require "pathname"
3
4
 
4
5
  module VagrantPlugins
@@ -12,18 +13,52 @@ module VagrantPlugins
12
13
  end
13
14
 
14
15
  def call(env)
15
- image_path = nil
16
+ image_path = Array.new
16
17
  if env[:machine].provider_config.image_path
17
- image_path = Pathname.new(env[:machine].provider_config.image_path)
18
- elsif env[:machine].box
19
- image_path = env[:machine].box.directory.join("box.img")
18
+ paths = env[:machine].provider_config.image_path
19
+ paths = [paths] if !paths.kind_of?(Array)
20
+ paths.each do |p|
21
+ image_path.append(Pathname.new(p))
22
+ end
23
+ else
24
+ disks = env[:machine].box.metadata.fetch('disks', [])
25
+ if disks.empty?
26
+ # box v1 format
27
+ image_path.append(env[:machine].box.directory.join("box.img"))
28
+ else
29
+ # box v2 format
30
+ disks.each_with_index do |d, i|
31
+ if d['path'].nil?
32
+ @logger.error("Missing box image path for disk #{i}")
33
+ raise Errors::BoxInvalid, name: env[:machine].name, err: "Missing box image path for disk #{i}"
34
+ end
35
+ image_path.append(env[:machine].box.directory.join(d['path']))
36
+ end
37
+ end
20
38
  end
21
39
 
22
- if !image_path || !image_path.file?
23
- @logger.error("Invalid box image path: #{image_path}")
24
- raise Errors::BoxInvalid, name: env[:machine].name, err: "Invalid box image path: #{image_path}"
25
- else
26
- @logger.info("Found box image path: #{image_path}")
40
+ if image_path.empty?
41
+ @logger.error("Empty box image path")
42
+ raise Errors::BoxInvalid, name: env[:machine].name, err: "Empty box image path"
43
+ end
44
+ image_path.each do |img|
45
+ if !img.file?
46
+ @logger.error("Invalid box image path: #{img}")
47
+ raise Errors::BoxInvalid, name: env[:machine].name, err: "Invalid box image path: #{img}"
48
+ end
49
+ img_str = img.to_s
50
+ stdout, stderr, status = Open3.capture3('qemu-img', 'info', '--output=json', img_str)
51
+ if !status.success?
52
+ @logger.error("Run qemu-img info failed, #{img_str}, out: #{stdout}, err: #{stderr}")
53
+ raise Errors::BoxInvalid, name: env[:machine].name, err: "Run qemu-img info failed, #{img_str}, out: #{stdout}, err: #{stderr}"
54
+ end
55
+ img_info = JSON.parse(stdout)
56
+ format = img_info['format']
57
+ if format != 'qcow2'
58
+ @logger.error("Invalid box image format, #{img_str}, format: #{format}")
59
+ raise Errors::BoxInvalid, name: env[:machine].name, err: "Invalid box image format, #{img_str}, format: #{format}"
60
+ end
61
+ @logger.info("Found box image path: #{img_info}")
27
62
  end
28
63
 
29
64
  qemu_dir = Pathname.new(env[:machine].provider_config.qemu_dir)
@@ -16,16 +16,23 @@ module VagrantPlugins
16
16
  # Build the remap for any existing collision detections
17
17
  remap = {}
18
18
  env[:port_collision_remap] = remap
19
+
20
+ has_ssh_forward = false
19
21
  machine.config.vm.networks.each do |type, options|
20
22
  next if type != :forwarded_port
21
23
 
22
24
  # remap ssh.host to ssh_port
23
25
  if options[:id] == "ssh"
24
26
  remap[options[:host]] = machine.provider_config.ssh_port
27
+ has_ssh_forward = true
25
28
  break
26
29
  end
27
30
  end
28
31
 
32
+ if !has_ssh_forward
33
+ machine.config.vm.networks.forward_port(22, machine.provider_config.ssh_port, [id: "ssh", auto_correct: machine.provider_config.ssh_auto_correct])
34
+ end
35
+
29
36
  @app.call(env)
30
37
  end
31
38
  end
@@ -23,6 +23,11 @@ module VagrantPlugins
23
23
  else
24
24
  env[:machine_state_id] = :not_created
25
25
  end
26
+
27
+ # Update ssh_port if needed
28
+ if env[:machine_state_id] != :not_created
29
+ env[:machine].provider_config.ssh_port = env[:machine].provider.driver.get_ssh_port(env[:machine].provider_config.ssh_port)
30
+ end
26
31
  @app.call(env)
27
32
  end
28
33
  end
@@ -11,6 +11,7 @@ module VagrantPlugins
11
11
  end
12
12
 
13
13
  def call(env)
14
+ fwPorts = forwarded_ports(env)
14
15
  options = {
15
16
  :ssh_host => env[:machine].provider_config.ssh_host,
16
17
  :ssh_port => env[:machine].provider_config.ssh_port,
@@ -23,7 +24,7 @@ module VagrantPlugins
23
24
  :drive_interface => env[:machine].provider_config.drive_interface,
24
25
  :extra_qemu_args => env[:machine].provider_config.extra_qemu_args,
25
26
  :extra_netdev_args => env[:machine].provider_config.extra_netdev_args,
26
- :ports => forwarded_ports(env),
27
+ :ports => fwPorts,
27
28
  :control_port => env[:machine].provider_config.control_port,
28
29
  :debug_port => env[:machine].provider_config.debug_port,
29
30
  :no_daemonize => env[:machine].provider_config.no_daemonize,
@@ -43,7 +44,12 @@ module VagrantPlugins
43
44
  next if type != :forwarded_port
44
45
 
45
46
  # Don't include SSH
46
- next if options[:id] == "ssh"
47
+ if options[:id] == "ssh"
48
+ if options[:host] != env[:machine].provider_config.ssh_port
49
+ env[:machine].provider_config.ssh_port = options[:host]
50
+ end
51
+ next
52
+ end
47
53
 
48
54
  # Skip port if it is disabled
49
55
  next if options[:disabled]
@@ -116,7 +116,7 @@ module VagrantPlugins
116
116
  end
117
117
 
118
118
  b1.use Provision
119
- b1.use EnvSet, port_collision_repair: false
119
+ b1.use EnvSet, port_collision_repair: true
120
120
  b1.use PrepareForwardedPortCollisionParams
121
121
  b1.use HandleForwardedPortCollisions
122
122
  b1.use SyncedFolderCleanup
@@ -5,6 +5,7 @@ module VagrantPlugins
5
5
  class Config < Vagrant.plugin("2", :config)
6
6
  attr_accessor :ssh_host
7
7
  attr_accessor :ssh_port
8
+ attr_accessor :ssh_auto_correct
8
9
  attr_accessor :arch
9
10
  attr_accessor :machine
10
11
  attr_accessor :cpu
@@ -25,6 +26,7 @@ module VagrantPlugins
25
26
  def initialize
26
27
  @ssh_host = UNSET_VALUE
27
28
  @ssh_port = UNSET_VALUE
29
+ @ssh_auto_correct = UNSET_VALUE
28
30
  @arch = UNSET_VALUE
29
31
  @machine = UNSET_VALUE
30
32
  @cpu = UNSET_VALUE
@@ -55,6 +57,7 @@ module VagrantPlugins
55
57
  def finalize!
56
58
  @ssh_host = "127.0.0.1" if @ssh_host == UNSET_VALUE
57
59
  @ssh_port = 50022 if @ssh_port == UNSET_VALUE
60
+ @ssh_auto_correct = false if @ssh_auto_correct == UNSET_VALUE
58
61
  @arch = "aarch64" if @arch == UNSET_VALUE
59
62
  @machine = "virt,accel=hvf,highmem=on" if @machine == UNSET_VALUE
60
63
  @cpu = "host" if @cpu == UNSET_VALUE
@@ -1,5 +1,6 @@
1
1
  require 'childprocess'
2
2
  require 'securerandom'
3
+ require 'yaml'
3
4
 
4
5
  require "vagrant/util/busy"
5
6
  require 'vagrant/util/io'
@@ -10,7 +11,7 @@ require_relative "plugin"
10
11
 
11
12
  module VagrantPlugins
12
13
  module QEMU
13
- class Driver
14
+ class Driver
14
15
  # @return [String] VM ID
15
16
  attr_reader :vm_id
16
17
  attr_reader :data_dir
@@ -45,12 +46,21 @@ module VagrantPlugins
45
46
  def start(options)
46
47
  if !running?
47
48
  id_dir = @data_dir.join(@vm_id)
48
- image_path = id_dir.join("linked-box.img").to_s
49
- pid_file = id_dir.join("qemu.pid").to_s
49
+
50
+ image_path = Array.new
51
+ image_count = id_dir.glob("linked-box*.img").count
52
+ for i in 0..image_count-1 do
53
+ suffix_index = i > 0 ? "-#{i}" : ''
54
+ image_path.append(id_dir.join("linked-box#{suffix_index}.img").to_s)
55
+ end
50
56
 
51
57
  id_tmp_dir = @tmp_dir.join(@vm_id)
52
58
  FileUtils.mkdir_p(id_tmp_dir)
53
59
 
60
+ # dump options
61
+ options_file = id_tmp_dir.join("options.yml")
62
+ File.write(options_file, options.to_yaml)
63
+
54
64
  control_socket = ""
55
65
  if !options[:control_port].nil?
56
66
  control_socket = "port=#{options[:control_port]},host=localhost,ipv4=on"
@@ -95,7 +105,9 @@ module VagrantPlugins
95
105
 
96
106
  # drive
97
107
  if !options[:drive_interface].nil?
98
- cmd += %W(-drive if=#{options[:drive_interface]},format=qcow2,file=#{image_path})
108
+ image_path.each do |img|
109
+ cmd += %W(-drive if=#{options[:drive_interface]},format=qcow2,file=#{img})
110
+ end
99
111
  end
100
112
  if options[:arch] == "aarch64" && !options[:firmware_format].nil?
101
113
  fm1_path = id_dir.join("edk2-aarch64-code.fd").to_s
@@ -105,6 +117,7 @@ module VagrantPlugins
105
117
  end
106
118
 
107
119
  # control
120
+ pid_file = id_tmp_dir.join("qemu.pid").to_s
108
121
  cmd += %W(-chardev socket,id=mon0,#{control_socket},server=on,wait=off)
109
122
  cmd += %W(-mon chardev=mon0,mode=readline)
110
123
  cmd += %W(-chardev socket,id=ser0,#{debug_socket},server=on,wait=off)
@@ -131,7 +144,7 @@ module VagrantPlugins
131
144
  Socket.tcp("localhost", options[:control_port], connect_timeout: 5) do |sock|
132
145
  sock.print "system_powerdown\n"
133
146
  sock.close_write
134
- sock.read
147
+ sock.read rescue nil
135
148
  end
136
149
  else
137
150
  id_tmp_dir = @tmp_dir.join(@vm_id)
@@ -139,12 +152,24 @@ module VagrantPlugins
139
152
  Socket.unix(unix_socket_path) do |sock|
140
153
  sock.print "system_powerdown\n"
141
154
  sock.close_write
142
- sock.read
155
+ sock.read rescue nil
143
156
  end
144
- end
157
+ end
145
158
  end
146
159
  end
147
160
 
161
+ def get_ssh_port(ssh_port)
162
+ id_tmp_dir = @tmp_dir.join(@vm_id)
163
+ options_file = id_tmp_dir.join("options.yml")
164
+
165
+ if options_file.file?
166
+ options = YAML.load_file(options_file) rescue nil
167
+ ssh_port = options[:ssh_port] if !options.nil? && options.key?(:ssh_port)
168
+ end
169
+
170
+ ssh_port
171
+ end
172
+
148
173
  def import(options)
149
174
  new_id = "vq_" + SecureRandom.urlsafe_base64(8)
150
175
 
@@ -162,7 +187,10 @@ module VagrantPlugins
162
187
  end
163
188
 
164
189
  # Create image
165
- execute("qemu-img", "create", "-f", "qcow2", "-F", "qcow2", "-b", options[:image_path].to_s, id_dir.join("linked-box.img").to_s)
190
+ options[:image_path].each_with_index do |img, i|
191
+ suffix_index = i > 0 ? "-#{i}" : ''
192
+ execute("qemu-img", "create", "-f", "qcow2", "-F", "qcow2", "-b", img.to_s, id_dir.join("linked-box#{suffix_index}.img").to_s)
193
+ end
166
194
 
167
195
  server = {
168
196
  :id => new_id,
@@ -174,7 +202,7 @@ module VagrantPlugins
174
202
  end
175
203
 
176
204
  def running?
177
- pid_file = @data_dir.join(@vm_id).join("qemu.pid")
205
+ pid_file = @tmp_dir.join(@vm_id).join("qemu.pid")
178
206
  return false if !pid_file.file?
179
207
 
180
208
  begin
@@ -1,5 +1,5 @@
1
1
  module VagrantPlugins
2
2
  module QEMU
3
- VERSION = '0.3.5'
3
+ VERSION = '0.3.7'
4
4
  end
5
5
  end
data/x ADDED
@@ -0,0 +1,76 @@
1
+ diff --git a/lib/vagrant-qemu/action.rb b/lib/vagrant-qemu/action.rb
2
+ index bb87e38..8818aa9 100644
3
+ --- a/lib/vagrant-qemu/action.rb
4
+ +++ b/lib/vagrant-qemu/action.rb
5
+ @@ -116,7 +116,7 @@ module VagrantPlugins
6
+ end
7
+
8
+ b1.use Provision
9
+ - b1.use EnvSet, port_collision_repair: false
10
+ + b1.use EnvSet, port_collision_repair: true
11
+ b1.use PrepareForwardedPortCollisionParams
12
+ b1.use HandleForwardedPortCollisions
13
+ b1.use SyncedFolderCleanup
14
+ diff --git a/lib/vagrant-qemu/action/prepare_forwarded_port_collision_params.rb b/lib/vagrant-qemu/action/prepare_forwarded_port_collision_params.rb
15
+ index 159a785..b7c93a3 100644
16
+ --- a/lib/vagrant-qemu/action/prepare_forwarded_port_collision_params.rb
17
+ +++ b/lib/vagrant-qemu/action/prepare_forwarded_port_collision_params.rb
18
+ @@ -16,16 +16,23 @@ module VagrantPlugins
19
+ # Build the remap for any existing collision detections
20
+ remap = {}
21
+ env[:port_collision_remap] = remap
22
+ +
23
+ + has_ssh_forward = false
24
+ machine.config.vm.networks.each do |type, options|
25
+ next if type != :forwarded_port
26
+
27
+ # remap ssh.host to ssh_port
28
+ if options[:id] == "ssh"
29
+ remap[options[:host]] = machine.provider_config.ssh_port
30
+ + has_ssh_forward = true
31
+ break
32
+ end
33
+ end
34
+
35
+ + if !has_ssh_forward
36
+ + machine.config.vm.networks.forward_port(22, machine.provider_config.ssh_port, [id: "ssh", auto_correct: true])
37
+ + end
38
+ +
39
+ @app.call(env)
40
+ end
41
+ end
42
+ diff --git a/lib/vagrant-qemu/action/start_instance.rb b/lib/vagrant-qemu/action/start_instance.rb
43
+ index 13c1d9d..b434bb3 100644
44
+ --- a/lib/vagrant-qemu/action/start_instance.rb
45
+ +++ b/lib/vagrant-qemu/action/start_instance.rb
46
+ @@ -11,6 +11,7 @@ module VagrantPlugins
47
+ end
48
+
49
+ def call(env)
50
+ + fwPorts = forwarded_ports(env)
51
+ options = {
52
+ :ssh_host => env[:machine].provider_config.ssh_host,
53
+ :ssh_port => env[:machine].provider_config.ssh_port,
54
+ @@ -23,7 +24,7 @@ module VagrantPlugins
55
+ :drive_interface => env[:machine].provider_config.drive_interface,
56
+ :extra_qemu_args => env[:machine].provider_config.extra_qemu_args,
57
+ :extra_netdev_args => env[:machine].provider_config.extra_netdev_args,
58
+ - :ports => forwarded_ports(env),
59
+ + :ports => fwPorts,
60
+ :control_port => env[:machine].provider_config.control_port,
61
+ :debug_port => env[:machine].provider_config.debug_port,
62
+ :no_daemonize => env[:machine].provider_config.no_daemonize,
63
+ @@ -43,7 +44,12 @@ module VagrantPlugins
64
+ next if type != :forwarded_port
65
+
66
+ # Don't include SSH
67
+ - next if options[:id] == "ssh"
68
+ + if options[:id] == "ssh"
69
+ + if options[:host] != env[:machine].provider_config.ssh_port
70
+ + env[:machine].provider_config.ssh_port = options[:host]
71
+ + end
72
+ + next
73
+ + end
74
+
75
+ # Skip port if it is disabled
76
+ next if options[:disabled]
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.3.5
4
+ version: 0.3.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - ppggff
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-07-27 00:00:00.000000000 Z
11
+ date: 2025-02-02 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Enables Vagrant to manage machines with QEMU.
14
14
  email: pgf00a@gmail.com
@@ -43,6 +43,7 @@ files:
43
43
  - lib/vagrant-qemu/version.rb
44
44
  - locales/en.yml
45
45
  - vagrant-qemu.gemspec
46
+ - x
46
47
  homepage: https://github.com/ppggff/vagrant-qemu
47
48
  licenses:
48
49
  - MIT