diff --git a/lib/vagrant/action/builtin/nfs.rb b/lib/vagrant/action/builtin/nfs.rb deleted file mode 100644 index 3c77f6bc3..000000000 --- a/lib/vagrant/action/builtin/nfs.rb +++ /dev/null @@ -1,128 +0,0 @@ -require 'fileutils' -require 'pathname' -require 'zlib' - -require "log4r" - -require 'vagrant/util/platform' - -module Vagrant - module Action - module Builtin - # This built-in middleware exports and mounts NFS shared folders. - # - # To use this middleware, two configuration parameters must be given - # via the environment hash: - # - # - `:nfs_host_ip` - The IP of where to mount the NFS folder from. - # - `:nfs_machine_ip` - The IP of the machine where the NFS folder - # will be mounted. - # - class NFS - def initialize(app, env) - @app = app - @logger = Log4r::Logger.new("vagrant::action::builtin::nfs") - end - - def call(env) - # We forward things along first. We do everything on the tail - # end of the middleware call. - @app.call(env) - - # Used by prepare_permission, so we need to save it - @env = env - - folders = {} - env[:machine].config.vm.synced_folders.each do |id, opts| - # If this synced folder doesn't enable NFS, ignore it. - next if !opts[:nfs] - - # Expand the host path, create it if we have to and - # store away the folder. - hostpath = Pathname.new(opts[:hostpath]). - expand_path(env[:root_path]) - - if !hostpath.directory? && opts[:create] - # Host path doesn't exist, so let's create it. - @logger.debug("Host path doesn't exist, creating: #{hostpath}") - - begin - FileUtils.mkpath(hostpath) - rescue Errno::EACCES - raise Vagrant::Errors::SharedFolderCreateFailed, - :path => hostpath.to_s - end - end - - # Determine the real path by expanding symlinks and getting - # proper casing. We have to do this after creating it - # if it doesn't exist. - hostpath = hostpath.realpath - hostpath = Util::Platform.fs_real_path(hostpath) - - # Set the hostpath back on the options and save it - opts[:hostpath] = hostpath.to_s - folders[id] = opts - end - - if !folders.empty? - raise Errors::NFSNoHostIP if !env[:nfs_host_ip] - raise Errors::NFSNoGuestIP if !env[:nfs_machine_ip] - - machine_ip = env[:nfs_machine_ip] - machine_ip = [machine_ip] if !machine_ip.is_a?(Array) - - # Prepare the folder, this means setting up various options - # and such on the folder itself. - folders.each { |id, opts| prepare_folder(opts) } - - # Export the folders - env[:ui].info I18n.t("vagrant.actions.vm.nfs.exporting") - env[:host].nfs_export(env[:machine].id, machine_ip, folders) - - # Mount - env[:ui].info I18n.t("vagrant.actions.vm.nfs.mounting") - - # Only mount folders that have a guest path specified. - mount_folders = {} - folders.each do |id, opts| - mount_folders[id] = opts.dup if opts[:guestpath] - end - - # Mount them! - env[:machine].guest.capability( - :mount_nfs_folder, env[:nfs_host_ip], mount_folders) - end - end - - protected - - def prepare_folder(opts) - opts[:map_uid] = prepare_permission(:uid, opts) - opts[:map_gid] = prepare_permission(:gid, opts) - opts[:nfs_version] ||= 3 - - # We use a CRC32 to generate a 32-bit checksum so that the - # fsid is compatible with both old and new kernels. - opts[:uuid] = Zlib.crc32(opts[:hostpath]).to_s - end - - # Prepares the UID/GID settings for a single folder. - def prepare_permission(perm, opts) - key = "map_#{perm}".to_sym - return nil if opts.has_key?(key) && opts[key].nil? - - # The options on the hash get priority, then the default - # values - value = opts.has_key?(key) ? opts[key] : @env[:machine].config.nfs.send(key) - return value if value != :auto - - # Get UID/GID from folder if we've made it this far - # (value == :auto) - stat = File.stat(opts[:hostpath]) - return stat.send(perm) - end - end - end - end -end diff --git a/lib/vagrant/action/builtin/synced_folders.rb b/lib/vagrant/action/builtin/synced_folders.rb index 47f5b7782..d897c4633 100644 --- a/lib/vagrant/action/builtin/synced_folders.rb +++ b/lib/vagrant/action/builtin/synced_folders.rb @@ -1,5 +1,7 @@ require "log4r" +require 'vagrant/util/platform' + module Vagrant module Action module Builtin @@ -29,15 +31,20 @@ module Vagrant fs.each do |id, data| data[:hostpath] = File.expand_path(data[:hostpath], env[:root_path]) - # Don't do anything else if this directory exists or its - # not flagged to auto-create - next if File.directory?(data[:hostpath]) || !data[:create] - @logger.info("Creating shared folder host directory: #{data[:hostpath]}") - begin - Pathname.new(data[:hostpath]).mkpath - rescue Errno::EACCES - raise Vagrant::Errors::SharedFolderCreateFailed, - path: data[:hostpath] + # Create the hostpath if it doesn't exist and we've been told to + if !File.directory?(data[:hostpath]) && data[:create] + @logger.info("Creating shared folder host directory: #{data[:hostpath]}") + begin + Pathname.new(data[:hostpath]).mkpath + rescue Errno::EACCES + raise Vagrant::Errors::SharedFolderCreateFailed, + path: data[:hostpath] + end + end + + if File.directory?(data[:hostpath]) + data[:hostpath] = File.realpath(data[:hostpath]) + data[:hostpath] = Util::Platform.fs_real_path(data[:hostpath]) end end end diff --git a/lib/vagrant/plugin/v2/synced_folder.rb b/lib/vagrant/plugin/v2/synced_folder.rb index 691e49b45..6774882c8 100644 --- a/lib/vagrant/plugin/v2/synced_folder.rb +++ b/lib/vagrant/plugin/v2/synced_folder.rb @@ -6,10 +6,10 @@ module Vagrant def usable?(machine) end - def prepare(machine, folders) + def prepare(machine, folders, opts) end - def enable(machine, folders) + def enable(machine, folders, opts) end end end diff --git a/plugins/providers/virtualbox/synced_folder.rb b/plugins/providers/virtualbox/synced_folder.rb index 15149c01a..37dd3d527 100644 --- a/plugins/providers/virtualbox/synced_folder.rb +++ b/plugins/providers/virtualbox/synced_folder.rb @@ -8,7 +8,7 @@ module VagrantPlugins machine.provider_name == :virtualbox end - def prepare(machine, folders) + def prepare(machine, folders, _opts) defs = [] folders.each do |id, data| hostpath = Vagrant::Util::Platform.cygwin_windows_path(data[:hostpath]) @@ -23,7 +23,7 @@ module VagrantPlugins driver(machine).share_folders(defs) end - def enable(machine, folders) + def enable(machine, folders, _opts) # short guestpaths first, so we don't step on ourselves folders = folders.sort_by do |id, data| if data[:guestpath] diff --git a/plugins/synced_folders/nfs/plugin.rb b/plugins/synced_folders/nfs/plugin.rb new file mode 100644 index 000000000..131d043a1 --- /dev/null +++ b/plugins/synced_folders/nfs/plugin.rb @@ -0,0 +1,18 @@ +require "vagrant" + +module VagrantPlugins + module SyncedFolderNFS + class Plugin < Vagrant.plugin("2") + name "NFS synced folders" + description <<-EOF + The NFS synced folders plugin enables you to use NFS as a synced folder + implementation. + EOF + + synced_folder(:nfs, 5) do + require File.expand_path("../synced_folder", __FILE__) + SyncedFolder + end + end + end +end diff --git a/plugins/synced_folders/nfs/synced_folder.rb b/plugins/synced_folders/nfs/synced_folder.rb new file mode 100644 index 000000000..ec16c6a97 --- /dev/null +++ b/plugins/synced_folders/nfs/synced_folder.rb @@ -0,0 +1,83 @@ +require 'fileutils' +require 'zlib' + +require "vagrant/util/platform" + +module VagrantPlugins + module SyncedFolderNFS + # This synced folder requires that two keys be set on the environment + # within the middleware sequence: + # + # - `:nfs_host_ip` - The IP of where to mount the NFS folder from. + # - `:nfs_machine_ip` - The IP of the machine where the NFS folder + # will be mounted. + # + class SyncedFolder < Vagrant.plugin("2", :synced_folder) + def usable?(machine) + # NFS is always available + true + end + + def prepare(machine, folders, opts) + # Nothing is necessary to do before VM boot. + end + + def enable(machine, folders, nfsopts) + raise Errors::NFSNoHostIP if !nfsopts[:nfs_host_ip] + raise Errors::NFSNoGuestIP if !nfsopts[:nfs_machine_ip] + + machine_ip = nfsopts[:nfs_machine_ip] + machine_ip = [machine_ip] if !machine_ip.is_a?(Array) + + # Prepare the folder, this means setting up various options + # and such on the folder itself. + folders.each { |id, opts| prepare_folder(machine, opts) } + + # Export the folders + machine.ui.info I18n.t("vagrant.actions.vm.nfs.exporting") + machine.env.host.nfs_export(machine.id, machine_ip, folders) + + # Mount + machine.ui.info I18n.t("vagrant.actions.vm.nfs.mounting") + + # Only mount folders that have a guest path specified. + mount_folders = {} + folders.each do |id, opts| + mount_folders[id] = opts.dup if opts[:guestpath] + end + + # Mount them! + machine.guest.capability( + :mount_nfs_folder, nfsopts[:nfs_host_ip], mount_folders) + end + + protected + + def prepare_folder(machine, opts) + opts[:map_uid] = prepare_permission(machine, :uid, opts) + opts[:map_gid] = prepare_permission(machine, :gid, opts) + opts[:nfs_version] ||= 3 + + # We use a CRC32 to generate a 32-bit checksum so that the + # fsid is compatible with both old and new kernels. + opts[:uuid] = Zlib.crc32(opts[:hostpath]).to_s + end + + # Prepares the UID/GID settings for a single folder. + def prepare_permission(machine, perm, opts) + key = "map_#{perm}".to_sym + return nil if opts.has_key?(key) && opts[key].nil? + + # The options on the hash get priority, then the default + # values + value = opts.has_key?(key) ? opts[key] : machine.config.nfs.send(key) + return value if value != :auto + + # Get UID/GID from folder if we've made it this far + # (value == :auto) + stat = File.stat(opts[:hostpath]) + return stat.send(perm) + end + end + end +end