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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c22d83ed499aea91dd64bc9cdfa9f161a690e510e1e8c28fa9d912a2a0478606
4
- data.tar.gz: c4f0be1c3eefa6d8412e60d7f193e00426462a34b90e34016539a75b34195da1
3
+ metadata.gz: 4afb59e8282747e3cca61c9ed2b297b7084606c268cc4e6231856f12fb2510b0
4
+ data.tar.gz: 1a4ba9a73219106a661fdddad221d14128d203fc8c273dc22fa3018d72b25e0b
5
5
  SHA512:
6
- metadata.gz: 4539bf98ad765bb41946fc1b825e24161ad05e1e56b0b63416521c17c60ec182a78b6a5b6115fc8eea75879ba863c04468fe9881bd7996e928902fe7150198f1
7
- data.tar.gz: 430329351ee74c943093194d6d64ce3e230bc8677153337e0f342a3f5c448f4b76bb390d51c6fe817f7cd09d1197185421bd7a97027b9f2869efff04cdada695
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
- - Initial release
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 second network interface (adapter 1 or index 1) must be a `Emulated VLAN` adapter. Vagrant uses this to connect the first time.
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
@@ -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 start VM in disposable mode.
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 the IP address of the guest machine.
89
+ # Returns a list of all UUIDs of virtual machines currently
90
+ # known by UTM.
90
91
  #
91
- # @return [String] The IP address of the guest machine.
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.5.0 just doesn't work with Vagrant (https://github.com/utmapp/UTM/issues/5963),
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.5.0")
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
- command = ["read_guest_ip.applescript", @uuid]
178
- output = execute_osa_script(command)
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
- @adapter = (options[:adapter] || 1).to_i # if adapter is not set, use 1. index 0 is the default adapter
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
@@ -21,12 +21,7 @@ module VagrantPlugins
21
21
  DESCRIPTION
22
22
 
23
23
  # Register the provider
24
- # TODO: Define box format for UTM
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
- Disposable
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
@@ -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 if '&' is used to concatenate
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
@@ -4,6 +4,6 @@ module VagrantPlugins
4
4
  # Top level module for the Utm provider plugin.
5
5
  module Utm
6
6
  # Current version of the Utm provider plugin.
7
- VERSION = "0.1.0"
7
+ VERSION = "0.1.2.beta"
8
8
  end
9
9
  end
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.0
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-30 00:00:00.000000000 Z
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
@@ -1,9 +0,0 @@
1
- on run argv
2
- set vmID to item 1 of argv
3
- tell application "UTM"
4
- set vm to virtual machine id vmID
5
- --- get IP address (QEMU Guest Agent must be installed) of first interface
6
- get item 1 of (query ip of vm) -- Result: "192.168.64.9"
7
- end tell
8
- end run
9
-