diff --git a/lib/vagrant/errors.rb b/lib/vagrant/errors.rb index 0a7b1f479..3db73cefb 100644 --- a/lib/vagrant/errors.rb +++ b/lib/vagrant/errors.rb @@ -432,6 +432,10 @@ module Vagrant error_key(:rsync_not_found) end + class RSyncNotInstalledInGuest < VagrantError + error_key(:rsync_not_installed_in_guest) + end + class SCPPermissionDenied < VagrantError error_key(:scp_permission_denied) end diff --git a/plugins/guests/darwin/cap/rsync.rb b/plugins/guests/darwin/cap/rsync.rb new file mode 100644 index 000000000..3ddbe485e --- /dev/null +++ b/plugins/guests/darwin/cap/rsync.rb @@ -0,0 +1,20 @@ +module VagrantPlugins + module GuestDarwin + module Cap + class RSync + def self.rsync_installed(machine) + machine.communicate.test("which rsync") + end + + def self.rsync_pre(machine, folder_opts) + username = machine.ssh_info[:username] + + machine.communicate.tap do |comm| + comm.sudo("mkdir -p '#{folder_opts[:guestpath]}'") + comm.sudo("chown -R #{username} '#{folder_opts[:guestpath]}'") + end + end + end + end + end +end diff --git a/plugins/guests/darwin/plugin.rb b/plugins/guests/darwin/plugin.rb index 5b23b8f4f..a2fb0b2db 100644 --- a/plugins/guests/darwin/plugin.rb +++ b/plugins/guests/darwin/plugin.rb @@ -36,6 +36,16 @@ module VagrantPlugins Cap::MountVmwareSharedFolder end + guest_capability("darwin", "rsync_installed") do + require_relative "cap/rsync" + Cap::RSync + end + + guest_capability("darwin", "rsync_pre") do + require_relative "cap/rsync" + Cap::RSync + end + guest_capability("darwin", "shell_expand_guest_path") do require_relative "cap/shell_expand_guest_path" Cap::ShellExpandGuestPath diff --git a/plugins/guests/debian/cap/rsync.rb b/plugins/guests/debian/cap/rsync.rb new file mode 100644 index 000000000..80735cc9e --- /dev/null +++ b/plugins/guests/debian/cap/rsync.rb @@ -0,0 +1,14 @@ +module VagrantPlugins + module GuestDebian + module Cap + class RSync + def self.rsync_install(machine) + machine.communicate.tap do |comm| + comm.sudo("apt-get -y update") + comm.sudo("apt-get -y install rsync") + end + end + end + end + end +end diff --git a/plugins/guests/debian/plugin.rb b/plugins/guests/debian/plugin.rb index 82c211bdf..0ba72ed5d 100644 --- a/plugins/guests/debian/plugin.rb +++ b/plugins/guests/debian/plugin.rb @@ -25,6 +25,11 @@ module VagrantPlugins require_relative "cap/nfs_client" Cap::NFSClient end + + guest_capability("debian", "rsync_install") do + require_relative "cap/rsync" + Cap::RSync + end end end end diff --git a/plugins/guests/freebsd/cap/rsync.rb b/plugins/guests/freebsd/cap/rsync.rb new file mode 100644 index 000000000..3dc6d6718 --- /dev/null +++ b/plugins/guests/freebsd/cap/rsync.rb @@ -0,0 +1,26 @@ +module VagrantPlugins + module GuestFreeBSD + module Cap + class RSync + def self.rsync_install(machine) + machine.communicate.tap do |comm| + comm.sudo("pkg_add -r rsync") + end + end + + def self.rsync_installed(machine) + machine.communicate.test("which rsync") + end + + def self.rsync_pre(machine, folder_opts) + username = machine.ssh_info[:username] + + machine.communicate.tap do |comm| + comm.sudo("mkdir -p '#{folder_opts[:guestpath]}'", shell: "sh") + comm.sudo("chown -R #{username} '#{folder_opts[:guestpath]}'", shell: "sh") + end + end + end + end + end +end diff --git a/plugins/guests/freebsd/plugin.rb b/plugins/guests/freebsd/plugin.rb index 8e147087b..1cc9b449f 100644 --- a/plugins/guests/freebsd/plugin.rb +++ b/plugins/guests/freebsd/plugin.rb @@ -30,6 +30,21 @@ module VagrantPlugins require_relative "cap/mount_nfs_folder" Cap::MountNFSFolder end + + guest_capability("freebsd", "rsync_install") do + require_relative "cap/rsync" + Cap::RSync + end + + guest_capability("freebsd", "rsync_installed") do + require_relative "cap/rsync" + Cap::RSync + end + + guest_capability("freebsd", "rsync_pre") do + require_relative "cap/rsync" + Cap::RSync + end end end end diff --git a/plugins/guests/linux/cap/rsync.rb b/plugins/guests/linux/cap/rsync.rb index 2bed51e33..5469b3a13 100644 --- a/plugins/guests/linux/cap/rsync.rb +++ b/plugins/guests/linux/cap/rsync.rb @@ -2,6 +2,10 @@ module VagrantPlugins module GuestLinux module Cap class RSync + def self.rsync_installed(machine) + machine.communicate.test("which rsync") + end + def self.rsync_pre(machine, folder_opts) username = machine.ssh_info[:username] diff --git a/plugins/guests/linux/plugin.rb b/plugins/guests/linux/plugin.rb index fb91b722c..9a93ab5b9 100644 --- a/plugins/guests/linux/plugin.rb +++ b/plugins/guests/linux/plugin.rb @@ -46,7 +46,11 @@ module VagrantPlugins Cap::ReadIPAddress end - # RSync synced folders + guest_capability("linux", "rsync_installed") do + require_relative "cap/rsync" + Cap::RSync + end + guest_capability("linux", "rsync_pre") do require_relative "cap/rsync" Cap::RSync diff --git a/plugins/guests/netbsd/cap/rsync.rb b/plugins/guests/netbsd/cap/rsync.rb new file mode 100644 index 000000000..1c7d4e72e --- /dev/null +++ b/plugins/guests/netbsd/cap/rsync.rb @@ -0,0 +1,27 @@ +module VagrantPlugins + module GuestNetBSD + module Cap + class RSync + def self.rsync_installed(machine) + machine.communicate.test("which rsync") + end + + def self.rsync_install(machine) + machine.communicate.sudo( + 'export PKG_PATH="http://ftp.NetBSD.org/pub/pkgsrc/packages/NetBSD/' \ + '`uname -m`/`uname -r | cut -d. -f1-2`/All"; ' \ + 'pkg_add rsync') + end + + def self.rsync_pre(machine, folder_opts) + username = machine.ssh_info[:username] + + machine.communicate.tap do |comm| + comm.sudo("mkdir -p '#{folder_opts[:guestpath]}'") + comm.sudo("chown -R #{username} '#{folder_opts[:guestpath]}'") + end + end + end + end + end +end diff --git a/plugins/guests/netbsd/plugin.rb b/plugins/guests/netbsd/plugin.rb index ca55706fc..00f67144a 100644 --- a/plugins/guests/netbsd/plugin.rb +++ b/plugins/guests/netbsd/plugin.rb @@ -30,6 +30,21 @@ module VagrantPlugins require_relative "cap/mount_nfs_folder" Cap::MountNFSFolder end + + guest_capability("netbsd", "rsync_install") do + require_relative "cap/rsync" + Cap::RSync + end + + guest_capability("netbsd", "rsync_installed") do + require_relative "cap/rsync" + Cap::RSync + end + + guest_capability("netbsd", "rsync_pre") do + require_relative "cap/rsync" + Cap::RSync + end end end end diff --git a/plugins/guests/openbsd/cap/rsync.rb b/plugins/guests/openbsd/cap/rsync.rb new file mode 100644 index 000000000..269f6e101 --- /dev/null +++ b/plugins/guests/openbsd/cap/rsync.rb @@ -0,0 +1,26 @@ +module VagrantPlugins + module GuestOpenBSD + module Cap + class RSync + def self.rsync_install(machine) + machine.communicate.tap do |comm| + comm.sudo("pkg_add -I rsync--") + end + end + + def self.rsync_installed(machine) + machine.communicate.test("which rsync") + end + + def self.rsync_pre(machine, folder_opts) + username = machine.ssh_info[:username] + + machine.communicate.tap do |comm| + comm.sudo("mkdir -p '#{folder_opts[:guestpath]}'") + comm.sudo("chown -R #{username} '#{folder_opts[:guestpath]}'") + end + end + end + end + end +end diff --git a/plugins/guests/openbsd/plugin.rb b/plugins/guests/openbsd/plugin.rb index fc1043a53..05d1217c0 100644 --- a/plugins/guests/openbsd/plugin.rb +++ b/plugins/guests/openbsd/plugin.rb @@ -30,6 +30,21 @@ module VagrantPlugins require_relative "cap/mount_nfs_folder" Cap::MountNFSFolder end + + guest_capability("openbsd", "rsync_install") do + require_relative "cap/rsync" + Cap::RSync + end + + guest_capability("openbsd", "rsync_installed") do + require_relative "cap/rsync" + Cap::RSync + end + + guest_capability("openbsd", "rsync_pre") do + require_relative "cap/rsync" + Cap::RSync + end end end end diff --git a/plugins/guests/redhat/cap/rsync.rb b/plugins/guests/redhat/cap/rsync.rb new file mode 100644 index 000000000..9a1cfeeac --- /dev/null +++ b/plugins/guests/redhat/cap/rsync.rb @@ -0,0 +1,13 @@ +module VagrantPlugins + module GuestRedHat + module Cap + class RSync + def self.rsync_install(machine) + machine.communicate.tap do |comm| + comm.sudo("yum -y install rsync") + end + end + end + end + end +end diff --git a/plugins/guests/redhat/plugin.rb b/plugins/guests/redhat/plugin.rb index 503b37423..56e6b8031 100644 --- a/plugins/guests/redhat/plugin.rb +++ b/plugins/guests/redhat/plugin.rb @@ -30,6 +30,11 @@ module VagrantPlugins require_relative "cap/nfs_client" Cap::NFSClient end + + guest_capability("redhat", "rsync_install") do + require_relative "cap/rsync" + Cap::RSync + end end end end diff --git a/plugins/guests/solaris/cap/rsync.rb b/plugins/guests/solaris/cap/rsync.rb new file mode 100644 index 000000000..a470011b2 --- /dev/null +++ b/plugins/guests/solaris/cap/rsync.rb @@ -0,0 +1,20 @@ +module VagrantPlugins + module GuestSolaris + module Cap + class RSync + def self.rsync_installed(machine) + machine.communicate.test("which rsync") + end + + def self.rsync_pre(machine, folder_opts) + username = machine.ssh_info[:username] + + machine.communicate.tap do |comm| + comm.sudo("mkdir -p '#{folder_opts[:guestpath]}'") + comm.sudo("chown -R #{username} '#{folder_opts[:guestpath]}'") + end + end + end + end + end +end diff --git a/plugins/guests/solaris/plugin.rb b/plugins/guests/solaris/plugin.rb index 9f1fc80d9..d7bb5e474 100644 --- a/plugins/guests/solaris/plugin.rb +++ b/plugins/guests/solaris/plugin.rb @@ -35,6 +35,16 @@ module VagrantPlugins require_relative "cap/mount_virtualbox_shared_folder" Cap::MountVirtualBoxSharedFolder end + + guest_capability("solaris", "rsync_installed") do + require_relative "cap/rsync" + Cap::RSync + end + + guest_capability("solaris", "rsync_pre") do + require_relative "cap/rsync" + Cap::RSync + end end end end diff --git a/plugins/guests/solaris11/cap/rsync.rb b/plugins/guests/solaris11/cap/rsync.rb new file mode 100644 index 000000000..0175bf86d --- /dev/null +++ b/plugins/guests/solaris11/cap/rsync.rb @@ -0,0 +1,20 @@ +module VagrantPlugins + module GuestSolaris11 + module Cap + class RSync + def self.rsync_installed(machine) + machine.communicate.test("which rsync") + end + + def self.rsync_pre(machine, folder_opts) + username = machine.ssh_info[:username] + + machine.communicate.tap do |comm| + comm.sudo("mkdir -p '#{folder_opts[:guestpath]}'") + comm.sudo("chown -R #{username} '#{folder_opts[:guestpath]}'") + end + end + end + end + end +end diff --git a/plugins/guests/solaris11/plugin.rb b/plugins/guests/solaris11/plugin.rb index fa6739584..707fd2bfc 100644 --- a/plugins/guests/solaris11/plugin.rb +++ b/plugins/guests/solaris11/plugin.rb @@ -39,6 +39,16 @@ module VagrantPlugins require_relative "cap/mount_virtualbox_shared_folder" Cap::MountVirtualBoxSharedFolder end + + guest_capability("solaris11", "rsync_installed") do + require_relative "cap/rsync" + Cap::RSync + end + + guest_capability("solaris11", "rsync_pre") do + require_relative "cap/rsync" + Cap::RSync + end end end end diff --git a/plugins/synced_folders/rsync/synced_folder.rb b/plugins/synced_folders/rsync/synced_folder.rb index 416a1b06c..4e978f371 100644 --- a/plugins/synced_folders/rsync/synced_folder.rb +++ b/plugins/synced_folders/rsync/synced_folder.rb @@ -28,6 +28,16 @@ module VagrantPlugins end def enable(machine, folders, opts) + if machine.guest.capability?(:rsync_installed) + installed = machine.guest.capability(:rsync_installed) + if !installed + can_install = machine.guest.capability?(:rsync_install) + raise Vagrant::Errors::RSyncNotInstalledInGuest if !can_install + machine.ui.info I18n.t("vagrant.rsync_installing") + machine.guest.capability(:rsync_install) + end + end + ssh_info = machine.ssh_info if ssh_info[:private_key_path].empty? && ssh_info[:password] diff --git a/templates/locales/en.yml b/templates/locales/en.yml index fd4590754..baffa7b12 100644 --- a/templates/locales/en.yml +++ b/templates/locales/en.yml @@ -99,6 +99,7 @@ en: rsync_folder: |- Rsyncing folder: %{hostpath} => %{guestpath} rsync_folder_excludes: " - Exclude: %{excludes}" + rsync_installing: "Installing rsync to the VM..." rsync_ssh_password: |- The machine you're rsyncing folders to is configured to use password-based authentication. Vagrant can't script rsync to automatically @@ -574,6 +575,11 @@ en: rsync_not_found: |- "rsync" could not be found on your PATH. Make sure that rsync is properly installed on your system and available on the PATH. + rsync_not_installed_in_guest: |- + "rsync" was not detected as installed in your guest machine. This + is required for rsync synced folders to work. In addition to this, + Vagrant doesn't know how to automatically install rsync for your + machine, so you must do this manually. scp_permission_denied: |- Failed to upload a file to the guest VM via SCP due to a permissions error. This is normally because the user running Vagrant doesn't have diff --git a/test/unit/plugins/synced_folders/rsync/synced_folder_test.rb b/test/unit/plugins/synced_folders/rsync/synced_folder_test.rb index 2b7df8781..2dae9cb82 100644 --- a/test/unit/plugins/synced_folders/rsync/synced_folder_test.rb +++ b/test/unit/plugins/synced_folders/rsync/synced_folder_test.rb @@ -48,6 +48,7 @@ describe VagrantPlugins::SyncedFolderRSync::SyncedFolder do before do machine.stub(ssh_info: ssh_info) + guest.stub(:capability?).with(:rsync_installed) end it "rsyncs each folder" do @@ -64,5 +65,33 @@ describe VagrantPlugins::SyncedFolderRSync::SyncedFolder do subject.enable(machine, folders, {}) end + + it "installs rsync if capable" do + folders = [ [:foo, {}] ] + + helper_class.stub(:rsync_single) + + guest.stub(:capability?).with(:rsync_installed).and_return(true) + guest.stub(:capability?).with(:rsync_install).and_return(true) + + expect(guest).to receive(:capability).with(:rsync_installed).and_return(false) + expect(guest).to receive(:capability).with(:rsync_install) + + subject.enable(machine, folders, {}) + end + + it "errors if rsync not installable" do + folders = [ [:foo, {}] ] + + helper_class.stub(:rsync_single) + + guest.stub(:capability?).with(:rsync_installed).and_return(true) + guest.stub(:capability?).with(:rsync_install).and_return(false) + + expect(guest).to receive(:capability).with(:rsync_installed).and_return(false) + + expect { subject.enable(machine, folders, {}) }. + to raise_error(Vagrant::Errors::RSyncNotInstalledInGuest) + end end end