diff --git a/config/default.rb b/config/default.rb index e8c34c204..a5cb31f6c 100644 --- a/config/default.rb +++ b/config/default.rb @@ -35,6 +35,9 @@ Vagrant::Config.run do |config| config.unison.crontab_entry_file = "/tmp/vagrant-unison-crontab" config.unison.log_file = "/tmp/v-unison-log-%s" + config.nfs.map_uid = :auto + config.nfs.map_gid = :auto + # TODO fix these # config.vm.sync_opts = "-terse -group -owner -batch -silent" # config.vm.sync_script = "/tmp/sync" diff --git a/lib/vagrant/action/vm/nfs.rb b/lib/vagrant/action/vm/nfs.rb index 1f65e746c..30116a108 100644 --- a/lib/vagrant/action/vm/nfs.rb +++ b/lib/vagrant/action/vm/nfs.rb @@ -32,6 +32,7 @@ module Vagrant extract_folders if !folders.empty? + prepare_folders clear_nfs_exports(env) export_folders end @@ -73,6 +74,36 @@ module Vagrant 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[:nfs] = {} if !opts.is_a?(Hash) + opts[:map_uid] = prepare_permission(:uid, opts) + opts[:map_gid] = prepare_permission(:gid, opts) + + 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[key] || @env["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. diff --git a/lib/vagrant/config.rb b/lib/vagrant/config.rb index 0bfbc89e0..34d26c0bb 100644 --- a/lib/vagrant/config.rb +++ b/lib/vagrant/config.rb @@ -86,6 +86,11 @@ module Vagrant attr_accessor :log_file end + class NFSConfig < Base + attr_accessor :map_uid + attr_accessor :map_gid + end + class VMConfig < Base include Util::StackedProcRunner @@ -216,6 +221,7 @@ module Vagrant # Setup default configures configures :package, PackageConfig + configures :nfs, NFSConfig configures :ssh, SSHConfig configures :unison, UnisonConfig configures :vm, VMConfig diff --git a/templates/nfs/exports.erb b/templates/nfs/exports.erb index 026934636..e870e466c 100644 --- a/templates/nfs/exports.erb +++ b/templates/nfs/exports.erb @@ -1,3 +1,3 @@ # VAGRANT-BEGIN: <%= uuid %> -<% folders.each do |name, opts| %><%= opts[:hostpath] %> <%= ip %><% end %> +<% folders.each do |name, opts| %><%= opts[:hostpath] %> <%= ip %><% if opts[:map_uid] %> -mapall=<%= opts[:map_uid] %><% end %><% end %> # VAGRANT-END: <%= uuid %> \ No newline at end of file diff --git a/test/vagrant/action/vm/nfs_test.rb b/test/vagrant/action/vm/nfs_test.rb index 1bfc211ae..83609c939 100644 --- a/test/vagrant/action/vm/nfs_test.rb +++ b/test/vagrant/action/vm/nfs_test.rb @@ -37,7 +37,7 @@ class NFSVMActionTest < Test::Unit::TestCase setup do @instance.stubs(:folders).returns([:a]) - [:clear_nfs_exports, :extract_folders, :export_folders, :mount_folders].each do |meth| + [:clear_nfs_exports, :extract_folders, :prepare_folders, :export_folders, :mount_folders].each do |meth| @instance.stubs(meth) end end @@ -45,6 +45,7 @@ class NFSVMActionTest < Test::Unit::TestCase should "call the proper sequence and succeed" do seq = sequence('seq') @instance.expects(:extract_folders).in_sequence(seq) + @instance.expects(:prepare_folders).in_sequence(seq) @instance.expects(:clear_nfs_exports).with(@env).in_sequence(seq) @instance.expects(:export_folders).in_sequence(seq) @app.expects(:call).with(@env).in_sequence(seq) @@ -57,6 +58,7 @@ class NFSVMActionTest < Test::Unit::TestCase seq = sequence('seq') @instance.expects(:extract_folders).in_sequence(seq) + @instance.expects(:prepare_folders).never @instance.expects(:export_folders).never @instance.expects(:clear_nfs_exports).never @app.expects(:call).with(@env).in_sequence(seq) @@ -69,6 +71,7 @@ class NFSVMActionTest < Test::Unit::TestCase seq = sequence('seq') @instance.expects(:extract_folders).in_sequence(seq) + @instance.expects(:prepare_folders).in_sequence(seq) @instance.expects(:clear_nfs_exports).in_sequence(seq) @instance.expects(:export_folders).in_sequence(seq) @app.expects(:call).never @@ -111,6 +114,38 @@ class NFSVMActionTest < Test::Unit::TestCase end end + context "preparing UID/GID" do + setup do + @stat = mock("stat") + File.stubs(:stat).returns(@stat) + end + + should "return nil if the perm is not set" do + assert_nil @instance.prepare_permission(:uid, {:gid => 7}) + end + + should "return nil if the perm explicitly says nil" do + assert_nil @instance.prepare_permission(:uid, {:uid => nil}) + end + + should "return the set value if it is set" do + assert_equal 7, @instance.prepare_permission(:gid, {:map_gid => 7}) + end + + should "return the global config value if set and not explicitly set on folder" do + @env.env.config.nfs.map_gid = 12 + assert_equal 12, @instance.prepare_permission(:gid, {}) + end + + should "return the stat result of the hostpath if :auto" do + opts = { :hostpath => "foo", :map_uid => :auto } + File.expects(:stat).with(opts[:hostpath]).returns(@stat) + @stat.stubs(:uid).returns(24) + + assert_equal 24, @instance.prepare_permission(:uid, opts) + end + end + context "exporting folders" do setup do @instance.stubs(:folders).returns({}) diff --git a/vagrant.gemspec b/vagrant.gemspec index fd444575e..cafe8dbe8 100644 --- a/vagrant.gemspec +++ b/vagrant.gemspec @@ -9,7 +9,7 @@ Gem::Specification.new do |s| s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version= s.authors = ["Mitchell Hashimoto", "John Bender"] - s.date = %q{2010-07-14} + s.date = %q{2010-07-15} s.default_executable = %q{vagrant} s.description = %q{Vagrant is a tool for building and distributing virtualized development environments.} s.email = ["mitchell.hashimoto@gmail.com", "john.m.bender@gmail.com"]