Skip to content

Commit

Permalink
Fixes for host path checking
Browse files Browse the repository at this point in the history
For some time there have been some issues related to differing
behavior for "path validation" whether a user was executing
`vagrant sshfs` directly vs `vagrant up`. If calling `vagrant sshfs`
the host mount in the Vagrantfile wasn't checked by the code within [1]
that requires the host folder to exist on the Vagrant host machine,
but if calling `vagrant up` it was checked. We don't necessarily want
this checked because we could be using an arbitrary mount where
the actual sshfs host is not the Vagrant host. In this commit
we override the config during the validation [1] to get it to pass
validation and then we fix it back after.

Fixes #59
Fixes #72
Fixes #82

[1] https://github.com/hashicorp/vagrant/blob/030a08f869be0571e649a5372ce8b14ba752ba6c/plugins/kernel_v2/config/vm.rb#L658-L660
  • Loading branch information
dustymabe committed Mar 11, 2018
1 parent 799f36e commit ff8a417
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 3 deletions.
130 changes: 130 additions & 0 deletions lib/vagrant-sshfs/action_hostpath_fixup.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
require "log4r"

require "vagrant/action/builtin/mixin_synced_folders"

module VagrantPlugins
module SyncedFolderSSHFS

# Class that contains common function that are called by both
# HostPathFix and HostPathUnfix classes.
class HostPathFixCommon

include Vagrant::Action::Builtin::MixinSyncedFolders

def initialize()
@logger = Log4r::Logger.new("vagrant::synced_folders::sshfs")
end

def fix(data)
# If this is an arbitrary host mount we need to set the hostpath
# to something that will pass the config checks that assume the
# hostpath is coming from the vagrant host and not from an arbitrary
# host. Save off the original hostpath and then set the hostpath to
# "." to pass the checks.
if data[:ssh_host]
data[:hostpath_orig] = data[:hostpath]
data[:hostpath] = "."
end
end

def unfix(data)
# If this is a reverse mounted folder or an arbitrary host mount
# then we'll set "hostpath_exact" so they don't try to create a
# folder on the host in Vagrant::Action::Builtin::SyncedFolders.
if data[:ssh_host]
data[:hostpath_exact] = true
data[:hostpath] = data[:hostpath_orig]
data.delete(:hostpath_orig)
end
end

# Loop through synced folder entries and either fix or unfix
# based on the fix arg
def loop_and_fix_unfix(env, fix)

opts = {
cached: !!env[:synced_folders_cached],
config: env[:synced_folders_config],
}

@logger.debug("SyncedFolders loading from cache: #{opts[:cached]}")
folders = synced_folders(env[:machine], **opts)

folders.each do |impl_name, fs|
next if impl_name != :sshfs
@logger.debug("Synced Folder Implementation: #{impl_name}")

fs.each do |id, data|

# replace data with a copy since we may delete/add new data to the config
data = data.dup

if fix
@logger.debug("fixup host path before: - #{id}: #{data[:hostpath]} => #{data[:guestpath]}")
fix(data)
@logger.debug("fixup host path after: - #{id}: #{data[:hostpath]} => #{data[:guestpath]}")
else
@logger.debug("unfixup host path before: - #{id}: #{data[:hostpath]} => #{data[:guestpath]}")
unfix(data)
@logger.debug("fixup host path after: - #{id}: #{data[:hostpath]} => #{data[:guestpath]}")
end

# Replace the entry in the config with the updated one
env[:machine].config.vm.synced_folders.delete(id)
env[:machine].config.vm.synced_folder(
data[:hostpath],
data[:guestpath],
data)
end
end
end
end

# Class that will massage the data for synced folders that are
# arbitrary host mounts (contain ssh_host in the options) to make
# it so that "host path checking" isn't performed on the vagrant
# host machine
class HostPathFix

def initialize(app, env)
@app = app
@logger = Log4r::Logger.new("vagrant::synced_folders::sshfs")
end

def call(env)
classname = "VagrantPlugins::SyncedFolderSSHFS::HostPathFix"
@logger.debug("Executing hook within #{classname}")

# This part is for the IN action call
HostPathFixCommon.new().loop_and_fix_unfix(env, fix=true)

# Now continue until the OUT call
@app.call(env)

end
end


# Class that will undo the data manipulation that was done in
# HostPathFix and also set hostpath_exact=true if necessary
class HostPathUnfix

def initialize(app, env)
@app = app
@logger = Log4r::Logger.new("vagrant::synced_folders::sshfs")
end

def call(env)
classname = "VagrantPlugins::SyncedFolderSSHFS::HostPathUnfix"
@logger.debug("Executing hook within #{classname}")

# This part is for the IN action call
HostPathFixCommon.new().loop_and_fix_unfix(env, fix=false)

# Now continue until the OUT call
@app.call(env)

end
end
end
end
14 changes: 11 additions & 3 deletions lib/vagrant-sshfs/cap/guest/linux/sshfs_forward_mount.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require "log4r"
require "vagrant/util/retryable"
require "vagrant/util/platform"
require "tempfile"

# This is already done for us in lib/vagrant-sshfs.rb. We needed to
Expand Down Expand Up @@ -70,9 +71,16 @@ def self.sshfs_forward_mount_folder(machine, opts)
comm.sudo("chmod 777 #{expanded_guest_path}")
end

# Mount path information
hostpath = opts[:hostpath].dup
hostpath.gsub!("'", "'\\\\''")
# Mount path information: if arbitrary host mounting then
# take as is. If not, then expand the hostpath to the real
# path.
if opts[:ssh_host]
hostpath = opts[:hostpath].dup
else
hostpath = File.expand_path(opts[:hostpath], machine.env.root_path)
hostpath = Vagrant::Util::Platform.fs_real_path(hostpath).to_s
end


# Add in some sshfs/fuse options that are common to both mount methods
opts[:sshfs_opts] = ' -o allow_other ' # allow non-root users to access
Expand Down
17 changes: 17 additions & 0 deletions lib/vagrant-sshfs/plugin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,23 @@ class Plugin < Vagrant.plugin("2")
Command::SSHFS
end

# The following two hooks allow us to workaround
# the config validations that assume the hostpaths
# are coming from our host machine. This is not the
# case for arbitrary host mounts.
action_hook("sshfs_hostpath_fixup") do |hook|
require_relative "action_hostpath_fixup"
hook.before(
Vagrant::Action::Builtin::ConfigValidate,
HostPathFix)
end
action_hook("sshfs_hostpath_unfix") do |hook|
require_relative "action_hostpath_fixup"
hook.after(
Vagrant::Action::Builtin::ConfigValidate,
HostPathUnfix)
end

host_capability("linux", "sshfs_reverse_mount_folder") do
require_relative "cap/host/linux/sshfs_reverse_mount"
VagrantPlugins::HostLinux::Cap::MountSSHFS
Expand Down

0 comments on commit ff8a417

Please sign in to comment.