Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for remote_exec on Windows SSH #26865

Merged
merged 8 commits into from
Nov 12, 2020
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 38 additions & 21 deletions communicator/ssh/communicator.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ var (
// max time to wait for for a KeepAlive response before considering the
// connection to be dead.
maxKeepAliveDelay = 120 * time.Second

// isWindows, determines whether or not the target ssh is a windows machine, determined by the path. On windows SSH some things need to be skipped, like chmodding the file
isWindows = false
)

// Communicator represents the SSH communicator
Expand Down Expand Up @@ -343,7 +346,7 @@ func (c *Communicator) Start(cmd *remote.Cmd) error {
session.Stdout = cmd.Stdout
session.Stderr = cmd.Stderr

if !c.config.noPty {
if !c.config.noPty && !isWindows {
// Request a PTY
termModes := ssh.TerminalModes{
ssh.ECHO: 0, // do not echo
Expand Down Expand Up @@ -420,40 +423,44 @@ func (c *Communicator) Upload(path string, input io.Reader) error {

// UploadScript implementation of communicator.Communicator interface
func (c *Communicator) UploadScript(path string, input io.Reader) error {
// Check if path is specified as windows driveletter, if so set isWindows to true
if isWindowsPath(path) {
isWindows = true
}
reader := bufio.NewReader(input)
prefix, err := reader.Peek(2)
if err != nil {
return fmt.Errorf("Error reading script: %s", err)
}

var script bytes.Buffer
if string(prefix) != "#!" {

if string(prefix) != "#!" && !isWindows {
script.WriteString(DefaultShebang)
}

script.ReadFrom(reader)

if err := c.Upload(path, &script); err != nil {
return err
}
if !isWindows {
var stdout, stderr bytes.Buffer
cmd := &remote.Cmd{
Command: fmt.Sprintf("chmod 0777 %s", path),
Stdout: &stdout,
Stderr: &stderr,
}
if err := c.Start(cmd); err != nil {
return fmt.Errorf(
"Error chmodding script file to 0777 in remote "+
"machine: %s", err)
}

var stdout, stderr bytes.Buffer
cmd := &remote.Cmd{
Command: fmt.Sprintf("chmod 0777 %s", path),
Stdout: &stdout,
Stderr: &stderr,
}
if err := c.Start(cmd); err != nil {
return fmt.Errorf(
"Error chmodding script file to 0777 in remote "+
"machine: %s", err)
}

if err := cmd.Wait(); err != nil {
return fmt.Errorf(
"Error chmodding script file to 0777 in remote "+
"machine %v: %s %s", err, stdout.String(), stderr.String())
if err := cmd.Wait(); err != nil {
return fmt.Errorf(
"Error chmodding script file to 0777 in remote "+
"machine %v: %s %s", err, stdout.String(), stderr.String())
}
}

return nil
}

Expand Down Expand Up @@ -812,3 +819,13 @@ func (c *bastionConn) Close() error {
c.Conn.Close()
return c.Bastion.Close()
}

func isWindowsPath(path string) bool {
// Check if first letter of path is in range a-z:A-Z
c := rune(path[0:1][0])
if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') {
// if second rune is a colon, we know it's a windows path
return rune(path[1:2][0]) == ':'
}
return false
}