From 40eaef08b79d6c170c8b41c417f45b943a8c2583 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Thu, 10 Aug 2017 15:49:47 -0700 Subject: [PATCH 1/3] (#8603) Ensure remote folder exists prior to scp in file provisioner Prior to this commit, if a file provisioner block was ran twice with a folder on a remote host, due to how scp works, it would first copy over that folder, and then on the second action it would copy an identical folder nested within the first one. While this is 'intended' behavior with scp, it is unexpected behavior for the file provisioner. This commit updates the file provisioner to first ensure that the directory to be copied exists on the remote host prior to copying, and then the destination dir has been changed to the directory that the destination will be copied to, rather than the exact directly that includes the folder from the host to prevent the nested folder behavior. --- plugins/provisioners/file/provisioner.rb | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/plugins/provisioners/file/provisioner.rb b/plugins/provisioners/file/provisioner.rb index 7b997a7dc..3c8081fce 100644 --- a/plugins/provisioners/file/provisioner.rb +++ b/plugins/provisioners/file/provisioner.rb @@ -3,14 +3,30 @@ module VagrantPlugins class Provisioner < Vagrant.plugin("2", :provisioner) def provision @machine.communicate.tap do |comm| + source = File.expand_path(config.source) destination = expand_guest_path(config.destination) + # if source is a directory, make it then trim destination with dirname # Make sure the remote path exists - command = "mkdir -p %s" % File.dirname(destination) + if File.directory?(source) + # We need to make sure the actual destination folder + # also exists before uploading, otherwise + # you will get nested folders. We also need to append + # a './' to the source folder so we copy the contents + # rather than the folder itself, in case a users destination + # folder differs from its source. + # + # https://serverfault.com/questions/538368/make-scp-always-overwrite-or-create-directory + # https://unix.stackexchange.com/questions/292641/get-scp-path-behave-like-rsync-path/292732 + command = "mkdir -p %s" % destination + source << "/." + else + command = "mkdir -p %s" % File.dirname(destination) + end comm.execute(command) # now upload the file - comm.upload(File.expand_path(config.source), destination) + comm.upload(source, destination) end end From 61c501cc653e75e45758c1ef71fe7f11d854ae33 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Mon, 14 Aug 2017 15:34:10 -0700 Subject: [PATCH 2/3] Ensure paths with spaces are preserved Prior to this commit, if a user set the `destination` path to include a space, the `shell_expand_guest_path` function would remove that space and return a partial path. This commit updates that to quote the path to be expanded to preserve the entire path. --- .../darwin/cap/shell_expand_guest_path.rb | 2 +- .../freebsd/cap/shell_expand_guest_path.rb | 2 +- .../linux/cap/shell_expand_guest_path.rb | 2 +- .../netbsd/cap/shell_expand_guest_path.rb | 2 +- .../openbsd/cap/shell_expand_guest_path.rb | 2 +- plugins/provisioners/file/provisioner.rb | 4 ++-- .../provisioners/file/provisioner_test.rb | 20 ++++++++++++++++++- 7 files changed, 26 insertions(+), 8 deletions(-) diff --git a/plugins/guests/darwin/cap/shell_expand_guest_path.rb b/plugins/guests/darwin/cap/shell_expand_guest_path.rb index 1fdcf5215..3bf439ef9 100644 --- a/plugins/guests/darwin/cap/shell_expand_guest_path.rb +++ b/plugins/guests/darwin/cap/shell_expand_guest_path.rb @@ -4,7 +4,7 @@ module VagrantPlugins class ShellExpandGuestPath def self.shell_expand_guest_path(machine, path) real_path = nil - machine.communicate.execute("printf #{path}") do |type, data| + machine.communicate.execute("printf \"#{path}\"") do |type, data| if type == :stdout real_path ||= "" real_path += data diff --git a/plugins/guests/freebsd/cap/shell_expand_guest_path.rb b/plugins/guests/freebsd/cap/shell_expand_guest_path.rb index 6d2f6e16a..854a2eef8 100644 --- a/plugins/guests/freebsd/cap/shell_expand_guest_path.rb +++ b/plugins/guests/freebsd/cap/shell_expand_guest_path.rb @@ -4,7 +4,7 @@ module VagrantPlugins class ShellExpandGuestPath def self.shell_expand_guest_path(machine, path) real_path = nil - machine.communicate.execute("printf #{path}", + machine.communicate.execute("printf \"#{path}\"", shell: "sh") do |type, data| if type == :stdout real_path ||= "" diff --git a/plugins/guests/linux/cap/shell_expand_guest_path.rb b/plugins/guests/linux/cap/shell_expand_guest_path.rb index cc32d7f7c..9065873b2 100644 --- a/plugins/guests/linux/cap/shell_expand_guest_path.rb +++ b/plugins/guests/linux/cap/shell_expand_guest_path.rb @@ -4,7 +4,7 @@ module VagrantPlugins class ShellExpandGuestPath def self.shell_expand_guest_path(machine, path) real_path = nil - machine.communicate.execute("echo; printf #{path}") do |type, data| + machine.communicate.execute("echo; printf \"#{path}\"") do |type, data| if type == :stdout real_path ||= "" real_path += data diff --git a/plugins/guests/netbsd/cap/shell_expand_guest_path.rb b/plugins/guests/netbsd/cap/shell_expand_guest_path.rb index 8471f4724..4dce5e2d6 100644 --- a/plugins/guests/netbsd/cap/shell_expand_guest_path.rb +++ b/plugins/guests/netbsd/cap/shell_expand_guest_path.rb @@ -4,7 +4,7 @@ module VagrantPlugins class ShellExpandGuestPath def self.shell_expand_guest_path(machine, path) real_path = nil - machine.communicate.execute("printf #{path}") do |type, data| + machine.communicate.execute("printf \"#{path}\"") do |type, data| if type == :stdout real_path ||= "" real_path += data diff --git a/plugins/guests/openbsd/cap/shell_expand_guest_path.rb b/plugins/guests/openbsd/cap/shell_expand_guest_path.rb index 653493548..b1a82813f 100644 --- a/plugins/guests/openbsd/cap/shell_expand_guest_path.rb +++ b/plugins/guests/openbsd/cap/shell_expand_guest_path.rb @@ -4,7 +4,7 @@ module VagrantPlugins class ShellExpandGuestPath def self.shell_expand_guest_path(machine, path) real_path = nil - machine.communicate.execute("printf #{path}") do |type, data| + machine.communicate.execute("printf \"#{path}\"") do |type, data| if type == :stdout real_path ||= "" real_path += data diff --git a/plugins/provisioners/file/provisioner.rb b/plugins/provisioners/file/provisioner.rb index 3c8081fce..46355c11b 100644 --- a/plugins/provisioners/file/provisioner.rb +++ b/plugins/provisioners/file/provisioner.rb @@ -18,10 +18,10 @@ module VagrantPlugins # # https://serverfault.com/questions/538368/make-scp-always-overwrite-or-create-directory # https://unix.stackexchange.com/questions/292641/get-scp-path-behave-like-rsync-path/292732 - command = "mkdir -p %s" % destination + command = "mkdir -p \"%s\"" % destination source << "/." else - command = "mkdir -p %s" % File.dirname(destination) + command = "mkdir -p \"%s\"" % File.dirname(destination) end comm.execute(command) diff --git a/test/unit/plugins/provisioners/file/provisioner_test.rb b/test/unit/plugins/provisioners/file/provisioner_test.rb index a42f1169c..8da38e6d7 100644 --- a/test/unit/plugins/provisioners/file/provisioner_test.rb +++ b/test/unit/plugins/provisioners/file/provisioner_test.rb @@ -34,7 +34,25 @@ describe VagrantPlugins::FileUpload::Provisioner do allow(config).to receive(:source).and_return("/source") allow(config).to receive(:destination).and_return("/foo/bar") - expect(communicator).to receive(:execute).with("mkdir -p /foo") + expect(communicator).to receive(:execute).with("mkdir -p \"/foo\"") + + subject.provision + end + + it "creates the destination directory with a space" do + allow(config).to receive(:source).and_return("/source") + allow(config).to receive(:destination).and_return("/foo bar/bar") + + expect(communicator).to receive(:execute).with("mkdir -p \"/foo bar\"") + + subject.provision + end + + it "creates the destination directory above file" do + allow(config).to receive(:source).and_return("/source/file.sh") + allow(config).to receive(:destination).and_return("/foo/bar/file.sh") + + expect(communicator).to receive(:execute).with("mkdir -p \"/foo/bar\"") subject.provision end From 2b8f7f67ead6e6dbdb10cefc1a794b5553cf4b77 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Tue, 15 Aug 2017 09:33:29 -0700 Subject: [PATCH 3/3] Add unit tests for shell_expand_guest_path function --- .../darwin/cap/shell_expand_guest_path.rb | 2 +- .../freebsd/cap/shell_expand_guest_path.rb | 2 +- .../linux/cap/shell_expand_guest_path.rb | 2 +- .../netbsd/cap/shell_expand_guest_path.rb | 2 +- .../openbsd/cap/shell_expand_guest_path.rb | 2 +- .../cap/shell_expand_guest_path_test.rb | 43 ++++++++++++++++++ .../cap/shell_expand_guest_path_test.rb | 44 +++++++++++++++++++ .../linux/cap/shell_expand_guest_path_test.rb | 43 ++++++++++++++++++ .../cap/shell_expand_guest_path_test.rb | 43 ++++++++++++++++++ .../cap/shell_expand_guest_path_test.rb | 43 ++++++++++++++++++ 10 files changed, 221 insertions(+), 5 deletions(-) create mode 100644 test/unit/plugins/guests/darwin/cap/shell_expand_guest_path_test.rb create mode 100644 test/unit/plugins/guests/freebsd/cap/shell_expand_guest_path_test.rb create mode 100644 test/unit/plugins/guests/linux/cap/shell_expand_guest_path_test.rb create mode 100644 test/unit/plugins/guests/netbsd/cap/shell_expand_guest_path_test.rb create mode 100644 test/unit/plugins/guests/openbsd/cap/shell_expand_guest_path_test.rb diff --git a/plugins/guests/darwin/cap/shell_expand_guest_path.rb b/plugins/guests/darwin/cap/shell_expand_guest_path.rb index 3bf439ef9..22c7bd11a 100644 --- a/plugins/guests/darwin/cap/shell_expand_guest_path.rb +++ b/plugins/guests/darwin/cap/shell_expand_guest_path.rb @@ -14,7 +14,7 @@ module VagrantPlugins if !real_path # If no real guest path was detected, this is really strange # and we raise an exception because this is a bug. - raise ShellExpandFailed + raise Vagrant::Errors::ShellExpandFailed end # Chomp the string so that any trailing newlines are killed diff --git a/plugins/guests/freebsd/cap/shell_expand_guest_path.rb b/plugins/guests/freebsd/cap/shell_expand_guest_path.rb index 854a2eef8..14ae7184d 100644 --- a/plugins/guests/freebsd/cap/shell_expand_guest_path.rb +++ b/plugins/guests/freebsd/cap/shell_expand_guest_path.rb @@ -15,7 +15,7 @@ module VagrantPlugins if !real_path # If no real guest path was detected, this is really strange # and we raise an exception because this is a bug. - raise ShellExpandFailed + raise Vagrant::Errors::ShellExpandFailed end # Chomp the string so that any trailing newlines are killed diff --git a/plugins/guests/linux/cap/shell_expand_guest_path.rb b/plugins/guests/linux/cap/shell_expand_guest_path.rb index 9065873b2..653068a78 100644 --- a/plugins/guests/linux/cap/shell_expand_guest_path.rb +++ b/plugins/guests/linux/cap/shell_expand_guest_path.rb @@ -19,7 +19,7 @@ module VagrantPlugins if !real_path # If no real guest path was detected, this is really strange # and we raise an exception because this is a bug. - raise ShellExpandFailed + raise Vagrant::Errors::ShellExpandFailed end # Chomp the string so that any trailing newlines are killed diff --git a/plugins/guests/netbsd/cap/shell_expand_guest_path.rb b/plugins/guests/netbsd/cap/shell_expand_guest_path.rb index 4dce5e2d6..007c5f944 100644 --- a/plugins/guests/netbsd/cap/shell_expand_guest_path.rb +++ b/plugins/guests/netbsd/cap/shell_expand_guest_path.rb @@ -14,7 +14,7 @@ module VagrantPlugins if !real_path # If no real guest path was detected, this is really strange # and we raise an exception because this is a bug. - raise ShellExpandFailed + raise Vagrant::Errors::ShellExpandFailed end # Chomp the string so that any trailing newlines are killed diff --git a/plugins/guests/openbsd/cap/shell_expand_guest_path.rb b/plugins/guests/openbsd/cap/shell_expand_guest_path.rb index b1a82813f..2a4f8b5ed 100644 --- a/plugins/guests/openbsd/cap/shell_expand_guest_path.rb +++ b/plugins/guests/openbsd/cap/shell_expand_guest_path.rb @@ -14,7 +14,7 @@ module VagrantPlugins if !real_path # If no real guest path was detected, this is really strange # and we raise an exception because this is a bug. - raise ShellExpandFailed + raise Vagrant::Errors::ShellExpandFailed end # Chomp the string so that any trailing newlines are killed diff --git a/test/unit/plugins/guests/darwin/cap/shell_expand_guest_path_test.rb b/test/unit/plugins/guests/darwin/cap/shell_expand_guest_path_test.rb new file mode 100644 index 000000000..fbbc45588 --- /dev/null +++ b/test/unit/plugins/guests/darwin/cap/shell_expand_guest_path_test.rb @@ -0,0 +1,43 @@ +require_relative "../../../../base" + +describe "VagrantPlugins::GuestDarwin::Cap::ShellExpandGuestPath" do + let(:caps) do + VagrantPlugins::GuestDarwin::Plugin + .components + .guest_capabilities[:darwin] + end + + let(:machine) { double("machine") } + let(:comm) { VagrantTests::DummyCommunicator::Communicator.new(machine) } + + before do + allow(machine).to receive(:communicate).and_return(comm) + end + + describe "#shell_expand_guest_path" do + let(:cap) { caps.get(:shell_expand_guest_path) } + + it "expands the path" do + path = "/home/vagrant/folder" + allow(machine.communicate).to receive(:execute). + with(any_args).and_yield(:stdout, "/home/vagrant/folder") + + cap.shell_expand_guest_path(machine, path) + end + + it "raises an exception if no path was detected" do + path = "/home/vagrant/folder" + expect { cap.shell_expand_guest_path(machine, path) }. + to raise_error(Vagrant::Errors::ShellExpandFailed) + end + + it "returns a path with a space in it" do + path = "/home/vagrant folder/folder" + allow(machine.communicate).to receive(:execute). + with(any_args).and_yield(:stdout, "/home/vagrant folder/folder") + + expect(machine.communicate).to receive(:execute).with("printf \"#{path}\"") + cap.shell_expand_guest_path(machine, path) + end + end +end diff --git a/test/unit/plugins/guests/freebsd/cap/shell_expand_guest_path_test.rb b/test/unit/plugins/guests/freebsd/cap/shell_expand_guest_path_test.rb new file mode 100644 index 000000000..2f10f8663 --- /dev/null +++ b/test/unit/plugins/guests/freebsd/cap/shell_expand_guest_path_test.rb @@ -0,0 +1,44 @@ +require_relative "../../../../base" + +describe "VagrantPlugins::GuestFreeBSD::Cap::ShellExpandGuestPath" do + let(:caps) do + VagrantPlugins::GuestFreeBSD::Plugin + .components + .guest_capabilities[:freebsd] + end + + let(:machine) { double("machine") } + let(:comm) { VagrantTests::DummyCommunicator::Communicator.new(machine) } + + before do + allow(machine).to receive(:communicate).and_return(comm) + end + + describe "#shell_expand_guest_path" do + let(:cap) { caps.get(:shell_expand_guest_path) } + + it "expands the path" do + path = "/home/vagrant/folder" + allow(machine.communicate).to receive(:execute). + with(any_args).and_yield(:stdout, "/home/vagrant/folder") + + cap.shell_expand_guest_path(machine, path) + end + + it "raises an exception if no path was detected" do + path = "/home/vagrant/folder" + expect { cap.shell_expand_guest_path(machine, path) }. + to raise_error(Vagrant::Errors::ShellExpandFailed) + end + + it "returns a path with a space in it" do + path = "/home/vagrant folder/folder" + allow(machine.communicate).to receive(:execute). + with(any_args).and_yield(:stdout, "/home/vagrant folder/folder") + + expect(machine.communicate).to receive(:execute) + .with("printf \"#{path}\"", {:shell=>"sh"}) + cap.shell_expand_guest_path(machine, path) + end + end +end diff --git a/test/unit/plugins/guests/linux/cap/shell_expand_guest_path_test.rb b/test/unit/plugins/guests/linux/cap/shell_expand_guest_path_test.rb new file mode 100644 index 000000000..0caf4ae1d --- /dev/null +++ b/test/unit/plugins/guests/linux/cap/shell_expand_guest_path_test.rb @@ -0,0 +1,43 @@ +require_relative "../../../../base" + +describe "VagrantPlugins::GuestLinux::Cap::ShellExpandGuestPath" do + let(:caps) do + VagrantPlugins::GuestLinux::Plugin + .components + .guest_capabilities[:linux] + end + + let(:machine) { double("machine") } + let(:comm) { VagrantTests::DummyCommunicator::Communicator.new(machine) } + + before do + allow(machine).to receive(:communicate).and_return(comm) + end + + describe "#shell_expand_guest_path" do + let(:cap) { caps.get(:shell_expand_guest_path) } + + it "expands the path" do + path = "/home/vagrant/folder" + allow(machine.communicate).to receive(:execute). + with(any_args).and_yield(:stdout, "/home/vagrant/folder") + + cap.shell_expand_guest_path(machine, path) + end + + it "raises an exception if no path was detected" do + path = "/home/vagrant/folder" + expect { cap.shell_expand_guest_path(machine, path) }. + to raise_error(Vagrant::Errors::ShellExpandFailed) + end + + it "returns a path with a space in it" do + path = "/home/vagrant folder/folder" + allow(machine.communicate).to receive(:execute). + with(any_args).and_yield(:stdout, "/home/vagrant folder/folder") + + expect(machine.communicate).to receive(:execute).with("echo; printf \"#{path}\"") + cap.shell_expand_guest_path(machine, path) + end + end +end diff --git a/test/unit/plugins/guests/netbsd/cap/shell_expand_guest_path_test.rb b/test/unit/plugins/guests/netbsd/cap/shell_expand_guest_path_test.rb new file mode 100644 index 000000000..49e4e6305 --- /dev/null +++ b/test/unit/plugins/guests/netbsd/cap/shell_expand_guest_path_test.rb @@ -0,0 +1,43 @@ +require_relative "../../../../base" + +describe "VagrantPlugins::GuestNetBSD::Cap::ShellExpandGuestPath" do + let(:caps) do + VagrantPlugins::GuestNetBSD::Plugin + .components + .guest_capabilities[:netbsd] + end + + let(:machine) { double("machine") } + let(:comm) { VagrantTests::DummyCommunicator::Communicator.new(machine) } + + before do + allow(machine).to receive(:communicate).and_return(comm) + end + + describe "#shell_expand_guest_path" do + let(:cap) { caps.get(:shell_expand_guest_path) } + + it "expands the path" do + path = "/home/vagrant/folder" + allow(machine.communicate).to receive(:execute). + with(any_args).and_yield(:stdout, "/home/vagrant/folder") + + cap.shell_expand_guest_path(machine, path) + end + + it "raises an exception if no path was detected" do + path = "/home/vagrant/folder" + expect { cap.shell_expand_guest_path(machine, path) }. + to raise_error(Vagrant::Errors::ShellExpandFailed) + end + + it "returns a path with a space in it" do + path = "/home/vagrant folder/folder" + allow(machine.communicate).to receive(:execute). + with(any_args).and_yield(:stdout, "/home/vagrant folder/folder") + + expect(machine.communicate).to receive(:execute).with("printf \"#{path}\"") + cap.shell_expand_guest_path(machine, path) + end + end +end diff --git a/test/unit/plugins/guests/openbsd/cap/shell_expand_guest_path_test.rb b/test/unit/plugins/guests/openbsd/cap/shell_expand_guest_path_test.rb new file mode 100644 index 000000000..1cd787911 --- /dev/null +++ b/test/unit/plugins/guests/openbsd/cap/shell_expand_guest_path_test.rb @@ -0,0 +1,43 @@ +require_relative "../../../../base" + +describe "VagrantPlugins::GuestOpenBSD::Cap::ShellExpandGuestPath" do + let(:caps) do + VagrantPlugins::GuestOpenBSD::Plugin + .components + .guest_capabilities[:openbsd] + end + + let(:machine) { double("machine") } + let(:comm) { VagrantTests::DummyCommunicator::Communicator.new(machine) } + + before do + allow(machine).to receive(:communicate).and_return(comm) + end + + describe "#shell_expand_guest_path" do + let(:cap) { caps.get(:shell_expand_guest_path) } + + it "expands the path" do + path = "/home/vagrant/folder" + allow(machine.communicate).to receive(:execute). + with(any_args).and_yield(:stdout, "/home/vagrant/folder") + + cap.shell_expand_guest_path(machine, path) + end + + it "raises an exception if no path was detected" do + path = "/home/vagrant/folder" + expect { cap.shell_expand_guest_path(machine, path) }. + to raise_error(Vagrant::Errors::ShellExpandFailed) + end + + it "returns a path with a space in it" do + path = "/home/vagrant folder/folder" + allow(machine.communicate).to receive(:execute). + with(any_args).and_yield(:stdout, "/home/vagrant folder/folder") + + expect(machine.communicate).to receive(:execute).with("printf \"#{path}\"") + cap.shell_expand_guest_path(machine, path) + end + end +end