vagrant-qemu 0.1.9 → 0.3.1

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: b46cfaa2964de5f308d27d5547506b100bb794ab6bbf24be6cd9cef45af02079
4
- data.tar.gz: a94f3b9be8cec1a6bc0834bee7db2818a233678a6281dba2b3b62272b8618749
3
+ metadata.gz: d41d79a9352f176fa81c510f886f0ed1df1ca82d57d1956ee5f39b5a7e88cd4f
4
+ data.tar.gz: 27fa931a926e246aa8235ccb45b984603b103d9a0e3a8d098bb0a95be094057c
5
5
  SHA512:
6
- metadata.gz: a5b9b84028dc8625e775fb058ed25bbe19f1eb5d0f12b3c2ba3ad65a35310305ac2ebe6ee4129ca1b1db7d548f3ecf25f14e0893a161be06167f29635530ad4d
7
- data.tar.gz: d203be0515807c605c83e0206f4fcadbc9550455de9cea4554f4e8948fc57601e25aa9eb75fc3532909c885f39522d35f7de443d2af49e59da6847a043ecd61e
6
+ metadata.gz: 6e5034e4bfae98b9e28a456b4c83e8bb3180681eb44239caa1ff95b38d4abd535a299b2db4ce8c47005b764479d201abf4277561562a671651f3619cf6ed9279
7
+ data.tar.gz: 1f5e62e279fa5a751980d5d9038fe0a1521e6b8acf5862f28e3b3d471baf8107e7510957303755c96996a5111568585ab913766b30c7c0875218b928d14a68d2
data/CHANGELOG.md CHANGED
@@ -30,3 +30,19 @@
30
30
  # 0.1.9 (2022-08-01)
31
31
 
32
32
  * Set default config for newer qemu (>=7.0.0)
