vagrant_utm 0.1.2.beta → 0.1.3
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 +14 -0
- data/README.md +1 -1
- data/docs/Gemfile.lock +2 -2
- data/docs/_config.yml +2 -2
- data/docs/boxes/creating_utm_box.md +7 -6
- data/docs/boxes/utm_box_gallery.md +10 -5
- data/docs/features/synced_folders.md +11 -11
- data/docs/index.md +7 -7
- data/docs/internals/actions.md +2 -1
- data/docs/known_issues.md +2 -2
- data/lib/vagrant_utm/cap/mount_options.rb +55 -0
- data/lib/vagrant_utm/config.rb +26 -6
- data/lib/vagrant_utm/driver/meta.rb +10 -3
- data/lib/vagrant_utm/driver/version_4_6.rb +67 -0
- data/lib/vagrant_utm/plugin.rb +21 -0
- data/lib/vagrant_utm/scripts/add_folder_share.applescript +96 -0
- data/lib/vagrant_utm/scripts/add_qemu_additional_args.applescript +43 -0
- data/lib/vagrant_utm/scripts/read_shared_folders.js +47 -0
- data/lib/vagrant_utm/scripts/read_shared_folders_args.js +53 -0
- data/lib/vagrant_utm/scripts/remove_qemu_additional_args.applescript +46 -0
- data/lib/vagrant_utm/synced_folder.rb +127 -0
- data/lib/vagrant_utm/util/unix_mount_helpers.rb +124 -0
- data/lib/vagrant_utm/version.rb +1 -1
- data/notes/README.md +14 -1
- metadata +13 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bc0499e6b39496b2bd9590d3683631bcc213f7b0f4f1a5fc259b9373e160da33
|
4
|
+
data.tar.gz: 36b2a3029c3d8ddb9d4e84865f657a989732495f59adf90e4f2eb19731780ae0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: adf69f5cc2fbb3d73e5453b761d374dfd29aded42d1581927a1bbfea2405a93817c11e4a79de57d1c144b6acd120e4d21dceb9140c38083436605f2f2f4a2889
|
7
|
+
data.tar.gz: c305e4949e66c6643646025c649dba12093e228dbbe298b0aada54be0974fa526bfdded85afbcf2b0c062d1982100f601bb77d290784b9d4b57e8fc4173644cf
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,20 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
3
|
|
4
|
+
## [0.1.3] - 2025-04-20
|
5
|
+
|
6
|
+
### Added
|
7
|
+
|
8
|
+
- Implements VirtFS synced folder in UTM using qemu additional args and vm registry (for permission)
|
9
|
+
|
10
|
+
### Changed
|
11
|
+
|
12
|
+
- Config: Makes `virtFS` as default directory_share_mode in UTM
|
13
|
+
|
14
|
+
### Removed
|
15
|
+
|
16
|
+
- Driver: Removed support for UTM versions < 4.6.5
|
17
|
+
|
4
18
|
## [0.1.2.beta] - 2024-12-05
|
5
19
|
|
6
20
|
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`
|
data/README.md
CHANGED
data/docs/Gemfile.lock
CHANGED
data/docs/_config.yml
CHANGED
@@ -28,8 +28,8 @@ nav_external_links:
|
|
28
28
|
url: https://mac.getutm.app
|
29
29
|
- title: Packer plugin for UTM
|
30
30
|
url: https://github.com/naveenrajm7/packer-plugin-utm
|
31
|
-
|
32
|
-
|
31
|
+
- title: UTM Gallery
|
32
|
+
url: https://naveenrajm7.github.io/utm-gallery/
|
33
33
|
|
34
34
|
|
35
35
|
# Aux links for the upper right navigation
|
@@ -60,17 +60,18 @@ Check the [UTM Guide on Guest Support](https://docs.getutm.app/guest-support/gue
|
|
60
60
|
|
61
61
|
By satisfying the [general guidance on creating vagrant boxes](https://developer.hashicorp.com/vagrant/docs/boxes/base) and the above [Virtual Machine](#virtual-machine) requirements you can use your VM with Vagrant UTM plugin.
|
62
62
|
|
63
|
-
Apart from manually building the boxes, you can also use the
|
63
|
+
Apart from manually building the boxes, you can also use the automated (almost) way of building these boxes using [packer plugin for UTM](https://github.com/naveenrajm7/packer-plugin-utm).
|
64
64
|
The packer plugin has the following components:
|
65
65
|
1. Builder
|
66
|
-
|
67
|
-
|
66
|
+
1. UTM - Use existing utm file
|
67
|
+
2. ISO - Start from scratch using ISO files
|
68
|
+
3. CLOUD - Use existing qcow2 cloud images
|
68
69
|
2. Post-processor
|
69
|
-
|
70
|
-
|
70
|
+
1. ZIP - Package UTM VM into zip file
|
71
|
+
2. Vagrant - Package UTM VM into vagrant box.
|
71
72
|
|
72
73
|
|
73
|
-
Checkout [UTM Box
|
74
|
+
Checkout [UTM Box Packer recipe](https://github.com/naveenrajm7/utm-box?tab=readme-ov-file#building-boxes) to know how to build Box using packer.
|
74
75
|
|
75
76
|
## Using your own UTM VMs
|
76
77
|
|
@@ -10,22 +10,27 @@ nav_order: 1
|
|
10
10
|
To work with Vagrant, a base VM (box) must have
|
11
11
|
[certain features](https://developer.hashicorp.com/vagrant/docs/boxes/base), like an ssh user for vagrant to connect.
|
12
12
|
|
13
|
-
To help you get started with Vagrant UTM provider,
|
13
|
+
To help you get started with Vagrant UTM provider, some pre-built VMs that work with Vagrant are published in [HCP Vagrant registry](https://portal.cloud.hashicorp.com/vagrant/discover/utm).
|
14
14
|
|
15
15
|
{: .important}
|
16
|
-
All the VMs provided are built from
|
16
|
+
All the VMs provided are built from Cloud Images or ISO files in an (semi) automated way using [packer plugin for UTM][packer plugin for UTM]. Please see the [UTM Box Guide][UTM Box Guide] on how these UTM Vagrant boxes were built using packer.
|
17
17
|
|
18
|
-
* Debian
|
18
|
+
* Debian 12 - Built from cloud image:
|
19
|
+
```ruby
|
20
|
+
config.vm.box = "utm/bookworm"
|
21
|
+
```
|
22
|
+
|
23
|
+
* Debian 11 (Xfce) - Built from UTM file of UTM gallery:
|
19
24
|
```ruby
|
20
25
|
config.vm.box = "utm/debian11"
|
21
26
|
```
|
22
27
|
|
23
|
-
* Ubuntu 24.04 :
|
28
|
+
* Ubuntu 24.04 - Built from ISO:
|
24
29
|
```ruby
|
25
30
|
config.vm.box = "utm/ubuntu-24.04"
|
26
31
|
```
|
27
32
|
|
28
|
-
*
|
33
|
+
* Build your own boxes using [packer plugin for UTM][packer plugin for UTM]
|
29
34
|
<!-- * ArchLinux ARM -->
|
30
35
|
|
31
36
|
|
@@ -7,22 +7,22 @@ nav_order: 1
|
|
7
7
|
|
8
8
|
# Synced Folders
|
9
9
|
|
10
|
-
UTM Vagrant plugin
|
11
|
-
The plugin
|
12
|
-
After which the the host directory can be selected from UTM UI, and the guest directory can be mounted in guest OS. Both of these steps are now manual until UTM exposes API to configure Host/Guest directory.
|
10
|
+
UTM Vagrant plugin has support for syncing multiple folders between host and guest machine.
|
11
|
+
The plugin implements [UTM QEMU VirtFS](https://docs.getutm.app/guest-support/linux/#virtfs) as the default synced folder implementation for UTM provider.
|
13
12
|
|
14
13
|
```ruby
|
15
14
|
Vagrant.configure("2") do |config|
|
16
|
-
config.vm.box = "utm/
|
17
|
-
config.vm.
|
18
|
-
# QEMU Directoy Share mode for the VM.
|
19
|
-
# Takes none, webDAV or virtFS
|
20
|
-
u.directory_share_mode = "webDAV"
|
21
|
-
end
|
15
|
+
config.vm.box = "utm/bookworm"
|
16
|
+
config.vm.synced_folder "../test", "/vagrant-test"
|
22
17
|
end
|
23
18
|
```
|
24
19
|
|
25
|
-
|
20
|
+
Vagrant by default syncs the current folder where that Vagrantfile is, and you can access them at `/vagrant` in the guest.
|
26
21
|
|
27
22
|
{: .important}
|
28
|
-
|
23
|
+
|
24
|
+
|
25
|
+
## Other Vagrant options
|
26
|
+
|
27
|
+
Apart from the provider specific Sync options, Vagrant has components to provide sync folders feature using NFS and RSync. These features are also supported in UTM plugin.
|
28
|
+
Check all Vagrant provided sync options at [Vagrant synced folders](https://developer.hashicorp.com/vagrant/docs/synced-folders).
|
data/docs/index.md
CHANGED
@@ -19,8 +19,8 @@ allowing Vagrant to control and provision machines via UTM's API.
|
|
19
19
|
---
|
20
20
|
|
21
21
|
{: .new}
|
22
|
-
>
|
23
|
-
>
|
22
|
+
> Plugin now supports [Vagrant boxes](https://developer.hashicorp.com/vagrant/docs/boxes)!, find UTM boxes at [HCP Vagrant registry](https://portal.cloud.hashicorp.com/vagrant/discover/utm)
|
23
|
+
> Plugin now supports multiple synced folders, check out [Synced Folder](features/synced_folders.md)
|
24
24
|
|
25
25
|
[UTM] is a free, full-featured system emulator and virtual machine host for iOS and macOS.
|
26
26
|
The UTM provider currently supports UTM versions
|
@@ -59,14 +59,14 @@ vagrant plugin install vagrant_utm
|
|
59
59
|
Option 1: Create a Vagrantfile and initiate the box (OR)
|
60
60
|
|
61
61
|
```
|
62
|
-
vagrant init utm/
|
62
|
+
vagrant init utm/bookworm
|
63
63
|
```
|
64
64
|
|
65
65
|
Option 2: Open the Vagrantfile and replace the contents with the following
|
66
66
|
|
67
67
|
```ruby
|
68
68
|
Vagrant.configure("2") do |config|
|
69
|
-
config.vm.box = "utm/
|
69
|
+
config.vm.box = "utm/bookworm"
|
70
70
|
end
|
71
71
|
```
|
72
72
|
|
@@ -81,9 +81,9 @@ Now start using your machine!
|
|
81
81
|
|
82
82
|
`vagrant ssh` to log into machine or forward ports to check your website or share folders and start developing.
|
83
83
|
|
84
|
-
Check [Commands](commands.md) for all supported Vagrant commands.
|
85
|
-
Check [Configuration](configuration.md) for more UTM provider config options.
|
86
|
-
|
84
|
+
Check [Commands](commands.md) for all supported Vagrant commands.
|
85
|
+
Check [Configuration](configuration.md) for more UTM provider config options.
|
86
|
+
Discover UTM Vagrant boxes at [HCP Vagrant UTM Registry](https://portal.cloud.hashicorp.com/vagrant/discover/utm), which as boxes of popular OS including OpenBSD!
|
87
87
|
|
88
88
|
## About the project
|
89
89
|
|
data/docs/internals/actions.md
CHANGED
@@ -17,4 +17,5 @@ The Table below maps the vagrant commands to the corresponding UTM commands that
|
|
17
17
|
| `vagrant destroy` | `utmctl delete` |
|
18
18
|
| `vagrant status` | `utmctl status` |
|
19
19
|
| `vagrant disposable` | `utmctl start --disposable` |
|
20
|
-
| `vagrant snapshot` | `qemu-img snapshot` |
|
20
|
+
| `vagrant snapshot` | `qemu-img snapshot` |
|
21
|
+
| `vagrant ip-address` | `utmctl ip-address` |
|
data/docs/known_issues.md
CHANGED
@@ -5,7 +5,7 @@ nav_order: 7
|
|
5
5
|
|
6
6
|
# Known Issues
|
7
7
|
|
8
|
-
This plugin
|
8
|
+
This plugin is built around the existing UTM API.
|
9
9
|
Hence there are things which are not ideal.
|
10
10
|
|
11
11
|
1. ~~vagrant up : Loads new VM by downloading zip file every time, and manually asks the user to confirm the download completion.~~
|
@@ -21,4 +21,4 @@ Draw back - UTM does not expose export API. (UTM already has 'Share')~~
|
|
21
21
|
|
22
22
|
5. vagrant snapshot: Even though UTM does not have snapshot feature, this plugin has a experimental support for offline VM snapshots using qemu-img.
|
23
23
|
The VM must be stopped, for any snapshot commands to work.
|
24
|
-
The snapshot only works for **single** qcow2 based VM images
|
24
|
+
The snapshot only works for **single** qcow2 based VM images
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) HashiCorp, Inc.
|
4
|
+
# SPDX-License-Identifier: BUSL-1.1
|
5
|
+
|
6
|
+
require_relative "../util/unix_mount_helpers"
|
7
|
+
|
8
|
+
module VagrantPlugins
|
9
|
+
module Utm
|
10
|
+
module Cap
|
11
|
+
# Capability for mount options
|
12
|
+
module MountOptions
|
13
|
+
extend VagrantPlugins::SyncedFolder::UnixMountHelpers
|
14
|
+
|
15
|
+
# Mount type for VirtFS
|
16
|
+
UTM_MOUNT_TYPE = "9p"
|
17
|
+
|
18
|
+
# Returns mount options for a utm synced folder
|
19
|
+
#
|
20
|
+
# @param [Machine] machine
|
21
|
+
# @param [String] name of mount
|
22
|
+
# @param [String] path of mount on guest
|
23
|
+
# @param [Hash] hash of mount options
|
24
|
+
def self.mount_options(machine, _name, guest_path, options)
|
25
|
+
mount_options = options.fetch(:mount_options, [])
|
26
|
+
detected_ids = detect_owner_group_ids(machine, guest_path, mount_options, options)
|
27
|
+
mount_uid = detected_ids[:uid]
|
28
|
+
mount_gid = detected_ids[:gid]
|
29
|
+
|
30
|
+
# VirtFS mount options
|
31
|
+
mount_options << "trans=virtio"
|
32
|
+
mount_options << "version=9p2000.L"
|
33
|
+
mount_options << if mount_options.include?("ro")
|
34
|
+
"ro"
|
35
|
+
else
|
36
|
+
"rw"
|
37
|
+
end
|
38
|
+
mount_options << "_netdev"
|
39
|
+
mount_options << "nofail"
|
40
|
+
|
41
|
+
mount_options = mount_options.join(",")
|
42
|
+
[mount_options, mount_uid, mount_gid]
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.mount_type(_machine)
|
46
|
+
UTM_MOUNT_TYPE
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.mount_name(_machine, name, _data)
|
50
|
+
name.gsub(%r{[\s/\\]}, "_").sub(/^_/, "")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/lib/vagrant_utm/config.rb
CHANGED
@@ -7,11 +7,6 @@ module VagrantPlugins
|
|
7
7
|
module Utm
|
8
8
|
# This is the configuration class for the UTM provider.
|
9
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
10
|
# If true, will check if guest additions are installed and up to
|
16
11
|
# date. By default, this is true.
|
17
12
|
#
|
@@ -23,6 +18,19 @@ module VagrantPlugins
|
|
23
18
|
# @return [Array]
|
24
19
|
attr_reader :customizations
|
25
20
|
|
21
|
+
# Whether or not this VM has a functional VirtFS 9P filesystem module
|
22
|
+
# for VirtFS directory sharing to work.
|
23
|
+
# This defaults to true. If you set this to false, then the "utm"
|
24
|
+
# synced folder type won't be valid.
|
25
|
+
#
|
26
|
+
# @return [Boolean]
|
27
|
+
attr_accessor :functional_9pfs
|
28
|
+
|
29
|
+
# This should be set to the name of the machine in the UTM GUI.
|
30
|
+
#
|
31
|
+
# @return [String]
|
32
|
+
attr_accessor :name
|
33
|
+
|
26
34
|
# The time to wait for the VM to be 'running' after 'started'.
|
27
35
|
#
|
28
36
|
# @return [Integer]
|
@@ -33,6 +41,7 @@ module VagrantPlugins
|
|
33
41
|
super
|
34
42
|
@check_guest_additions = UNSET_VALUE
|
35
43
|
@customizations = []
|
44
|
+
@functional_9pfs = UNSET_VALUE
|
36
45
|
@name = UNSET_VALUE
|
37
46
|
@wait_time = UNSET_VALUE
|
38
47
|
end
|
@@ -76,6 +85,8 @@ module VagrantPlugins
|
|
76
85
|
customize("pre-boot", ["customize_vm.applescript", :id, "--notes", notes])
|
77
86
|
end
|
78
87
|
|
88
|
+
# TODO: All warning if user sets directory_share_mode,
|
89
|
+
# because default implementation is 'virtFS'
|
79
90
|
# Shortcut for setting the directory share mode of the virtual machine.
|
80
91
|
# Calls #customize internally.
|
81
92
|
#
|
@@ -101,8 +112,13 @@ module VagrantPlugins
|
|
101
112
|
# This is the hook that is called to finalize the object before it
|
102
113
|
# is put into use.
|
103
114
|
def finalize!
|
115
|
+
# By default, we check for guest additions (qemu-ga)
|
104
116
|
@check_guest_additions = true if @check_guest_additions == UNSET_VALUE
|
105
|
-
|
117
|
+
# Always set the directory share mode to 'virtFS'
|
118
|
+
# default share folder implementation in utm plugin
|
119
|
+
self.directory_share_mode = "virtFS"
|
120
|
+
# By default, we assume the VM supports virtio 9p filesystems
|
121
|
+
@functional_9pfs = true if @functional_9pfs == UNSET_VALUE
|
106
122
|
# The default name is just nothing, and we default it
|
107
123
|
@name = nil if @name == UNSET_VALUE
|
108
124
|
|
@@ -127,6 +143,10 @@ module VagrantPlugins
|
|
127
143
|
|
128
144
|
{ "UTM Provider" => errors }
|
129
145
|
end
|
146
|
+
|
147
|
+
def to_s
|
148
|
+
"UTM"
|
149
|
+
end
|
130
150
|
end
|
131
151
|
end
|
132
152
|
end
|
@@ -58,9 +58,14 @@ module VagrantPlugins
|
|
58
58
|
"4.6" => Version_4_6
|
59
59
|
}
|
60
60
|
|
61
|
-
# UTM 4.6.
|
62
|
-
#
|
63
|
-
|
61
|
+
# UTM version < 4.6.5 doesn't have
|
62
|
+
# import support to work with Vagrant box (< 4.6.1)
|
63
|
+
# registry support to work with synced folders (< 4.6.5)
|
64
|
+
# Restrict to UTM versions >= 4.6.5
|
65
|
+
unless Gem::Version.new(@version) >= Gem::Version.new("4.6.5")
|
66
|
+
raise Errors::UtmInvalidVersion,
|
67
|
+
supported_versions: "4.6.5 or earlier"
|
68
|
+
end
|
64
69
|
|
65
70
|
driver_klass = nil
|
66
71
|
driver_map.each do |key, klass|
|
@@ -88,6 +93,7 @@ module VagrantPlugins
|
|
88
93
|
def_delegators :@driver,
|
89
94
|
:check_qemu_guest_agent,
|
90
95
|
:clear_forwarded_ports,
|
96
|
+
:clear_shared_folders,
|
91
97
|
:create_snapshot,
|
92
98
|
:delete,
|
93
99
|
:delete_snapshot,
|
@@ -108,6 +114,7 @@ module VagrantPlugins
|
|
108
114
|
:restore_snapshot,
|
109
115
|
:set_mac_address,
|
110
116
|
:set_name,
|
117
|
+
:share_folders,
|
111
118
|
:ssh_port,
|
112
119
|
:start,
|
113
120
|
:start_disposable,
|
@@ -13,6 +13,25 @@ module VagrantPlugins
|
|
13
13
|
@logger = Log4r::Logger.new("vagrant::provider::utm::version_4_6")
|
14
14
|
end
|
15
15
|
|
16
|
+
# Implement clear_shared_folders
|
17
|
+
def clear_shared_folders
|
18
|
+
# Get the list of shared folders
|
19
|
+
shared_folders = read_shared_folders
|
20
|
+
# Get the args to remove the shared folders
|
21
|
+
script_path = @script_path.join("read_shared_folders_args.js")
|
22
|
+
cmd = ["osascript", script_path.to_s, @uuid, "--ids", shared_folders.join(",")]
|
23
|
+
output = execute_shell(*cmd)
|
24
|
+
result = JSON.parse(output)
|
25
|
+
return unless result["status"]
|
26
|
+
|
27
|
+
# Flatten the list of args and build the command
|
28
|
+
sf_args = result["result"].flatten
|
29
|
+
return unless sf_args.any?
|
30
|
+
|
31
|
+
command = ["remove_qemu_additional_args.applescript", @uuid, "--args", *sf_args]
|
32
|
+
execute_osa_script(command)
|
33
|
+
end
|
34
|
+
|
16
35
|
def import(utm)
|
17
36
|
utm = Vagrant::Util::Platform.windows_path(utm)
|
18
37
|
|
@@ -36,6 +55,54 @@ module VagrantPlugins
|
|
36
55
|
command = ["export_vm.applescript", @uuid, path]
|
37
56
|
execute_osa_script(command)
|
38
57
|
end
|
58
|
+
|
59
|
+
def read_shared_folders
|
60
|
+
@logger.debug("Reading shared folders")
|
61
|
+
script_path = @script_path.join("read_shared_folders.js")
|
62
|
+
cmd = ["osascript", script_path.to_s, @uuid]
|
63
|
+
output = execute_shell(*cmd)
|
64
|
+
result = JSON.parse(output)
|
65
|
+
return unless result["status"]
|
66
|
+
|
67
|
+
# Return the list of shared folders names(id)
|
68
|
+
result["result"]
|
69
|
+
end
|
70
|
+
|
71
|
+
def share_folders(folders)
|
72
|
+
# sync folder cleanup will call clear_shared_folders
|
73
|
+
# This is just a precaution, to make sure we don't
|
74
|
+
# have duplicate shared folders
|
75
|
+
shared_folders = read_shared_folders
|
76
|
+
@logger.debug("Shared folders: #{shared_folders}")
|
77
|
+
@logger.debug("Sharing folders: #{folders}")
|
78
|
+
|
79
|
+
folders.each do |folder|
|
80
|
+
# Skip if the folder is already shared
|
81
|
+
next if shared_folders.include?(folder[:name])
|
82
|
+
|
83
|
+
args = ["--id", folder[:name],
|
84
|
+
"--dir", folder[:hostpath]]
|
85
|
+
command = ["add_folder_share.applescript", @uuid, *args]
|
86
|
+
execute_osa_script(command)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def unshare_folders(folders)
|
91
|
+
@logger.debug("Unsharing folder: #{folder[:name]}")
|
92
|
+
# Get the args to remove the shared folders
|
93
|
+
script_path = @script_path.join("read_shared_folders_args.js")
|
94
|
+
cmd = ["osascript", script_path.to_s, @uuid, "--ids", folders.join(",")]
|
95
|
+
output = execute_shell(*cmd)
|
96
|
+
result = JSON.parse(output)
|
97
|
+
return unless result["status"]
|
98
|
+
|
99
|
+
# Flatten the list of args and build the command
|
100
|
+
sf_args = result["result"].flatten
|
101
|
+
return unless sf_args.any?
|
102
|
+
|
103
|
+
command = ["remove_qemu_additional_args.applescript", @uuid, "--args", *sf_args]
|
104
|
+
execute_osa_script(command)
|
105
|
+
end
|
39
106
|
end
|
40
107
|
end
|
41
108
|
end
|
data/lib/vagrant_utm/plugin.rb
CHANGED
@@ -33,6 +33,12 @@ module VagrantPlugins
|
|
33
33
|
Config
|
34
34
|
end
|
35
35
|
|
36
|
+
# Register the synced folder implementation
|
37
|
+
synced_folder(:utm) do
|
38
|
+
require_relative "synced_folder"
|
39
|
+
SyncedFolder
|
40
|
+
end
|
41
|
+
|
36
42
|
# Register capabilities
|
37
43
|
provider_capability(:utm, :forwarded_ports) do
|
38
44
|
require_relative "cap"
|
@@ -44,6 +50,21 @@ module VagrantPlugins
|
|
44
50
|
Cap
|
45
51
|
end
|
46
52
|
|
53
|
+
synced_folder_capability(:utm, "mount_options") do
|
54
|
+
require_relative "cap/mount_options"
|
55
|
+
Cap::MountOptions
|
56
|
+
end
|
57
|
+
|
58
|
+
synced_folder_capability(:utm, "mount_type") do
|
59
|
+
require_relative "cap/mount_options"
|
60
|
+
Cap::MountOptions
|
61
|
+
end
|
62
|
+
|
63
|
+
synced_folder_capability(:utm, "mount_name") do
|
64
|
+
require_relative "cap/mount_options"
|
65
|
+
Cap::MountOptions
|
66
|
+
end
|
67
|
+
|
47
68
|
# Register the command
|
48
69
|
## Start machine as a snapshot and do not save changes to disk
|
49
70
|
command "disposable" do
|
@@ -0,0 +1,96 @@
|
|
1
|
+
---
|
2
|
+
-- add_directory_share.applescript
|
3
|
+
-- This script adds QEMU arguments for directory sharing in UTM (QEMU) for given id and directory pairs.
|
4
|
+
-- Usage: osascript add_directory_share.applescript UUID --id <ID1> --dir <DIR1> --id <ID2> --dir <DIR2> ...
|
5
|
+
-- Example: osascript add_directory_share.applescript UUID --id no1 --dir "/path/to/dir1" --id no2 --dir "/path/to/dir2"
|
6
|
+
|
7
|
+
-- Function to create QEMU arguments for directory sharing
|
8
|
+
on createQemuArgsForDir(dirId, dirPath)
|
9
|
+
|
10
|
+
-- Prepare the QEMU argument strings
|
11
|
+
set fsdevArgStr to "-fsdev local,id=" & dirId & ",path=" & dirPath & ",security_model=mapped-xattr"
|
12
|
+
set deviceArgStr to "-device virtio-9p-pci,fsdev=" & dirId & ",mount_tag=" & dirId
|
13
|
+
|
14
|
+
return {fsdevArgStr, deviceArgStr}
|
15
|
+
end createQemuArgsForDir
|
16
|
+
|
17
|
+
-- Main script
|
18
|
+
on run argv
|
19
|
+
-- VM id is assumed to be the first argument
|
20
|
+
set vmId to item 1 of argv
|
21
|
+
|
22
|
+
-- Initialize variables
|
23
|
+
set idList to {} --
|
24
|
+
set dirList to {}
|
25
|
+
set idFlag to false
|
26
|
+
set dirFlag to false
|
27
|
+
|
28
|
+
-- Parse arguments
|
29
|
+
repeat with i from 2 to (count of argv)
|
30
|
+
set currentArg to item i of argv
|
31
|
+
if currentArg is "--id" then
|
32
|
+
set idFlag to true
|
33
|
+
set dirFlag to false
|
34
|
+
else if currentArg is "--dir" then
|
35
|
+
set dirFlag to true
|
36
|
+
set idFlag to false
|
37
|
+
else if idFlag then
|
38
|
+
set end of idList to currentArg
|
39
|
+
set idFlag to false
|
40
|
+
else if dirFlag then
|
41
|
+
set end of dirList to currentArg
|
42
|
+
set dirFlag to false
|
43
|
+
end if
|
44
|
+
end repeat
|
45
|
+
|
46
|
+
-- Ensure the lists are of the same length
|
47
|
+
if (count of idList) is not (count of dirList) then
|
48
|
+
error "The number of IDs and directories must be the same."
|
49
|
+
end if
|
50
|
+
|
51
|
+
-- Initialize the list of QEMU arguments
|
52
|
+
set qemuNewArgs to {}
|
53
|
+
|
54
|
+
-- Initialize the directory list
|
55
|
+
set directoryList to {}
|
56
|
+
|
57
|
+
-- Create QEMU arguments for each directory
|
58
|
+
repeat with i from 1 to (count of dirList)
|
59
|
+
set dirPath to item i of dirList
|
60
|
+
set dirId to item i of idList
|
61
|
+
set dirURL to POSIX file dirPath
|
62
|
+
set {fsdevArgStr, deviceArgStr} to createQemuArgsForDir(dirId, dirPath)
|
63
|
+
|
64
|
+
-- add the directory file obj to the list
|
65
|
+
set end of directoryList to dirURL
|
66
|
+
-- append the arguments to the list
|
67
|
+
set end of qemuNewArgs to {fsdevArg:fsdevArgStr, deviceArg:deviceArgStr, dirURL:dirURL}
|
68
|
+
end repeat
|
69
|
+
|
70
|
+
-- Example usage in UTM
|
71
|
+
tell application "UTM"
|
72
|
+
set vm to virtual machine id vmId
|
73
|
+
set config to configuration of vm
|
74
|
+
|
75
|
+
-- Get the current QEMU additional arguments
|
76
|
+
set qemuAddArgs to qemu additional arguments of config
|
77
|
+
|
78
|
+
-- Add the new arguments to the existing ones
|
79
|
+
repeat with arg in qemuNewArgs
|
80
|
+
-- SKIP: adding file urls to qemu args file urls , since it is not necessary. UTM#6977
|
81
|
+
set end of qemuAddArgs to {argument string:fsdevArg of arg}
|
82
|
+
set end of qemuAddArgs to {argument string:deviceArg of arg}
|
83
|
+
end repeat
|
84
|
+
|
85
|
+
-- Update the configuration with the new arguments list
|
86
|
+
set qemu additional arguments of config to qemuAddArgs
|
87
|
+
update configuration of vm with config
|
88
|
+
|
89
|
+
-- Get the current directory shares in registry
|
90
|
+
set reg to registry of vm
|
91
|
+
-- Add new directory shares to the registry
|
92
|
+
set reg to reg & directoryList
|
93
|
+
-- Update registry of vm with new directory shares
|
94
|
+
update registry of vm with reg
|
95
|
+
end tell
|
96
|
+
end run
|
@@ -0,0 +1,43 @@
|
|
1
|
+
---
|
2
|
+
-- add_qemu_additional_args.applescript
|
3
|
+
-- This script adds qemu arguments to a specified UTM virtual machine.
|
4
|
+
-- Usage: osascript add_qemu_additional_args.applescript <VM_UUID> --args <arg1> <arg2> ...
|
5
|
+
-- Example: osascript add_qemu_additional_args.applescript A123 --args "-vnc 127.0.0.1:13" "-vnc..."
|
6
|
+
|
7
|
+
on run argv
|
8
|
+
set vmId to item 1 of argv # UUID of the VM
|
9
|
+
|
10
|
+
-- Initialize variables
|
11
|
+
set argsList to {}
|
12
|
+
set argsFlag to false
|
13
|
+
|
14
|
+
-- Parse the --args arguments
|
15
|
+
repeat with i from 2 to (count of argv)
|
16
|
+
set currentArg to item i of argv
|
17
|
+
if currentArg is "--args" then
|
18
|
+
set argsFlag to true
|
19
|
+
else if argsFlag then
|
20
|
+
set end of argsList to currentArg
|
21
|
+
end if
|
22
|
+
end repeat
|
23
|
+
|
24
|
+
tell application "UTM"
|
25
|
+
-- Get the VM and its configuration
|
26
|
+
set vm to virtual machine id vmId -- Id is assumed to be valid
|
27
|
+
set config to configuration of vm
|
28
|
+
|
29
|
+
-- Existing arguments
|
30
|
+
set qemuAddArgs to qemu additional arguments of config
|
31
|
+
|
32
|
+
-- Create new arguments from argsList and add them to the existing arguments
|
33
|
+
repeat with arg in argsList
|
34
|
+
set end of qemuAddArgs to {argument string:arg}
|
35
|
+
end repeat
|
36
|
+
|
37
|
+
--- set qemu args with new args list
|
38
|
+
set qemu additional arguments of config to qemuAddArgs
|
39
|
+
|
40
|
+
--- save the configuration (VM must be stopped)
|
41
|
+
update configuration of vm with config
|
42
|
+
end tell
|
43
|
+
end run
|
@@ -0,0 +1,47 @@
|
|
1
|
+
/**
|
2
|
+
* Reads the shared directory IDs from the QEMU additional arguments of a specified VM in UTM.
|
3
|
+
*
|
4
|
+
* This function uses the UTM application to read the QEMU additional arguments
|
5
|
+
* of a VM identified by the given VM ID and extracts the IDs of shared directories.
|
6
|
+
*
|
7
|
+
* @param {string} vmIdentifier - The ID of the VM.
|
8
|
+
* @returns {string} A JSON string containing the shared directory IDs or an error message.
|
9
|
+
*/
|
10
|
+
function run(argv) {
|
11
|
+
// Check if a VM ID is provided
|
12
|
+
if (argv.length === 0) {
|
13
|
+
console.log("Usage: osascript -l JavaScript read_shared_directories.js <vm_id>");
|
14
|
+
return JSON.stringify({ status: false, result: "No VM ID provided." });
|
15
|
+
}
|
16
|
+
|
17
|
+
const vmIdentifier = argv[0];
|
18
|
+
const utm = Application('UTM');
|
19
|
+
utm.includeStandardAdditions = true;
|
20
|
+
|
21
|
+
try {
|
22
|
+
// Attempt to get the VM by ID
|
23
|
+
const vm = utm.virtualMachines.byId(vmIdentifier);
|
24
|
+
// Get the config of the VM
|
25
|
+
const config = vm.configuration();
|
26
|
+
// Get the QEMU additional arguments
|
27
|
+
const qemuArgs = config.qemuAdditionalArguments;
|
28
|
+
|
29
|
+
// Extract shared directory IDs
|
30
|
+
const sharedDirIds = [];
|
31
|
+
qemuArgs.forEach(arg => {
|
32
|
+
const argStr = arg.argumentString;
|
33
|
+
if (argStr.startsWith("-fsdev")) {
|
34
|
+
const match = argStr.match(/id=([^,]+)/);
|
35
|
+
if (match) {
|
36
|
+
sharedDirIds.push(match[1]);
|
37
|
+
}
|
38
|
+
}
|
39
|
+
});
|
40
|
+
|
41
|
+
// Return the shared directory IDs
|
42
|
+
return JSON.stringify({ status: true, result: sharedDirIds });
|
43
|
+
} catch (error) {
|
44
|
+
// Return an error message
|
45
|
+
return JSON.stringify({ status: false, result: error.message });
|
46
|
+
}
|
47
|
+
}
|
@@ -0,0 +1,53 @@
|
|
1
|
+
/**
|
2
|
+
* Reads the shared folder QEMU arguments for specified IDs from the QEMU additional arguments of a VM in UTM.
|
3
|
+
*
|
4
|
+
* This function uses the UTM application to read the QEMU additional arguments
|
5
|
+
* of a VM identified by the given VM ID and extracts the arguments for the specified IDs.
|
6
|
+
*
|
7
|
+
* @param {string} vmIdentifier - The ID of the VM.
|
8
|
+
* @param {string} ids - Comma-separated list of directory IDs.
|
9
|
+
* @returns {string} A JSON string containing the QEMU arguments for the specified IDs or an error message.
|
10
|
+
*/
|
11
|
+
function run(argv) {
|
12
|
+
// Check if a VM ID and IDs are provided
|
13
|
+
if (argv.length < 2) {
|
14
|
+
console.log("Usage: osascript -l JavaScript read_shared_folders_args.js <vm_id> --ids <dirID>,<dirID>");
|
15
|
+
return JSON.stringify({ status: false, result: "No VM ID or IDs provided." });
|
16
|
+
}
|
17
|
+
|
18
|
+
const vmIdentifier = argv[0];
|
19
|
+
const idsArgIndex = argv.indexOf("--ids");
|
20
|
+
if (idsArgIndex === -1 || idsArgIndex + 1 >= argv.length) {
|
21
|
+
return JSON.stringify({ status: false, result: "No IDs provided." });
|
22
|
+
}
|
23
|
+
const ids = argv[idsArgIndex + 1].split(",");
|
24
|
+
|
25
|
+
const utm = Application('UTM');
|
26
|
+
utm.includeStandardAdditions = true;
|
27
|
+
|
28
|
+
try {
|
29
|
+
// Attempt to get the VM by ID
|
30
|
+
const vm = utm.virtualMachines.byId(vmIdentifier);
|
31
|
+
// Get the config of the VM
|
32
|
+
const config = vm.configuration();
|
33
|
+
// Get the QEMU additional arguments
|
34
|
+
const qemuArgs = config.qemuAdditionalArguments;
|
35
|
+
|
36
|
+
// Extract QEMU arguments for the specified IDs
|
37
|
+
const sharedDirArgs = [];
|
38
|
+
qemuArgs.forEach(arg => {
|
39
|
+
const argStr = arg.argumentString;
|
40
|
+
ids.forEach(id => {
|
41
|
+
if (argStr.includes(`id=${id}`) || argStr.includes(`fsdev=${id}`)) {
|
42
|
+
sharedDirArgs.push(argStr);
|
43
|
+
}
|
44
|
+
});
|
45
|
+
});
|
46
|
+
|
47
|
+
// Return the QEMU arguments for the specified IDs
|
48
|
+
return JSON.stringify({ status: true, result: sharedDirArgs });
|
49
|
+
} catch (error) {
|
50
|
+
// Return an error message
|
51
|
+
return JSON.stringify({ status: false, result: error.message });
|
52
|
+
}
|
53
|
+
}
|
@@ -0,0 +1,46 @@
|
|
1
|
+
---
|
2
|
+
-- remove_qemu_additional_args.applescript
|
3
|
+
-- This script removes specified qemu arguments from a specified UTM virtual machine.
|
4
|
+
-- Usage: osascript remove_qemu_additional_args.applescript <VM_UUID> --args <arg1> <arg2> ...
|
5
|
+
-- Example: osascript remove_qemu_additional_args.applescript A123 --args "-vnc 127.0.0.1:13" "-vnc..."
|
6
|
+
|
7
|
+
on run argv
|
8
|
+
set vmId to item 1 of argv -- UUID of the VM
|
9
|
+
|
10
|
+
-- Initialize variables
|
11
|
+
set argsToRemove to {}
|
12
|
+
set argsFlag to false
|
13
|
+
|
14
|
+
-- Parse the --args arguments
|
15
|
+
repeat with i from 2 to (count of argv)
|
16
|
+
set currentArg to item i of argv
|
17
|
+
if currentArg is "--args" then
|
18
|
+
set argsFlag to true
|
19
|
+
else if argsFlag then
|
20
|
+
set end of argsToRemove to currentArg
|
21
|
+
end if
|
22
|
+
end repeat
|
23
|
+
|
24
|
+
tell application "UTM"
|
25
|
+
-- Get the VM and its configuration
|
26
|
+
set vm to virtual machine id vmId -- Id is assumed to be valid
|
27
|
+
set config to configuration of vm
|
28
|
+
|
29
|
+
-- Get the current QEMU additional arguments
|
30
|
+
set qemuAddArgs to qemu additional arguments of config
|
31
|
+
|
32
|
+
-- Initialize a new list for the updated arguments
|
33
|
+
set updatedArgs to {}
|
34
|
+
|
35
|
+
-- Iterate through the current arguments and add all except the ones to remove
|
36
|
+
repeat with arg in qemuAddArgs
|
37
|
+
if arg is not in argsToRemove then
|
38
|
+
set end of updatedArgs to arg
|
39
|
+
end if
|
40
|
+
end repeat
|
41
|
+
|
42
|
+
-- Update the configuration with the new arguments list
|
43
|
+
set qemu additional arguments of config to updatedArgs
|
44
|
+
update configuration of vm with config
|
45
|
+
end tell
|
46
|
+
end run
|
@@ -0,0 +1,127 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module Utm
|
5
|
+
# Default Synced folder implementation for UTM
|
6
|
+
class SyncedFolder < Vagrant.plugin("2", :synced_folder)
|
7
|
+
def usable?(machine, _raise_errors = false) # rubocop:disable Style/OptionalBooleanParameter
|
8
|
+
# These synced folders only work if the provider is UTM
|
9
|
+
return false if machine.provider_name != :utm
|
10
|
+
|
11
|
+
# This only happens with `vagrant package --base`. Sigh.
|
12
|
+
return true unless machine.provider_config
|
13
|
+
|
14
|
+
machine.provider_config.functional_9pfs
|
15
|
+
end
|
16
|
+
|
17
|
+
# This is called before VM Boot to prepare the synced folders.
|
18
|
+
# Add required configs to the VM.
|
19
|
+
def prepare(machine, folders, _opts)
|
20
|
+
share_folders(machine, folders)
|
21
|
+
end
|
22
|
+
|
23
|
+
# This is called after VM Boot to mount the synced folders.
|
24
|
+
# Mount the shared folders inside the VM.
|
25
|
+
def enable(machine, folders, _opts) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength,Metrics/PerceivedComplexity
|
26
|
+
share_folders(machine, folders)
|
27
|
+
|
28
|
+
# sort guestpaths first, so we don't step on ourselves
|
29
|
+
folders = folders.sort_by do |_id, data|
|
30
|
+
if data[:guestpath]
|
31
|
+
data[:guestpath].length
|
32
|
+
else
|
33
|
+
# A long enough path to just do this at the end.
|
34
|
+
10_000
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Go through each folder and mount
|
39
|
+
machine.ui.output(I18n.t("vagrant.actions.vm.share_folders.mounting"))
|
40
|
+
# refresh fstab
|
41
|
+
fstab_folders = [] # rubocop:disable Lint/UselessAssignment
|
42
|
+
folders.each do |id, data|
|
43
|
+
if data[:guestpath]
|
44
|
+
# Guest path specified, so mount the folder to specified point
|
45
|
+
machine.ui.detail(I18n.t("vagrant.actions.vm.share_folders.mounting_entry",
|
46
|
+
guestpath: data[:guestpath],
|
47
|
+
hostpath: data[:hostpath]))
|
48
|
+
|
49
|
+
# Dup the data so we can pass it to the guest API
|
50
|
+
data = data.dup
|
51
|
+
|
52
|
+
# Calculate the owner and group
|
53
|
+
ssh_info = machine.ssh_info
|
54
|
+
data[:owner] ||= ssh_info[:username]
|
55
|
+
data[:group] ||= ssh_info[:username]
|
56
|
+
|
57
|
+
# Unmount the folder before we mount it
|
58
|
+
machine.guest.capability(
|
59
|
+
:unmount_virtualbox_shared_folder,
|
60
|
+
data[:guestpath], data
|
61
|
+
)
|
62
|
+
|
63
|
+
# Mount the actual folder
|
64
|
+
machine.guest.capability(
|
65
|
+
:mount_virtualbox_shared_folder,
|
66
|
+
os_friendly_id(id), data[:guestpath], data
|
67
|
+
)
|
68
|
+
else
|
69
|
+
# If no guest path is specified, then automounting is disabled
|
70
|
+
machine.ui.detail(I18n.t("vagrant.actions.vm.share_folders.nomount_entry",
|
71
|
+
hostpath: data[:hostpath]))
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def disable(machine, folders, _opts)
|
77
|
+
if machine.guest.capability?(:unmount_virtualbox_shared_folder)
|
78
|
+
folders.each_value do |data|
|
79
|
+
machine.guest.capability(
|
80
|
+
:unmount_virtualbox_shared_folder,
|
81
|
+
data[:guestpath], data
|
82
|
+
)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Remove the shared folders from the VM metadata
|
87
|
+
names = folders.map { |id, _data| os_friendly_id(id) }
|
88
|
+
driver(machine).unshare_folders(names)
|
89
|
+
end
|
90
|
+
|
91
|
+
def cleanup(machine, _opts)
|
92
|
+
driver(machine).clear_shared_folders if machine.id && machine.id != ""
|
93
|
+
end
|
94
|
+
|
95
|
+
protected
|
96
|
+
|
97
|
+
# This is here so that we can stub it for tests
|
98
|
+
def driver(machine)
|
99
|
+
machine.provider.driver
|
100
|
+
end
|
101
|
+
|
102
|
+
def os_friendly_id(id)
|
103
|
+
id.gsub(%r{[\s/\\]}, "_").sub(/^_/, "")
|
104
|
+
end
|
105
|
+
|
106
|
+
# share_folders sets up the shared folder definitions on the
|
107
|
+
# UTM VM.
|
108
|
+
#
|
109
|
+
def share_folders(machine, folders)
|
110
|
+
defs = []
|
111
|
+
|
112
|
+
folders.each do |id, data|
|
113
|
+
hostpath = data[:hostpath]
|
114
|
+
hostpath = Vagrant::Util::Platform.cygwin_windows_path(hostpath) unless data[:hostpath_exact]
|
115
|
+
|
116
|
+
defs << {
|
117
|
+
name: os_friendly_id(id),
|
118
|
+
hostpath: hostpath.to_s,
|
119
|
+
automount: !data[:automount].nil?
|
120
|
+
}
|
121
|
+
end
|
122
|
+
|
123
|
+
driver(machine).share_folders(defs)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copied from vagrant/plugins/synced_folder/unix_mount_helpers.rb
|
4
|
+
# Copyright (c) HashiCorp, Inc.
|
5
|
+
# SPDX-License-Identifier: BUSL-1.1
|
6
|
+
|
7
|
+
require "shellwords"
|
8
|
+
require "vagrant/util/retryable"
|
9
|
+
|
10
|
+
module VagrantPlugins
|
11
|
+
module SyncedFolder
|
12
|
+
# Contains helper methods for mounting folders on Unix-based systems.
|
13
|
+
module UnixMountHelpers # rubocop:disable Metrics/ModuleLength
|
14
|
+
def self.extended(klass)
|
15
|
+
unless klass.class_variable_defined?(:@@logger)
|
16
|
+
klass.class_variable_set(:@@logger, Log4r::Logger.new(klass.name.downcase)) # rubocop:disable Style/ClassVars
|
17
|
+
end
|
18
|
+
klass.extend Vagrant::Util::Retryable
|
19
|
+
end
|
20
|
+
|
21
|
+
def detect_owner_group_ids(machine, guest_path, mount_options, options) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity
|
22
|
+
mount_uid = find_mount_options_id("uid", mount_options)
|
23
|
+
mount_gid = find_mount_options_id("gid", mount_options)
|
24
|
+
|
25
|
+
if mount_uid.nil?
|
26
|
+
if options[:owner].to_i.to_s == options[:owner].to_s
|
27
|
+
mount_uid = options[:owner]
|
28
|
+
class_variable_get(:@@logger).debug("Owner user ID (provided): #{mount_uid}")
|
29
|
+
else
|
30
|
+
output = { stdout: String.new, stderr: String.new } # Ensure strings are not frozen
|
31
|
+
uid_command = "id -u #{options[:owner]}"
|
32
|
+
machine.communicate.execute(uid_command,
|
33
|
+
error_class: Vagrant::Errors::VirtualBoxMountFailed,
|
34
|
+
error_key: :virtualbox_mount_failed,
|
35
|
+
command: uid_command,
|
36
|
+
output: output[:stderr]) { |type, data| output[type] << data if output[type] }
|
37
|
+
mount_uid = output[:stdout].chomp
|
38
|
+
class_variable_get(:@@logger).debug("Owner user ID (lookup): #{options[:owner]} -> #{mount_uid}")
|
39
|
+
end
|
40
|
+
else
|
41
|
+
machine.ui.warn "Detected mount owner ID within mount options. (uid: #{mount_uid} guestpath: #{guest_path})"
|
42
|
+
end
|
43
|
+
|
44
|
+
if mount_gid.nil?
|
45
|
+
if options[:group].to_i.to_s == options[:group].to_s
|
46
|
+
mount_gid = options[:group]
|
47
|
+
class_variable_get(:@@logger).debug("Owner group ID (provided): #{mount_gid}")
|
48
|
+
else
|
49
|
+
begin
|
50
|
+
{ stdout: String.new, stderr: String.new } # Ensure strings are not frozen
|
51
|
+
gid_command = "getent group #{options[:group]}"
|
52
|
+
machine.communicate.execute(gid_command,
|
53
|
+
error_class: Vagrant::Errors::VirtualBoxMountFailed,
|
54
|
+
error_key: :virtualbox_mount_failed,
|
55
|
+
command: gid_command,
|
56
|
+
output: output[:stderr]) { |type, data| output[type] << data if output[type] }
|
57
|
+
mount_gid = output[:stdout].split(":").at(2).to_s.chomp
|
58
|
+
class_variable_get(:@@logger).debug("Owner group ID (lookup): #{options[:group]} -> #{mount_gid}")
|
59
|
+
rescue Vagrant::Errors::VirtualBoxMountFailed
|
60
|
+
if options[:owner] == options[:group] # rubocop:disable Metrics/BlockNesting
|
61
|
+
class_variable_get(:@@logger).debug("Failed to locate group `#{options[:group]}`. Group name matches owner. Fetching effective group ID.") # rubocop:disable Layout/LineLength
|
62
|
+
output = { stdout: String.new }
|
63
|
+
result = machine.communicate.execute("id -g #{options[:owner]}",
|
64
|
+
error_check: false) do |type, data|
|
65
|
+
output[type] << data if output[type] # rubocop:disable Metrics/BlockNesting
|
66
|
+
end
|
67
|
+
mount_gid = output[:stdout].chomp if result.zero? # rubocop:disable Metrics/BlockNesting
|
68
|
+
class_variable_get(:@@logger).debug("Owner group ID (effective): #{mount_gid}")
|
69
|
+
end
|
70
|
+
raise unless mount_gid
|
71
|
+
end
|
72
|
+
end
|
73
|
+
else
|
74
|
+
machine.ui.warn "Detected mount group ID within mount options. (gid: #{mount_gid} guestpath: #{guest_path})"
|
75
|
+
end
|
76
|
+
{ gid: mount_gid, uid: mount_uid }
|
77
|
+
end
|
78
|
+
|
79
|
+
def find_mount_options_id(id_name, mount_options) # rubocop:disable Metrics/AbcSize
|
80
|
+
id_line = mount_options.detect { |line| line.include?("#{id_name}=") }
|
81
|
+
if id_line
|
82
|
+
match = id_line.match(/,?#{Regexp.escape(id_name)}=(?<option_id>\d+),?/)
|
83
|
+
found_id = match["option_id"]
|
84
|
+
updated_id_line = [
|
85
|
+
match.pre_match,
|
86
|
+
match.post_match
|
87
|
+
].find_all { |string| !string.empty? }.join(",")
|
88
|
+
if updated_id_line.empty?
|
89
|
+
mount_options.delete(id_line)
|
90
|
+
else
|
91
|
+
idx = mount_options.index(id_line)
|
92
|
+
mount_options.delete(idx)
|
93
|
+
mount_options.insert(idx, updated_id_line)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
found_id
|
97
|
+
end
|
98
|
+
|
99
|
+
def emit_upstart_notification(machine, guest_path)
|
100
|
+
# Emit an upstart event if we can
|
101
|
+
machine.communicate.sudo <<-NOTIFICATION.gsub(/^ {12}/, "")
|
102
|
+
if test -x /sbin/initctl && command -v /sbin/init && /sbin/init 2>/dev/null --version | grep upstart; then
|
103
|
+
/sbin/initctl emit --no-wait vagrant-mounted MOUNTPOINT=#{guest_path}
|
104
|
+
fi
|
105
|
+
NOTIFICATION
|
106
|
+
end
|
107
|
+
|
108
|
+
def merge_mount_options(base, overrides) # rubocop:disable Metrics/AbcSize
|
109
|
+
base = base.join(",").split(",")
|
110
|
+
overrides = overrides.join(",").split(",")
|
111
|
+
b_kv = Hash[base.map { |item| item.split("=", 2) }]
|
112
|
+
o_kv = Hash[overrides.map { |item| item.split("=", 2) }]
|
113
|
+
merged = {}.tap do |opts|
|
114
|
+
(b_kv.keys + o_kv.keys).uniq.each do |key|
|
115
|
+
opts[key] = o_kv.fetch(key, b_kv[key])
|
116
|
+
end
|
117
|
+
end
|
118
|
+
merged.map do |key, value|
|
119
|
+
[key, value].compact.join("=")
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
data/lib/vagrant_utm/version.rb
CHANGED
data/notes/README.md
CHANGED
@@ -34,4 +34,17 @@ GHA will publish gems to GHR and rubygems
|
|
34
34
|
|
35
35
|
To update specific gems in the project
|
36
36
|
|
37
|
-
`bundle update rubocop`
|
37
|
+
`bundle update rubocop`
|
38
|
+
|
39
|
+
To update all gems
|
40
|
+
|
41
|
+
`bundle update`
|
42
|
+
|
43
|
+
To update project after a version bump
|
44
|
+
|
45
|
+
```
|
46
|
+
Unable to resolve dependency: user requested 'vagrant_utm (= 0.1.1)'
|
47
|
+
```
|
48
|
+
|
49
|
+
Due to mismatch versions between global installed version and plugin version in the development setup, since they are same name.
|
50
|
+
Fix: Uninstall the global version, while using different version of development setup
|
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.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Naveenraj M
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-04-21 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:
|
@@ -95,6 +95,7 @@ files:
|
|
95
95
|
- lib/vagrant_utm/action/suspend.rb
|
96
96
|
- lib/vagrant_utm/action/wait_for_running.rb
|
97
97
|
- lib/vagrant_utm/cap.rb
|
98
|
+
- lib/vagrant_utm/cap/mount_options.rb
|
98
99
|
- lib/vagrant_utm/commands/disposable.rb
|
99
100
|
- lib/vagrant_utm/commands/ip_address.rb
|
100
101
|
- lib/vagrant_utm/config.rb
|
@@ -107,7 +108,9 @@ files:
|
|
107
108
|
- lib/vagrant_utm/model/list_result.rb
|
108
109
|
- lib/vagrant_utm/plugin.rb
|
109
110
|
- lib/vagrant_utm/provider.rb
|
111
|
+
- lib/vagrant_utm/scripts/add_folder_share.applescript
|
110
112
|
- lib/vagrant_utm/scripts/add_port_forwards.applescript
|
113
|
+
- lib/vagrant_utm/scripts/add_qemu_additional_args.applescript
|
111
114
|
- lib/vagrant_utm/scripts/clear_port_forwards.applescript
|
112
115
|
- lib/vagrant_utm/scripts/customize_vm.applescript
|
113
116
|
- lib/vagrant_utm/scripts/downloadVM.sh
|
@@ -117,8 +120,13 @@ files:
|
|
117
120
|
- lib/vagrant_utm/scripts/open_with_utm.js
|
118
121
|
- lib/vagrant_utm/scripts/read_forwarded_ports.applescript
|
119
122
|
- lib/vagrant_utm/scripts/read_network_interfaces.applescript
|
123
|
+
- lib/vagrant_utm/scripts/read_shared_folders.js
|
124
|
+
- lib/vagrant_utm/scripts/read_shared_folders_args.js
|
125
|
+
- lib/vagrant_utm/scripts/remove_qemu_additional_args.applescript
|
120
126
|
- lib/vagrant_utm/scripts/set_mac_address.applescript
|
127
|
+
- lib/vagrant_utm/synced_folder.rb
|
121
128
|
- lib/vagrant_utm/util/compile_forwarded_ports.rb
|
129
|
+
- lib/vagrant_utm/util/unix_mount_helpers.rb
|
122
130
|
- lib/vagrant_utm/version.rb
|
123
131
|
- locales/en.yml
|
124
132
|
- notes/README.md
|
@@ -131,7 +139,7 @@ metadata:
|
|
131
139
|
homepage_uri: https://naveenrajm7.github.io/vagrant_utm/
|
132
140
|
source_code_uri: https://github.com/naveenrajm7/vagrant_utm
|
133
141
|
changelog_uri: https://github.com/naveenrajm7/vagrant_utm/blob/main/CHANGELOG.md
|
134
|
-
post_install_message:
|
142
|
+
post_install_message:
|
135
143
|
rdoc_options: []
|
136
144
|
require_paths:
|
137
145
|
- lib
|
@@ -147,7 +155,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
147
155
|
version: '0'
|
148
156
|
requirements: []
|
149
157
|
rubygems_version: 3.5.11
|
150
|
-
signing_key:
|
158
|
+
signing_key:
|
151
159
|
specification_version: 4
|
152
160
|
summary: Vagrant UTM provider
|
153
161
|
test_files: []
|