Skip to content

Commit

Permalink
Merge pull request #12 from naveenrajm7/nfs
Browse files Browse the repository at this point in the history
Sync Folder support
  • Loading branch information
naveenrajm7 authored Dec 5, 2024
2 parents a275cb1 + f43982e commit d3f9bf4
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 7 deletions.
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
## [Unreleased]

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`

```ruby
Vagrant.configure("2") do |config|
config.vm.synced_folder ".", "/vagrant", type: "rsync"
config.vm.box = "utm/ubuntu-24.04"
end
```

### Added

- Initial Synced Folder support with sync
- Warning: By default vagrant brings other sync methods eg: SMB, NFS but they are not ready to use.

## [0.1.1] - 2024-12-03

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.
Expand Down
24 changes: 22 additions & 2 deletions lib/vagrant_utm/action.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ module Action # rubocop:disable Metrics/ModuleLength
autoload :PackageSetupFiles, action_root.join("package_setup_files")
autoload :PackageSetupFolders, action_root.join("package_setup_folders")
autoload :PackageVagrantfile, action_root.join("package_vagrantfile")
autoload :PrepareNFSSettings, action_root.join("prepare_nfs_settings")
autoload :PrepareNFSValidIds, action_root.join("prepare_nfs_valid_ids")
autoload :PrepareForwardedPortCollisionParams, action_root.join("prepare_forwarded_port_collision_params")
autoload :Resume, action_root.join("resume")
autoload :SetId, action_root.join("set_id")
Expand All @@ -66,6 +68,10 @@ def self.action_boot # rubocop:disable Metrics/AbcSize
b.use EnvSet, port_collision_repair: true
b.use PrepareForwardedPortCollisionParams
b.use HandleForwardedPortCollisions
b.use PrepareNFSValidIds
b.use SyncedFolderCleanup
b.use SyncedFolders
b.use PrepareNFSSettings
b.use ForwardPorts
b.use SetHostname
b.use Customize, "pre-boot"
Expand All @@ -90,7 +96,7 @@ def self.action_boot # rubocop:disable Metrics/AbcSize
# This is the action that is primarily responsible for completely
# freeing the resources of the underlying virtual machine.
# UTM equivalent of `utmctl delete <uuid>`
def self.action_destroy
def self.action_destroy # rubocop:disable Metrics/AbcSize
Vagrant::Action::Builder.new.tap do |b|
b.use CheckUtm
b.use Call, Created do |env1, b2|
Expand All @@ -106,6 +112,8 @@ def self.action_destroy
b3.use CheckAccessible
b3.use action_halt
b3.use Destroy
b3.use PrepareNFSValidIds
b3.use SyncedFolderCleanup
else
b3.use MessageWillNotDestroy
end
Expand Down Expand Up @@ -160,7 +168,7 @@ def self.action_ip_address
end

# This action packages the virtual machine into a single box file.
def self.action_package
def self.action_package # rubocop:disable Metrics/AbcSize
Vagrant::Action::Builder.new.tap do |b|
b.use CheckUtm
b.use Call, Created do |env, b2|
Expand All @@ -174,6 +182,8 @@ def self.action_package
b2.use CheckAccessible
b2.use action_halt
b2.use ClearForwardedPorts
b2.use PrepareNFSValidIds
b2.use SyncedFolderCleanup
b2.use Package
b2.use Export
b2.use PackageVagrantfile
Expand Down Expand Up @@ -405,6 +415,16 @@ def self.action_suspend
end
end

# This is the action that is called to sync folders to a running
# machine without a reboot.
def self.action_sync_folders
Vagrant::Action::Builder.new.tap do |b|
b.use PrepareNFSValidIds
b.use SyncedFolders
b.use PrepareNFSSettings
end
end

# This action brings the machine up from nothing, including importing
# the box, configuring metadata, and booting.
def self.action_up
Expand Down
79 changes: 79 additions & 0 deletions lib/vagrant_utm/action/prepare_nfs_settings.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# frozen_string_literal: true

module VagrantPlugins
module Utm
module Action
# This action prepares the NFS settings for the machine.
class PrepareNFSSettings
include Vagrant::Action::Builtin::MixinSyncedFolders
include Vagrant::Util::Retryable

def initialize(app, _env)
@app = app
@logger = Log4r::Logger.new("vagrant::action::vm::nfs")
end

def call(env)
@machine = env[:machine]

@app.call(env)

opts = {
cached: !env[:synced_folders_cached].nil?,
config: env[:synced_folders_config],
disable_usable_check: !env[:test].nil?
}
folders = synced_folders(env[:machine], **opts)

return unless folders.key?(:nfs)

@logger.info("Using NFS, preparing NFS settings by reading host IP and machine IP")
add_ips_to_env!(env)
end

# Extracts the proper host and guest IPs for NFS mounts and stores them
# in the environment for the SyncedFolder action to use them in
# mounting.
#
# The ! indicates that this method modifies its argument.
def add_ips_to_env!(env)
# Hardcoded IP for the host IP
host_ip = "10.0.2.2"
machine_ip = read_dynamic_machine_ip

raise Vagrant::Errors::NFSNoHostonlyNetwork if !host_ip || !machine_ip

env[:nfs_host_ip] = host_ip
env[:nfs_machine_ip] = machine_ip
end

# Returns the IP address of the guest by looking at utm guest additions
# for the appropriate guest adapter.
#
# For DHCP interfaces, the guest property will not be present until the
# guest completes
#
# @param [Integer] adapter number to read IP for
# @return [String] ip address of adapter
def read_dynamic_machine_ip
# we need to wait for the guest's IP to show up as a guest property.
# retry thresholds are relatively high since we might need to wait
# for DHCP, but even static IPs can take a second or two to appear.
retryable(retry_options.merge(on: Vagrant::Errors::VirtualBoxGuestPropertyNotFound)) do
# Read the IP address from the list given by qemu-guest-agent
@machine.provider.driver.read_guest_ip[0]
end
rescue Vagrant::Errors::VirtualBoxGuestPropertyNotFound
# this error is more specific with a better error message directing
# the user towards the fact that it's probably a reportable bug
raise Vagrant::Errors::NFSNoGuestIP
end

# Separating these out so we can stub out the sleep in tests
def retry_options
{ tries: 15, sleep: 1 }
end
end
end
end
end
24 changes: 24 additions & 0 deletions lib/vagrant_utm/action/prepare_nfs_valid_ids.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# frozen_string_literal: true

# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1

module VagrantPlugins
module Utm
module Action
# This action prepares the NFS valid IDs for the VMs.
# The ids that are valid and should not be pruned by NFS
class PrepareNFSValidIds
def initialize(app, _env)
@app = app
@logger = Log4r::Logger.new("vagrant::action::vm::nfs")
end

def call(env)
env[:nfs_valid_ids] = env[:machine].provider.driver.read_vms.keys
@app.call(env)
end
end
end
end
end
12 changes: 7 additions & 5 deletions notes/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@ To release
To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`
GitHub action upon tag push with "v*" will publish gem to GHR and rubygems

1. Update the version number in `version.rb`
2. Run `bundle exec rake release`
3. Commit version and Gemlock file
4. Run `bundle exec rake release` again
5. Cancel push to rubygems.org
1. Update
CHANGELOG.md
version number in `version.rb`
version number Gemlock file
2. Commit
3. Run `bundle exec rake release` (Commit and tags are pushed)
4. Cancel push to rubygems.org

GHA will publish gems to GHR and rubygems

Expand Down

0 comments on commit d3f9bf4

Please sign in to comment.