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.
Files changed (96) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +11 -0
  4. data/CHANGELOG.md +5 -0
  5. data/CODE_OF_CONDUCT.md +132 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +59 -0
  8. data/Rakefile +12 -0
  9. data/docs/.gitignore +15 -0
  10. data/docs/Gemfile +10 -0
  11. data/docs/Gemfile.lock +276 -0
  12. data/docs/README.md +174 -0
  13. data/docs/_config.yml +76 -0
  14. data/docs/_includes/footer_custom.html +3 -0
  15. data/docs/_sass/gallery.scss +64 -0
  16. data/docs/_virtual_machines/archlinux-arm.md +13 -0
  17. data/docs/assets/images/favicon.ico +0 -0
  18. data/docs/assets/images/logo.png +0 -0
  19. data/docs/assets/images/screens/archlinux-logo.png +0 -0
  20. data/docs/assets/images/screens/debian-11-xfce-arm64.png +0 -0
  21. data/docs/boxes/creating_utm_box.md +70 -0
  22. data/docs/boxes/index.md +6 -0
  23. data/docs/boxes/utm_box_gallery.md +117 -0
  24. data/docs/commands.md +156 -0
  25. data/docs/configuration.md +51 -0
  26. data/docs/features/index.md +5 -0
  27. data/docs/features/synced_folders.md +28 -0
  28. data/docs/index.md +103 -0
  29. data/docs/internals/actions.md +20 -0
  30. data/docs/internals/index.md +5 -0
  31. data/docs/internals/status.md +25 -0
  32. data/docs/internals/utm_api.md +31 -0
  33. data/docs/known_issues.md +24 -0
  34. data/lib/vagrant_utm/action/boot.rb +22 -0
  35. data/lib/vagrant_utm/action/boot_disposable.rb +22 -0
  36. data/lib/vagrant_utm/action/check_accessible.rb +33 -0
  37. data/lib/vagrant_utm/action/check_created.rb +24 -0
  38. data/lib/vagrant_utm/action/check_guest_additions.rb +37 -0
  39. data/lib/vagrant_utm/action/check_qemu_img.rb +21 -0
  40. data/lib/vagrant_utm/action/check_running.rb +25 -0
  41. data/lib/vagrant_utm/action/check_utm.rb +30 -0
  42. data/lib/vagrant_utm/action/clear_forwarded_ports.rb +26 -0
  43. data/lib/vagrant_utm/action/created.rb +26 -0
  44. data/lib/vagrant_utm/action/customize.rb +50 -0
  45. data/lib/vagrant_utm/action/destroy.rb +25 -0
  46. data/lib/vagrant_utm/action/download_confirm.rb +19 -0
  47. data/lib/vagrant_utm/action/export.rb +22 -0
  48. data/lib/vagrant_utm/action/forced_halt.rb +28 -0
  49. data/lib/vagrant_utm/action/forward_ports.rb +90 -0
  50. data/lib/vagrant_utm/action/import.rb +63 -0
  51. data/lib/vagrant_utm/action/is_paused.rb +26 -0
  52. data/lib/vagrant_utm/action/is_running.rb +26 -0
  53. data/lib/vagrant_utm/action/is_stopped.rb +26 -0
  54. data/lib/vagrant_utm/action/message_already_running.rb +22 -0
  55. data/lib/vagrant_utm/action/message_not_created.rb +22 -0
  56. data/lib/vagrant_utm/action/message_not_running.rb +22 -0
  57. data/lib/vagrant_utm/action/message_not_stopped.rb +22 -0
  58. data/lib/vagrant_utm/action/message_will_not_create.rb +23 -0
  59. data/lib/vagrant_utm/action/message_will_not_destroy.rb +23 -0
  60. data/lib/vagrant_utm/action/prepare_forwarded_port_collision_params.rb +43 -0
  61. data/lib/vagrant_utm/action/resume.rb +24 -0
  62. data/lib/vagrant_utm/action/set_id.rb +20 -0
  63. data/lib/vagrant_utm/action/set_name.rb +62 -0
  64. data/lib/vagrant_utm/action/snapshot_delete.rb +34 -0
  65. data/lib/vagrant_utm/action/snapshot_restore.rb +28 -0
  66. data/lib/vagrant_utm/action/snapshot_save.rb +34 -0
  67. data/lib/vagrant_utm/action/suspend.rb +23 -0
  68. data/lib/vagrant_utm/action/wait_for_running.rb +28 -0
  69. data/lib/vagrant_utm/action.rb +413 -0
  70. data/lib/vagrant_utm/cap.rb +40 -0
  71. data/lib/vagrant_utm/config.rb +141 -0
  72. data/lib/vagrant_utm/disposable.rb +16 -0
  73. data/lib/vagrant_utm/driver/base.rb +358 -0
  74. data/lib/vagrant_utm/driver/meta.rb +132 -0
  75. data/lib/vagrant_utm/driver/version_4_5.rb +307 -0
  76. data/lib/vagrant_utm/errors.rb +77 -0
  77. data/lib/vagrant_utm/model/forwarded_port.rb +75 -0
  78. data/lib/vagrant_utm/model/list_result.rb +77 -0
  79. data/lib/vagrant_utm/plugin.rb +65 -0
  80. data/lib/vagrant_utm/provider.rb +139 -0
  81. data/lib/vagrant_utm/scripts/add_port_forwards.applescript +72 -0
  82. data/lib/vagrant_utm/scripts/clear_port_forwards.applescript +56 -0
  83. data/lib/vagrant_utm/scripts/customize_vm.applescript +59 -0
  84. data/lib/vagrant_utm/scripts/downloadVM.sh +1 -0
  85. data/lib/vagrant_utm/scripts/list_vm.js +32 -0
  86. data/lib/vagrant_utm/scripts/open_with_utm.js +30 -0
  87. data/lib/vagrant_utm/scripts/read_forwarded_ports.applescript +27 -0
  88. data/lib/vagrant_utm/scripts/read_guest_ip.applescript +9 -0
  89. data/lib/vagrant_utm/scripts/read_network_interfaces.applescript +12 -0
  90. data/lib/vagrant_utm/util/compile_forwarded_ports.rb +43 -0
  91. data/lib/vagrant_utm/version.rb +9 -0
  92. data/lib/vagrant_utm.rb +40 -0
  93. data/locales/en.yml +154 -0
  94. data/sig/vagrant_utm.rbs +4 -0
  95. data/vagrantfile_examples/Vagrantfile +27 -0
  96. metadata +140 -0
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module VagrantPlugins
4
+ module Utm
5
+ module Action
6
+ # This action is responsible for suspending the VM.
7
+ class Suspend
8
+ def initialize(app, _env)
9
+ @app = app
10
+ end
11
+
12
+ def call(env)
13
+ if env[:machine].state.id == :started
14
+ env[:ui].info I18n.t("vagrant.actions.vm.suspend.suspending")
15
+ env[:machine].provider.driver.suspend
16
+ end
17
+
18
+ @app.call(env)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module VagrantPlugins
4
+ module Utm
5
+ module Action
6
+ # This action waits for a given amount of seconds.
7
+ # This is a workaround for the UTM provider, which does not
8
+ # report when the VM is running. As soon as UTM reports the
9
+ # state as 'running', this action can and will be removed.
10
+ # Then we use the state 'running', rather than 'started'
11
+ class WaitForRunning
12
+ def initialize(app, _env)
13
+ @app = app
14
+ end
15
+
16
+ def call(env)
17
+ # set the wait time to user configured time or
18
+ # default time.
19
+ wait_time = env[:machine].provider_config.wait_time
20
+ env[:ui].info I18n.t("vagrant_utm.messages.waiting_for_vm", time: wait_time)
21
+ sleep(wait_time)
22
+
23
+ @app.call(env)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,413 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "vagrant"
4
+ require "vagrant/action/builder"
5
+
6
+ module VagrantPlugins
7
+ module Utm
8
+ # Contains all the supported actions of the UTM provider.
9
+ module Action # rubocop:disable Metrics/ModuleLength
10
+ # Autoloading action blocks
11
+ action_root = Pathname.new(File.expand_path("action", __dir__))
12
+ autoload :Boot, action_root.join("boot")
13
+ autoload :BootDisposable, action_root.join("boot_disposable")
14
+ autoload :CheckAccessible, action_root.join("check_accessible")
15
+ autoload :CheckCreated, action_root.join("check_created")
16
+ autoload :CheckGuestAdditions, action_root.join("check_guest_additions")
17
+ autoload :CheckQemuImg, action_root.join("check_qemu_img")
18
+ autoload :CheckRunning, action_root.join("check_running")
19
+ autoload :CheckUtm, action_root.join("check_utm")
20
+ autoload :ClearForwardedPorts, action_root.join("clear_forwarded_ports")
21
+ autoload :Created, action_root.join("created")
22
+ autoload :Customize, action_root.join("customize")
23
+ autoload :Destroy, action_root.join("destroy")
24
+ autoload :DownloadConfirm, action_root.join("download_confirm")
25
+ autoload :Export, action_root.join("export")
26
+ autoload :ForcedHalt, action_root.join("forced_halt")
27
+ autoload :ForwardPorts, action_root.join("forward_ports")
28
+ autoload :Import, action_root.join("import")
29
+ autoload :IsPaused, action_root.join("is_paused")
30
+ autoload :IsRunning, action_root.join("is_running")
31
+ autoload :IsStopped, action_root.join("is_stopped")
32
+ autoload :MessageAlreadyRunning, action_root.join("message_already_running")
33
+ autoload :MessageNotCreated, action_root.join("message_not_created")
34
+ autoload :MessageNotRunning, action_root.join("message_not_running")
35
+ autoload :MessageNotStopped, action_root.join("message_not_stopped")
36
+ autoload :MessageWillNotCreate, action_root.join("message_will_not_create")
37
+ autoload :MessageWillNotDestroy, action_root.join("message_will_not_destroy")
38
+ autoload :PrepareForwardedPortCollisionParams, action_root.join("prepare_forwarded_port_collision_params")
39
+ autoload :Resume, action_root.join("resume")
40
+ autoload :SetId, action_root.join("set_id")
41
+ autoload :SetName, action_root.join("set_name")
42
+ autoload :SnapshotDelete, action_root.join("snapshot_delete")
43
+ autoload :SnapshotRestore, action_root.join("snapshot_restore")
44
+ autoload :SnapshotSave, action_root.join("snapshot_save")
45
+ autoload :Suspend, action_root.join("suspend")
46
+ autoload :WaitForRunning, action_root.join("wait_for_running")
47
+
48
+ # Include the built-in Vagrant action modules (e.g., DestroyConfirm)
49
+ include Vagrant::Action::Builtin
50
+
51
+ # State of VM is given by Driver read state
52
+
53
+ # This action boots the VM, assuming the VM is in a state that requires
54
+ # a bootup (i.e. not saved).
55
+ def self.action_boot # rubocop:disable Metrics/AbcSize
56
+ Vagrant::Action::Builder.new.tap do |b|
57
+ b.use CheckAccessible
58
+ b.use SetName
59
+ b.use ClearForwardedPorts
60
+ b.use Provision
61
+ b.use EnvSet, port_collision_repair: true
62
+ b.use PrepareForwardedPortCollisionParams
63
+ b.use HandleForwardedPortCollisions
64
+ b.use ForwardPorts
65
+ b.use SetHostname
66
+ b.use Customize, "pre-boot"
67
+ b.use Boot
68
+ b.use Customize, "post-boot"
69
+
70
+ # UTM does not have a running state, if you want to
71
+ # wait manually for the VM to be running, use the following:
72
+ # b.use WaitForRunning
73
+ # Since we use forwarded ports , we do not query ip address of VM
74
+ # for Vagrant communicator.
75
+ # So we can rely on WaitForCommunicator to wait for VM to be up and running
76
+
77
+ # Machine need to be up and running before we can connect to it.
78
+ # TODO: change valid states to starting, started, running (after UTM provides running state)
79
+ b.use WaitForCommunicator, %i[starting started]
80
+ b.use Customize, "post-comm"
81
+ b.use CheckGuestAdditions
82
+ end
83
+ end
84
+
85
+ # This is the action that is primarily responsible for completely
86
+ # freeing the resources of the underlying virtual machine.
87
+ # UTM equivalent of `utmctl delete <uuid>`
88
+ def self.action_destroy
89
+ Vagrant::Action::Builder.new.tap do |b|
90
+ b.use CheckUtm
91
+ b.use Call, Created do |env1, b2|
92
+ unless env1[:result]
93
+ b2.use MessageNotCreated
94
+ next
95
+ end
96
+
97
+ b2.use Call, DestroyConfirm do |env2, b3|
98
+ if env2[:result]
99
+ b3.use ConfigValidate
100
+ b3.use ProvisionerCleanup, :before
101
+ b3.use CheckAccessible
102
+ b3.use action_halt
103
+ b3.use Destroy
104
+ else
105
+ b3.use MessageWillNotDestroy
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
111
+
112
+ # This action is primarily responsible for halting the VM.
113
+ # gracefully or by force.
114
+ # UTM equivalent of `utmctl stop <uuid>`
115
+ def self.action_halt
116
+ Vagrant::Action::Builder.new.tap do |b|
117
+ b.use CheckUtm
118
+ b.use Call, Created do |env, b2|
119
+ if env[:result]
120
+ b2.use CheckAccessible
121
+
122
+ # if VM is paused, resume it before halting
123
+ # utmctl stop will not work on paused VM
124
+ b2.use Call, IsPaused do |env2, b3|
125
+ next unless env2[:result]
126
+
127
+ b3.use Resume
128
+ end
129
+
130
+ b2.use Call, GracefulHalt, :stopped, :started do |env2, b3|
131
+ b3.use ForcedHalt unless env2[:result]
132
+ end
133
+ else
134
+ b2.use MessageNotCreated
135
+ end
136
+ end
137
+ end
138
+ end
139
+
140
+ # This action packages the virtual machine into a single box file.
141
+ def self.action_package
142
+ Vagrant::Action::Builder.new.tap do |b|
143
+ b.use CheckUtm
144
+ b.use Call, Created do |env, b2|
145
+ unless env[:result]
146
+ b2.use MessageNotCreated
147
+ next
148
+ end
149
+ b2.use CheckAccessible
150
+ b2.use action_halt
151
+ b2.use ClearForwardedPorts
152
+ b2.use Export
153
+ end
154
+ end
155
+ end
156
+
157
+ # This action just runs the provisioners on the machine.
158
+ def self.action_provision
159
+ Vagrant::Action::Builder.new.tap do |b|
160
+ b.use CheckUtm
161
+ b.use ConfigValidate
162
+ b.use Call, Created do |env1, b2|
163
+ unless env1[:result]
164
+ b2.use MessageNotCreated
165
+ next
166
+ end
167
+
168
+ b2.use Call, IsRunning do |env2, b3|
169
+ unless env2[:result]
170
+ b3.use MessageNotRunning
171
+ next
172
+ end
173
+
174
+ b3.use CheckAccessible
175
+ b3.use Provision
176
+ end
177
+ end
178
+ end
179
+ end
180
+
181
+ # This action is responsible for reloading the machine, which
182
+ # brings it down, sucks in new configuration, and brings the
183
+ # machine back up with the new configuration.
184
+ def self.action_reload
185
+ Vagrant::Action::Builder.new.tap do |b|
186
+ b.use CheckUtm
187
+ b.use Call, Created do |env1, b2|
188
+ unless env1[:result]
189
+ b2.use MessageNotCreated
190
+ next
191
+ end
192
+
193
+ b2.use ConfigValidate
194
+ b2.use action_halt
195
+ b2.use action_start
196
+ end
197
+ end
198
+ end
199
+
200
+ # This action is primarily responsible for resuming the suspended VM.
201
+ # UTM equivalent of `utmctl start <uuid>`
202
+ def self.action_resume
203
+ Vagrant::Action::Builder.new.tap do |b|
204
+ b.use CheckUtm
205
+ b.use Call, Created do |env, b2|
206
+ if env[:result]
207
+ b2.use CheckAccessible
208
+
209
+ # if VM is paused , QEMU still holds the port
210
+ # so we disable port collision check while resuming
211
+ # lsof -i tcp:8989
212
+ # COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
213
+ # QEMULaunc 27754 xxxxxxxxx 21u IPv4 0x41d02c3ade4c04f1 0t0 TCP *:sunwebadmins (LISTEN)
214
+ # b2.use EnvSet, port_collision_repair: false
215
+ # b2.use PrepareForwardedPortCollisionParams
216
+ # b2.use HandleForwardedPortCollisions
217
+
218
+ b2.use Resume
219
+ b2.use Provision
220
+ b2.use WaitForCommunicator, %i[resuming started]
221
+ else
222
+ b2.use MessageNotCreated
223
+ end
224
+ end
225
+ end
226
+ end
227
+
228
+ # This is the action that is primarily responsible for deleting a snapshot
229
+ def self.action_snapshot_delete
230
+ Vagrant::Action::Builder.new.tap do |b|
231
+ b.use CheckUtm
232
+ b.use CheckQemuImg
233
+ b.use Call, Created do |env, b2|
234
+ if env[:result]
235
+ # qemu-img needs write-lock to file, so VM should be stopped
236
+ b2.use Call, IsStopped do |env2, b3|
237
+ if env2[:result]
238
+ b3.use SnapshotDelete
239
+ else
240
+ b3.use MessageNotStopped
241
+ end
242
+ end
243
+ else
244
+ b2.use MessageNotCreated
245
+ end
246
+ end
247
+ end
248
+ end
249
+
250
+ # This is the action that is primarily responsible for restoring a snapshot
251
+ def self.action_snapshot_restore # rubocop:disable Metrics/AbcSize
252
+ Vagrant::Action::Builder.new.tap do |b|
253
+ b.use CheckUtm
254
+ b.use CheckQemuImg
255
+ b.use Call, Created do |env, b2|
256
+ raise Vagrant::Errors::VMNotCreatedError unless env[:result]
257
+
258
+ b2.use CheckAccessible
259
+ b2.use EnvSet, force_halt: true
260
+ b2.use action_halt
261
+ b2.use SnapshotRestore
262
+
263
+ b2.use Call, IsEnvSet, :snapshot_delete do |env2, b3|
264
+ b3.use action_snapshot_delete if env2[:result]
265
+ end
266
+
267
+ b2.use Call, IsEnvSet, :snapshot_start do |env2, b3|
268
+ b3.use action_start if env2[:result]
269
+ end
270
+ end
271
+ end
272
+ end
273
+
274
+ # This is the action that is primarily responsible for saving a snapshot
275
+ def self.action_snapshot_save
276
+ Vagrant::Action::Builder.new.tap do |b|
277
+ b.use CheckUtm
278
+ b.use CheckQemuImg
279
+ b.use Call, Created do |env, b2|
280
+ if env[:result]
281
+ # qemu-img does offline snapshot, so VM should be stopped
282
+ b2.use Call, IsStopped do |env2, b3|
283
+ if env2[:result]
284
+ b3.use SnapshotSave
285
+ else
286
+ b3.use MessageNotStopped
287
+ end
288
+ end
289
+ else
290
+ b2.use MessageNotCreated
291
+ end
292
+ end
293
+ end
294
+ end
295
+
296
+ # This is the action that will exec into an SSH shell.
297
+ def self.action_ssh
298
+ Vagrant::Action::Builder.new.tap do |b|
299
+ b.use CheckUtm
300
+ b.use CheckCreated
301
+ b.use CheckAccessible
302
+ b.use CheckRunning
303
+ b.use SSHExec
304
+ end
305
+ end
306
+
307
+ # This is the action that will run a single SSH command.
308
+ def self.action_ssh_run
309
+ Vagrant::Action::Builder.new.tap do |b|
310
+ b.use CheckUtm
311
+ b.use CheckCreated
312
+ b.use CheckAccessible
313
+ b.use CheckRunning
314
+ b.use SSHRun
315
+ end
316
+ end
317
+
318
+ # This action starts a VM, assuming it is already imported and exists.
319
+ # A precondition of this action is that the VM exists.
320
+ def self.action_start
321
+ Vagrant::Action::Builder.new.tap do |b|
322
+ b.use CheckUtm
323
+ b.use ConfigValidate
324
+ b.use Call, IsRunning do |env, b2|
325
+ # If the VM is running, run the necessary provisioners
326
+ if env[:result]
327
+ b2.use action_provision
328
+ next
329
+ end
330
+
331
+ b2.use Call, IsPaused do |env2, b3|
332
+ if env2[:result]
333
+ b3.use Resume
334
+ next
335
+ end
336
+
337
+ # The VM is not paused, so we must have to boot it up
338
+ # like normal. Boot!
339
+ b3.use action_boot
340
+ end
341
+ end
342
+ end
343
+ end
344
+
345
+ # This action start VM in disposable mode.
346
+ # UTM equivalent of `utmctl start <uuid> --disposable`
347
+ def self.action_start_disposable
348
+ Vagrant::Action::Builder.new.tap do |b|
349
+ b.use CheckUtm
350
+ b.use ConfigValidate
351
+ b.use Call, IsRunning do |env1, b2|
352
+ if env1[:result]
353
+ b2.use MessageAlreadyRunning
354
+ next
355
+ end
356
+ # If the VM is NOT running, then start in disposable mode
357
+ b2.use BootDisposable
358
+ end
359
+ end
360
+ end
361
+
362
+ # This action is primarily responsible for suspending the VM.
363
+ # UTM equivalent of `utmctl suspend <uuid>`
364
+ def self.action_suspend
365
+ Vagrant::Action::Builder.new.tap do |b|
366
+ b.use CheckUtm
367
+ b.use Call, Created do |env, b2|
368
+ if env[:result]
369
+ b2.use CheckAccessible
370
+ b2.use Suspend
371
+ else
372
+ b2.use MessageNotCreated
373
+ end
374
+ end
375
+ end
376
+ end
377
+
378
+ # This action brings the machine up from nothing, including importing
379
+ # the UTM file, configuring metadata, and booting.
380
+ def self.action_up # rubocop:disable Metrics/AbcSize
381
+ Vagrant::Action::Builder.new.tap do |b|
382
+ b.use CheckUtm
383
+ b.use ConfigValidate
384
+ b.use Call, Created do |env, b2|
385
+ # If the VM is NOT created yet, then do the setup steps
386
+ unless env[:result]
387
+ b2.use CheckAccessible
388
+ b2.use Customize, "pre-import"
389
+ # load UTM file to UTM app, through 'utm://downloadVM?url='
390
+ b2.use Import
391
+
392
+ b2.use Call, DownloadConfirm do |env1, b3|
393
+ if env1[:result]
394
+ # SetID
395
+ b3.use SetId
396
+ b3.use SetName
397
+ # Customize
398
+ b3.use Customize, "pre-boot"
399
+ else
400
+ b3.use MessageWillNotCreate
401
+ raise Errors::UtmImportFailed
402
+ end
403
+ end
404
+ end
405
+ end
406
+
407
+ # Start the VM
408
+ b.use action_start
409
+ end
410
+ end
411
+ end
412
+ end
413
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module VagrantPlugins
4
+ module Utm
5
+ # Contains all the supported capabilities of the UTM provider.
6
+ module Cap
7
+ # Reads the forwarded ports that currently exist on the machine
8
+ # itself. This raises an exception if the machine isn't running (UTM 'started').
9
+ #
10
+ # This also may not match up with configured forwarded ports, because
11
+ # Vagrant auto port collision fixing may have taken place.
12
+ #
13
+ # @return [Hash<Integer, Integer>] Host => Guest port mappings.
14
+ def self.forwarded_ports(machine)
15
+ return nil if machine.state.id != :started
16
+
17
+ {}.tap do |result|
18
+ machine.provider.driver.read_forwarded_ports.each do |_, _, h, g|
19
+ result[h] = g
20
+ end
21
+ end
22
+ end
23
+
24
+ # Returns a list of the snapshots that are taken on this machine.
25
+ #
26
+ # @return [Array<String>] Snapshot Name
27
+ def self.snapshot_list(machine)
28
+ return [] if machine.id.nil?
29
+
30
+ begin
31
+ machine.provider.driver.list_snapshots(machine.id)
32
+ rescue VagrantPlugins::Utm::Errors::CommandError => e
33
+ raise Errors::SnapShotCommandFailed, {
34
+ stderr: e.inspect
35
+ }
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,141 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "i18n"
4
+ require "vagrant"
5
+
6
+ module VagrantPlugins
7
+ module Utm
8
+ # This is the configuration class for the UTM provider.
9
+ class Config < Vagrant.plugin("2", :config)
10
+ # This should be set to the name of the machine in the UTM GUI.
11
+ #
12
+ # @return [String]
13
+ attr_accessor :name
14
+
15
+ # The path to the UTM VM file.
16
+ #
17
+ # @return [String]
18
+ attr_accessor :utm_file_url
19
+
20
+ # If true, will check if guest additions are installed and up to
21
+ # date. By default, this is true.
22
+ #
23
+ # @return [Boolean]
24
+ attr_accessor :check_guest_additions
25
+
26
+ # An array of customizations to make on the VM prior to booting it.
27
+ #
28
+ # @return [Array]
29
+ attr_reader :customizations
30
+
31
+ # The time to wait for the VM to be 'running' after 'started'.
32
+ #
33
+ # @return [Integer]
34
+ attr_accessor :wait_time
35
+
36
+ # Initialize the configuration with unset values.
37
+ def initialize
38
+ super
39
+ @check_guest_additions = UNSET_VALUE
40
+ @customizations = []
41
+ @name = UNSET_VALUE
42
+ @utm_file_url = UNSET_VALUE
43
+ @wait_time = UNSET_VALUE
44
+ end
45
+
46
+ # Customize the VM by calling 'osascript' with the given
47
+ # arguments.
48
+ #
49
+ # When called multiple times, the customizations will be applied
50
+ # in the order given.
51
+ #
52
+ # @param [Array] command An array of arguments to pass to
53
+ # osascript config function.
54
+ def customize(*command)
55
+ # Append the event and command to the customizations array
56
+ event = command.first.is_a?(String) ? command.shift : "pre-boot"
57
+ command = command[0]
58
+ @customizations << [event, command]
59
+ end
60
+
61
+ # Shortcut for setting memory size for the virtual machine.
62
+ # Calls #customize internally.
63
+ #
64
+ # @param size [Integer] the memory size in MB
65
+ def memory=(size)
66
+ customize("pre-boot", ["customize_vm.applescript", :id, "--memory", size.to_s])
67
+ end
68
+
69
+ # Shortcut for setting CPU count for the virtual machine.
70
+ # Calls #customize internally.
71
+ #
72
+ # @param count [Integer] the count of CPUs
73
+ def cpus=(count)
74
+ customize("pre-boot", ["customize_vm.applescript", :id, "--cpus", count.to_i])
75
+ end
76
+
77
+ # Shortcut for setting the notes of the virtual machine.
78
+ # Calls #customize internally.
79
+ #
80
+ # @param notes [String] the notes for the VM
81
+ def notes=(notes)
82
+ customize("pre-boot", ["customize_vm.applescript", :id, "--notes", notes])
83
+ end
84
+
85
+ # Shortcut for setting the directory share mode of the virtual machine.
86
+ # Calls #customize internally.
87
+ #
88
+ # @param mode [String] the directory share mode for the VM
89
+ def directory_share_mode=(mode)
90
+ # The mode can be 'none', 'webDAV', 'virtFS'
91
+ # Convert the mode to the corresponding 4-byte code
92
+ # and pass it to the customize_vm.applescript
93
+ mode_code = case mode.to_s
94
+ when "none"
95
+ "SmOf"
96
+ when "webDAV"
97
+ "SmWv"
98
+ when "virtFS"
99
+ "SmVs"
100
+ else
101
+ raise Vagrant::Errors::ConfigInvalid,
102
+ errors: "Invalid directory share mode, must be 'none', 'webDAV', or 'virtFS'"
103
+ end
104
+ customize("pre-boot", ["customize_vm.applescript", :id, "--directory-share-mode", mode_code])
105
+ end
106
+
107
+ # This is the hook that is called to finalize the object before it
108
+ # is put into use.
109
+ def finalize!
110
+ @check_guest_additions = true if @check_guest_additions == UNSET_VALUE
111
+
112
+ # The default name is just nothing, and we default it
113
+ @name = nil if @name == UNSET_VALUE
114
+
115
+ @utm_file_url = nil if @utm_file_url == UNSET_VALUE
116
+
117
+ @wait_time = 20 if @wait_time == UNSET_VALUE
118
+ end
119
+
120
+ def validate(_machine)
121
+ errors = _detected_errors
122
+
123
+ # Checks for the UTM file URL
124
+ errors << I18n.t("vagrant_utm.config.utm_file_url_required") if @utm_file_url.nil? || @utm_file_url.empty?
125
+
126
+ valid_events = %w[pre-import pre-boot post-boot post-comm]
127
+ @customizations.each do |event, _| # rubocop:disable Style/HashEachMethods
128
+ next if valid_events.include?(event)
129
+
130
+ errors << I18n.t(
131
+ "vagrant.virtualbox.config.invalid_event",
132
+ event: event.to_s,
133
+ valid_events: valid_events.join(", ")
134
+ )
135
+ end
136
+
137
+ { "UTM Provider" => errors }
138
+ end
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module VagrantPlugins
4
+ module Utm
5
+ # Run VM as a snapshot and do not save changes to disk.
6
+ class Disposable < Vagrant.plugin(2, :command)
7
+ def execute
8
+ with_target_vms do |machine|
9
+ machine.action(:start_disposable)
10
+ end
11
+
12
+ 0
13
+ end
14
+ end
15
+ end
16
+ end