33
+
34
+ # 0.2.0 (2022-08-31)
35
+
36
+ * Add config extra_qemu_args'.
37
+ * Refine error message, such as 'Invalid qemu dir'.
38
+ * Add a 'Force Multicore' to Readme.
39
+
40
+ # 0.3.0 (2022-09-16)
41
+
42
+ * Add config extra_netdev_args.
43
+ * Replace `nc` with ruby's socket
44
+ * Add config control_port, debug_port, no_daemonize config for window host
45
+
46
+ # 0.3.1 (2022-09-16)
47
+
48
+ * Fix missing :arch for driver.import(options)
data/README.md CHANGED
@@ -73,16 +73,23 @@ Same as [vagrant-libvirt version-1](https://github.com/vagrant-libvirt/vagrant-l
73
73
 
74
74
  This provider exposes a few provider-specific configuration options:
75
75
 
76
- * `ssh_port` - The SSH port number used to access VM (IP is 127.0.0.1),
76
+ * basic
77
+ * `ssh_port` - The SSH port number used to access VM (IP is 127.0.0.1),
77
78
  default: `50022`
78
- * `arch` - The architecture of VM, default: `aarch64`
79
- * `machine` - The machine type of VM, default: `virt,accel=hvf,highmem=off`
80
- * `cpu` - The cpu model of VM, default: `cortex-a72`
81
- * `smp` - The smp setting (Simulate an SMP system with n CPUs) of VM, default: `2`
82
- * `memory` - The memory setting of VM, default: `4G`
83
- * `net_device` - The network device, default: `virtio-net-device`
84
- * `image_path` - The path to qcow2 image for box-less VM, default is nil value
85
- * `qemu_dir` - The path to QEMU's install dir, default: `/opt/homebrew/share/qemu`
79
+ * `arch` - The architecture of VM, default: `aarch64`
80
+ * `machine` - The machine type of VM, default: `virt,accel=hvf,highmem=off`
81
+ * `cpu` - The cpu model of VM, default: `cortex-a72`
82
+ * `smp` - The smp setting (Simulate an SMP system with n CPUs) of VM, default: `2`
83
+ * `memory` - The memory setting of VM, default: `4G`
84
+ * debug/expert
85
+ * `net_device` - The network device, default: `virtio-net-device`
86
+ * `image_path` - The path to qcow2 image for box-less VM, default is nil value
87
+ * `qemu_dir` - The path to QEMU's install dir, default: `/opt/homebrew/share/qemu`
88
+ * `extra_qemu_args` - The raw list of additional arguments to pass to QEMU. Use with extreme caution. (see "Force Multicore" below as example)
89
+ * `extra_netdev_args` - extra, comma-separated arguments to pass to the -netdev parameter. Use with caution. (see "Force Local IP" below as example)
90
+ * `control_port` - The port number used to control vm from vagrant, default is nil value. (nil means use unix socket)
91
+ * `debug_port` - The port number used to export serial port of the vm for debug, default is nil value. (nil means use unix socket, see "Debug" below for details)
92
+ * `no_daemonize` - Disable the "daemonize" mode of QEMU, default is false. (see "Windows host" below as example)
86
93
 
87
94
  These can be set like typical provider-specific configuration:
88
95
 
@@ -157,16 +164,73 @@ Vagrant.configure(2) do |config|
157
164
  end
158
165
  ```
159
166
 
167
+ 6. Force Multicore (x86)
168
+
169
+ Thanks to [taraszka](https://github.com/taraszka) for providing this config.
170
+
171
+ ```
172
+ Vagrant.configure("2") do |config|
173
+ config.vm.box = "centos/7"
174
+
175
+ config.vm.provider "qemu" do |qe|
176
+ qe.arch = "x86_64"
177
+ qe.machine = "q35"
178
+ qe.cpu = "max"
179
+ qe.smp = "cpus=2,sockets=1,cores=2,threads=1"
180
+ qe.net_device = "virtio-net-pci"
181
+ qe.extra_qemu_args = %w(-accel tcg,thread=multi,tb-size=512)
182
+ qe.qemu_dir = "/usr/local/share/qemu"
183
+ end
184
+ end
185
+ ```
186
+
187
+ 7. Force Local IP
188
+
189
+ ```
190
+ Vagrant.configure("2") do |config|
191
+ config.vm.box = "debian/bullseye64"
192
+
193
+ config.vm.provider "qemu" do |qe|
194
+ qe.extra_netdev_args = "net=192.168.51.0/24,dhcpstart=192.168.51.10"
195
+ end
196
+ end
197
+ ```
198
+
199
+ 8. Windows host
200
+
201
+ Windows version QEMU doesn't support `daemonize` mode and unix socket
202
+ (Notes: not tested)
203
+
204
+ ```
205
+ Vagrant.configure("2") do |config|
206
+ # ... other stuff
207
+
208
+ config.vm.provider "qemu" do |qe|
209
+ qe.no_daemonize = true
210
+ qe.control_port = 33333
211
+ qe.debug_port = 33334
212
+ end
213
+ end
214
+ ```
215
+
160
216
  ## Debug
161
217
 
162
- Serial port is exported to unix socket: `<user_home>/.vagrant.d/tmp/vagrant-qemu/<id>/qemu_socket_serial`.
218
+ Serial port is exported to unix socket: `<user_home>/.vagrant.d/tmp/vagrant-qemu/<id>/qemu_socket_serial`, or `debug_port`.
219
+
163
220
  To debug and login to the GuestOS from serial port:
164
221
 
165
- 1. Get the id: `.vagrant/machines/default/qemu/id` in same directory with `Vagrantfile`
166
- 2. Get the path to `qemu_socket_serial`
167
- 3. Use `nc` to connect: `nc -U /Users/.../qemu_socket_serial`
222
+ * unix socket
223
+ 1. Get the id: `.vagrant/machines/default/qemu/id` in same directory with `Vagrantfile`
224
+ 2. Get the path to `qemu_socket_serial`
225
+ 3. Use `nc` to connect: `nc -U /Users/.../qemu_socket_serial`
226
+ * `debug_port` (for example: 33334)
227
+ * Use `nc` to connect: `nc localhost 33334`
168
228
 
169
- To send ctrl+c to GuestOS from `nc`, try `echo 03 | xxd -r -p | nc -U /Users/.../qemu_socket_serial`
229
+ To send ctrl+c to GuestOS from `nc`, try:
230
+ * unix socket
231
+ * `echo 03 | xxd -r -p | nc -U /Users/.../qemu_socket_serial`
232
+ * `debug_port` (for example: 33334)
233
+ * `echo 03 | xxd -r -p | nc localhost 33334`
170
234
 
171
235
  ## Build
172
236
 
@@ -226,6 +290,22 @@ If you get this error when running `vagrant up`
226
290
  4. Click Done
227
291
  5. Run `vagrant up` again
228
292
 
293
+ ### 4. The box you're using with the QEMU provider ('default') is invalid
294
+
295
+ This may cause by invalid default qemu dir (`/opt/homebrew/share/qemu`).
296
+
297
+ You can find the correct one by:
298
+ ```
299
+ echo `brew --prefix`/share/qemu
300
+ ```
301
+
302
+ And then set it (for example `/usr/local/share/qemu`) in the `Vagrantfile` as:
303
+ ```
304
+ config.vm.provider "qemu" do |qe|
305
+ qe.qemu_dir = "/usr/local/share/qemu"
306
+ end
307
+ ```
308
+
229
309
  ## TODO
230
310
 
231
311
  * Support NFS shared folder
@@ -21,7 +21,7 @@ module VagrantPlugins
21
21
 
22
22
  if !image_path || !image_path.file?
23
23
  @logger.error("Invalid box image path: #{image_path}")
24
- raise Errors::BoxInvalid, name: env[:machine].name
24
+ raise Errors::BoxInvalid, name: env[:machine].name, err: "Invalid box image path: #{image_path}"
25
25
  else
26
26
  @logger.info("Found box image path: #{image_path}")
27
27
  end
@@ -29,7 +29,7 @@ module VagrantPlugins
29
29
  qemu_dir = Pathname.new(env[:machine].provider_config.qemu_dir)
30
30
  if !qemu_dir.directory?
31
31
  @logger.error("Invalid qemu dir: #{qemu_dir}")
32
- raise Errors::BoxInvalid, name: env[:machine].name
32
+ raise Errors::ConfigError, err: "Invalid qemu dir: #{qemu_dir}"
33
33
  else
34
34
  @logger.info("Found qemu dir: #{qemu_dir}")
35
35
  end
@@ -39,6 +39,7 @@ module VagrantPlugins
39
39
  options = {
40
40
  :image_path => image_path,
41
41
  :qemu_dir => qemu_dir,
42
+ :arch => env[:machine].provider_config.arch,
42
43
  }
43
44
 
44
45
  env[:ui].detail("Creating and registering the VM...")
@@ -19,7 +19,12 @@ module VagrantPlugins
19
19
  :smp => env[:machine].provider_config.smp,
20
20
  :memory => env[:machine].provider_config.memory,
21
21
  :net_device => env[:machine].provider_config.net_device,
22
- :ports => forwarded_ports(env)
22
+ :extra_qemu_args => env[:machine].provider_config.extra_qemu_args,
23
+ :extra_netdev_args => env[:machine].provider_config.extra_netdev_args,
24
+ :ports => forwarded_ports(env),
25
+ :control_port => env[:machine].provider_config.control_port,
26
+ :debug_port => env[:machine].provider_config.debug_port,
27
+ :no_daemonize => env[:machine].provider_config.no_daemonize
23
28
  }
24
29
 
25
30
  env[:ui].output(I18n.t("vagrant_qemu.starting"))
@@ -8,8 +8,12 @@ module VagrantPlugins
8
8
  end
9
9
 
10
10
  def call(env)
11
+ options = {
12
+ :control_port => env[:machine].provider_config.control_port
13
+ }
14
+
11
15
  env[:ui].info(I18n.t("vagrant_qemu.stopping"))
12
- env[:machine].provider.driver.stop
16
+ env[:machine].provider.driver.stop(options)
13
17
  @app.call(env)
14
18
  end
15
19
  end
@@ -12,6 +12,11 @@ module VagrantPlugins
12
12
  attr_accessor :net_device
13
13
  attr_accessor :image_path
14
14
  attr_accessor :qemu_dir
15
+ attr_accessor :extra_qemu_args
16
+ attr_accessor :extra_netdev_args
17
+ attr_accessor :control_port
18
+ attr_accessor :debug_port
19
+ attr_accessor :no_daemonize
15
20
 
16
21
  def initialize
17
22
  @ssh_port = UNSET_VALUE
@@ -23,6 +28,11 @@ module VagrantPlugins
23
28
  @net_device = UNSET_VALUE
24
29
  @image_path = UNSET_VALUE
25
30
  @qemu_dir = UNSET_VALUE
31
+ @extra_qemu_args = UNSET_VALUE
32
+ @extra_netdev_args = UNSET_VALUE
33
+ @control_port = UNSET_VALUE
34
+ @debug_port = UNSET_VALUE
35
+ @no_daemonize = UNSET_VALUE
26
36
  end
27
37
 
28
38
  #-------------------------------------------------------------------
@@ -44,6 +54,11 @@ module VagrantPlugins
44
54
  @net_device = "virtio-net-device" if @net_device == UNSET_VALUE
45
55
  @image_path = nil if @image_path == UNSET_VALUE
46
56
  @qemu_dir = "/opt/homebrew/share/qemu" if @qemu_dir == UNSET_VALUE
57
+ @extra_qemu_args = [] if @extra_qemu_args == UNSET_VALUE
58
+ @extra_netdev_args = nil if @extra_netdev_args == UNSET_VALUE
59
+ @control_port = nil if @control_port == UNSET_VALUE
60
+ @debug_port = nil if @debug_port == UNSET_VALUE
61
+ @no_daemonize = false if @no_daemonize == UNSET_VALUE
47
62
  end
48
63
 
49
64
  def validate(machine)
@@ -1,6 +1,9 @@
1
+ require 'childprocess'
1
2
  require 'securerandom'
2
3
 
3
4
  require "vagrant/util/busy"
5
+ require 'vagrant/util/io'
6
+ require "vagrant/util/safe_chdir"
4
7
  require "vagrant/util/subprocess"
5
8
 
6
9
  require_relative "plugin"
@@ -47,8 +50,22 @@ module VagrantPlugins
47
50
 
48
51
  id_tmp_dir = @tmp_dir.join(@vm_id)
49
52
  FileUtils.mkdir_p(id_tmp_dir)
50
- unix_socket_path = id_tmp_dir.join("qemu_socket").to_s
51
- unix_socket_serial_path = id_tmp_dir.join("qemu_socket_serial").to_s
53
+
54
+ control_socket = ""
55
+ if !options[:control_port].nil?
56
+ control_socket = "port=#{options[:control_port]},host=localhost,ipv4=on"
57
+ else
58
+ unix_socket_path = id_tmp_dir.join("qemu_socket").to_s
59
+ control_socket = "path=#{unix_socket_path}"
60
+ end
61
+
62
+ debug_socket = ""
63
+ if !options[:debug_port].nil?
64
+ debug_socket = "port=#{options[:debug_port]},host=localhost,ipv4=on"
65
+ else
66
+ unix_socket_serial_path = id_tmp_dir.join("qemu_socket_serial").to_s
67
+ debug_socket = "path=#{unix_socket_serial_path}"
68
+ end
52
69
 
53
70
  cmd = []
54
71
  cmd += %W(qemu-system-#{options[:arch]})
@@ -65,7 +82,11 @@ module VagrantPlugins
65
82
  options[:ports].each do |v|
66
83
  hostfwd += ",hostfwd=#{v}"
67
84
  end
68
- cmd += %W(-netdev user,id=net0,#{hostfwd})
85
+ extra_netdev = ""
86
+ if !options[:extra_netdev_args].nil?
87
+ extra_netdev = ",#{options[:extra_netdev_args]}"
88
+ end
89
+ cmd += %W(-netdev user,id=net0,#{hostfwd}#{extra_netdev})
69
90
 
70
91
  # drive
71
92
  cmd += %W(-drive if=virtio,format=qcow2,file=#{image_path})
@@ -77,32 +98,40 @@ module VagrantPlugins
77
98
  end
78
99
 
79
100
  # control
80
- cmd += %W(-chardev socket,id=mon0,path=#{unix_socket_path},server=on,wait=off)
101
+ cmd += %W(-chardev socket,id=mon0,#{control_socket},server=on,wait=off)
81
102
  cmd += %W(-mon chardev=mon0,mode=readline)
82
- cmd += %W(-chardev socket,id=ser0,path=#{unix_socket_serial_path},server=on,wait=off)
103
+ cmd += %W(-chardev socket,id=ser0,#{debug_socket},server=on,wait=off)
83
104
  cmd += %W(-serial chardev:ser0)
84
105
  cmd += %W(-pidfile #{pid_file})
85
106
  cmd += %W(-parallel null -monitor none -display none -vga none)
86
- cmd += %W(-daemonize)
107
+ if !options[:no_daemonize]
108
+ cmd += %W(-daemonize)
109
+ end
87
110
 
88
- execute(*cmd)
111
+ # user-defined
112
+ cmd += options[:extra_qemu_args]
113
+
114
+ execute(*cmd, {:detach => options[:no_daemonize]})
89
115
  end
90
116
  end
91
117
 
92
- def stop
118
+ def stop(options)
93
119
  if running?
94
- id_tmp_dir = @tmp_dir.join(@vm_id)
95
- unix_socket_path = id_tmp_dir.join("qemu_socket").to_s
96
- sent = false
97
- execute("nc", "-w", "5", "-U", unix_socket_path) do |type, data|
98
- case type
99
- when :stdin
100
- if !sent
101
- data.write("system_powerdown\n")
102
- sent = true
103
- end
120
+ if !options[:control_port].nil?
121
+ Socket.tcp("localhost", options[:control_port], connect_timeout: 5) do |sock|
122
+ sock.print "system_powerdown\n"
123
+ sock.close_write
124
+ sock.read
104
125
  end
105
- end
126
+ else
127
+ id_tmp_dir = @tmp_dir.join(@vm_id)
128
+ unix_socket_path = id_tmp_dir.join("qemu_socket").to_s
129
+ Socket.unix(unix_socket_path) do |sock|
130
+ sock.print "system_powerdown\n"
131
+ sock.close_write
132
+ sock.read
133
+ end
134
+ end
106
135
  end
107
136
  end
108
137
 
@@ -116,8 +145,10 @@ module VagrantPlugins
116
145
  FileUtils.mkdir_p(id_tmp_dir)
117
146
 
118
147
  # Prepare firmware
119
- execute("cp", options[:qemu_dir].join("edk2-aarch64-code.fd").to_s, id_dir.join("edk2-aarch64-code.fd").to_s)
120
- execute("cp", options[:qemu_dir].join("edk2-arm-vars.fd").to_s, id_dir.join("edk2-arm-vars.fd").to_s)
148
+ if options[:arch] == "aarch64"
149
+ execute("cp", options[:qemu_dir].join("edk2-aarch64-code.fd").to_s, id_dir.join("edk2-aarch64-code.fd").to_s)
150
+ execute("cp", options[:qemu_dir].join("edk2-arm-vars.fd").to_s, id_dir.join("edk2-arm-vars.fd").to_s)
151
+ end
121
152
 
122
153
  # Create image
123
154
  execute("qemu-img", "create", "-f", "qcow2", "-F", "qcow2", "-b", options[:image_path].to_s, id_dir.join("linked-box.img").to_s)
@@ -144,13 +175,73 @@ module VagrantPlugins
144
175
  end
145
176
 
146
177
  def execute(*cmd, **opts, &block)
147
- # Append in the options for subprocess
148
- cmd << { notify: [:stdout, :stderr, :stdin] }
178
+ result = nil
179
+
180
+ if opts && opts[:detach]
181
+ # give it some time to startup
182
+ timeout = 5
183
+
184
+ # edit version of "Subprocess.execute" for detach
185
+ workdir = Dir.pwd
186
+ process = ChildProcess.build(*cmd)
187
+
188
+ stdout, stdout_writer = ::IO.pipe
189
+ stderr, stderr_writer = ::IO.pipe
190
+ process.io.stdout = stdout_writer
191
+ process.io.stderr = stderr_writer
192
+
193
+ process.leader = true
194
+ process.detach = true
149
195
 
150
- interrupted = false
151
- int_callback = ->{ interrupted = true }
152
- result = ::Vagrant::Util::Busy.busy(int_callback) do
153
- ::Vagrant::Util::Subprocess.execute(*cmd, &block)
196
+ ::Vagrant::Util::SafeChdir.safe_chdir(workdir) do
197
+ process.start
198
+ end
199
+
200
+ if RUBY_PLATFORM != "java"
201
+ stdout_writer.close
202
+ stderr_writer.close
203
+ end
204
+
205
+ io_data = { stdout: "", stderr: "" }
206
+ start_time = Time.now.to_i
207
+ open_readers = [stdout, stderr]
208
+
209
+ while true
210
+ results = ::IO.select(open_readers, nil, nil, 0.1)
211
+ results ||= []
212
+ readers = results[0]
213
+
214
+ # Check if we have exceeded our timeout
215
+ return if (Time.now.to_i - start_time) > timeout
216
+
217
+ if readers && !readers.empty?
218
+ readers.each do |r|
219
+ data = ::Vagrant::Util::IO.read_until_block(r)
220
+ next if data.empty?
221
+
222
+ io_name = r == stdout ? :stdout : :stderr
223
+ io_data[io_name] += data
224
+ end
225
+ end
226
+
227
+ break if process.exited?
228
+ end
229
+
230
+ if RUBY_PLATFORM == "java"
231
+ stdout_writer.close
232
+ stderr_writer.close
233
+ end
234
+
235
+ result = ::Vagrant::Util::Subprocess::Result.new(process.exit_code, io_data[:stdout], io_data[:stderr])
236
+ else
237
+ # Append in the options for subprocess
238
+ cmd << { notify: [:stdout, :stderr, :stdin] }
239
+
240
+ interrupted = false
241
+ int_callback = ->{ interrupted = true }
242
+ result = ::Vagrant::Util::Busy.busy(int_callback) do
243
+ ::Vagrant::Util::Subprocess.execute(*cmd, &block)
244
+ end
154
245
  end
155
246
 
156
247
  result.stderr.gsub!("\r\n", "\n")
@@ -26,6 +26,10 @@ module VagrantPlugins
26
26
  class ExecuteError < VagrantQEMUError
27
27
  error_key(:execute_error)
28
28
  end
29
+
30
+ class ConfigError < VagrantQEMUError
31
+ error_key(:config_error)
32
+ end
29
33
  end
30
34
  end
31
35
  end
@@ -1,5 +1,5 @@
1
1
  module VagrantPlugins
2
2
  module QEMU
3
- VERSION = '0.1.9'
3
+ VERSION = '0.3.1'
4
4
  end
5
5
  end
data/locales/en.yml CHANGED
@@ -42,6 +42,8 @@ en:
42
42
  box_invalid: |-
43
43
  The box you're using with the QEMU provider ('%{name}')
44
44
  is invalid.
45
+
46
+ Error: %{err}
45
47
  execute_error: |-
46
48
  A command executed by Vagrant didn't complete successfully!
47
49
  The command run along with the output from the command is shown
@@ -52,3 +54,7 @@ en:
52
54
  Stderr: %{stderr}
53
55
 
54
56
  Stdout: %{stdout}
57
+ config_error: |-
58
+ Invalid config.
59
+
60
+ Error: %{err}
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.1.9
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - ppggff
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-08-01 00:00:00.000000000 Z
11
+ date: 2022-09-16 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Enables Vagrant to manage machines with QEMU.
14
14
  email: pgf00a@gmail.com