vagrant_utm 0.1.0 → 0.1.2.beta
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 +4 -4
- data/CHANGELOG.md +61 -2
- data/docs/boxes/creating_utm_box.md +26 -2
- data/docs/commands.md +8 -0
- data/lib/vagrant_utm/action/ip_address.rb +33 -0
- data/lib/vagrant_utm/action/match_mac_address.rb +37 -0
- data/lib/vagrant_utm/action/prepare_nfs_settings.rb +79 -0
- data/lib/vagrant_utm/action/prepare_nfs_valid_ids.rb +24 -0
- data/lib/vagrant_utm/action.rb +45 -3
- data/lib/vagrant_utm/commands/disposable.rb +29 -0
- data/lib/vagrant_utm/commands/ip_address.rb +28 -0
- data/lib/vagrant_utm/driver/base.rb +29 -2
- data/lib/vagrant_utm/driver/meta.rb +4 -3
- data/lib/vagrant_utm/driver/version_4_5.rb +20 -3
- data/lib/vagrant_utm/model/forwarded_port.rb +3 -1
- data/lib/vagrant_utm/plugin.rb +11 -8
- data/lib/vagrant_utm/provider.rb +2 -1
- data/lib/vagrant_utm/scripts/read_network_interfaces.applescript +2 -1
- data/lib/vagrant_utm/scripts/set_mac_address.applescript +25 -0
- data/lib/vagrant_utm/version.rb +1 -1
- data/locales/en.yml +8 -0
- data/notes/README.md +16 -1
- metadata +9 -4
- data/lib/vagrant_utm/disposable.rb +0 -16
- data/lib/vagrant_utm/scripts/read_guest_ip.applescript +0 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4afb59e8282747e3cca61c9ed2b297b7084606c268cc4e6231856f12fb2510b0
|
4
|
+
data.tar.gz: 1a4ba9a73219106a661fdddad221d14128d203fc8c273dc22fa3018d72b25e0b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 01e79bc38a232a68a08eb43e7cddfcc2ed0866acd54a559b797e8c26f84fce16c5d8ec171492758fc514080c8b98be32dd2505554f9e04a8c2897a1d05fb3d2a
|
7
|
+
data.tar.gz: '07951106f1403e2bb7811f699ed914c12eb701e15cb4142f6f2318a2ffc4fd9065e49bfdc098b544d547f3129005b4cf8370bad9d513a356d0b9c9b77b8b2719'
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,64 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
-
## [0.1.0] - 2024-07-13
|
4
3
|
|
5
|
-
-
|
4
|
+
## [0.1.2.beta] - 2024-12-05
|
5
|
+
|
6
|
+
WARNING: This version of the plugin adds initial synced folder support. By default, Vagrant will pick the directory share method which it supports and prefers. e.g., SMB. However, SMB is not fully tested, so you need to force the plugin to pick the one that is simple and tested `rsync`
|
7
|
+
|
8
|
+
```ruby
|
9
|
+
Vagrant.configure("2") do |config|
|
10
|
+
config.vm.synced_folder ".", "/vagrant", type: "rsync"
|
11
|
+
config.vm.box = "utm/ubuntu-24.04"
|
12
|
+
end
|
13
|
+
```
|
14
|
+
|
15
|
+
### Added
|
16
|
+
|
17
|
+
- Initial Synced Folder support with sync
|
18
|
+
- Warning: By default vagrant brings other sync methods eg: SMB, NFS but they are not ready to use.
|
19
|
+
|
20
|
+
## [0.1.1] - 2024-12-03
|
21
|
+
|
22
|
+
IMPORTANT: This version of the plugin only works with UTM version 4.5.1 and above, and is incompatible with 0.0.1 version of the plugin.
|
23
|
+
|
24
|
+
### Added
|
25
|
+
|
26
|
+
- command: add new vagrant command `vagrant ip-address` (9252020)
|
27
|
+
- command: add help messages to custom plugin commands (a35466f)
|
28
|
+
- action: Set mac address when bringing up new machine (0efe15b)
|
29
|
+
|
30
|
+
### Changed
|
31
|
+
|
32
|
+
- plugin: Make config.vm.box mandatory for this plugin (b5be5e8)
|
33
|
+
|
34
|
+
### Fixed
|
35
|
+
|
36
|
+
- disposable: allow disposable start only for machines already created (cbf591e)
|
37
|
+
- up: Set given mac address or random mac address for first interface of a machine to get different IPs of a same base box.
|
38
|
+
|
39
|
+
### Removed
|
40
|
+
|
41
|
+
- Driver: Removed support for UTM version 4.5.x (9aea46e)
|
42
|
+
|
43
|
+
## [0.1.0] (Beta) - 2024-11-30
|
44
|
+
|
45
|
+
IMPORTANT: This version of the plugin only works with UTM version 4.5.1 and above, and is incompatible with previous versions of the plugin.
|
46
|
+
|
47
|
+
### Added
|
48
|
+
|
49
|
+
- driver: add new driver for UTM version 4.6.x (13d0ca0)
|
50
|
+
- vagrant: add vagrant box support (f7accad)
|
51
|
+
- command: support `vagrant package` command (39fb5a5)
|
52
|
+
|
53
|
+
|
54
|
+
### Removed
|
55
|
+
|
56
|
+
- Drop support for `utm_file_url` from provider config (4fb0ac0)
|
57
|
+
- Remove support for importing utm files in zip format (c988671)
|
58
|
+
|
59
|
+
|
60
|
+
|
61
|
+
## [0.0.1] (Pilot release) - 2024-08-08
|
62
|
+
|
63
|
+
* Initial release with all basic vagrant commands
|
64
|
+
* Uses UTM file in zip format from a url as VM box to import
|
@@ -8,6 +8,23 @@ nav_order: 2
|
|
8
8
|
|
9
9
|
As with [every Vagrant Provider](https://developer.hashicorp.com/vagrant/docs/providers/basic_usage), the Vagrant UTM provider has a custom box format that is required to work with Vagrant and the UTM plugin.
|
10
10
|
|
11
|
+
## UTM Vagrant box format
|
12
|
+
|
13
|
+
UTM file (in macOS) is a directory containing Data/qcow2 (s), Data/efi_vars.fd and config.plist.
|
14
|
+
Vagrant Box format will require additional metadata.json file.
|
15
|
+
|
16
|
+
Vagrant .box is a tar file
|
17
|
+
|
18
|
+
The contents of a `utm/ubuntu-24.04` vagrant box.
|
19
|
+
```bash
|
20
|
+
$tar -tf ubuntu-24.04.box
|
21
|
+
Vagrantfile
|
22
|
+
box.utm/Data/7FB247A3-DC9F-4A61-A123-0AEE1BEEC636.qcow2
|
23
|
+
box.utm/Data/efi_vars.fd
|
24
|
+
box.utm/config.plist
|
25
|
+
box.utm/screenshot.png
|
26
|
+
metadata.json
|
27
|
+
```
|
11
28
|
|
12
29
|
{: .warning }
|
13
30
|
This is a reasonably advanced topic that a beginning user of Vagrant does not need to understand. If you are just getting started with Vagrant, skip this and use an [available box](/utm_box_gallery.md). If you are an experienced user of Vagrant and want to create your own custom boxes, this is for you.
|
@@ -16,9 +33,16 @@ This is a reasonably advanced topic that a beginning user of Vagrant does not ne
|
|
16
33
|
|
17
34
|
The virtual machine created in UTM can use any configuration you would like, but Vagrant has some hard requirements:
|
18
35
|
|
19
|
-
* The
|
36
|
+
* The first network interface (adapter 1 or index 0) must be `Shared Network`, which is recommended for new virtual machines.
|
37
|
+
|
38
|
+
We use 'Shared Network' as a NAT equivalent in Vagrant.
|
39
|
+
|
40
|
+
* The second network interface (adapter 2 or index 1) must be a `Emulated VLAN` adapter. Vagrant uses this to connect the first time via forwarded ports.
|
41
|
+
|
42
|
+
We use 'Emulated VLAN' to achieve port forwarding.
|
43
|
+
|
44
|
+
|
20
45
|
|
21
|
-
* Use can use the first network interface (adapter 0 or index 0) to be `Shared Network`, which is recommended for new virtual machines.
|
22
46
|
|
23
47
|
Other than the above, you are free to customize the base virtual machine as you see fit.
|
24
48
|
|
data/docs/commands.md
CHANGED
@@ -141,6 +141,14 @@ Import VM (if not created)
|
|
141
141
|
|
142
142
|
These are the commands not available in vagrant but specific to UTM provider.
|
143
143
|
|
144
|
+
## IP Address
|
145
|
+
|
146
|
+
**Command: `vagrant ip-address [name|id]`**
|
147
|
+
|
148
|
+
`utmctl ip-address`
|
149
|
+
|
150
|
+
List all IP addresses associated with network interfaces on the guest.
|
151
|
+
|
144
152
|
## Disposable
|
145
153
|
|
146
154
|
**Command: `vagrant disposable [name|id]`**
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module Utm
|
5
|
+
module Action
|
6
|
+
# Action to get IP address of machine.
|
7
|
+
class IpAddress
|
8
|
+
def initialize(app, _env)
|
9
|
+
@app = app
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(env) # rubocop:disable Metrics/AbcSize
|
13
|
+
# Get IP address of the machine.
|
14
|
+
env[:ui].warn I18n.t("vagrant_utm.actions.vm.ip_address.reading")
|
15
|
+
guest_ips = env[:machine].provider.driver.read_guest_ip
|
16
|
+
|
17
|
+
if guest_ips.empty?
|
18
|
+
# Inform user that no IP address was found.
|
19
|
+
env[:ui].warn I18n.t("vagrant_utm.actions.vm.ip_address.not_found")
|
20
|
+
else
|
21
|
+
# Show IP address of the machine.
|
22
|
+
env[:ui].info I18n.t("vagrant_utm.actions.vm.ip_address.show")
|
23
|
+
guest_ips.each do |ip|
|
24
|
+
env[:ui].info " #{ip}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
@app.call(env)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) HashiCorp, Inc.
|
4
|
+
# SPDX-License-Identifier: BUSL-1.1
|
5
|
+
|
6
|
+
module VagrantPlugins
|
7
|
+
module Utm
|
8
|
+
module Action
|
9
|
+
# This action matches the MAC address of the virtual machine to the
|
10
|
+
# configured MAC address in the Vagrantfile.
|
11
|
+
# OR generates a new MAC address if none is set.
|
12
|
+
# This is useful to make sure that different virtual machines
|
13
|
+
# have different MAC addresses.
|
14
|
+
class MatchMACAddress
|
15
|
+
def initialize(app, _env)
|
16
|
+
@app = app
|
17
|
+
end
|
18
|
+
|
19
|
+
def call(env) # rubocop:disable Metrics/AbcSize
|
20
|
+
base_mac = env[:machine].config.vm.base_mac
|
21
|
+
# If we have a base MAC address and not is empty (empty in some default Vagranfile)
|
22
|
+
# then we use that to match
|
23
|
+
if base_mac && !base_mac.empty?
|
24
|
+
# Create the proc which we want to use to modify the virtual machine
|
25
|
+
env[:ui].info I18n.t("vagrant.actions.vm.match_mac.matching")
|
26
|
+
env[:machine].provider.driver.set_mac_address(env[:machine].config.vm.base_mac)
|
27
|
+
else
|
28
|
+
env[:ui].info I18n.t("vagrant.actions.vm.match_mac.generating")
|
29
|
+
env[:machine].provider.driver.set_mac_address(nil)
|
30
|
+
end
|
31
|
+
|
32
|
+
@app.call(env)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module Utm
|
5
|
+
module Action
|
6
|
+
# This action prepares the NFS settings for the machine.
|
7
|
+
class PrepareNFSSettings
|
8
|
+
include Vagrant::Action::Builtin::MixinSyncedFolders
|
9
|
+
include Vagrant::Util::Retryable
|
10
|
+
|
11
|
+
def initialize(app, _env)
|
12
|
+
@app = app
|
13
|
+
@logger = Log4r::Logger.new("vagrant::action::vm::nfs")
|
14
|
+
end
|
15
|
+
|
16
|
+
def call(env)
|
17
|
+
@machine = env[:machine]
|
18
|
+
|
19
|
+
@app.call(env)
|
20
|
+
|
21
|
+
opts = {
|
22
|
+
cached: !env[:synced_folders_cached].nil?,
|
23
|
+
config: env[:synced_folders_config],
|
24
|
+
disable_usable_check: !env[:test].nil?
|
25
|
+
}
|
26
|
+
folders = synced_folders(env[:machine], **opts)
|
27
|
+
|
28
|
+
return unless folders.key?(:nfs)
|
29
|
+
|
30
|
+
@logger.info("Using NFS, preparing NFS settings by reading host IP and machine IP")
|
31
|
+
add_ips_to_env!(env)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Extracts the proper host and guest IPs for NFS mounts and stores them
|
35
|
+
# in the environment for the SyncedFolder action to use them in
|
36
|
+
# mounting.
|
37
|
+
#
|
38
|
+
# The ! indicates that this method modifies its argument.
|
39
|
+
def add_ips_to_env!(env)
|
40
|
+
# Hardcoded IP for the host IP
|
41
|
+
host_ip = "10.0.2.2"
|
42
|
+
machine_ip = read_dynamic_machine_ip
|
43
|
+
|
44
|
+
raise Vagrant::Errors::NFSNoHostonlyNetwork if !host_ip || !machine_ip
|
45
|
+
|
46
|
+
env[:nfs_host_ip] = host_ip
|
47
|
+
env[:nfs_machine_ip] = machine_ip
|
48
|
+
end
|
49
|
+
|
50
|
+
# Returns the IP address of the guest by looking at utm guest additions
|
51
|
+
# for the appropriate guest adapter.
|
52
|
+
#
|
53
|
+
# For DHCP interfaces, the guest property will not be present until the
|
54
|
+
# guest completes
|
55
|
+
#
|
56
|
+
# @param [Integer] adapter number to read IP for
|
57
|
+
# @return [String] ip address of adapter
|
58
|
+
def read_dynamic_machine_ip
|
59
|
+
# we need to wait for the guest's IP to show up as a guest property.
|
60
|
+
# retry thresholds are relatively high since we might need to wait
|
61
|
+
# for DHCP, but even static IPs can take a second or two to appear.
|
62
|
+
retryable(retry_options.merge(on: Vagrant::Errors::VirtualBoxGuestPropertyNotFound)) do
|
63
|
+
# Read the IP address from the list given by qemu-guest-agent
|
64
|
+
@machine.provider.driver.read_guest_ip[0]
|
65
|
+
end
|
66
|
+
rescue Vagrant::Errors::VirtualBoxGuestPropertyNotFound
|
67
|
+
# this error is more specific with a better error message directing
|
68
|
+
# the user towards the fact that it's probably a reportable bug
|
69
|
+
raise Vagrant::Errors::NFSNoGuestIP
|
70
|
+
end
|
71
|
+
|
72
|
+
# Separating these out so we can stub out the sleep in tests
|
73
|
+
def retry_options
|
74
|
+
{ tries: 15, sleep: 1 }
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) HashiCorp, Inc.
|
4
|
+
# SPDX-License-Identifier: BUSL-1.1
|
5
|
+
|
6
|
+
module VagrantPlugins
|
7
|
+
module Utm
|
8
|
+
module Action
|
9
|
+
# This action prepares the NFS valid IDs for the VMs.
|
10
|
+
# The ids that are valid and should not be pruned by NFS
|
11
|
+
class PrepareNFSValidIds
|
12
|
+
def initialize(app, _env)
|
13
|
+
@app = app
|
14
|
+
@logger = Log4r::Logger.new("vagrant::action::vm::nfs")
|
15
|
+
end
|
16
|
+
|
17
|
+
def call(env)
|
18
|
+
env[:nfs_valid_ids] = env[:machine].provider.driver.read_vms.keys
|
19
|
+
@app.call(env)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/vagrant_utm/action.rb
CHANGED
@@ -25,9 +25,11 @@ module VagrantPlugins
|
|
25
25
|
autoload :ForcedHalt, action_root.join("forced_halt")
|
26
26
|
autoload :ForwardPorts, action_root.join("forward_ports")
|
27
27
|
autoload :Import, action_root.join("import")
|
28
|
+
autoload :IpAddress, action_root.join("ip_address")
|
28
29
|
autoload :IsPaused, action_root.join("is_paused")
|
29
30
|
autoload :IsRunning, action_root.join("is_running")
|
30
31
|
autoload :IsStopped, action_root.join("is_stopped")
|
32
|
+
autoload :MatchMACAddress, action_root.join("match_mac_address")
|
31
33
|
autoload :MessageAlreadyRunning, action_root.join("message_already_running")
|
32
34
|
autoload :MessageNotCreated, action_root.join("message_not_created")
|
33
35
|
autoload :MessageNotRunning, action_root.join("message_not_running")
|
@@ -38,6 +40,8 @@ module VagrantPlugins
|
|
38
40
|
autoload :PackageSetupFiles, action_root.join("package_setup_files")
|
39
41
|
autoload :PackageSetupFolders, action_root.join("package_setup_folders")
|
40
42
|
autoload :PackageVagrantfile, action_root.join("package_vagrantfile")
|
43
|
+
autoload :PrepareNFSSettings, action_root.join("prepare_nfs_settings")
|
44
|
+
autoload :PrepareNFSValidIds, action_root.join("prepare_nfs_valid_ids")
|
41
45
|
autoload :PrepareForwardedPortCollisionParams, action_root.join("prepare_forwarded_port_collision_params")
|
42
46
|
autoload :Resume, action_root.join("resume")
|
43
47
|
autoload :SetId, action_root.join("set_id")
|
@@ -64,6 +68,10 @@ module VagrantPlugins
|
|
64
68
|
b.use EnvSet, port_collision_repair: true
|
65
69
|
b.use PrepareForwardedPortCollisionParams
|
66
70
|
b.use HandleForwardedPortCollisions
|
71
|
+
b.use PrepareNFSValidIds
|
72
|
+
b.use SyncedFolderCleanup
|
73
|
+
b.use SyncedFolders
|
74
|
+
b.use PrepareNFSSettings
|
67
75
|
b.use ForwardPorts
|
68
76
|
b.use SetHostname
|
69
77
|
b.use Customize, "pre-boot"
|
@@ -88,7 +96,7 @@ module VagrantPlugins
|
|
88
96
|
# This is the action that is primarily responsible for completely
|
89
97
|
# freeing the resources of the underlying virtual machine.
|
90
98
|
# UTM equivalent of `utmctl delete <uuid>`
|
91
|
-
def self.action_destroy
|
99
|
+
def self.action_destroy # rubocop:disable Metrics/AbcSize
|
92
100
|
Vagrant::Action::Builder.new.tap do |b|
|
93
101
|
b.use CheckUtm
|
94
102
|
b.use Call, Created do |env1, b2|
|
@@ -104,6 +112,8 @@ module VagrantPlugins
|
|
104
112
|
b3.use CheckAccessible
|
105
113
|
b3.use action_halt
|
106
114
|
b3.use Destroy
|
115
|
+
b3.use PrepareNFSValidIds
|
116
|
+
b3.use SyncedFolderCleanup
|
107
117
|
else
|
108
118
|
b3.use MessageWillNotDestroy
|
109
119
|
end
|
@@ -140,8 +150,25 @@ module VagrantPlugins
|
|
140
150
|
end
|
141
151
|
end
|
142
152
|
|
153
|
+
# This action returns ip address of the machine.
|
154
|
+
# UTM equivalent of `utmctl ip-address <uuid>`
|
155
|
+
def self.action_ip_address
|
156
|
+
Vagrant::Action::Builder.new.tap do |b|
|
157
|
+
b.use CheckUtm
|
158
|
+
b.use ConfigValidate
|
159
|
+
b.use Call, IsRunning do |env1, b2|
|
160
|
+
unless env1[:result]
|
161
|
+
b2.use MessageNotRunning
|
162
|
+
next
|
163
|
+
end
|
164
|
+
# If the VM is running, then get the IP address.
|
165
|
+
b2.use IpAddress
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
143
170
|
# This action packages the virtual machine into a single box file.
|
144
|
-
def self.action_package
|
171
|
+
def self.action_package # rubocop:disable Metrics/AbcSize
|
145
172
|
Vagrant::Action::Builder.new.tap do |b|
|
146
173
|
b.use CheckUtm
|
147
174
|
b.use Call, Created do |env, b2|
|
@@ -155,6 +182,8 @@ module VagrantPlugins
|
|
155
182
|
b2.use CheckAccessible
|
156
183
|
b2.use action_halt
|
157
184
|
b2.use ClearForwardedPorts
|
185
|
+
b2.use PrepareNFSValidIds
|
186
|
+
b2.use SyncedFolderCleanup
|
158
187
|
b2.use Package
|
159
188
|
b2.use Export
|
160
189
|
b2.use PackageVagrantfile
|
@@ -351,12 +380,14 @@ module VagrantPlugins
|
|
351
380
|
end
|
352
381
|
end
|
353
382
|
|
354
|
-
# This action
|
383
|
+
# This action starts VM in disposable mode.
|
355
384
|
# UTM equivalent of `utmctl start <uuid> --disposable`
|
356
385
|
def self.action_start_disposable
|
357
386
|
Vagrant::Action::Builder.new.tap do |b|
|
358
387
|
b.use CheckUtm
|
359
388
|
b.use ConfigValidate
|
389
|
+
b.use CheckCreated
|
390
|
+
|
360
391
|
b.use Call, IsRunning do |env1, b2|
|
361
392
|
if env1[:result]
|
362
393
|
b2.use MessageAlreadyRunning
|
@@ -384,6 +415,16 @@ module VagrantPlugins
|
|
384
415
|
end
|
385
416
|
end
|
386
417
|
|
418
|
+
# This is the action that is called to sync folders to a running
|
419
|
+
# machine without a reboot.
|
420
|
+
def self.action_sync_folders
|
421
|
+
Vagrant::Action::Builder.new.tap do |b|
|
422
|
+
b.use PrepareNFSValidIds
|
423
|
+
b.use SyncedFolders
|
424
|
+
b.use PrepareNFSSettings
|
425
|
+
end
|
426
|
+
end
|
427
|
+
|
387
428
|
# This action brings the machine up from nothing, including importing
|
388
429
|
# the box, configuring metadata, and booting.
|
389
430
|
def self.action_up
|
@@ -405,6 +446,7 @@ module VagrantPlugins
|
|
405
446
|
b2.use Customize, "pre-import"
|
406
447
|
|
407
448
|
b2.use Import
|
449
|
+
b2.use MatchMACAddress
|
408
450
|
end
|
409
451
|
end
|
410
452
|
|
@@ -0,0 +1,29 @@
|
|
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 CommandDisposable < Vagrant.plugin(2, :command)
|
7
|
+
def self.synopsis
|
8
|
+
"UTM: boots machine in UTM disposable mode"
|
9
|
+
end
|
10
|
+
|
11
|
+
def execute
|
12
|
+
opts = OptionParser.new do |o|
|
13
|
+
o.banner = "Usage: vagrant disposable [name|id]"
|
14
|
+
end
|
15
|
+
|
16
|
+
# Parse the options
|
17
|
+
argv = parse_options(opts)
|
18
|
+
return unless argv
|
19
|
+
|
20
|
+
with_target_vms do |machine|
|
21
|
+
machine.action(:start_disposable)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Success, exit status 0
|
25
|
+
0
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module Utm
|
5
|
+
# Get All IP Adress of a machine.
|
6
|
+
class CommandIpAddress < Vagrant.plugin(2, :command)
|
7
|
+
def self.synopsis
|
8
|
+
"UTM: outputs ip address of the vagrant machine"
|
9
|
+
end
|
10
|
+
|
11
|
+
def execute
|
12
|
+
opts = OptionParser.new do |o|
|
13
|
+
o.banner = "Usage: vagrant ip-address [name|id]"
|
14
|
+
end
|
15
|
+
|
16
|
+
# Parse the options
|
17
|
+
argv = parse_options(opts)
|
18
|
+
return unless argv
|
19
|
+
|
20
|
+
with_target_vms do |machine|
|
21
|
+
machine.action(:ip_address)
|
22
|
+
end
|
23
|
+
|
24
|
+
0
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -86,9 +86,16 @@ module VagrantPlugins
|
|
86
86
|
# @return [Array]
|
87
87
|
def read_used_ports(active_only: true); end
|
88
88
|
|
89
|
-
# Returns
|
89
|
+
# Returns a list of all UUIDs of virtual machines currently
|
90
|
+
# known by UTM.
|
90
91
|
#
|
91
|
-
# @return [String]
|
92
|
+
# @return [Array<String>]
|
93
|
+
def read_vms; end
|
94
|
+
|
95
|
+
# Returns the IP addresses of the guest machine.
|
96
|
+
# Only supported for VMs with qemu-guest-agent installed.
|
97
|
+
#
|
98
|
+
# @return [Array<String>] The IP addresses of the guest machine.
|
92
99
|
def read_guest_ip; end
|
93
100
|
|
94
101
|
# Returns a list of network interfaces of the VM.
|
@@ -96,6 +103,11 @@ module VagrantPlugins
|
|
96
103
|
# @return [Hash]
|
97
104
|
def read_network_interfaces; end
|
98
105
|
|
106
|
+
# Sets the MAC address of the first network adapter.
|
107
|
+
#
|
108
|
+
# @param [String] mac MAC address without any spaces/hyphens.
|
109
|
+
def set_mac_address(mac); end # rubocop:disable Naming/AccessorMethodName
|
110
|
+
|
99
111
|
# Execute the 'list' command and returns the list of machines.
|
100
112
|
# @return [ListResult] The list of machines.
|
101
113
|
def list; end
|
@@ -142,6 +154,21 @@ module VagrantPlugins
|
|
142
154
|
# This should raise a VagrantError if things are not ready.
|
143
155
|
def verify!; end
|
144
156
|
|
157
|
+
# Generate a random MAC address.
|
158
|
+
#
|
159
|
+
# This method generates a random MAC address because it is difficult
|
160
|
+
# to get UTM to generate one through scripting.
|
161
|
+
#
|
162
|
+
# @return [String] The MAC address.
|
163
|
+
def random_mac_address
|
164
|
+
# Generate 6 random bytes
|
165
|
+
bytes = Array.new(6) { rand(256) }
|
166
|
+
# Ensure the first byte is local
|
167
|
+
bytes[0] = (bytes[0] & 0xFC) | 0x02
|
168
|
+
# Convert bytes to MAC address string
|
169
|
+
bytes.map { |byte| format("%02X", byte) }.join(":")
|
170
|
+
end
|
171
|
+
|
145
172
|
# Execute a script using the OSA interface.
|
146
173
|
def execute_osa_script(command); end
|
147
174
|
|
@@ -55,13 +55,12 @@ module VagrantPlugins
|
|
55
55
|
# Instantiate the proper version driver for UTM
|
56
56
|
@logger.debug("Finding driver for UTM version: #{@version}")
|
57
57
|
driver_map = {
|
58
|
-
"4.5" => Version_4_5,
|
59
58
|
"4.6" => Version_4_6
|
60
59
|
}
|
61
60
|
|
62
|
-
# UTM 4.
|
61
|
+
# UTM 4.6.0 doesn't have import support to work with Vagrant box,
|
63
62
|
# so show error
|
64
|
-
raise Errors::UtmInvalidVersion if @version.start_with?("4.
|
63
|
+
raise Errors::UtmInvalidVersion if @version.start_with?("4.6.0")
|
65
64
|
|
66
65
|
driver_klass = nil
|
67
66
|
driver_map.each do |key, klass|
|
@@ -105,7 +104,9 @@ module VagrantPlugins
|
|
105
104
|
:read_network_interfaces,
|
106
105
|
:read_state,
|
107
106
|
:read_used_ports,
|
107
|
+
:read_vms,
|
108
108
|
:restore_snapshot,
|
109
|
+
:set_mac_address,
|
109
110
|
:set_name,
|
110
111
|
:ssh_port,
|
111
112
|
:start,
|
@@ -174,9 +174,8 @@ module VagrantPlugins
|
|
174
174
|
end
|
175
175
|
|
176
176
|
def read_guest_ip
|
177
|
-
|
178
|
-
output
|
179
|
-
output.strip
|
177
|
+
output = execute("ip-address", @uuid)
|
178
|
+
output.strip.split("\n")
|
180
179
|
end
|
181
180
|
|
182
181
|
def read_network_interfaces
|
@@ -195,6 +194,14 @@ module VagrantPlugins
|
|
195
194
|
nics
|
196
195
|
end
|
197
196
|
|
197
|
+
def set_mac_address(mac) # rubocop:disable Naming/AccessorMethodName
|
198
|
+
# Set the MAC address of the first NIC (index 0)
|
199
|
+
# Set MAC address to given value or randomize it if nil
|
200
|
+
mac = random_mac_address if mac.nil?
|
201
|
+
command = ["set_mac_address.applescript", @uuid, "0", mac]
|
202
|
+
execute_osa_script(command)
|
203
|
+
end
|
204
|
+
|
198
205
|
def ssh_port(expected_port)
|
199
206
|
@logger.debug("Searching for SSH port: #{expected_port.inspect}")
|
200
207
|
|
@@ -232,6 +239,16 @@ module VagrantPlugins
|
|
232
239
|
ports
|
233
240
|
end
|
234
241
|
|
242
|
+
def read_vms
|
243
|
+
results = {}
|
244
|
+
list.machines.each do |machine|
|
245
|
+
# Store UUID (Unique) as key and name as value
|
246
|
+
results[machine.uuid] = machine.name
|
247
|
+
end
|
248
|
+
|
249
|
+
results
|
250
|
+
end
|
251
|
+
|
235
252
|
def set_name(name) # rubocop:disable Naming/AccessorMethodName
|
236
253
|
command = ["customize_vm.applescript", @uuid, "--name", name.to_s]
|
237
254
|
execute_osa_script(command)
|
@@ -57,7 +57,9 @@ module VagrantPlugins
|
|
57
57
|
options ||= {}
|
58
58
|
@auto_correct = false
|
59
59
|
@auto_correct = options[:auto_correct] if options.key?(:auto_correct)
|
60
|
-
|
60
|
+
# if adapter is not set, use index 1 (Emulated VLAN).
|
61
|
+
# index 0 is the default adapter (Shared Network)
|
62
|
+
@adapter = (options[:adapter] || 1).to_i
|
61
63
|
@guest_ip = options[:guest_ip] || nil
|
62
64
|
@host_ip = options[:host_ip] || nil
|
63
65
|
@protocol = options[:protocol] || "tcp" # default to TCP
|
data/lib/vagrant_utm/plugin.rb
CHANGED
@@ -21,12 +21,7 @@ module VagrantPlugins
|
|
21
21
|
DESCRIPTION
|
22
22
|
|
23
23
|
# Register the provider
|
24
|
-
|
25
|
-
# IDEA: UTM file comes as a zip file containing
|
26
|
-
# directory with Data/qcow2, Data/efi_vars.fd and config.plist
|
27
|
-
# Box format will only require additional metadata.json file
|
28
|
-
# Till then use UTM file directly and so box_optional: true
|
29
|
-
provider(:utm, box_optional: true, parallel: false) do
|
24
|
+
provider(:utm, box_optional: false, parallel: false) do
|
30
25
|
setup_i18n
|
31
26
|
require_relative "provider"
|
32
27
|
Provider
|
@@ -50,9 +45,17 @@ module VagrantPlugins
|
|
50
45
|
end
|
51
46
|
|
52
47
|
# Register the command
|
48
|
+
## Start machine as a snapshot and do not save changes to disk
|
53
49
|
command "disposable" do
|
54
|
-
require_relative "disposable"
|
55
|
-
|
50
|
+
require_relative "commands/disposable"
|
51
|
+
CommandDisposable
|
52
|
+
end
|
53
|
+
|
54
|
+
## Get the IP address of the machine
|
55
|
+
## Only supported if machine as qemu-guest-additions
|
56
|
+
command "ip-address" do
|
57
|
+
require_relative "commands/ip_address"
|
58
|
+
CommandIpAddress
|
56
59
|
end
|
57
60
|
|
58
61
|
# Load the translation files
|
data/lib/vagrant_utm/provider.rb
CHANGED
@@ -94,6 +94,8 @@ module VagrantPlugins
|
|
94
94
|
# If we have multiple network adapters, we need to pick the right one, read_guest_ip returns just first IP
|
95
95
|
# Also, since Vagrant by default adds port forwarding for ssh port 22,
|
96
96
|
# we might aswell use the forwarded ports to connect to the VM using the localhost.
|
97
|
+
# and the forwarded port.
|
98
|
+
# So we use 127.0.0.1 and the forwarded port to connect to the VM.
|
97
99
|
{
|
98
100
|
host: "127.0.0.1",
|
99
101
|
port: @driver.ssh_port(@machine.config.ssh.guest_port)
|
@@ -124,7 +126,6 @@ module VagrantPlugins
|
|
124
126
|
Vagrant::MachineState.new(state_id, short, long)
|
125
127
|
end
|
126
128
|
|
127
|
-
# TODO: Get UUID of the VM from UTM
|
128
129
|
# Returns a human-friendly string version of this provider which
|
129
130
|
# includes the machine's ID that this provider represents, if it
|
130
131
|
# has one.
|
@@ -5,7 +5,8 @@ on run argv
|
|
5
5
|
set config to configuration of vm
|
6
6
|
set networkInterfaces to network interfaces of config
|
7
7
|
repeat with anInterface in networkInterfaces
|
8
|
-
# if you start log with variable you'll get "," at the end of the log
|
8
|
+
# if you start log with variable you'll get "," at the end of the log so '&' is used to concatenate
|
9
|
+
# Example output: nic0,shared
|
9
10
|
log "nic" & index of anInterface & "," & mode of anInterface
|
10
11
|
end repeat
|
11
12
|
end tell
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# This script sets the MAC address of a network interface in a specified UTM virtual machine.
|
2
|
+
# Usage: osascript set_mac_address.applescript <VM_UUID> <NIC_INDEX> <MAC_ADDRESS>
|
3
|
+
# Example: osascript set_mac_address.applescript A123 1 XX:XX:XX:XX:XX:XX
|
4
|
+
on run argv
|
5
|
+
set vmID to item 1 of argv
|
6
|
+
set nicIndex to item 2 of argv
|
7
|
+
set macAddress to item 3 of argv
|
8
|
+
|
9
|
+
tell application "UTM"
|
10
|
+
set vm to virtual machine id vmID
|
11
|
+
set config to configuration of vm
|
12
|
+
set networkInterfaces to network interfaces of config
|
13
|
+
|
14
|
+
repeat with anInterface in networkInterfaces
|
15
|
+
if nicIndex as integer is index of anInterface then
|
16
|
+
-- Set the provided MAC address
|
17
|
+
set address of anInterface to macAddress
|
18
|
+
end if
|
19
|
+
end repeat
|
20
|
+
|
21
|
+
-- Update the VM configuration
|
22
|
+
update configuration of vm with config
|
23
|
+
end tell
|
24
|
+
|
25
|
+
end run
|
data/lib/vagrant_utm/version.rb
CHANGED
data/locales/en.yml
CHANGED
@@ -149,7 +149,15 @@ en:
|
|
149
149
|
WARNING: The UTM virtual machine is booting in disposable mode.
|
150
150
|
Changes made to the VM will be lost when the VM is powered off.
|
151
151
|
Learn more at https://docs.getutm.app/advanced/disposable/
|
152
|
+
ip_address:
|
153
|
+
reading: |-
|
154
|
+
Getting IP address of UTM virtual machine...
|
155
|
+
show: |-
|
156
|
+
Guest IP address(es):
|
157
|
+
not_found: |-
|
158
|
+
IP address not found. The VM may not have guest tools or may not have an IP address.
|
152
159
|
snapshot:
|
153
160
|
list: |-
|
154
161
|
Listing snapshots for UTM virtual machine...
|
162
|
+
|
155
163
|
|
data/notes/README.md
CHANGED
@@ -19,4 +19,19 @@ bundle exec jekyll serve
|
|
19
19
|
To release
|
20
20
|
|
21
21
|
To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`
|
22
|
-
GitHub action upon tag push with "v*" will publish gem to GHR and rubygems
|
22
|
+
GitHub action upon tag push with "v*" will publish gem to GHR and rubygems
|
23
|
+
|
24
|
+
1. Update
|
25
|
+
CHANGELOG.md
|
26
|
+
version number in `version.rb`
|
27
|
+
version number Gemlock file
|
28
|
+
2. Commit
|
29
|
+
3. Run `bundle exec rake release` (Commit and tags are pushed)
|
30
|
+
4. Cancel push to rubygems.org
|
31
|
+
|
32
|
+
GHA will publish gems to GHR and rubygems
|
33
|
+
|
34
|
+
|
35
|
+
To update specific gems in the project
|
36
|
+
|
37
|
+
`bundle update rubocop`
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vagrant_utm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2.beta
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Naveenraj M
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-12-05 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Vagrant UTM provider that allows you to manage UTM virtual machines.
|
14
14
|
email:
|
@@ -68,9 +68,11 @@ files:
|
|
68
68
|
- lib/vagrant_utm/action/forced_halt.rb
|
69
69
|
- lib/vagrant_utm/action/forward_ports.rb
|
70
70
|
- lib/vagrant_utm/action/import.rb
|
71
|
+
- lib/vagrant_utm/action/ip_address.rb
|
71
72
|
- lib/vagrant_utm/action/is_paused.rb
|
72
73
|
- lib/vagrant_utm/action/is_running.rb
|
73
74
|
- lib/vagrant_utm/action/is_stopped.rb
|
75
|
+
- lib/vagrant_utm/action/match_mac_address.rb
|
74
76
|
- lib/vagrant_utm/action/message_already_running.rb
|
75
77
|
- lib/vagrant_utm/action/message_not_created.rb
|
76
78
|
- lib/vagrant_utm/action/message_not_running.rb
|
@@ -82,6 +84,8 @@ files:
|
|
82
84
|
- lib/vagrant_utm/action/package_setup_folders.rb
|
83
85
|
- lib/vagrant_utm/action/package_vagrantfile.rb
|
84
86
|
- lib/vagrant_utm/action/prepare_forwarded_port_collision_params.rb
|
87
|
+
- lib/vagrant_utm/action/prepare_nfs_settings.rb
|
88
|
+
- lib/vagrant_utm/action/prepare_nfs_valid_ids.rb
|
85
89
|
- lib/vagrant_utm/action/resume.rb
|
86
90
|
- lib/vagrant_utm/action/set_id.rb
|
87
91
|
- lib/vagrant_utm/action/set_name.rb
|
@@ -91,8 +95,9 @@ files:
|
|
91
95
|
- lib/vagrant_utm/action/suspend.rb
|
92
96
|
- lib/vagrant_utm/action/wait_for_running.rb
|
93
97
|
- lib/vagrant_utm/cap.rb
|
98
|
+
- lib/vagrant_utm/commands/disposable.rb
|
99
|
+
- lib/vagrant_utm/commands/ip_address.rb
|
94
100
|
- lib/vagrant_utm/config.rb
|
95
|
-
- lib/vagrant_utm/disposable.rb
|
96
101
|
- lib/vagrant_utm/driver/base.rb
|
97
102
|
- lib/vagrant_utm/driver/meta.rb
|
98
103
|
- lib/vagrant_utm/driver/version_4_5.rb
|
@@ -111,8 +116,8 @@ files:
|
|
111
116
|
- lib/vagrant_utm/scripts/list_vm.js
|
112
117
|
- lib/vagrant_utm/scripts/open_with_utm.js
|
113
118
|
- lib/vagrant_utm/scripts/read_forwarded_ports.applescript
|
114
|
-
- lib/vagrant_utm/scripts/read_guest_ip.applescript
|
115
119
|
- lib/vagrant_utm/scripts/read_network_interfaces.applescript
|
120
|
+
- lib/vagrant_utm/scripts/set_mac_address.applescript
|
116
121
|
- lib/vagrant_utm/util/compile_forwarded_ports.rb
|
117
122
|
- lib/vagrant_utm/version.rb
|
118
123
|
- locales/en.yml
|
@@ -1,16 +0,0 @@
|
|
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
|