vagrant/lib/vagrant/action/vm/nfs.rb

190 lines
5.8 KiB
Ruby

require 'fileutils'
require 'pathname'
require 'log4r'
module Vagrant
module Action
module VM
# Enables NFS based shared folders. `nfsd` must already be installed
# on the host machine, and NFS client must already be installed on
# the guest machine.
#
# This is a two part process:
#
# 1. Adds an entry to `/etc/exports` on the host machine using
# the host class to export the proper folder to the proper
# machine.
# 2. After boot, runs `mount` on the guest to mount the shared
# folder.
#
class NFS
def initialize(app,env)
@logger = Log4r::Logger.new("vagrant::action::vm::nfs")
@app = app
@env = env
verify_settings if nfs_enabled?
end
def call(env)
@env = env
extract_folders
if !folders.empty?
prepare_folders
export_folders
end
@app.call(env)
mount_folders if !folders.empty?
end
# Returns the folders which are to be synced via NFS.
def folders
@folders ||= {}
end
# Removes the NFS enabled shared folders from the configuration,
# so they will no longer be mounted by the actual shared folder
# task.
def extract_folders
# Load the NFS enabled shared folders
@folders = {}
@env[:vm].config.vm.shared_folders.each do |key, opts|
if opts[:nfs]
# Duplicate the options, set the hostpath, and set disabled on the original
# options so the ShareFolders middleware doesn't try to mount it.
folder = opts.dup
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 Errors::SharedFolderCreateFailed, :path => hostpath.to_s
end
end
# Set the hostpath now that it exists.
folder[:hostpath] = hostpath.to_s
# Assign the folder to our instance variable for later use
@folders[key] = folder
# Disable the folder so that regular shared folders don't try to
# mount it.
opts[:disabled] = true
end
end
end
# Prepares the settings for the NFS folders, such as setting the
# options on the NFS folders.
def prepare_folders
@folders = @folders.inject({}) do |acc, data|
key, opts = data
opts[:map_uid] = prepare_permission(:uid, opts)
opts[:map_gid] = prepare_permission(:gid, opts)
opts[:version] ||= 3
acc[key] = opts
acc
end
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[:vm].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
# Uses the host class to export the folders via NFS. This typically
# involves adding a line to `/etc/exports` for this VM, but it is
# up to the host class to define the specific behavior.
def export_folders
@env[:ui].info I18n.t("vagrant.actions.vm.nfs.exporting")
@env[:host].nfs_export(@env[:vm].uuid, guest_ip, folders)
end
# Uses the system class to mount the NFS folders.
def mount_folders
@env[:ui].info I18n.t("vagrant.actions.vm.nfs.mounting")
# Only mount the folders which have a guest path specified
mount_folders = {}
folders.each do |name, opts|
if opts[:guestpath]
mount_folders[name] = opts.dup
end
end
@env[:vm].guest.mount_nfs(host_ip, mount_folders)
end
# Returns the IP address of the first host only network adapter
#
# @return [String]
def host_ip
@env[:vm].driver.read_network_interfaces.each do |adapter, opts|
if opts[:type] == :hostonly
@env[:vm].driver.read_host_only_interfaces.each do |interface|
if interface[:name] == opts[:hostonly]
return interface[:ip]
end
end
end
end
nil
end
# Returns the IP address of the guest by looking at the first
# enabled host only network.
#
# @return [String]
def guest_ip
@env[:vm].config.vm.networks.each do |type, args|
if type == :hostonly && args[0].is_a?(String)
return args[0]
end
end
nil
end
# Checks if there are any NFS enabled shared folders.
def nfs_enabled?
@env[:vm].config.vm.shared_folders.each do |key, opts|
return true if opts[:nfs]
end
false
end
# Verifies that the host is set and supports NFS.
def verify_settings
raise Errors::NFSHostRequired if @env[:host].nil?
raise Errors::NFSNotSupported if !@env[:host].nfs?
raise Errors::NFSNoHostNetwork if !guest_ip
end
end
end
end
end