From f0dbca9406394fc0aa846f5fabb7822a9984df43 Mon Sep 17 00:00:00 2001 From: Dusty Mabe Date: Wed, 27 Jul 2016 16:10:38 -0400 Subject: [PATCH 1/9] caps: make guests subdir for capabilities This will enable us to make host capabilities in a different subdir. --- .../cap/{ => guest}/arch/sshfs_client.rb | 0 .../cap/{ => guest}/debian/sshfs_client.rb | 0 .../cap/{ => guest}/fedora/sshfs_client.rb | 0 .../cap/{ => guest}/linux/sshfs_client.rb | 0 .../cap/{ => guest}/linux/sshfs_mount.rb | 0 .../cap/{ => guest}/redhat/sshfs_client.rb | 0 .../cap/{ => guest}/suse/sshfs_client.rb | 0 lib/vagrant-sshfs/plugin.rb | 26 +++++++++---------- 8 files changed, 13 insertions(+), 13 deletions(-) rename lib/vagrant-sshfs/cap/{ => guest}/arch/sshfs_client.rb (100%) rename lib/vagrant-sshfs/cap/{ => guest}/debian/sshfs_client.rb (100%) rename lib/vagrant-sshfs/cap/{ => guest}/fedora/sshfs_client.rb (100%) rename lib/vagrant-sshfs/cap/{ => guest}/linux/sshfs_client.rb (100%) rename lib/vagrant-sshfs/cap/{ => guest}/linux/sshfs_mount.rb (100%) rename lib/vagrant-sshfs/cap/{ => guest}/redhat/sshfs_client.rb (100%) rename lib/vagrant-sshfs/cap/{ => guest}/suse/sshfs_client.rb (100%) diff --git a/lib/vagrant-sshfs/cap/arch/sshfs_client.rb b/lib/vagrant-sshfs/cap/guest/arch/sshfs_client.rb similarity index 100% rename from lib/vagrant-sshfs/cap/arch/sshfs_client.rb rename to lib/vagrant-sshfs/cap/guest/arch/sshfs_client.rb diff --git a/lib/vagrant-sshfs/cap/debian/sshfs_client.rb b/lib/vagrant-sshfs/cap/guest/debian/sshfs_client.rb similarity index 100% rename from lib/vagrant-sshfs/cap/debian/sshfs_client.rb rename to lib/vagrant-sshfs/cap/guest/debian/sshfs_client.rb diff --git a/lib/vagrant-sshfs/cap/fedora/sshfs_client.rb b/lib/vagrant-sshfs/cap/guest/fedora/sshfs_client.rb similarity index 100% rename from lib/vagrant-sshfs/cap/fedora/sshfs_client.rb rename to lib/vagrant-sshfs/cap/guest/fedora/sshfs_client.rb diff --git a/lib/vagrant-sshfs/cap/linux/sshfs_client.rb b/lib/vagrant-sshfs/cap/guest/linux/sshfs_client.rb similarity index 100% rename from lib/vagrant-sshfs/cap/linux/sshfs_client.rb rename to lib/vagrant-sshfs/cap/guest/linux/sshfs_client.rb diff --git a/lib/vagrant-sshfs/cap/linux/sshfs_mount.rb b/lib/vagrant-sshfs/cap/guest/linux/sshfs_mount.rb similarity index 100% rename from lib/vagrant-sshfs/cap/linux/sshfs_mount.rb rename to lib/vagrant-sshfs/cap/guest/linux/sshfs_mount.rb diff --git a/lib/vagrant-sshfs/cap/redhat/sshfs_client.rb b/lib/vagrant-sshfs/cap/guest/redhat/sshfs_client.rb similarity index 100% rename from lib/vagrant-sshfs/cap/redhat/sshfs_client.rb rename to lib/vagrant-sshfs/cap/guest/redhat/sshfs_client.rb diff --git a/lib/vagrant-sshfs/cap/suse/sshfs_client.rb b/lib/vagrant-sshfs/cap/guest/suse/sshfs_client.rb similarity index 100% rename from lib/vagrant-sshfs/cap/suse/sshfs_client.rb rename to lib/vagrant-sshfs/cap/guest/suse/sshfs_client.rb diff --git a/lib/vagrant-sshfs/plugin.rb b/lib/vagrant-sshfs/plugin.rb index 8471f43..4f0e854 100644 --- a/lib/vagrant-sshfs/plugin.rb +++ b/lib/vagrant-sshfs/plugin.rb @@ -21,67 +21,67 @@ class Plugin < Vagrant.plugin("2") end guest_capability("linux", "sshfs_mount_folder") do - require_relative "cap/linux/sshfs_mount" + require_relative "cap/guest/linux/sshfs_mount" VagrantPlugins::GuestLinux::Cap::MountSSHFS end guest_capability("linux", "sshfs_unmount_folder") do - require_relative "cap/linux/sshfs_mount" + require_relative "cap/guest/linux/sshfs_mount" VagrantPlugins::GuestLinux::Cap::MountSSHFS end guest_capability("linux", "sshfs_is_folder_mounted") do - require_relative "cap/linux/sshfs_mount" + require_relative "cap/guest/linux/sshfs_mount" VagrantPlugins::GuestLinux::Cap::MountSSHFS end guest_capability("redhat", "sshfs_installed") do - require_relative "cap/redhat/sshfs_client" + require_relative "cap/guest/redhat/sshfs_client" VagrantPlugins::GuestRedHat::Cap::SSHFSClient end guest_capability("redhat", "sshfs_install") do - require_relative "cap/redhat/sshfs_client" + require_relative "cap/guest/redhat/sshfs_client" VagrantPlugins::GuestRedHat::Cap::SSHFSClient end guest_capability("fedora", "sshfs_installed") do - require_relative "cap/fedora/sshfs_client" + require_relative "cap/guest/fedora/sshfs_client" VagrantPlugins::GuestFedora::Cap::SSHFSClient end guest_capability("fedora", "sshfs_install") do - require_relative "cap/fedora/sshfs_client" + require_relative "cap/guest/fedora/sshfs_client" VagrantPlugins::GuestFedora::Cap::SSHFSClient end guest_capability("debian", "sshfs_installed") do - require_relative "cap/debian/sshfs_client" + require_relative "cap/guest/debian/sshfs_client" VagrantPlugins::GuestDebian::Cap::SSHFSClient end guest_capability("debian", "sshfs_install") do - require_relative "cap/debian/sshfs_client" + require_relative "cap/guest/debian/sshfs_client" VagrantPlugins::GuestDebian::Cap::SSHFSClient end guest_capability("arch", "sshfs_installed") do - require_relative "cap/arch/sshfs_client" + require_relative "cap/guest/arch/sshfs_client" VagrantPlugins::GuestArch::Cap::SSHFSClient end guest_capability("arch", "sshfs_install") do - require_relative "cap/arch/sshfs_client" + require_relative "cap/guest/arch/sshfs_client" VagrantPlugins::GuestArch::Cap::SSHFSClient end guest_capability("suse", "sshfs_installed") do - require_relative "cap/suse/sshfs_client" + require_relative "cap/guest/suse/sshfs_client" VagrantPlugins::GuestSUSE::Cap::SSHFSClient end guest_capability("suse", "sshfs_install") do - require_relative "cap/suse/sshfs_client" + require_relative "cap/guest/suse/sshfs_client" VagrantPlugins::GuestSUSE::Cap::SSHFSClient end From 9caebaa856c8a404d1fb04851840c857ad4cef5f Mon Sep 17 00:00:00 2001 From: Dusty Mabe Date: Wed, 27 Jul 2016 16:25:34 -0400 Subject: [PATCH 2/9] sshfs_mount: rename to sshfs_forward_mount In preparation for adding reverse mounting capabilities we'll rename all existing functions to be known as "forward mounting" where: - reverse: mounting guest directory onto the host - forward: mounting host direcotry into the guest Forward mounting is how vagrant-sshfs acts today and is the most common use case. --- lib/vagrant-sshfs/cap/guest/linux/sshfs_mount.rb | 6 +++--- lib/vagrant-sshfs/plugin.rb | 6 +++--- lib/vagrant-sshfs/synced_folder.rb | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/vagrant-sshfs/cap/guest/linux/sshfs_mount.rb b/lib/vagrant-sshfs/cap/guest/linux/sshfs_mount.rb index 2bd28ad..a2d0362 100644 --- a/lib/vagrant-sshfs/cap/guest/linux/sshfs_mount.rb +++ b/lib/vagrant-sshfs/cap/guest/linux/sshfs_mount.rb @@ -16,7 +16,7 @@ class MountSSHFS extend Vagrant::Util::Retryable @@logger = Log4r::Logger.new("vagrant::synced_folders::sshfs_mount") - def self.sshfs_is_folder_mounted(machine, opts) + def self.sshfs_forward_is_folder_mounted(machine, opts) mounted = false # expand the guest path so we can handle things like "~/vagrant" expanded_guest_path = machine.guest.capability( @@ -34,7 +34,7 @@ def self.sshfs_is_folder_mounted(machine, opts) return mounted end - def self.sshfs_mount_folder(machine, opts) + def self.sshfs_forward_mount_folder(machine, opts) # opts contains something like: # { :type=>:sshfs, # :guestpath=>"/sharedfolder", @@ -76,7 +76,7 @@ def self.sshfs_mount_folder(machine, opts) end end - def self.sshfs_unmount_folder(machine, opts) + def self.sshfs_forward_unmount_folder(machine, opts) # opts contains something like: # { :type=>:sshfs, # :guestpath=>"/sharedfolder", diff --git a/lib/vagrant-sshfs/plugin.rb b/lib/vagrant-sshfs/plugin.rb index 4f0e854..76eb8de 100644 --- a/lib/vagrant-sshfs/plugin.rb +++ b/lib/vagrant-sshfs/plugin.rb @@ -20,17 +20,17 @@ class Plugin < Vagrant.plugin("2") Command::SSHFS end - guest_capability("linux", "sshfs_mount_folder") do + guest_capability("linux", "sshfs_forward_mount_folder") do require_relative "cap/guest/linux/sshfs_mount" VagrantPlugins::GuestLinux::Cap::MountSSHFS end - guest_capability("linux", "sshfs_unmount_folder") do + guest_capability("linux", "sshfs_forward_unmount_folder") do require_relative "cap/guest/linux/sshfs_mount" VagrantPlugins::GuestLinux::Cap::MountSSHFS end - guest_capability("linux", "sshfs_is_folder_mounted") do + guest_capability("linux", "sshfs_forward_is_folder_mounted") do require_relative "cap/guest/linux/sshfs_mount" VagrantPlugins::GuestLinux::Cap::MountSSHFS end diff --git a/lib/vagrant-sshfs/synced_folder.rb b/lib/vagrant-sshfs/synced_folder.rb index aae2aa4..f0918f7 100644 --- a/lib/vagrant-sshfs/synced_folder.rb +++ b/lib/vagrant-sshfs/synced_folder.rb @@ -51,7 +51,7 @@ def enable(machine, folders, pluginopts) folders.each do |id, opts| # If already mounted then there is nothing to do - if machine.guest.capability(:sshfs_is_folder_mounted, opts) + if machine.guest.capability(:sshfs_forward_is_folder_mounted, opts) machine.ui.info( I18n.t("vagrant.sshfs.info.already_mounted", folder: opts[:guestpath])) @@ -75,7 +75,7 @@ def enable(machine, folders, pluginopts) end # Do the mount machine.ui.info(I18n.t("vagrant.sshfs.actions.mounting")) - machine.guest.capability(:sshfs_mount_folder, opts) + machine.guest.capability(:sshfs_forward_mount_folder, opts) end end @@ -95,7 +95,7 @@ def disable(machine, folders, opts) folders.each do |id, opts| # If not mounted then there is nothing to do - if ! machine.guest.capability(:sshfs_is_folder_mounted, opts) + if ! machine.guest.capability(:sshfs_forward_is_folder_mounted, opts) machine.ui.info( I18n.t("vagrant.sshfs.info.not_mounted", folder: opts[:guestpath])) @@ -104,7 +104,7 @@ def disable(machine, folders, opts) # Do the Unmount machine.ui.info(I18n.t("vagrant.sshfs.actions.unmounting")) - machine.guest.capability(:sshfs_unmount_folder, opts) + machine.guest.capability(:sshfs_forward_unmount_folder, opts) end end From 02935a63583890d10622cf64bb21c0cea3b24055 Mon Sep 17 00:00:00 2001 From: Dusty Mabe Date: Wed, 27 Jul 2016 16:30:34 -0400 Subject: [PATCH 3/9] sshfs_forward_mount: rename to sshfs_forward_mount.rb --- .../guest/linux/{sshfs_mount.rb => sshfs_forward_mount.rb} | 0 lib/vagrant-sshfs/plugin.rb | 6 +++--- 2 files changed, 3 insertions(+), 3 deletions(-) rename lib/vagrant-sshfs/cap/guest/linux/{sshfs_mount.rb => sshfs_forward_mount.rb} (100%) diff --git a/lib/vagrant-sshfs/cap/guest/linux/sshfs_mount.rb b/lib/vagrant-sshfs/cap/guest/linux/sshfs_forward_mount.rb similarity index 100% rename from lib/vagrant-sshfs/cap/guest/linux/sshfs_mount.rb rename to lib/vagrant-sshfs/cap/guest/linux/sshfs_forward_mount.rb diff --git a/lib/vagrant-sshfs/plugin.rb b/lib/vagrant-sshfs/plugin.rb index 76eb8de..5b379e8 100644 --- a/lib/vagrant-sshfs/plugin.rb +++ b/lib/vagrant-sshfs/plugin.rb @@ -21,17 +21,17 @@ class Plugin < Vagrant.plugin("2") end guest_capability("linux", "sshfs_forward_mount_folder") do - require_relative "cap/guest/linux/sshfs_mount" + require_relative "cap/guest/linux/sshfs_forward_mount" VagrantPlugins::GuestLinux::Cap::MountSSHFS end guest_capability("linux", "sshfs_forward_unmount_folder") do - require_relative "cap/guest/linux/sshfs_mount" + require_relative "cap/guest/linux/sshfs_forward_mount" VagrantPlugins::GuestLinux::Cap::MountSSHFS end guest_capability("linux", "sshfs_forward_is_folder_mounted") do - require_relative "cap/guest/linux/sshfs_mount" + require_relative "cap/guest/linux/sshfs_forward_mount" VagrantPlugins::GuestLinux::Cap::MountSSHFS end From a90efa55a145959e79001fa343932358ce80227e Mon Sep 17 00:00:00 2001 From: Dusty Mabe Date: Wed, 27 Jul 2016 18:06:51 -0400 Subject: [PATCH 4/9] sshfs_forward_mount: fix typo --- lib/vagrant-sshfs/cap/guest/linux/sshfs_forward_mount.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/vagrant-sshfs/cap/guest/linux/sshfs_forward_mount.rb b/lib/vagrant-sshfs/cap/guest/linux/sshfs_forward_mount.rb index a2d0362..98fd6f2 100644 --- a/lib/vagrant-sshfs/cap/guest/linux/sshfs_forward_mount.rb +++ b/lib/vagrant-sshfs/cap/guest/linux/sshfs_forward_mount.rb @@ -199,7 +199,7 @@ def self.sshfs_slave_mount(machine, opts, hostpath, expanded_guest_path) mounted = false for i in 0..6 machine.ui.info("Checking Mount..") - if self.sshfs_is_folder_mounted(machine, opts) + if self.sshfs_forward_is_folder_mounted(machine, opts) mounted = true break end From 5e598853293fa5e11d98cd7314404334949fd1ca Mon Sep 17 00:00:00 2001 From: Dusty Mabe Date: Wed, 27 Jul 2016 18:11:57 -0400 Subject: [PATCH 5/9] synced_folder: factor out forward mount functions Put them in their own file to make way for us doing the same thing with reverse mount functions. --- lib/vagrant-sshfs/synced_folder.rb | 100 +-------------- .../synced_folder/sshfs_forward_mount.rb | 116 ++++++++++++++++++ 2 files changed, 120 insertions(+), 96 deletions(-) create mode 100644 lib/vagrant-sshfs/synced_folder/sshfs_forward_mount.rb diff --git a/lib/vagrant-sshfs/synced_folder.rb b/lib/vagrant-sshfs/synced_folder.rb index f0918f7..503cbce 100644 --- a/lib/vagrant-sshfs/synced_folder.rb +++ b/lib/vagrant-sshfs/synced_folder.rb @@ -3,6 +3,8 @@ require "vagrant/util/platform" require "vagrant/util/which" +require_relative "synced_folder/sshfs_forward_mount" + module VagrantPlugins module SyncedFolderSSHFS class SyncedFolder < Vagrant.plugin("2", :synced_folder) @@ -35,47 +37,9 @@ def usable?(machine, raise_error=false) # No return value. def enable(machine, folders, pluginopts) - # Check to see if sshfs software is in the guest - if machine.guest.capability?(:sshfs_installed) - if !machine.guest.capability(:sshfs_installed) - can_install = machine.guest.capability?(:sshfs_install) - if !can_install - raise VagrantPlugins::SyncedFolderSSHFS::Errors::SSHFSNotInstalledInGuest - end - machine.ui.info(I18n.t("vagrant.sshfs.actions.installing")) - machine.guest.capability(:sshfs_install) - end - end - # Iterate through the folders and mount if needed folders.each do |id, opts| - - # If already mounted then there is nothing to do - if machine.guest.capability(:sshfs_forward_is_folder_mounted, opts) - machine.ui.info( - I18n.t("vagrant.sshfs.info.already_mounted", - folder: opts[:guestpath])) - next - end - - # If the synced folder entry has host information in it then - # assume we are doing a normal sshfs mount to a host that isn't - # the machine running vagrant. Rely on password/ssh keys. - # - # If not, then we are doing a slave mount and we need to - # make sure we can find the sftp-server and ssh execuatable - # files on the host. - if opts.has_key?(:ssh_host) and opts[:ssh_host] - # Check port information and find out auth info - check_host_port(machine, opts) - get_auth_info(machine, opts) - else - opts[:ssh_exe_path] = find_executable('ssh') - opts[:sftp_server_exe_path] = find_executable('sftp-server') - end - # Do the mount - machine.ui.info(I18n.t("vagrant.sshfs.actions.mounting")) - machine.guest.capability(:sshfs_forward_mount_folder, opts) + do_forward_mount(machine, opts) end end @@ -93,18 +57,7 @@ def disable(machine, folders, opts) # Iterate through the folders and mount if needed folders.each do |id, opts| - - # If not mounted then there is nothing to do - if ! machine.guest.capability(:sshfs_forward_is_folder_mounted, opts) - machine.ui.info( - I18n.t("vagrant.sshfs.info.not_mounted", - folder: opts[:guestpath])) - next - end - - # Do the Unmount - machine.ui.info(I18n.t("vagrant.sshfs.actions.unmounting")) - machine.guest.capability(:sshfs_forward_unmount_folder, opts) + do_forward_unmount(machine, opts) end end @@ -121,51 +74,6 @@ def cleanup(machine, opts) protected - # Check if port information was provided in the options. If not, - # then default to port 22 for ssh - def check_host_port(machine, opts) - if not opts.has_key?(:ssh_port) or not opts[:ssh_port] - opts[:ssh_port] = '22' - end - end - - # Function to gather authentication information (username/password) - # for doing a normal sshfs mount - def get_auth_info(machine, opts) - prompt_for_password = false - ssh_info = machine.ssh_info - - # Detect the username of the current user - username = `whoami`.strip - - # If no username provided then default to the current - # user that is executing vagrant - if not opts.has_key?(:ssh_username) or not opts[:ssh_username] - opts[:ssh_username] = username - end - - # Check to see if we need to prompt the user for a password. - # We will prompt if: - # - User asked us to via prompt_for_password option - # - User did not provide a password in options and is not fwding ssh agent - # - if opts.has_key?(:prompt_for_password) and opts[:prompt_for_password] - prompt_for_password = opts[:prompt_for_password] - end - if not opts.has_key?(:ssh_password) or not opts[:ssh_password] - if not ssh_info.has_key?(:forward_agent) or not ssh_info[:forward_agent] - prompt_for_password = true - end - end - - # Now do the prompt - if prompt_for_password - opts[:ssh_password] = machine.ui.ask( - I18n.t("vagrant.sshfs.ask.prompt_for_password", username: opts[:ssh_username]), - echo: false) - end - end - # Function to find the path to an executable with name "name" def find_executable(name) error_class = VagrantPlugins::SyncedFolderSSHFS::Errors::SSHFSExeNotAvailable diff --git a/lib/vagrant-sshfs/synced_folder/sshfs_forward_mount.rb b/lib/vagrant-sshfs/synced_folder/sshfs_forward_mount.rb new file mode 100644 index 0000000..8e83d6e --- /dev/null +++ b/lib/vagrant-sshfs/synced_folder/sshfs_forward_mount.rb @@ -0,0 +1,116 @@ +require "log4r" + +require "vagrant/util/platform" +require "vagrant/util/which" + +module VagrantPlugins + module SyncedFolderSSHFS + class SyncedFolder < Vagrant.plugin("2", :synced_folder) + + protected + + # Do a forward mount: mounting host folder into the guest + def do_forward_mount(machine, opts) + + # Check to see if sshfs software is in the guest + if machine.guest.capability?(:sshfs_installed) + if !machine.guest.capability(:sshfs_installed) + can_install = machine.guest.capability?(:sshfs_install) + if !can_install + raise VagrantPlugins::SyncedFolderSSHFS::Errors::SSHFSNotInstalledInGuest + end + machine.ui.info(I18n.t("vagrant.sshfs.actions.installing")) + machine.guest.capability(:sshfs_install) + end + end + + # If already mounted then there is nothing to do + if machine.guest.capability(:sshfs_forward_is_folder_mounted, opts) + machine.ui.info( + I18n.t("vagrant.sshfs.info.already_mounted", + folder: opts[:guestpath])) + return + end + + # If the synced folder entry has host information in it then + # assume we are doing a normal sshfs mount to a host that isn't + # the machine running vagrant. Rely on password/ssh keys. + # + # If not, then we are doing a slave mount and we need to + # make sure we can find the sftp-server and ssh execuatable + # files on the host. + if opts.has_key?(:ssh_host) and opts[:ssh_host] + # Check port information and find out auth info + check_host_port(machine, opts) + get_auth_info(machine, opts) + else + opts[:ssh_exe_path] = find_executable('ssh') + opts[:sftp_server_exe_path] = find_executable('sftp-server') + end + # Do the mount + machine.ui.info(I18n.t("vagrant.sshfs.actions.mounting")) + machine.guest.capability(:sshfs_forward_mount_folder, opts) + end + + def do_forward_unmount(machine, opts) + + # If not mounted then there is nothing to do + if ! machine.guest.capability(:sshfs_forward_is_folder_mounted, opts) + machine.ui.info( + I18n.t("vagrant.sshfs.info.not_mounted", + folder: opts[:guestpath])) + return + end + + # Do the Unmount + machine.ui.info(I18n.t("vagrant.sshfs.actions.unmounting")) + machine.guest.capability(:sshfs_forward_unmount_folder, opts) + end + + # Check if port information was provided in the options. If not, + # then default to port 22 for ssh + def check_host_port(machine, opts) + if not opts.has_key?(:ssh_port) or not opts[:ssh_port] + opts[:ssh_port] = '22' + end + end + + # Function to gather authentication information (username/password) + # for doing a normal sshfs mount + def get_auth_info(machine, opts) + prompt_for_password = false + ssh_info = machine.ssh_info + + # Detect the username of the current user + username = `whoami`.strip + + # If no username provided then default to the current + # user that is executing vagrant + if not opts.has_key?(:ssh_username) or not opts[:ssh_username] + opts[:ssh_username] = username + end + + # Check to see if we need to prompt the user for a password. + # We will prompt if: + # - User asked us to via prompt_for_password option + # - User did not provide a password in options and is not fwding ssh agent + # + if opts.has_key?(:prompt_for_password) and opts[:prompt_for_password] + prompt_for_password = opts[:prompt_for_password] + end + if not opts.has_key?(:ssh_password) or not opts[:ssh_password] + if not ssh_info.has_key?(:forward_agent) or not ssh_info[:forward_agent] + prompt_for_password = true + end + end + + # Now do the prompt + if prompt_for_password + opts[:ssh_password] = machine.ui.ask( + I18n.t("vagrant.sshfs.ask.prompt_for_password", username: opts[:ssh_username]), + echo: false) + end + end + end + end +end From bbe97da109b05cb8b93914f348114d8492e86976 Mon Sep 17 00:00:00 2001 From: Dusty Mabe Date: Thu, 28 Jul 2016 12:24:46 -0400 Subject: [PATCH 6/9] sshfs_reverse_mount: support for mounting guest folder into the host This should fix #7. --- .../cap/host/linux/sshfs_reverse_mount.rb | 176 ++++++++++++++++++ lib/vagrant-sshfs/errors.rb | 4 + lib/vagrant-sshfs/plugin.rb | 15 ++ lib/vagrant-sshfs/synced_folder.rb | 14 +- .../synced_folder/sshfs_forward_mount.rb | 4 +- .../synced_folder/sshfs_reverse_mount.rb | 51 +++++ locales/synced_folder_sshfs.yml | 15 +- 7 files changed, 273 insertions(+), 6 deletions(-) create mode 100644 lib/vagrant-sshfs/cap/host/linux/sshfs_reverse_mount.rb create mode 100644 lib/vagrant-sshfs/synced_folder/sshfs_reverse_mount.rb diff --git a/lib/vagrant-sshfs/cap/host/linux/sshfs_reverse_mount.rb b/lib/vagrant-sshfs/cap/host/linux/sshfs_reverse_mount.rb new file mode 100644 index 0000000..2aa5b23 --- /dev/null +++ b/lib/vagrant-sshfs/cap/host/linux/sshfs_reverse_mount.rb @@ -0,0 +1,176 @@ +require "log4r" +require "vagrant/util/retryable" +require "tempfile" + +# This is already done for us in lib/vagrant-sshfs.rb. We needed to +# do it there before Process.uid is called the first time by Vagrant +# This provides a new Process.create() that works on Windows. +if Vagrant::Util::Platform.windows? + require 'win32/process' +end + +module VagrantPlugins + module HostLinux + module Cap + class MountSSHFS + extend Vagrant::Util::Retryable + @@logger = Log4r::Logger.new("vagrant::synced_folders::sshfs_reverse_mount") + + def self.sshfs_reverse_is_folder_mounted(env, opts) + mounted = false + hostpath = opts[:hostpath].dup + hostpath.gsub!("'", "'\\\\''") + hostpath = hostpath.chomp('/') # remove trailing / if exists + cat_cmd = Vagrant::Util::Which.which('cat') + result = Vagrant::Util::Subprocess.execute(cat_cmd, '/proc/mounts') + mounts = File.open('/proc/mounts', 'r') + mounts.each_line do |line| + if line.split()[1] == hostpath + mounted = true + break + end + end + return mounted + end + + def self.sshfs_reverse_mount_folder(env, machine, opts) + # opts contains something like: + # { :type=>:sshfs, + # :guestpath=>"/sharedfolder", + # :hostpath=>"/guests/sharedfolder", + # :disabled=>false + # :ssh_host=>"192.168.1.1" + # :ssh_port=>"22" + # :ssh_username=>"username" + # :ssh_password=>"password" + # } + self.sshfs_mount(machine, opts) + end + + def self.sshfs_reverse_unmount_folder(env, machine, opts) + self.sshfs_unmount(machine, opts) + end + + protected + + # Perform a mount by running an sftp-server on the vagrant host + # and piping stdin/stdout to sshfs running inside the guest + def self.sshfs_mount(machine, opts) + + sshfs_path = Vagrant::Util::Which.which('sshfs') + + # expand the guest path so we can handle things like "~/vagrant" + expanded_guest_path = machine.guest.capability( + :shell_expand_guest_path, opts[:guestpath]) + + # Mount path information + hostpath = opts[:hostpath].dup + hostpath.gsub!("'", "'\\\\''") + + # Add in some sshfs/fuse options that are common to both mount methods + opts[:sshfs_opts] = ' -o noauto_cache '# disable caching based on mtime + + # Add in some ssh options that are common to both mount methods + opts[:ssh_opts] = ' -o StrictHostKeyChecking=no '# prevent yes/no question + opts[:ssh_opts]+= ' -o ServerAliveInterval=30 ' # send keepalives + + # SSH connection options + ssh_opts = opts[:ssh_opts] + ssh_opts+= ' -o Port=' + machine.ssh_info[:port].to_s + ssh_opts+= ' -o IdentityFile=' + machine.ssh_info[:private_key_path][0] + ssh_opts+= ' -o UserKnownHostsFile=/dev/null ' + ssh_opts+= ' -F /dev/null ' # Don't pick up options from user's config + + ssh_opts_append = opts[:ssh_opts_append].to_s # provided by user + + # SSHFS executable options + sshfs_opts = opts[:sshfs_opts] + sshfs_opts_append = opts[:sshfs_opts_append].to_s # provided by user + + username = machine.ssh_info[:username] + host = machine.ssh_info[:host] + + + # The sshfs command to mount the guest directory on the host + sshfs_cmd = "#{sshfs_path} #{ssh_opts} #{ssh_opts_append} " + sshfs_cmd+= "#{sshfs_opts} #{sshfs_opts_append} " + sshfs_cmd+= "#{username}@#{host}:#{expanded_guest_path} #{hostpath}" + + # Log some information + @@logger.debug("sshfs cmd: #{sshfs_cmd}") + + machine.ui.info(I18n.t("vagrant.sshfs.actions.reverse_mounting_folder", + hostpath: hostpath, guestpath: expanded_guest_path)) + + # Log STDERR to predictable files so that we can inspect them + # later in case things go wrong. We'll use the machines data + # directory (i.e. .vagrant/machines/default/virtualbox/) for this + f1path = machine.data_dir.join('vagrant_sshfs_sshfs_stderr.txt') + f1 = File.new(f1path, 'w+') + + # Launch sshfs command to mount guest dir into the host + if Vagrant::Util::Platform.windows? + # Need to handle Windows differently. Kernel.spawn fails to work, + # if the shell creating the process is closed. + # See https://github.com/dustymabe/vagrant-sshfs/issues/31 + Process.create(:command_line => ssh_cmd, + :creation_flags => Process::DETACHED_PROCESS, + :process_inherit => false, + :thread_inherit => true, + :startup_info => {:stdin => w2, :stdout => r1, :stderr => f1}) + else + p1 = spawn(sshfs_cmd, :out => f1, :err => f1, :pgroup => true) + Process.detach(p1) # Detach so process will keep running + end + + # Check that the mount made it + mounted = false + for i in 0..6 + machine.ui.info("Checking Mount..") + if self.sshfs_reverse_is_folder_mounted(machine, opts) + mounted = true + break + end + sleep(2) + end + if !mounted + f1.rewind # Seek to beginning of the file + error_class = VagrantPlugins::SyncedFolderSSHFS::Errors::SSHFSReverseMountFailed + raise error_class, sshfs_output: f1.read + end + machine.ui.info("Folder Successfully Mounted!") + end + + def self.sshfs_unmount(machine, opts) + # opts contains something like: + # { :type=>:sshfs, + # :guestpath=>"/sharedfolder", + # :hostpath=>"/guests/sharedfolder", + # :disabled=>false + # :ssh_host=>"192.168.1.1" + # :ssh_port=>"22" + # :ssh_username=>"username" + # :ssh_password=>"password" + # } + + # Mount path information + hostpath = opts[:hostpath].dup + hostpath.gsub!("'", "'\\\\''") + + # Log some information + machine.ui.info(I18n.t("vagrant.sshfs.actions.reverse_unmounting_folder", + hostpath: hostpath)) + + # Build up the command and connect + error_class = VagrantPlugins::SyncedFolderSSHFS::Errors::SSHFSUnmountFailed + fusermount_cmd = Vagrant::Util::Which.which('fusermount') + cmd = "#{fusermount_cmd} -u #{hostpath}" + result = Vagrant::Util::Subprocess.execute(*cmd.split()) + if result.exit_code != 0 + raise error_class, command: cmd, stdout: result.stdout, stderr: result.stderr + end + end + end + end + end +end diff --git a/lib/vagrant-sshfs/errors.rb b/lib/vagrant-sshfs/errors.rb index d28d303..e9c7964 100644 --- a/lib/vagrant-sshfs/errors.rb +++ b/lib/vagrant-sshfs/errors.rb @@ -14,6 +14,10 @@ class SSHFSSlaveMountFailed < SSHFSError error_key(:slave_mount_failed) end + class SSHFSReverseMountFailed < SSHFSError + error_key(:reverse_mount_failed) + end + class SSHFSUnmountFailed < SSHFSError error_key(:unmount_failed) end diff --git a/lib/vagrant-sshfs/plugin.rb b/lib/vagrant-sshfs/plugin.rb index 5b379e8..0e98b5b 100644 --- a/lib/vagrant-sshfs/plugin.rb +++ b/lib/vagrant-sshfs/plugin.rb @@ -20,6 +20,21 @@ class Plugin < Vagrant.plugin("2") Command::SSHFS end + host_capability("linux", "sshfs_reverse_mount_folder") do + require_relative "cap/host/linux/sshfs_reverse_mount" + VagrantPlugins::HostLinux::Cap::MountSSHFS + end + + host_capability("linux", "sshfs_reverse_unmount_folder") do + require_relative "cap/host/linux/sshfs_reverse_mount" + VagrantPlugins::HostLinux::Cap::MountSSHFS + end + + host_capability("linux", "sshfs_reverse_is_folder_mounted") do + require_relative "cap/host/linux/sshfs_reverse_mount" + VagrantPlugins::HostLinux::Cap::MountSSHFS + end + guest_capability("linux", "sshfs_forward_mount_folder") do require_relative "cap/guest/linux/sshfs_forward_mount" VagrantPlugins::GuestLinux::Cap::MountSSHFS diff --git a/lib/vagrant-sshfs/synced_folder.rb b/lib/vagrant-sshfs/synced_folder.rb index 503cbce..b12f5cd 100644 --- a/lib/vagrant-sshfs/synced_folder.rb +++ b/lib/vagrant-sshfs/synced_folder.rb @@ -4,6 +4,7 @@ require "vagrant/util/which" require_relative "synced_folder/sshfs_forward_mount" +require_relative "synced_folder/sshfs_reverse_mount" module VagrantPlugins module SyncedFolderSSHFS @@ -39,7 +40,12 @@ def enable(machine, folders, pluginopts) # Iterate through the folders and mount if needed folders.each do |id, opts| - do_forward_mount(machine, opts) + + if opts.has_key?(:reverse) and opts[:reverse] + do_reverse_mount(machine, opts) + else + do_forward_mount(machine, opts) + end end end @@ -57,7 +63,11 @@ def disable(machine, folders, opts) # Iterate through the folders and mount if needed folders.each do |id, opts| - do_forward_unmount(machine, opts) + if opts.has_key?(:reverse) and opts[:reverse] + do_reverse_unmount(machine, opts) + else + do_forward_unmount(machine, opts) + end end end diff --git a/lib/vagrant-sshfs/synced_folder/sshfs_forward_mount.rb b/lib/vagrant-sshfs/synced_folder/sshfs_forward_mount.rb index 8e83d6e..a495878 100644 --- a/lib/vagrant-sshfs/synced_folder/sshfs_forward_mount.rb +++ b/lib/vagrant-sshfs/synced_folder/sshfs_forward_mount.rb @@ -28,7 +28,7 @@ def do_forward_mount(machine, opts) if machine.guest.capability(:sshfs_forward_is_folder_mounted, opts) machine.ui.info( I18n.t("vagrant.sshfs.info.already_mounted", - folder: opts[:guestpath])) + location: 'guest', folder: opts[:guestpath])) return end @@ -58,7 +58,7 @@ def do_forward_unmount(machine, opts) if ! machine.guest.capability(:sshfs_forward_is_folder_mounted, opts) machine.ui.info( I18n.t("vagrant.sshfs.info.not_mounted", - folder: opts[:guestpath])) + location: 'guest', folder: opts[:guestpath])) return end diff --git a/lib/vagrant-sshfs/synced_folder/sshfs_reverse_mount.rb b/lib/vagrant-sshfs/synced_folder/sshfs_reverse_mount.rb new file mode 100644 index 0000000..0f19f9c --- /dev/null +++ b/lib/vagrant-sshfs/synced_folder/sshfs_reverse_mount.rb @@ -0,0 +1,51 @@ +require "log4r" + +require "vagrant/util/platform" +require "vagrant/util/which" + +module VagrantPlugins + module SyncedFolderSSHFS + class SyncedFolder < Vagrant.plugin("2", :synced_folder) + + protected + + # Do a reverse mount: mounting guest folder onto the host + def do_reverse_mount(machine, opts) + + # Check to see if sshfs software is in the host + if machine.env.host.capability?(:sshfs_installed) + if !machine.env.host.capability(:sshfs_installed) + raise VagrantPlugins::SyncedFolderSSHFS::Errors::SSHFSNotInstalledInHost + end + end + + # If already mounted then there is nothing to do + if machine.env.host.capability(:sshfs_reverse_is_folder_mounted, opts) + machine.ui.info( + I18n.t("vagrant.sshfs.info.already_mounted", + location: 'host', folder: opts[:hostpath])) + return + end + + # Do the mount + machine.ui.info(I18n.t("vagrant.sshfs.actions.mounting")) + machine.env.host.capability(:sshfs_reverse_mount_folder, machine, opts) + end + + def do_reverse_unmount(machine, opts) + + # If not mounted then there is nothing to do + if ! machine.env.host.capability(:sshfs_reverse_is_folder_mounted, opts) + machine.ui.info( + I18n.t("vagrant.sshfs.info.not_mounted", + location: 'host', folder: opts[:hostpath])) + return + end + + # Do the Unmount + machine.ui.info(I18n.t("vagrant.sshfs.actions.unmounting")) + machine.env.host.capability(:sshfs_reverse_unmount_folder, machine, opts) + end + end + end +end diff --git a/locales/synced_folder_sshfs.yml b/locales/synced_folder_sshfs.yml index 0963bd7..7d6324b 100644 --- a/locales/synced_folder_sshfs.yml +++ b/locales/synced_folder_sshfs.yml @@ -7,6 +7,10 @@ en: unmounting: Unmounting SSHFS shared folder... unmounting_folder: |- Unmounting SSHFS shared folder mounted at %{guestpath} + reverse_unmounting_folder: |- + Unmounting SSHFS shared folder mounted at host's %{hostpath} + reverse_mounting_folder: |- + mounting folder via SSHFS: guestpath:%{guestpath} => hostpath:%{hostpath} slave_mounting_folder: |- Mounting folder via SSHFS: %{hostpath} => %{guestpath} normal_mounting_folder: |- @@ -18,9 +22,9 @@ en: detected_host_ip: |- Detected host IP address is '%{ip}' already_mounted: |- - The folder %{folder} in the guest already mounted. + The folder %{folder} in the %{location} is already mounted. not_mounted: |- - The folder %{folder} in the guest is not mounted. + The folder %{folder} in the %{location} is not mounted. errors: communicator_not_ready: |- The machine is reporting that it is not ready to communicate via ssh. Verify @@ -55,6 +59,13 @@ en: Stderr from the command: %{stderr} + reverse_mount_failed: |- + Mounting SSHFS shared folder via reverse SSHFS mount failed. Please + look at the below output from from the processes that were run. + + SSHFS command output: + + %{sshfs_output} slave_mount_failed: |- Mounting SSHFS shared folder via slave SSHFS mount failed. Please look at the below STDERR output from the processes that were run. From d3e4d8ec44c9e394af1b0e24976b7e61ea75e7df Mon Sep 17 00:00:00 2001 From: Dusty Mabe Date: Thu, 28 Jul 2016 12:27:04 -0400 Subject: [PATCH 7/9] Fix outdated comment. --- lib/vagrant-sshfs.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/vagrant-sshfs.rb b/lib/vagrant-sshfs.rb index bed4fe3..d52bf71 100644 --- a/lib/vagrant-sshfs.rb +++ b/lib/vagrant-sshfs.rb @@ -7,7 +7,7 @@ # Only load the gem on Windows since it replaces some methods in Ruby's # Process class. Also load it here before Process.uid is called the first # time by Vagrant. The Process.create() function actually gets used in -# lib/vagrant-sshfs/cap/linux/sshfs_mount.rb +# lib/vagrant-sshfs/cap/guest/linux/sshfs_forward_mount.rb if Vagrant::Util::Platform.windows? require 'win32/process' end From 0070b147d78ec3d10b2e07c103997cfe2eeb3803 Mon Sep 17 00:00:00 2001 From: Dusty Mabe Date: Thu, 28 Jul 2016 12:37:09 -0400 Subject: [PATCH 8/9] README: Update for new reverse mounting capability --- README.md | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index cc84266..105d1d9 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ folder plugin from the Vagrant core code and molding it to fit SSHFS. ## Modes of Operation -### Sharing Vagrant Host Directory to Vagrant Guest - 99% of users +### Sharing Vagrant Host Directory to Vagrant Guest - 98% of users This plugin uses SSHFS slave mounts (see [link](https://github.com/dustymabe/vagrant-sshfs/issues/11)) @@ -58,6 +58,19 @@ See [Options](#options-specific-to-arbitrary-host-mounting) and [Appendix A](#appendix-a-using-keys-and-forwarding-ssh-agent) for more information. +### Sharing Vagrant Guest Directory to Vagrant Host - 1% of users + +*NOTE:* This option is dangerous as data will be destroy upon `vagrant destroy` + +This plugin allows you to share a folder from a Vagrant guest into the +host. If you have workloads where there are a lot of disk intensive +operations (such as compilation) it may be ideal to have the files +live in the guest where the disk intensive operations would occur. +For discussion see [Issue #7](https://github.com/dustymabe/vagrant-sshfs/issues/7). + +See [Options](#options-specific-to-reverse-mounting-guest-host-mount) +for more information on how to enable this type of mount. + ## Getting Started In order to use this synced folder implementation perform the @@ -159,6 +172,23 @@ config.vm.synced_folder "/path/on/host", "/path/on/guest", disabled: false ``` +### Options Specific to Reverse Mounting (Guest->Host Mount) + +If your host has the `sshfs` software installed then the following +options enable mounting a folder from a Vagrant Guest into the +Vagrant Host: + +- `reverse` + - This can be set to 'true' to enable reverse mounting a guest + folder into the Vagrant host. + +An example snippet from a `Vagrantfile` where we want to mount `/data` +on the guest into `/guest/data` on the host: + +``` +config.vm.synced_folder "/guest/data", "/data", type: 'sshfs', reverse: true +``` + ## Appendix A: Using Keys and Forwarding SSH Agent When [sharing an arbitrary host directory](#sharing-arbitrary-host-directory-to-vagrant-guest---1-of-users) From 61ba845ec58b4e163460a0ac9451404c715ce6a2 Mon Sep 17 00:00:00 2001 From: Dusty Mabe Date: Thu, 28 Jul 2016 14:21:37 -0400 Subject: [PATCH 9/9] tests: add in a vagrantfile for testing normal/slave/reverse mounts. --- test/misc/README.txt | 29 +++++++++++++++++++++++++++++ test/misc/Vagrantfile | 27 +++++++++++++++++++++++++++ test/misc/dotests.sh | 13 +++++++++++++ 3 files changed, 69 insertions(+) create mode 100644 test/misc/README.txt create mode 100644 test/misc/Vagrantfile create mode 100644 test/misc/dotests.sh diff --git a/test/misc/README.txt b/test/misc/README.txt new file mode 100644 index 0000000..b716a22 --- /dev/null +++ b/test/misc/README.txt @@ -0,0 +1,29 @@ + +# This directory is for testing the three different mount modes +# that are supported by vagrant-sshfs + +# To test we will first create the directory on the machien where +# we will mount the guest /etc/ into the host (the reverse mount). + +mkdir /tmp/reverse_mount_etc + +# Next we will define where our 3rd party host is (the normal mount). +# This can be another vagrant box or whatever machine you want. +export THIRD_PARTY_HOST='192.168.121.73' +export THIRD_PARTY_HOST_USER='vagrant' +export THIRD_PARTY_HOST_PASS='vagrant' + +# Next vagrant up - will do 3 mounts (normal, slave, reverse). +vagrant up + +# Next run the script to test the mounts: +$ bash dotests.sh +Testing normal mount! +a57e39fa692f294e860349a9451be67c +Testing slave mount! +e2c4ceac71dc414cb3ed864cff04a917 +Testing reverse mount! +508619e7e68e446c84d1fcdf7e0dc577 + +# We are printing out the machine-id under each mount to prove each +# mount is from a different machine. diff --git a/test/misc/Vagrantfile b/test/misc/Vagrantfile new file mode 100644 index 0000000..f0ef39a --- /dev/null +++ b/test/misc/Vagrantfile @@ -0,0 +1,27 @@ +Vagrant.configure(2) do |config| + + config.ssh.insert_key = 'true' + + # Test a forward normal mount: + # mounting a folder from a 3rd party host into guest + config.vm.synced_folder "/etc/", "/tmp/forward_normal_mount_etc/", type: "sshfs", + ssh_host: ENV['THIRD_PARTY_HOST'], + ssh_username: ENV['THIRD_PARTY_HOST_USER'], + ssh_password: ENV['THIRD_PARTY_HOST_PASS'] + + # Test a forward slave mount: + # mounting /etc/ from the vagrant host into the guest + config.vm.synced_folder "/etc/", "/tmp/forward_slave_mount_etc/", type: "sshfs" + + # Test a reverse mount: + # mounting /etc/ from vagrant guest into vagrant host + config.vm.synced_folder "/tmp/reverse_mount_etc/", "/etc", type: "sshfs", reverse: true + + host = 'vagrant-sshfs-tests' + box = 'fedora/24-cloud-base' + + config.vm.define host do | tmp | + tmp.vm.hostname = host + tmp.vm.box = box + end +end diff --git a/test/misc/dotests.sh b/test/misc/dotests.sh new file mode 100644 index 0000000..ea6691d --- /dev/null +++ b/test/misc/dotests.sh @@ -0,0 +1,13 @@ +#!/bin/bash +set -eu + +# Test the three mounts we have done + +echo "Testing normal mount!" +vagrant ssh -- cat /tmp/forward_normal_mount_etc/machine-id + +echo "Testing slave mount!" +vagrant ssh -- cat /tmp/forward_slave_mount_etc/machine-id + +echo "Testing reverse mount!" +cat /tmp/reverse_mount_etc/machine-id