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:
parent
f0b8c0737f
commit
7fb7dd8608
|
@ -36,17 +36,35 @@ module Vagrant
|
||||||
|
|
||||||
# Get the command and wrap it in a login shell
|
# Get the command and wrap it in a login shell
|
||||||
command = ShellQuote.escape(env[:ssh_run_command], "'")
|
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!
|
# Execute!
|
||||||
opts = env[:ssh_opts] || {}
|
opts = env[:ssh_opts] || {}
|
||||||
opts[:extra_args] ||= []
|
opts[:extra_args] ||= []
|
||||||
|
|
||||||
# Allow the user to specify a tty or non-tty manually, but if they
|
# 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") &&
|
if !opts[:extra_args].include?("-t") &&
|
||||||
!opts[:extra_args].include?("-T") &&
|
!opts[:extra_args].include?("-T") &&
|
||||||
env[:tty]
|
env[:tty] &&
|
||||||
|
env[:machine].config.vm.communicator != :winssh
|
||||||
opts[:extra_args] << "-t"
|
opts[:extra_args] << "-t"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -18,8 +18,14 @@ describe Vagrant::Action::Builtin::SSHRun do
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
let(:vm) do
|
||||||
|
double("vm",
|
||||||
|
communicator: nil
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
# Configuration mock
|
# Configuration mock
|
||||||
let(:config) { double("config", ssh: ssh) }
|
let(:config) { double("config", ssh: ssh, vm: vm) }
|
||||||
|
|
||||||
let(:machine) do
|
let(:machine) do
|
||||||
double("machine",
|
double("machine",
|
||||||
|
@ -80,4 +86,63 @@ describe Vagrant::Action::Builtin::SSHRun do
|
||||||
env[:ssh_run_command] = "echo test"
|
env[:ssh_run_command] = "echo test"
|
||||||
described_class.new(app, env).call(env)
|
described_class.new(app, env).call(env)
|
||||||
end
|
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
|
end
|
||||||
|
|
|
@ -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`.
|
This defaults to the value of `config.ssh.username`.
|
||||||
|
|
||||||
* `config.ssh.shell` (string) - The shell to use when executing SSH commands from
|
* `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
|
Vagrant. By default this is `bash -l`.
|
||||||
the shell you get when you run `vagrant ssh`. This configuration option
|
|
||||||
only affects the shell to use when executing commands internally in Vagrant.
|
|
||||||
|
|
||||||
* `config.ssh.sudo_command` (string) - The command to use when executing a command
|
* `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
|
with `sudo`. This defaults to `sudo -E -H %c`. The `%c` will be replaced by
|
||||||
|
|
|
@ -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
|
* `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"`.
|
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`.
|
When the WinSSH provider is enabled, this shell will be used when you run `vagrant ssh`.
|
||||||
This configuration option only affects the shell to use when executing commands
|
|
||||||
internally in Vagrant.
|
|
||||||
|
|
||||||
* `config.winssh.export_command_template` (string) - The template used to generate
|
* `config.winssh.export_command_template` (string) - The template used to generate
|
||||||
exported environment variables in the active session. This can be useful
|
exported environment variables in the active session. This can be useful
|
||||||
|
|
Loading…
Reference in New Issue