diff --git a/easyssh/easyssh_test.go b/easyssh/easyssh_test.go deleted file mode 100644 index 4efb9cd..0000000 --- a/easyssh/easyssh_test.go +++ /dev/null @@ -1,130 +0,0 @@ -package easyssh - -import ( - "os" - "os/user" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestGetKeyFile(t *testing.T) { - // missing file - _, err := getKeyFile("abc") - assert.Error(t, err) - assert.Equal(t, "open abc: no such file or directory", err.Error()) - - // wrong format - _, err = getKeyFile("../tests/.ssh/id_rsa.pub") - assert.Error(t, err) - assert.Equal(t, "ssh: no key found", err.Error()) - - _, err = getKeyFile("../tests/.ssh/id_rsa") - assert.NoError(t, err) -} - -func TestRunCommand(t *testing.T) { - ssh := &MakeConfig{ - Server: "localhost", - User: "drone-scp", - Port: "22", - KeyPath: "../tests/.ssh/id_rsa", - } - - output, err := ssh.Run("whoami") - assert.Equal(t, "drone-scp\n", output) - assert.NoError(t, err) -} - -func TestSCPCommand(t *testing.T) { - ssh := &MakeConfig{ - Server: "localhost", - User: "drone-scp", - Port: "22", - KeyPath: "../tests/.ssh/id_rsa", - } - - err := ssh.Scp("../tests/a.txt") - assert.NoError(t, err) - - u, err := user.Lookup("drone-scp") - if err != nil { - t.Fatalf("Lookup: %v", err) - } - - // check file exist - if _, err := os.Stat(u.HomeDir + "/a.txt"); os.IsNotExist(err) { - t.Fatalf("SCP-error: %v", err) - } -} - -func TestSCPCommandWithKey(t *testing.T) { - ssh := &MakeConfig{ - Server: "localhost", - User: "drone-scp", - Port: "22", - Key: `-----BEGIN RSA PRIVATE KEY----- -MIIEpAIBAAKCAQEA4e2D/qPN08pzTac+a8ZmlP1ziJOXk45CynMPtva0rtK/RB26 -VbfAF0hIJji7ltvnYnqCU9oFfvEM33cTn7T96+od8ib/Vz25YU8ZbstqtIskPuwC -bv3K0mAHgsviJyRD7yM+QKTbBQEgbGuW6gtbMKhiYfiIB4Dyj7AdS/fk3v26wDgz -7SHI5OBqu9bv1KhxQYdFEnU3PAtAqeccgzNpbH3eYLyGzuUxEIJlhpZ/uU2G9ppj -/cSrONVPiI8Ahi4RrlZjmP5l57/sq1ClGulyLpFcMw68kP5FikyqHpHJHRBNgU57 -1y0Ph33SjBbs0haCIAcmreWEhGe+/OXnJe6VUQIDAQABAoIBAH97emORIm9DaVSD -7mD6DqA7c5m5Tmpgd6eszU08YC/Vkz9oVuBPUwDQNIX8tT0m0KVs42VVPIyoj874 -bgZMJoucC1G8V5Bur9AMxhkShx9g9A7dNXJTmsKilRpk2TOk7wBdLp9jZoKoZBdJ -jlp6FfaazQjjKD6zsCsMATwAoRCBpBNsmT6QDN0n0bIgY0tE6YGQaDdka0dAv68G -R0VZrcJ9voT6+f+rgJLoojn2DAu6iXaM99Gv8FK91YCymbQlXXgrk6CyS0IHexN7 -V7a3k767KnRbrkqd3o6JyNun/CrUjQwHs1IQH34tvkWScbseRaFehcAm6mLT93RP -muauvMECgYEA9AXGtfDMse0FhvDPZx4mx8x+vcfsLvDHcDLkf/lbyPpu97C27b/z -ia07bu5TAXesUZrWZtKA5KeRE5doQSdTOv1N28BEr8ZwzDJwfn0DPUYUOxsN2iIy -MheO5A45Ko7bjKJVkZ61Mb1UxtqCTF9mqu9R3PBdJGthWOd+HUvF460CgYEA7QRf -Z8+vpGA+eSuu29e0xgRKnRzed5zXYpcI4aERc3JzBgO4Z0er9G8l66OWVGdMfpe6 -CBajC5ToIiT8zqoYxXwqJgN+glir4gJe3mm8J703QfArZiQrdk0NTi5bY7+vLLG/ -knTrtpdsKih6r3kjhuPPaAsIwmMxIydFvATKjLUCgYEAh/y4EihRSk5WKC8GxeZt -oiZ58vT4z+fqnMIfyJmD5up48JuQNcokw/LADj/ODiFM7GUnWkGxBrvDA3H67WQm -49bJjs8E+BfUQFdTjYnJRlpJZ+7Zt1gbNQMf5ENw5CCchTDqEq6pN0DVf8PBnSIF -KvkXW9KvdV5J76uCAn15mDkCgYA1y8dHzbjlCz9Cy2pt1aDfTPwOew33gi7U3skS -RTerx29aDyAcuQTLfyrROBkX4TZYiWGdEl5Bc7PYhCKpWawzrsH2TNa7CRtCOh2E -R+V/84+GNNf04ALJYCXD9/ugQVKmR1XfDRCvKeFQFE38Y/dvV2etCswbKt5tRy2p -xkCe/QKBgQCkLqafD4S20YHf6WTp3jp/4H/qEy2X2a8gdVVBi1uKkGDXr0n+AoVU -ib4KbP5ovZlrjL++akMQ7V2fHzuQIFWnCkDA5c2ZAqzlM+ZN+HRG7gWur7Bt4XH1 -7XC9wlRna4b3Ln8ew3q1ZcBjXwD4ppbTlmwAfQIaZTGJUgQbdsO9YA== ------END RSA PRIVATE KEY----- -`, - } - - err := ssh.Scp("../tests/a.txt") - assert.NoError(t, err) - - u, err := user.Lookup("drone-scp") - if err != nil { - t.Fatalf("Lookup: %v", err) - } - - // check file exist - if _, err := os.Stat(u.HomeDir + "/a.txt"); os.IsNotExist(err) { - t.Fatalf("SCP-error: %v", err) - } -} - -func TestSCPCommandWithPassword(t *testing.T) { - ssh := &MakeConfig{ - Server: "localhost", - User: "drone-scp", - Port: "22", - Password: "1234", - } - - err := ssh.Scp("../tests/b.txt") - assert.NoError(t, err) - - u, err := user.Lookup("drone-scp") - if err != nil { - t.Fatalf("Lookup: %v", err) - } - - // check file exist - if _, err := os.Stat(u.HomeDir + "/b.txt"); os.IsNotExist(err) { - t.Fatalf("SCP-error: %v", err) - } -} diff --git a/main.go b/main.go index f9ff882..5f28a12 100644 --- a/main.go +++ b/main.go @@ -52,6 +52,12 @@ func main() { Usage: "connection timeout", EnvVar: "PLUGIN_TIMEOUT,SCP_TIMEOUT", }, + cli.IntFlag{ + Name: "command.timeout,T", + Usage: "command timeout", + EnvVar: "PLUGIN_COMMAND_TIMEOUT,SSH_COMMAND_TIMEOUT", + Value: 60, + }, cli.StringFlag{ Name: "key, k", Usage: "ssh private key", @@ -192,16 +198,17 @@ func run(c *cli.Context) error { Link: c.String("build.link"), }, Config: Config{ - Host: c.StringSlice("host"), - Port: c.String("port"), - Username: c.String("username"), - Password: c.String("password"), - Timeout: c.Duration("timeout"), - Key: c.String("key"), - KeyPath: c.String("key-path"), - Target: c.StringSlice("target"), - Source: c.StringSlice("source"), - Remove: c.Bool("rm"), + Host: c.StringSlice("host"), + Port: c.String("port"), + Username: c.String("username"), + Password: c.String("password"), + Timeout: c.Duration("timeout"), + CommandTimeout: c.Int("command.timeout"), + Key: c.String("key"), + KeyPath: c.String("key-path"), + Target: c.StringSlice("target"), + Source: c.StringSlice("source"), + Remove: c.Bool("rm"), }, } diff --git a/plugin.go b/plugin.go index e43b0ab..7be6bb0 100644 --- a/plugin.go +++ b/plugin.go @@ -13,7 +13,7 @@ import ( "time" "github.com/appleboy/com/random" - "github.com/appleboy/drone-scp/easyssh" + "github.com/appleboy/easyssh-proxy" ) type ( @@ -37,16 +37,17 @@ type ( // Config for the plugin. Config struct { - Host []string - Port string - Username string - Password string - Key string - KeyPath string - Timeout time.Duration - Target []string - Source []string - Remove bool + Host []string + Port string + Username string + Password string + Key string + KeyPath string + Timeout time.Duration + CommandTimeout int + Target []string + Source []string + Remove bool } // Plugin values. @@ -145,9 +146,8 @@ func (p Plugin) Exec() error { // Call Scp method with file you want to upload to remote server. p.log(host, "scp file to server.") - err = ssh.Scp(tar) + err := ssh.Scp(tar, dest) - // Handle errors if err != nil { errChannel <- err } @@ -157,7 +157,7 @@ func (p Plugin) Exec() error { if p.Config.Remove { p.log(host, "Remove target folder:", target) - _, err := ssh.Run(fmt.Sprintf("rm -rf %s", target)) + _, _, _, err := ssh.Run(fmt.Sprintf("rm -rf %s", target), p.Config.CommandTimeout) if err != nil { errChannel <- err @@ -166,15 +166,18 @@ func (p Plugin) Exec() error { // mkdir path p.log(host, "create folder", target) - response, _ := ssh.Run(fmt.Sprintf("mkdir -p %s", target)) + _, errStr, _, err := ssh.Run(fmt.Sprintf("mkdir -p %s", target), p.Config.CommandTimeout) + if err != nil { + errChannel <- err + } - if response != "" { - errChannel <- errors.New(response) + if len(errStr) != 0 { + errChannel <- fmt.Errorf(errStr) } // untar file p.log(host, "untar file", dest) - _, err = ssh.Run(fmt.Sprintf("tar -xf %s -C %s", dest, target)) + _, _, _, err = ssh.Run(fmt.Sprintf("tar -xf %s -C %s", dest, target), p.Config.CommandTimeout) if err != nil { errChannel <- err @@ -183,7 +186,7 @@ func (p Plugin) Exec() error { // remove tar file p.log(host, "remove file", dest) - _, err = ssh.Run(fmt.Sprintf("rm -rf %s", dest)) + _, _, _, err = ssh.Run(fmt.Sprintf("rm -rf %s", dest), p.Config.CommandTimeout) if err != nil { errChannel <- err diff --git a/plugin_test.go b/plugin_test.go index e82101b..06f70a5 100644 --- a/plugin_test.go +++ b/plugin_test.go @@ -71,12 +71,13 @@ func TestSCPFileFromPublicKey(t *testing.T) { plugin := Plugin{ Config: Config{ - Host: []string{"localhost"}, - Username: "drone-scp", - Port: "22", - KeyPath: "tests/.ssh/id_rsa", - Source: []string{"tests/a.txt", "tests/b.txt"}, - Target: []string{u.HomeDir + "/test"}, + Host: []string{"localhost"}, + Username: "drone-scp", + Port: "22", + KeyPath: "tests/.ssh/id_rsa", + Source: []string{"tests/a.txt", "tests/b.txt"}, + Target: []string{u.HomeDir + "/test"}, + CommandTimeout: 60, }, } @@ -117,12 +118,13 @@ func TestSCPWildcardFileList(t *testing.T) { plugin := Plugin{ Config: Config{ - Host: []string{"localhost"}, - Username: "drone-scp", - Port: "22", - KeyPath: "tests/.ssh/id_rsa", - Source: []string{"tests/global/*"}, - Target: []string{u.HomeDir + "/abc"}, + Host: []string{"localhost"}, + Username: "drone-scp", + Port: "22", + KeyPath: "tests/.ssh/id_rsa", + Source: []string{"tests/global/*"}, + Target: []string{u.HomeDir + "/abc"}, + CommandTimeout: 60, }, } @@ -188,12 +190,13 @@ func TestSCPWildcardFileList(t *testing.T) { func TestIncorrectPassword(t *testing.T) { plugin := Plugin{ Config: Config{ - Host: []string{"localhost"}, - Username: "drone-scp", - Port: "22", - Password: "123456", - Source: []string{"tests/a.txt", "tests/b.txt"}, - Target: []string{"/home"}, + Host: []string{"localhost"}, + Username: "drone-scp", + Port: "22", + Password: "123456", + Source: []string{"tests/a.txt", "tests/b.txt"}, + Target: []string{"/home"}, + CommandTimeout: 60, }, } @@ -204,28 +207,13 @@ func TestIncorrectPassword(t *testing.T) { func TestNoPermissionCreateFolder(t *testing.T) { plugin := Plugin{ Config: Config{ - Host: []string{"localhost"}, - Username: "drone-scp", - Port: "22", - KeyPath: "tests/.ssh/id_rsa", - Source: []string{"tests/a.txt", "tests/b.txt"}, - Target: []string{"/etc/test"}, - }, - } - - err := plugin.Exec() - assert.NotNil(t, err) -} - -func TestSourceNotFound(t *testing.T) { - plugin := Plugin{ - Config: Config{ - Host: []string{"localhost"}, - Username: "drone-scp", - Port: "22", - KeyPath: "tests/.ssh/id_rsa", - Source: []string{"tests/aa.txt", "tests/b.txt"}, - Target: []string{"/test"}, + Host: []string{"localhost"}, + Username: "drone-scp", + Port: "22", + KeyPath: "tests/.ssh/id_rsa", + Source: []string{"tests/a.txt", "tests/b.txt"}, + Target: []string{"/etc/test"}, + CommandTimeout: 60, }, } @@ -246,4 +234,8 @@ func TestGlobList(t *testing.T) { paterns = []string{"tests/?.txt"} expects = []string{"tests/a.txt", "tests/b.txt"} assert.Equal(t, expects, globList(paterns)) + + paterns = []string{"tests/aa.txt", "tests/b.txt"} + expects = []string{"tests/b.txt"} + assert.Equal(t, expects, globList(paterns)) } diff --git a/vendor/github.com/appleboy/easyssh-proxy/LICENSE b/vendor/github.com/appleboy/easyssh-proxy/LICENSE new file mode 100644 index 0000000..b6df010 --- /dev/null +++ b/vendor/github.com/appleboy/easyssh-proxy/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Bo-Yi Wu + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/appleboy/easyssh-proxy/Makefile b/vendor/github.com/appleboy/easyssh-proxy/Makefile new file mode 100644 index 0000000..f29113d --- /dev/null +++ b/vendor/github.com/appleboy/easyssh-proxy/Makefile @@ -0,0 +1,60 @@ +.PHONY: test drone-ssh build fmt vet errcheck lint install update release-dirs release-build release-copy release-check release coverage + +PACKAGES ?= $(shell go list ./... | grep -v /vendor/) + +all: build + +fmt: + find . -name "*.go" -type f -not -path "./vendor/*" | xargs gofmt -s -w + +vet: + go vet $(PACKAGES) + +errcheck: + @hash errcheck > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ + go get -u github.com/kisielk/errcheck; \ + fi + errcheck $(PACKAGES) + +lint: + @hash golint > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ + go get -u github.com/golang/lint/golint; \ + fi + for PKG in $(PACKAGES); do golint -set_exit_status $$PKG || exit 1; done; + +unconvert: + @hash unconvert > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ + go get -u github.com/mdempsky/unconvert; \ + fi + for PKG in $(PACKAGES); do unconvert -v $$PKG || exit 1; done; + +test: + for PKG in $(PACKAGES); do go test -v -cover -coverprofile $$GOPATH/src/$$PKG/coverage.txt $$PKG || exit 1; done; + +html: + go tool cover -html=coverage.txt + +coverage: + sed -i '/main.go/d' .cover/coverage.txt + curl -s https://codecov.io/bash > .codecov && \ + chmod +x .codecov && \ + ./.codecov -f .cover/coverage.txt + +clean: + go clean -x -i ./... + rm -rf coverage.txt $(EXECUTABLE) $(DIST) vendor + +ssh-server: + adduser -h /home/drone-scp -s /bin/bash -D -S drone-scp + echo drone-scp:1234 | chpasswd + mkdir -p /home/drone-scp/.ssh + chmod 700 /home/drone-scp/.ssh + cp tests/.ssh/id_rsa.pub /home/drone-scp/.ssh/authorized_keys + chown -R drone-scp /home/drone-scp/.ssh + # install ssh and start server + apk add --update openssh openrc + rm -rf /etc/ssh/ssh_host_rsa_key /etc/ssh/ssh_host_dsa_key + ./tests/entrypoint.sh /usr/sbin/sshd -D & + +version: + @echo $(VERSION) diff --git a/vendor/github.com/appleboy/easyssh-proxy/README.md b/vendor/github.com/appleboy/easyssh-proxy/README.md new file mode 100644 index 0000000..134bd52 --- /dev/null +++ b/vendor/github.com/appleboy/easyssh-proxy/README.md @@ -0,0 +1,5 @@ +# easyssh-proxy + +[![GoDoc](https://godoc.org/github.com/appleboy/easyssh-proxy?status.svg)](https://godoc.org/github.com/appleboy/easyssh-proxy) [![Build Status](http://drone.wu-boy.com/api/badges/appleboy/easyssh-proxy/status.svg)](http://drone.wu-boy.com/appleboy/easyssh-proxy) [![codecov](https://codecov.io/gh/appleboy/easyssh-proxy/branch/master/graph/badge.svg)](https://codecov.io/gh/appleboy/easyssh-proxy) [![Go Report Card](https://goreportcard.com/badge/github.com/appleboy/easyssh-proxy)](https://goreportcard.com/report/github.com/appleboy/easyssh-proxy) + +easyssh-proxy provides a simple implementation of some SSH protocol features in Go diff --git a/easyssh/easyssh.go b/vendor/github.com/appleboy/easyssh-proxy/easyssh.go similarity index 58% rename from easyssh/easyssh.go rename to vendor/github.com/appleboy/easyssh-proxy/easyssh.go index 157cd36..27a074d 100644 --- a/easyssh/easyssh.go +++ b/vendor/github.com/appleboy/easyssh-proxy/easyssh.go @@ -35,6 +35,14 @@ type MakeConfig struct { Timeout time.Duration } +type sshConfig struct { + User string + Key string + KeyPath string + Password string + Timeout time.Duration +} + // returns ssh.Signer from user you running app home path + cutted key path. // (ex. pubkey,err := getKeyFile("/.ssh/id_rsa") ) func getKeyFile(keypath string) (ssh.Signer, error) { @@ -51,14 +59,13 @@ func getKeyFile(keypath string) (ssh.Signer, error) { return pubkey, nil } -// connects to remote server using MakeConfig struct and returns *ssh.Session -func (ssh_conf *MakeConfig) connect() (*ssh.Session, error) { +func getSSHConfig(config sshConfig) *ssh.ClientConfig { // auths holds the detected ssh auth methods auths := []ssh.AuthMethod{} // figure out what auths are requested, what is supported - if ssh_conf.Password != "" { - auths = append(auths, ssh.Password(ssh_conf.Password)) + if config.Password != "" { + auths = append(auths, ssh.Password(config.Password)) } if sshAgent, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK")); err == nil { @@ -66,22 +73,33 @@ func (ssh_conf *MakeConfig) connect() (*ssh.Session, error) { defer sshAgent.Close() } - if ssh_conf.KeyPath != "" { - if pubkey, err := getKeyFile(ssh_conf.KeyPath); err == nil { + if config.KeyPath != "" { + if pubkey, err := getKeyFile(config.KeyPath); err == nil { auths = append(auths, ssh.PublicKeys(pubkey)) } } - if ssh_conf.Key != "" { - signer, _ := ssh.ParsePrivateKey([]byte(ssh_conf.Key)) + if config.Key != "" { + signer, _ := ssh.ParsePrivateKey([]byte(config.Key)) auths = append(auths, ssh.PublicKeys(signer)) } - config := &ssh.ClientConfig{ - Timeout: ssh_conf.Timeout, - User: ssh_conf.User, + return &ssh.ClientConfig{ + Timeout: config.Timeout, + User: config.User, Auth: auths, } +} + +// connect to remote server using MakeConfig struct and returns *ssh.Session +func (ssh_conf *MakeConfig) connect() (*ssh.Session, error) { + config := getSSHConfig(sshConfig{ + User: ssh_conf.User, + Key: ssh_conf.Key, + KeyPath: ssh_conf.KeyPath, + Password: ssh_conf.Password, + Timeout: ssh_conf.Timeout, + }) client, err := ssh.Dial("tcp", net.JoinHostPort(ssh_conf.Server, ssh_conf.Port), config) if err != nil { @@ -99,63 +117,95 @@ func (ssh_conf *MakeConfig) connect() (*ssh.Session, error) { // Stream returns one channel that combines the stdout and stderr of the command // as it is run on the remote machine, and another that sends true when the // command is done. The sessions and channels will then be closed. -func (ssh_conf *MakeConfig) Stream(command string) (output chan string, done chan bool, err error) { +func (ssh_conf *MakeConfig) Stream(command string, timeout int) (stdout chan string, stderr chan string, done chan bool, err error) { // connect to remote host session, err := ssh_conf.connect() if err != nil { - return output, done, err + return stdout, stderr, done, err } // connect to both outputs (they are of type io.Reader) outReader, err := session.StdoutPipe() if err != nil { - return output, done, err + return stdout, stderr, done, err } errReader, err := session.StderrPipe() if err != nil { - return output, done, err + return stdout, stderr, done, err } // combine outputs, create a line-by-line scanner - outputReader := io.MultiReader(outReader, errReader) + stdoutReader := io.MultiReader(outReader) + stderrReader := io.MultiReader(errReader) err = session.Start(command) - scanner := bufio.NewScanner(outputReader) + stdoutScanner := bufio.NewScanner(stdoutReader) + stderrScanner := bufio.NewScanner(stderrReader) // continuously send the command's output over the channel - outputChan := make(chan string) + stdoutChan := make(chan string) + stderrChan := make(chan string) done = make(chan bool) - go func(scanner *bufio.Scanner, out chan string, done chan bool) { - defer close(outputChan) + + go func(stdoutScanner, stderrScanner *bufio.Scanner, stdoutChan, stderrChan chan string, done chan bool) { + defer close(stdoutChan) + defer close(stderrChan) defer close(done) - for scanner.Scan() { - outputChan <- scanner.Text() + + timeoutChan := time.After(time.Duration(timeout) * time.Second) + res := make(chan bool, 1) + + go func() { + for stdoutScanner.Scan() { + stdoutChan <- stdoutScanner.Text() + } + for stderrScanner.Scan() { + stderrChan <- stderrScanner.Text() + } + // close all of our open resources + res <- true + }() + + select { + case <-res: + stdoutChan <- "" + stderrChan <- "" + done <- true + case <-timeoutChan: + stdoutChan <- "" + stderrChan <- "Run Command Timeout!" + done <- false } - // close all of our open resources - done <- true + session.Close() - }(scanner, outputChan, done) - return outputChan, done, err + }(stdoutScanner, stderrScanner, stdoutChan, stderrChan, done) + return stdoutChan, stderrChan, done, err } // Run command on remote machine and returns its stdout as a string -func (ssh_conf *MakeConfig) Run(command string) (outStr string, err error) { - outChan, doneChan, err := ssh_conf.Stream(command) +func (ssh_conf *MakeConfig) Run(command string, timeout int) (outStr string, errStr string, isTimeout bool, err error) { + stdoutChan, stderrChan, doneChan, err := ssh_conf.Stream(command, timeout) if err != nil { - return outStr, err + return outStr, errStr, isTimeout, err } // read from the output channel until the done signal is passed stillGoing := true for stillGoing { select { - case <-doneChan: + case isTimeout = <-doneChan: stillGoing = false - case line := <-outChan: - outStr += line + "\n" + case outline := <-stdoutChan: + if outline != "" { + outStr += outline + "\n" + } + case errline := <-stderrChan: + if errline != "" { + errStr += errline + "\n" + } } } // return the concatenation of all signals from the output channel - return outStr, err + return outStr, errStr, isTimeout, err } // Scp uploads sourceFile to remote machine like native scp console app. -func (ssh_conf *MakeConfig) Scp(sourceFile string) error { +func (ssh_conf *MakeConfig) Scp(sourceFile string, etargetFile string) error { session, err := ssh_conf.connect() if err != nil { @@ -163,7 +213,7 @@ func (ssh_conf *MakeConfig) Scp(sourceFile string) error { } defer session.Close() - targetFile := filepath.Base(sourceFile) + targetFile := filepath.Base(etargetFile) src, srcErr := os.Open(sourceFile) @@ -192,7 +242,7 @@ func (ssh_conf *MakeConfig) Scp(sourceFile string) error { } }() - if err := session.Run(fmt.Sprintf("scp -t %s", targetFile)); err != nil { + if err := session.Run(fmt.Sprintf("scp -tr %s", etargetFile)); err != nil { return err } diff --git a/vendor/vendor.json b/vendor/vendor.json index 6053b03..99441dc 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -10,6 +10,14 @@ "version": "master", "versionExact": "master" }, + { + "checksumSHA1": "NCdmzR+clcl2/1jUPn0vFeqjwjk=", + "path": "github.com/appleboy/easyssh-proxy", + "revision": "89c61a4555c1578454f75ae406f4e3cdded275d2", + "revisionTime": "2017-03-04T06:27:13Z", + "version": "=1.0.0", + "versionExact": "1.0.0" + }, { "checksumSHA1": "dvabztWVQX8f6oMLRyv4dLH+TGY=", "path": "github.com/davecgh/go-spew/spew", @@ -71,14 +79,14 @@ { "checksumSHA1": "fsrFs762jlaILyqqQImS1GfvIvw=", "path": "golang.org/x/crypto/ssh", - "revision": "453249f01cfeb54c3d549ddb75ff152ca243f9d8", - "revisionTime": "2017-02-08T20:51:15Z" + "revision": "40541ccb1c6e64c947ed6f606b8a6cb4b67d7436", + "revisionTime": "2017-02-12T21:20:41Z" }, { "checksumSHA1": "SJ3Ma3Ozavxpbh1usZWBCnzMKIc=", "path": "golang.org/x/crypto/ssh/agent", - "revision": "453249f01cfeb54c3d549ddb75ff152ca243f9d8", - "revisionTime": "2017-02-08T20:51:15Z" + "revision": "40541ccb1c6e64c947ed6f606b8a6cb4b67d7436", + "revisionTime": "2017-02-12T21:20:41Z" } ], "rootPath": "github.com/appleboy/drone-scp"