vagrant_utm 0.0.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 +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +11 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/LICENSE.txt +21 -0
- data/README.md +59 -0
- data/Rakefile +12 -0
- data/docs/.gitignore +15 -0
- data/docs/Gemfile +10 -0
- data/docs/Gemfile.lock +276 -0
- data/docs/README.md +174 -0
- data/docs/_config.yml +76 -0
- data/docs/_includes/footer_custom.html +3 -0
- data/docs/_sass/gallery.scss +64 -0
- data/docs/_virtual_machines/archlinux-arm.md +13 -0
- data/docs/assets/images/favicon.ico +0 -0
- data/docs/assets/images/logo.png +0 -0
- data/docs/assets/images/screens/archlinux-logo.png +0 -0
- data/docs/assets/images/screens/debian-11-xfce-arm64.png +0 -0
- data/docs/boxes/creating_utm_box.md +70 -0
- data/docs/boxes/index.md +6 -0
- data/docs/boxes/utm_box_gallery.md +117 -0
- data/docs/commands.md +156 -0
- data/docs/configuration.md +51 -0
- data/docs/features/index.md +5 -0
- data/docs/features/synced_folders.md +28 -0
- data/docs/index.md +103 -0
- data/docs/internals/actions.md +20 -0
- data/docs/internals/index.md +5 -0
- data/docs/internals/status.md +25 -0
- data/docs/internals/utm_api.md +31 -0
- data/docs/known_issues.md +24 -0
- data/lib/vagrant_utm/action/boot.rb +22 -0
- data/lib/vagrant_utm/action/boot_disposable.rb +22 -0
- data/lib/vagrant_utm/action/check_accessible.rb +33 -0
- data/lib/vagrant_utm/action/check_created.rb +24 -0
- data/lib/vagrant_utm/action/check_guest_additions.rb +37 -0
- data/lib/vagrant_utm/action/check_qemu_img.rb +21 -0
- data/lib/vagrant_utm/action/check_running.rb +25 -0
- data/lib/vagrant_utm/action/check_utm.rb +30 -0
- data/lib/vagrant_utm/action/clear_forwarded_ports.rb +26 -0
- data/lib/vagrant_utm/action/created.rb +26 -0
- data/lib/vagrant_utm/action/customize.rb +50 -0
- data/lib/vagrant_utm/action/destroy.rb +25 -0
- data/lib/vagrant_utm/action/download_confirm.rb +19 -0
- data/lib/vagrant_utm/action/export.rb +22 -0
- data/lib/vagrant_utm/action/forced_halt.rb +28 -0
- data/lib/vagrant_utm/action/forward_ports.rb +90 -0
- data/lib/vagrant_utm/action/import.rb +63 -0
- data/lib/vagrant_utm/action/is_paused.rb +26 -0
- data/lib/vagrant_utm/action/is_running.rb +26 -0
- data/lib/vagrant_utm/action/is_stopped.rb +26 -0
- data/lib/vagrant_utm/action/message_already_running.rb +22 -0
- data/lib/vagrant_utm/action/message_not_created.rb +22 -0
- data/lib/vagrant_utm/action/message_not_running.rb +22 -0
- data/lib/vagrant_utm/action/message_not_stopped.rb +22 -0
- data/lib/vagrant_utm/action/message_will_not_create.rb +23 -0
- data/lib/vagrant_utm/action/message_will_not_destroy.rb +23 -0
- data/lib/vagrant_utm/action/prepare_forwarded_port_collision_params.rb +43 -0
- data/lib/vagrant_utm/action/resume.rb +24 -0
- data/lib/vagrant_utm/action/set_id.rb +20 -0
- data/lib/vagrant_utm/action/set_name.rb +62 -0
- data/lib/vagrant_utm/action/snapshot_delete.rb +34 -0
- data/lib/vagrant_utm/action/snapshot_restore.rb +28 -0
- data/lib/vagrant_utm/action/snapshot_save.rb +34 -0
- data/lib/vagrant_utm/action/suspend.rb +23 -0
- data/lib/vagrant_utm/action/wait_for_running.rb +28 -0
- data/lib/vagrant_utm/action.rb +413 -0
- data/lib/vagrant_utm/cap.rb +40 -0
- data/lib/vagrant_utm/config.rb +141 -0
- data/lib/vagrant_utm/disposable.rb +16 -0
- data/lib/vagrant_utm/driver/base.rb +358 -0
- data/lib/vagrant_utm/driver/meta.rb +132 -0
- data/lib/vagrant_utm/driver/version_4_5.rb +307 -0
- data/lib/vagrant_utm/errors.rb +77 -0
- data/lib/vagrant_utm/model/forwarded_port.rb +75 -0
- data/lib/vagrant_utm/model/list_result.rb +77 -0
- data/lib/vagrant_utm/plugin.rb +65 -0
- data/lib/vagrant_utm/provider.rb +139 -0
- data/lib/vagrant_utm/scripts/add_port_forwards.applescript +72 -0
- data/lib/vagrant_utm/scripts/clear_port_forwards.applescript +56 -0
- data/lib/vagrant_utm/scripts/customize_vm.applescript +59 -0
- data/lib/vagrant_utm/scripts/downloadVM.sh +1 -0
- data/lib/vagrant_utm/scripts/list_vm.js +32 -0
- data/lib/vagrant_utm/scripts/open_with_utm.js +30 -0
- data/lib/vagrant_utm/scripts/read_forwarded_ports.applescript +27 -0
- data/lib/vagrant_utm/scripts/read_guest_ip.applescript +9 -0
- data/lib/vagrant_utm/scripts/read_network_interfaces.applescript +12 -0
- data/lib/vagrant_utm/util/compile_forwarded_ports.rb +43 -0
- data/lib/vagrant_utm/version.rb +9 -0
- data/lib/vagrant_utm.rb +40 -0
- data/locales/en.yml +154 -0
- data/sig/vagrant_utm.rbs +4 -0
- data/vagrantfile_examples/Vagrantfile +27 -0
- metadata +140 -0
@@ -0,0 +1,358 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "log4r"
|
4
|
+
require "pathname"
|
5
|
+
require "vagrant/util/busy"
|
6
|
+
require "vagrant/util/subprocess"
|
7
|
+
require "vagrant/util/which"
|
8
|
+
require_relative "../model/list_result"
|
9
|
+
|
10
|
+
module VagrantPlugins
|
11
|
+
module Utm
|
12
|
+
module Driver
|
13
|
+
# Executes commands on the host machine through the AppleScript bridge interface
|
14
|
+
# paired with a command line interface.
|
15
|
+
class Base # rubocop:disable Metrics/ClassLength
|
16
|
+
# Include this so we can use `Subprocess` more easily.
|
17
|
+
include Vagrant::Util::Retryable
|
18
|
+
|
19
|
+
def initialize
|
20
|
+
@logger = Log4r::Logger.new("vagrant::provider::utm::base")
|
21
|
+
|
22
|
+
# This flag is used to keep track of interrupted state (SIGINT)
|
23
|
+
@interrupted = false
|
24
|
+
# The path to the scripts directory.
|
25
|
+
@script_path = Pathname.new(File.expand_path("../scripts", __dir__))
|
26
|
+
|
27
|
+
# Set 'utmctl' path
|
28
|
+
@utmctl_path = Vagrant::Util::Which.which("utmctl")
|
29
|
+
|
30
|
+
# if not found, fall back to /usr/local/bin/utmctl
|
31
|
+
@utmctl_path ||= "/Applications/UTM.app/Contents/MacOS/utmctl"
|
32
|
+
@logger.info("utmctl path: #{@utmctl_path}")
|
33
|
+
end
|
34
|
+
|
35
|
+
# Clears the forwarded ports that have been set on the virtual machine.
|
36
|
+
def clear_forwarded_ports; end
|
37
|
+
|
38
|
+
# Checks if the qemu-guest-agent is installed and running in this VM.
|
39
|
+
# @return [Boolean]
|
40
|
+
def check_qemu_guest_agent; end
|
41
|
+
|
42
|
+
# Forwards a set of ports for a VM.
|
43
|
+
#
|
44
|
+
# This will not affect any previously set forwarded ports,
|
45
|
+
# so be sure to delete those if you need to.
|
46
|
+
#
|
47
|
+
# The format of each port hash should be the following:
|
48
|
+
#
|
49
|
+
# {
|
50
|
+
# name: "foo",
|
51
|
+
# hostport: 8500,
|
52
|
+
# guestport: 80,
|
53
|
+
# adapter: 1,
|
54
|
+
# protocol: "tcp"
|
55
|
+
# }
|
56
|
+
#
|
57
|
+
# Note that "adapter" and "protocol" are optional and will default
|
58
|
+
# to 1 and "tcp" respectively.
|
59
|
+
#
|
60
|
+
# @param [Array<Hash>] ports An array of ports to set. See documentation
|
61
|
+
# for more information on the format.
|
62
|
+
def forward_ports(ports); end
|
63
|
+
|
64
|
+
# Check if the VM with the given UUID (Name) exists.
|
65
|
+
def vm_exists?(uuid); end
|
66
|
+
|
67
|
+
# Returns a list of forwarded ports for a VM.
|
68
|
+
#
|
69
|
+
# @param [String] uuid UUID of the VM to read from, or `nil` if this
|
70
|
+
# VM.
|
71
|
+
|
72
|
+
# @return [Array<Array>] An array of arrays, each of which contains
|
73
|
+
# [nic, name(hostport), hostport, guestport]
|
74
|
+
def read_forwarded_ports(uuid = nil); end
|
75
|
+
|
76
|
+
# Returns the current state of this VM.
|
77
|
+
#
|
78
|
+
# @return [Symbol]
|
79
|
+
def read_state; end
|
80
|
+
|
81
|
+
# Returns a list of all forwarded ports in use by active
|
82
|
+
# virtual machines.
|
83
|
+
#
|
84
|
+
# @param [Boolean] active_only If true, only VMs that are running will
|
85
|
+
# be checked.
|
86
|
+
# @return [Array]
|
87
|
+
def read_used_ports(active_only: true); end
|
88
|
+
|
89
|
+
# Returns the IP address of the guest machine.
|
90
|
+
#
|
91
|
+
# @return [String] The IP address of the guest machine.
|
92
|
+
def read_guest_ip; end
|
93
|
+
|
94
|
+
# Returns a list of network interfaces of the VM.
|
95
|
+
#
|
96
|
+
# @return [Hash]
|
97
|
+
def read_network_interfaces; end
|
98
|
+
|
99
|
+
# Execute the 'list' command and returns the list of machines.
|
100
|
+
# @return [ListResult] The list of machines.
|
101
|
+
def list; end
|
102
|
+
|
103
|
+
# Execute the 'utm://downloadVM?url='
|
104
|
+
# See https://docs.getutm.app/advanced/remote-control/
|
105
|
+
# @param utm_file_url [String] The url to the UTM file.
|
106
|
+
# @return [uuid] The UUID of the imported machine.
|
107
|
+
def import(utm_file_url); end
|
108
|
+
|
109
|
+
# Sets the name of the virtual machine.
|
110
|
+
# @param name [String] The new name of the machine.
|
111
|
+
# @return [void]
|
112
|
+
def set_name(name); end # rubocop:disable Naming/AccessorMethodName
|
113
|
+
|
114
|
+
# Reads the SSH port of this VM.
|
115
|
+
#
|
116
|
+
# @param [Integer] expected Expected guest port of SSH.
|
117
|
+
def ssh_port(expected); end
|
118
|
+
|
119
|
+
# Starts the virtual machine referenced by this driver.
|
120
|
+
# @return [void]
|
121
|
+
def start; end
|
122
|
+
|
123
|
+
# Starts the virtual machine in disposable mode.
|
124
|
+
# @return [void]
|
125
|
+
def start_disposable; end
|
126
|
+
|
127
|
+
# Deletes the virtual machine references by this driver.
|
128
|
+
# @return [void]
|
129
|
+
def delete; end
|
130
|
+
|
131
|
+
# Return UUID of the last VM in the list.
|
132
|
+
# @return [uuid] The UUID of the VM.
|
133
|
+
def last_uuid; end
|
134
|
+
|
135
|
+
# Halts the virtual machine (pulls the plug).
|
136
|
+
def halt; end
|
137
|
+
|
138
|
+
# Suspend the virtual machine.
|
139
|
+
def suspend; end
|
140
|
+
|
141
|
+
# Verifies that the driver is ready to accept work.
|
142
|
+
#
|
143
|
+
# This should raise a VagrantError if things are not ready.
|
144
|
+
def verify!; end
|
145
|
+
|
146
|
+
# Execute a script using the OSA interface.
|
147
|
+
def execute_osa_script(command); end
|
148
|
+
|
149
|
+
# Execute a shell command and return the output.
|
150
|
+
def execute_shell(*command, &block) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity
|
151
|
+
# Get the options hash if it exists
|
152
|
+
opts = {}
|
153
|
+
opts = command.pop if command.last.is_a?(Hash)
|
154
|
+
|
155
|
+
tries = 0
|
156
|
+
tries = 3 if opts[:retryable]
|
157
|
+
|
158
|
+
# Variable to store our execution result
|
159
|
+
r = nil
|
160
|
+
|
161
|
+
retryable(on: VagrantPlugins::Utm::Errors::CommandError, tries: tries, sleep: 1) do
|
162
|
+
# If there is an error with VBoxManage, this gets set to true
|
163
|
+
errored = false
|
164
|
+
|
165
|
+
# Execute the command
|
166
|
+
r = raw_shell(*command, &block)
|
167
|
+
|
168
|
+
# If the command was a failure, then raise an exception that is
|
169
|
+
# nicely handled by Vagrant.
|
170
|
+
if r.exit_code != 0
|
171
|
+
if @interrupted
|
172
|
+
@logger.info("Exit code != 0, but interrupted. Ignoring.")
|
173
|
+
else
|
174
|
+
errored = true
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
if errored
|
179
|
+
raise VagrantPlugins::Utm::Errors::CommandError,
|
180
|
+
command: command.inspect,
|
181
|
+
stderr: r.stderr,
|
182
|
+
stdout: r.stdout
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
# Return the output, making sure to replace any Windows-style
|
187
|
+
# newlines with Unix-style.
|
188
|
+
# AppleScript logs are always in stderr, so we return that
|
189
|
+
# if there is any output.
|
190
|
+
if r.stdout && !r.stdout.empty?
|
191
|
+
r.stdout.gsub("\r\n", "\n")
|
192
|
+
elsif r.stderr && !r.stderr.empty?
|
193
|
+
r.stderr.gsub("\r\n", "\n")
|
194
|
+
else
|
195
|
+
""
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
# Executes a command and returns the raw result object.
|
200
|
+
def raw_shell(*command, &block)
|
201
|
+
int_callback = lambda do
|
202
|
+
@interrupted = true
|
203
|
+
|
204
|
+
# We have to execute this in a thread due to trap contexts
|
205
|
+
# and locks.
|
206
|
+
Thread.new { @logger.info("Interrupted.") }.join
|
207
|
+
end
|
208
|
+
|
209
|
+
# Append in the options for subprocess
|
210
|
+
# NOTE: We include the LANG env var set to C to prevent command output
|
211
|
+
# from being localized
|
212
|
+
command << { notify: %i[stdout stderr], env: env_lang }
|
213
|
+
|
214
|
+
Vagrant::Util::Busy.busy(int_callback) do
|
215
|
+
Vagrant::Util::Subprocess.execute(*command, &block)
|
216
|
+
end
|
217
|
+
rescue Vagrant::Util::Subprocess::LaunchError => e
|
218
|
+
raise Vagrant::Errors::UtmLaunchError,
|
219
|
+
message: e.to_s
|
220
|
+
end
|
221
|
+
|
222
|
+
# Execute the given subcommand for utmctl and return the output.
|
223
|
+
# Copied from https://github.com/hashicorp/vagrant/blob/main/plugins/providers/virtualbox/driver/base.rb.
|
224
|
+
# @param [String] subcommand The subcommand to execute.
|
225
|
+
# @return [String] The output of the command.
|
226
|
+
def execute(*command, &block) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity
|
227
|
+
# Get the options hash if it exists
|
228
|
+
opts = {}
|
229
|
+
opts = command.pop if command.last.is_a?(Hash)
|
230
|
+
|
231
|
+
tries = 0
|
232
|
+
tries = 3 if opts[:retryable]
|
233
|
+
|
234
|
+
# Variable to store our execution result
|
235
|
+
r = nil
|
236
|
+
|
237
|
+
retryable(on: Errors::UtmctlError, tries: tries, sleep: 1) do # rubocop:disable Metrics/BlockLength
|
238
|
+
# if there is an error with utmctl, this gets set to true
|
239
|
+
errored = false
|
240
|
+
|
241
|
+
# Execute the command
|
242
|
+
r = raw(*command, &block)
|
243
|
+
|
244
|
+
# If the command was a failure, then raise an exception that is
|
245
|
+
# nicely handled by Vagrant.
|
246
|
+
if r.exit_code != 0
|
247
|
+
if @interrupted
|
248
|
+
@logger.info("Exit code != 0, but interrupted. Ignoring.")
|
249
|
+
elsif r.exit_code == 126
|
250
|
+
# To be consistent with VBoxManage
|
251
|
+
raise Errors::UtmctlNotFoundError
|
252
|
+
else
|
253
|
+
errored = true
|
254
|
+
end
|
255
|
+
else
|
256
|
+
# if utmctl fails but doesn't exit with an error code
|
257
|
+
# Handle those cases here
|
258
|
+
|
259
|
+
if r.stderr =~ /Error/
|
260
|
+
@logger.info("Error found, assuming error.")
|
261
|
+
errored = true
|
262
|
+
end
|
263
|
+
|
264
|
+
if r.stderr =~ /OSStatus error/
|
265
|
+
@logger.info("OSStatus error found, assuming error.")
|
266
|
+
errored = true
|
267
|
+
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
# If there was an error running utmctl, show the error and the output
|
272
|
+
if errored
|
273
|
+
raise Errors::UtmctlError,
|
274
|
+
command: command.inspect,
|
275
|
+
stderr: r.stderr,
|
276
|
+
stdout: r.stdout
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
# Return the output, making sure to replace any Windows-style
|
281
|
+
# newlines with Unix-style.
|
282
|
+
r.stdout.gsub("\r\n", "\n")
|
283
|
+
end
|
284
|
+
|
285
|
+
# Executes a utmctl command and returns the raw result object.
|
286
|
+
def raw(*command, &block)
|
287
|
+
int_callback = lambda do
|
288
|
+
@interrupted = true
|
289
|
+
|
290
|
+
# We have to execute this in a thread due to trap contexts
|
291
|
+
# and locks.
|
292
|
+
Thread.new { @logger.info("Interrupted.") }.join
|
293
|
+
end
|
294
|
+
|
295
|
+
# Append in the options for subprocess
|
296
|
+
# NOTE: We include the LANG env var set to C to prevent command output
|
297
|
+
# from being localized
|
298
|
+
command << { notify: %i[stdout stderr], env: env_lang }
|
299
|
+
|
300
|
+
Vagrant::Util::Busy.busy(int_callback) do
|
301
|
+
Vagrant::Util::Subprocess.execute(@utmctl_path, *command, &block)
|
302
|
+
end
|
303
|
+
rescue Vagrant::Util::Subprocess::LaunchError => e
|
304
|
+
raise Vagrant::Errors::UtmLaunchError,
|
305
|
+
message: e.to_s
|
306
|
+
end
|
307
|
+
|
308
|
+
private
|
309
|
+
|
310
|
+
# List of LANG values to attempt to use
|
311
|
+
LANG_VARIATIONS = %w[C.UTF-8 C.utf8 en_US.UTF-8 en_US.utf8 C POSIX].map(&:freeze).freeze
|
312
|
+
|
313
|
+
# By default set the LANG to C. If the host has the locale command
|
314
|
+
# available, check installed locales and verify C is included (or
|
315
|
+
# use C variant if available).
|
316
|
+
def env_lang # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
|
317
|
+
# If already set, just return immediately
|
318
|
+
return @env_lang if @env_lang
|
319
|
+
|
320
|
+
# Default the LANG to C
|
321
|
+
@env_lang = { LANG: "C" }
|
322
|
+
|
323
|
+
# If the locale command is not available, return default
|
324
|
+
return @env_lang unless Vagrant::Util::Which.which("locale")
|
325
|
+
|
326
|
+
return @env_lang = @@env_lang if defined?(@@env_lang)
|
327
|
+
|
328
|
+
@logger.debug("validating LANG value for UTM cli commands")
|
329
|
+
# Get list of available locales on the system
|
330
|
+
result = Vagrant::Util::Subprocess.execute("locale", "-a")
|
331
|
+
|
332
|
+
# If the command results in an error, just log the error
|
333
|
+
# and return the default value
|
334
|
+
if result.exit_code != 0
|
335
|
+
@logger.warn("locale command failed (exit code: #{result.exit_code}): #{result.stderr}")
|
336
|
+
return @env_lang
|
337
|
+
end
|
338
|
+
available = result.stdout.lines.map(&:chomp).find_all do |l|
|
339
|
+
l == "C" || l == "POSIX" || l.start_with?("C.") || l.start_with?("en_US.")
|
340
|
+
end
|
341
|
+
@logger.debug("list of available C locales: #{available.inspect}")
|
342
|
+
|
343
|
+
# Attempt to find a valid LANG from locale list
|
344
|
+
lang = LANG_VARIATIONS.detect { |l| available.include?(l) }
|
345
|
+
|
346
|
+
if lang
|
347
|
+
@logger.debug("valid variation found for LANG value: #{lang}")
|
348
|
+
@env_lang[:LANG] = lang
|
349
|
+
@@env_lang = @env_lang # rubocop:disable Style/ClassVars
|
350
|
+
end
|
351
|
+
|
352
|
+
@logger.debug("LANG value set: #{@env_lang[:LANG].inspect}")
|
353
|
+
@env_lang
|
354
|
+
end
|
355
|
+
end
|
356
|
+
end
|
357
|
+
end
|
358
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "forwardable"
|
4
|
+
|
5
|
+
require "log4r"
|
6
|
+
|
7
|
+
require "vagrant/util/retryable"
|
8
|
+
|
9
|
+
require File.expand_path("base", __dir__)
|
10
|
+
|
11
|
+
module VagrantPlugins
|
12
|
+
module Utm
|
13
|
+
module Driver
|
14
|
+
# This driver uses the AppleScript bridge interface to interact with UTM.
|
15
|
+
class Meta < Base
|
16
|
+
# This is raised if the VM is not found when initializing a driver
|
17
|
+
# with a UUID.
|
18
|
+
class VMNotFound < StandardError; end
|
19
|
+
|
20
|
+
# We use forwardable to do all our driver forwarding
|
21
|
+
extend Forwardable
|
22
|
+
|
23
|
+
# We cache the read UTM version here once we have one,
|
24
|
+
# since during the execution of Vagrant, it likely doesn't change.
|
25
|
+
@version = nil
|
26
|
+
@@version_lock = Mutex.new # rubocop:disable Style/ClassVars
|
27
|
+
|
28
|
+
# The UUID of the virtual machine we represent (Name in UTM).
|
29
|
+
attr_reader :uuid
|
30
|
+
|
31
|
+
# The version of UTM that is running.
|
32
|
+
attr_reader :version
|
33
|
+
|
34
|
+
include Vagrant::Util::Retryable
|
35
|
+
|
36
|
+
def initialize(uuid = nil) # rubocop:disable Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/AbcSize,Metrics/PerceivedComplexity
|
37
|
+
# Setup the base
|
38
|
+
super()
|
39
|
+
|
40
|
+
@logger = Log4r::Logger.new("vagrant::provider::utm::meta")
|
41
|
+
@uuid = uuid
|
42
|
+
|
43
|
+
@@version_lock.synchronize do
|
44
|
+
unless @version
|
45
|
+
begin
|
46
|
+
@version = read_version
|
47
|
+
rescue Errors::CommandError
|
48
|
+
# This means that UTM was not found, so we raise this
|
49
|
+
# error here.
|
50
|
+
raise Errors::UtmNotDetected
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Instantiate the proper version driver for UTM
|
56
|
+
@logger.debug("Finding driver for UTM version: #{@version}")
|
57
|
+
driver_map = {
|
58
|
+
"4.5" => Version_4_5
|
59
|
+
}
|
60
|
+
|
61
|
+
# UTM 4.5.0 just doesn't work with Vagrant (https://github.com/utmapp/UTM/issues/5963),
|
62
|
+
# so show error
|
63
|
+
raise Errors::UtmInvalidVersion if @version.start_with?("4.5.0")
|
64
|
+
|
65
|
+
driver_klass = nil
|
66
|
+
driver_map.each do |key, klass|
|
67
|
+
if @version.start_with?(key)
|
68
|
+
driver_klass = klass
|
69
|
+
break
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
unless driver_klass
|
74
|
+
supported_versions = driver_map.keys.sort.join(", ")
|
75
|
+
raise Errors::UtmInvalidVersion,
|
76
|
+
supported_versions: supported_versions
|
77
|
+
end
|
78
|
+
|
79
|
+
@logger.info("Using UTM driver: #{driver_klass}")
|
80
|
+
@driver = driver_klass.new(@uuid)
|
81
|
+
|
82
|
+
return unless @uuid
|
83
|
+
# Verify the VM exists, and if it doesn't, then don't worry
|
84
|
+
# about it (mark the UUID as nil)
|
85
|
+
raise VMNotFound unless @driver.vm_exists?(@uuid)
|
86
|
+
end
|
87
|
+
|
88
|
+
def_delegators :@driver,
|
89
|
+
:check_qemu_guest_agent,
|
90
|
+
:clear_forwarded_ports,
|
91
|
+
:create_snapshot,
|
92
|
+
:delete,
|
93
|
+
:delete_snapshot,
|
94
|
+
:execute_osa_script,
|
95
|
+
:forward_ports,
|
96
|
+
:halt,
|
97
|
+
:import,
|
98
|
+
:last_uuid,
|
99
|
+
:list,
|
100
|
+
:list_snapshots,
|
101
|
+
:read_forwarded_ports,
|
102
|
+
:read_guest_ip,
|
103
|
+
:read_network_interfaces,
|
104
|
+
:read_state,
|
105
|
+
:read_used_ports,
|
106
|
+
:restore_snapshot,
|
107
|
+
:set_name,
|
108
|
+
:ssh_port,
|
109
|
+
:start,
|
110
|
+
:start_disposable,
|
111
|
+
:suspend,
|
112
|
+
:vm_exists?
|
113
|
+
|
114
|
+
protected
|
115
|
+
|
116
|
+
# This returns the version of UTM that is running.
|
117
|
+
#
|
118
|
+
# @return [String]
|
119
|
+
def read_version
|
120
|
+
# The version string is in the format "4.5.3"
|
121
|
+
# Error: Can’t get application "UTM"
|
122
|
+
# Success: "4.5.0"
|
123
|
+
cmd = ["osascript", "-e", 'tell application "System Events" to return version of application "UTM"']
|
124
|
+
output = execute_shell(*cmd)
|
125
|
+
return output.strip unless output =~ /get application/
|
126
|
+
|
127
|
+
raise Errors::UtmNotDetected
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|