Enable WinSSH shell for `vagrant ssh -c` (#11258)

This commit changes the behavior of the builtin SSHRun action to use a Windows
shell if the WinSSH communicator is active.  This allows for running one-off SSH
commands with Windows Command Prompt or PowerShell.  By default, this will not
allocate a TTY for any SSH commands.

Example usage:

```
vagrant ssh -c 'dir "c:\program files"'
```

Updates docs to reflect a change made in
a55a53e6a4.
This commit is contained in:
Jeff Bonhag 2019-12-20 13:10:11 -05:00 committed by GitHub
parent f0b8c0737f
commit 7fb7dd8608
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 89 additions and 10 deletions

View File

@ -36,17 +36,35 @@ module Vagrant
# Get the command and wrap it in a login shell
command = ShellQuote.escape(env[:ssh_run_command], "'")
command = "#{env[:machine].config.ssh.shell} -c '#{command}'"
if env[:machine].config.vm.communicator == :winssh
shell = env[:machine].config.winssh.shell
else
shell = env[:machine].config.ssh.shell
end
if shell == "cmd"
# Add an extra space to the command so cmd.exe quoting works
# properly
command = "#{shell} /C #{command} "
elsif shell == "powershell"
command = "$ProgressPreference = \"SilentlyContinue\"; #{command}"
command = Base64.strict_encode64(command.encode("UTF-16LE", "UTF-8"))
command = "#{shell} -encodedCommand #{command}"
else
command = "#{shell} -c '#{command}'"
end
# Execute!
opts = env[:ssh_opts] || {}
opts[:extra_args] ||= []
# Allow the user to specify a tty or non-tty manually, but if they
# don't then we default to a TTY
# don't then we default to a TTY unless they are using WinSSH
if !opts[:extra_args].include?("-t") &&
!opts[:extra_args].include?("-T") &&
env[:tty]
env[:tty] &&
env[:machine].config.vm.communicator != :winssh
opts[:extra_args] << "-t"
end

View File

@ -18,8 +18,14 @@ describe Vagrant::Action::Builtin::SSHRun do
)
end
let(:vm) do
double("vm",
communicator: nil
)
end
# Configuration mock
let(:config) { double("config", ssh: ssh) }
let(:config) { double("config", ssh: ssh, vm: vm) }
let(:machine) do
double("machine",
@ -80,4 +86,63 @@ describe Vagrant::Action::Builtin::SSHRun do
env[:ssh_run_command] = "echo test"
described_class.new(app, env).call(env)
end
context "when using the WinSSH communicator" do
let(:winssh) { double("winssh", shell: "foo") }
before do
expect(vm).to receive(:communicator).and_return(:winssh)
expect(config).to receive(:winssh).and_return(winssh)
env[:tty] = nil
end
it "should use the WinSSH shell for running ssh commands" do
ssh_info = { foo: :bar }
opts = {:extra_args=>["foo -c 'dir'"], :subprocess=>true}
expect(ssh_klass).to receive(:exec).
with(ssh_info, opts)
env[:ssh_info] = ssh_info
env[:ssh_run_command] = "dir"
described_class.new(app, env).call(env)
end
context "when shell is cmd" do
before do
expect(winssh).to receive(:shell).and_return('cmd')
end
it "should use appropriate options for cmd" do
ssh_info = { foo: :bar }
opts = {:extra_args=>["cmd /C dir "], :subprocess=>true}
expect(ssh_klass).to receive(:exec).
with(ssh_info, opts)
env[:ssh_info] = ssh_info
env[:ssh_run_command] = "dir"
described_class.new(app, env).call(env)
end
end
context "when shell is powershell" do
before do
expect(winssh).to receive(:shell).and_return('powershell')
end
it "should base64 encode the command" do
ssh_info = { foo: :bar }
encoded_command = "JABQAHIAbwBnAHIAZQBzAHMAUAByAGUAZgBlAHIAZQBuAGMAZQAgAD0AIAAiAFMAaQBsAGUAbgB0AGwAeQBDAG8AbgB0AGkAbgB1AGUAIgA7ACAAZABpAHIA"
opts = {:extra_args=>["powershell -encodedCommand #{encoded_command}"], :subprocess=>true}
expect(ssh_klass).to receive(:exec).
with(ssh_info, opts)
env[:ssh_info] = ssh_info
env[:ssh_run_command] = "dir"
described_class.new(app, env).call(env)
end
end
end
end

View File

@ -126,9 +126,7 @@ net-ssh library (ignored by the `ssh` executable) and should not be used in gene
This defaults to the value of `config.ssh.username`.
* `config.ssh.shell` (string) - The shell to use when executing SSH commands from
Vagrant. By default this is `bash -l`. Note that this has no effect on
the shell you get when you run `vagrant ssh`. This configuration option
only affects the shell to use when executing commands internally in Vagrant.
Vagrant. By default this is `bash -l`.
* `config.ssh.sudo_command` (string) - The command to use when executing a command
with `sudo`. This defaults to `sudo -E -H %c`. The `%c` will be replaced by

View File

@ -48,9 +48,7 @@ packets every 5 seconds by default to keep connections alive.
* `config.winssh.shell` (string) - The shell to use when executing SSH commands from
Vagrant. By default this is `cmd`. Valid values are `"cmd"` or `"powershell"`.
Note that this has no effect on the shell you get when you run `vagrant ssh`.
This configuration option only affects the shell to use when executing commands
internally in Vagrant.
When the WinSSH provider is enabled, this shell will be used when you run `vagrant ssh`.
* `config.winssh.export_command_template` (string) - The template used to generate
exported environment variables in the active session. This can be useful