From 2ddd12047c165d36bacd11b111e2e7441a3400a5 Mon Sep 17 00:00:00 2001 From: sophia Date: Tue, 14 Apr 2020 10:49:49 -0400 Subject: [PATCH 1/2] Ensure windows files get an extension --- plugins/provisioners/shell/provisioner.rb | 33 +++++++++-------- .../provisioners/shell/provisioner_test.rb | 36 ++++++++++++++++++- 2 files changed, 53 insertions(+), 16 deletions(-) diff --git a/plugins/provisioners/shell/provisioner.rb b/plugins/provisioners/shell/provisioner.rb index 9aaee60de..257c68d63 100644 --- a/plugins/provisioners/shell/provisioner.rb +++ b/plugins/provisioners/shell/provisioner.rb @@ -4,11 +4,14 @@ require "tempfile" require "vagrant/util/downloader" require "vagrant/util/retryable" +require "pry-byebug" module VagrantPlugins module Shell class Provisioner < Vagrant.plugin("2", :provisioner) include Vagrant::Util::Retryable + DEFAULT_WINDOWS_SHELL_EXT = ".ps1".freeze + def provision args = "" if config.args.is_a?(String) @@ -135,16 +138,14 @@ module VagrantPlugins # Upload the script to the machine @machine.communicate.tap do |comm| env = config.env.map{|k,v| comm.generate_environment_export(k, v)}.join(';') - shell = comm.machine_config_ssh.shell - if File.extname(upload_path).empty? - remote_ext = File.extname(path)[1..-1] - if !remote_ext - remote_ext = @machine.config.winssh.shell == "cmd" ? "bat" : "ps1" - end - upload_path << ".#{remote_ext}" + remote_ext = File.extname(path) + if remote_ext.empty? + remote_ext = @machine.config.winssh.shell == "cmd" ? ".bat" : ".ps1" end + + remote_path = add_extension(upload_path(), remote_ext) if remote_ext == "bat" - command = "#{env}\n cmd.exe /c \"#{upload_path}\" #{args}" + command = "#{env}\n cmd.exe /c \"#{remote_path}\" #{args}" else # Copy powershell_args from configuration shell_args = config.powershell_args @@ -152,7 +153,7 @@ module VagrantPlugins shell_args += " -ExecutionPolicy Bypass" if config.powershell_args !~ /[-\/]ExecutionPolicy/i # CLIXML output is kinda useless, especially on non-windows hosts shell_args += " -OutputFormat Text" if config.powershell_args !~ /[-\/]OutputFormat/i - command = "#{env}\npowershell #{shell_args} -file \"#{upload_path}\"#{args}" + command = "#{env}\npowershell #{shell_args} -file \"#{remote_path}\"#{args}" end # Reset upload path permissions for the current ssh user @@ -161,8 +162,8 @@ module VagrantPlugins info = @machine.ssh_info raise Vagrant::Errors::SSHNotReady if info.nil? end - - comm.upload(path.to_s, upload_path) + + comm.upload(path.to_s, remote_path) if config.name @machine.ui.detail(I18n.t("vagrant.provisioners.shell.running", @@ -198,10 +199,7 @@ module VagrantPlugins @machine.communicate.tap do |comm| # Make sure that the upload path has an extension, since # having an extension is critical for Windows execution - winrm_upload_path = upload_path - if File.extname(winrm_upload_path) == "" - winrm_upload_path += File.extname(path.to_s) - end + winrm_upload_path = add_extension(upload_path, DEFAULT_WINDOWS_SHELL_EXT) # Upload it comm.upload(path.to_s, winrm_upload_path) @@ -260,6 +258,11 @@ module VagrantPlugins "#{quote}#{text.gsub(/#{quote}/) { |m| "#{m}\\#{m}#{m}" }}#{quote}" end + def add_extension(path, ext) + return path if !File.extname(path.to_s).empty? + path + ext + end + # This method yields the path to a script to upload and execute # on the remote server. This method will properly clean up the # script file if needed. diff --git a/test/unit/plugins/provisioners/shell/provisioner_test.rb b/test/unit/plugins/provisioners/shell/provisioner_test.rb index dd83c42e4..03556fcf9 100644 --- a/test/unit/plugins/provisioners/shell/provisioner_test.rb +++ b/test/unit/plugins/provisioners/shell/provisioner_test.rb @@ -456,12 +456,46 @@ describe "Vagrant::Shell::Provisioner" do allow(machine).to receive(:communicate).and_return(communicator) allow(machine).to receive(:guest).and_return(guest) allow(machine).to receive(:ui).and_return(ui) - allow(vsp).to receive(:with_script_file).and_yield(config.path) } it "ensures that files are uploaded with an extension" do + allow(vsp).to receive(:with_script_file).and_yield(config.path) expect(communicator).to receive(:upload).with(config.path, /arbitrary.ps1$/) vsp.send(:provision_winrm, "") end + + context "inline option set" do + let(:config) { + double( + :config, + :args => "doesn't matter", + :env => {}, + :remote? => false, + :inline => "some commands", + :upload_path => nil, + :path => nil, + :binary => false, + :md5 => nil, + :sha1 => 'EXPECTED_VALUE', + :sha256 => nil, + :sha384 => nil, + :sha512 => nil, + :reset => false, + :reboot => false, + :powershell_args => "", + :name => nil, + :privileged => false, + :powershell_elevated_interactive => false + ) + } + + it "creates an executable with an extension" do + default_path = "C:/tmp/vagrant-shell" + allow(vsp).to receive(:with_script_file).and_yield(default_path) + allow(communicator).to receive(:upload).with(default_path, /vagrant-shell/) + expect(communicator).to receive(:sudo).with(/vagrant-shell.ps1/, anything) + vsp.send(:provision_winrm, "") + end + end end end From 4d516e2caee630a04cd6ea456d32cc2fee86d21a Mon Sep 17 00:00:00 2001 From: sophia Date: Tue, 14 Apr 2020 16:57:02 -0400 Subject: [PATCH 2/2] Test provision_winssh --- plugins/provisioners/shell/provisioner.rb | 3 +- .../provisioners/shell/provisioner_test.rb | 100 +++++++++++++++++- 2 files changed, 98 insertions(+), 5 deletions(-) diff --git a/plugins/provisioners/shell/provisioner.rb b/plugins/provisioners/shell/provisioner.rb index 257c68d63..d148969a6 100644 --- a/plugins/provisioners/shell/provisioner.rb +++ b/plugins/provisioners/shell/provisioner.rb @@ -4,7 +4,6 @@ require "tempfile" require "vagrant/util/downloader" require "vagrant/util/retryable" -require "pry-byebug" module VagrantPlugins module Shell class Provisioner < Vagrant.plugin("2", :provisioner) @@ -143,7 +142,7 @@ module VagrantPlugins remote_ext = @machine.config.winssh.shell == "cmd" ? ".bat" : ".ps1" end - remote_path = add_extension(upload_path(), remote_ext) + remote_path = add_extension(upload_path, remote_ext) if remote_ext == "bat" command = "#{env}\n cmd.exe /c \"#{remote_path}\" #{args}" else diff --git a/test/unit/plugins/provisioners/shell/provisioner_test.rb b/test/unit/plugins/provisioners/shell/provisioner_test.rb index 03556fcf9..73dc3ca70 100644 --- a/test/unit/plugins/provisioners/shell/provisioner_test.rb +++ b/test/unit/plugins/provisioners/shell/provisioner_test.rb @@ -4,6 +4,7 @@ require Vagrant.source_root.join("plugins/provisioners/shell/provisioner") describe "Vagrant::Shell::Provisioner" do include_context "unit" + let(:default_win_path) { "C:/tmp/vagrant-shell" } let(:env){ isolated_environment } let(:machine) { double(:machine, env: env, id: "ID").tap { |machine| @@ -490,12 +491,105 @@ describe "Vagrant::Shell::Provisioner" do } it "creates an executable with an extension" do - default_path = "C:/tmp/vagrant-shell" - allow(vsp).to receive(:with_script_file).and_yield(default_path) - allow(communicator).to receive(:upload).with(default_path, /vagrant-shell/) + allow(vsp).to receive(:with_script_file).and_yield(default_win_path) + allow(communicator).to receive(:upload).with(default_win_path, /vagrant-shell/) expect(communicator).to receive(:sudo).with(/vagrant-shell.ps1/, anything) vsp.send(:provision_winrm, "") end end end + + describe "#provision_winssh" do + let(:config) { + double( + :config, + :args => "doesn't matter", + :env => {}, + :upload_path => "arbitrary", + :remote? => false, + :path => nil, + :inline => "something", + :binary => false, + :md5 => nil, + :sha1 => 'EXPECTED_VALUE', + :sha256 => nil, + :sha384 => nil, + :sha512 => nil, + :reset => false, + :reboot => false, + :powershell_args => "", + :name => nil, + :privileged => false, + :powershell_elevated_interactive => false + ) + } + + let(:vsp) { + VagrantPlugins::Shell::Provisioner.new(machine, config) + } + + let(:communicator) { double("communicator") } + let(:guest) { double("guest") } + let(:ui) { double("ui") } + + before { + allow(guest).to receive(:capability?).with(:wait_for_reboot).and_return(false) + allow(ui).to receive(:detail) + allow(communicator).to receive(:sudo) + allow(communicator).to receive_message_chain(:machine_config_ssh, :shell) + allow(machine).to receive(:communicate).and_return(communicator) + allow(machine).to receive(:guest).and_return(guest) + allow(machine).to receive(:ui).and_return(ui) + allow(machine).to receive(:ssh_info).and_return(true) + } + + it "ensures that files are uploaded as .bat when shell is cmd" do + allow(machine).to receive_message_chain(:config, :winssh, :shell).and_return("cmd") + allow(vsp).to receive(:with_script_file).and_yield(default_win_path) + expect(communicator).to receive(:upload).with(default_win_path, /arbitrary.bat/) + expect(communicator).to receive(:execute).with(/arbitrary.bat/, anything) + vsp.send(:provision_winssh, "") + end + + it "ensures that files are uploaded as .ps1 when shell is not cmd" do + allow(machine).to receive_message_chain(:config, :winssh, :shell).and_return("ps") + allow(vsp).to receive(:with_script_file).and_yield(default_win_path) + expect(communicator).to receive(:upload).with(default_win_path, /arbitrary.ps1/) + expect(communicator).to receive(:execute).with(/arbitrary.ps1/, anything) + vsp.send(:provision_winssh, "") + end + + context "ps1 file being uploaded" do + let(:config) { + double( + :config, + :args => "doesn't matter", + :env => {}, + :upload_path => "arbitrary", + :remote? => false, + :path => "script/info.ps1", + :binary => false, + :md5 => nil, + :sha1 => 'EXPECTED_VALUE', + :sha256 => nil, + :sha384 => nil, + :sha512 => nil, + :reset => false, + :reboot => false, + :powershell_args => "", + :name => nil, + :privileged => false, + :powershell_elevated_interactive => false + ) + } + + it "ensures that files are uploaded same extension as provided path.ps1" do + allow(machine).to receive_message_chain(:config, :winssh, :shell).and_return("cmd") + allow(vsp).to receive(:with_script_file).and_yield(config.path) + expect(communicator).to receive(:upload).with(config.path, /arbitrary.ps1/) + expect(communicator).to receive(:execute).with(/arbitrary.ps1/, anything) + vsp.send(:provision_winssh, "") + end + end + end end