drone-ssh/vendor/github.com/appleboy/easyssh-proxy
Wataru Ashihara 097a640e79
[easyssh] fix: panic when using ssh-agent (appleboy/easyssh-proxy#42)
Before changes:

```sh
$ # This is what `keychain --eval --inherit any` does on Ubuntu.
$ # https://www.funtoo.org/Keychain
$ export SSH_AUTH_SOCK=/run/user/1000/keyring/ssh
$ go build example/ssh/ssh.go
$ ./ssh
panic: Can't run remote command: ssh: handshake failed: agent: client error: write unix @->/run/user/1000/keyring/ssh: use of closed network connection

goroutine 1 [running]:
main.main()
	/home/wsh/go/src/github.com/wataash/easyssh-proxy/example/ssh/ssh.go:32 +0x2d3
```

Error message `write unix @->/run/user/1000/keyring/ssh: use of closed network connection` comes from [`Write()`](https://github.com/golang/crypto/blob/2b6c08872f4/ssh/agent/client.go#L277) where `SSH_AUTH_SOCK` is already `Close()`ed.

After changes:

```sh
$ export SSH_AUTH_SOCK=/run/user/1000/keyring/ssh
$ go build example/ssh/ssh.go
$ ./ssh
github.com/wataash/easyssh-proxy
command-line-arguments
don is : true stdout is : total 640
drwxr-xr-x  68 wsh  wsh   4096 10月 16 21:25 .
drwxr-xr-x   3 root root  4096  9月 12 08:39 ..
drwxr-xr-x   2 wsh  wsh   4096  9月 20 20:48 .android
...
-rw-rw-r--   1 wsh  wsh    202  9月 12 19:51 .zshrc
 ;   stderr is : Identity added: /home/wsh/.ssh/id_rsa (/home/wsh/.ssh/id_rsa)
Identity added: /home/wsh/.ssh/id_ed25519 (wsh@wsh9b)

```

https://github.com/appleboy/drone-ssh/commit/9b697286281
2018-10-22 19:50:35 +09:00
..
easyssh.go [easyssh] fix: panic when using ssh-agent (appleboy/easyssh-proxy#42) 2018-10-22 19:50:35 +09:00
LICENSE feat: Add time out flag. (#53) 2017-03-04 17:50:05 +08:00
Makefile bump easyssh package. 2017-05-10 21:37:48 +08:00
README.md [easyssh] update ssh command document (appleboy/easyssh-proxy#32) 2018-10-22 19:50:01 +09:00

easyssh-proxy

GoDoc Build Status codecov Go Report Card Sourcegraph Release

easyssh-proxy provides a simple implementation of some SSH protocol features in Go.

Feature

This project is forked from easyssh but add some features as the following.

  • Support plain text of user private key.
  • Support key path of user private key.
  • Support Timeout for the TCP connection to establish.
  • Support SSH ProxyCommand.
     +--------+       +----------+      +-----------+
     | Laptop | <-->  | Jumphost | <--> | FooServer |
     +--------+       +----------+      +-----------+

                         OR

     +--------+       +----------+      +-----------+
     | Laptop | <-->  | Firewall | <--> | FooServer |
     +--------+       +----------+      +-----------+
     192.168.1.5       121.1.2.3         10.10.29.68

Usage:

You can see ssh, scp, ProxyCommand on examples folder.

ssh

See example/ssh/ssh.go

package main

import (
	"fmt"
	"time"

	"github.com/appleboy/easyssh-proxy"
)

func main() {
	// Create MakeConfig instance with remote username, server address and path to private key.
	ssh := &easyssh.MakeConfig{
		User:   "appleboy",
		Server: "example.com",
		// Optional key or Password without either we try to contact your agent SOCKET
		//Password: "password",
		// Paste your source content of private key
		// Key: `-----BEGIN RSA PRIVATE KEY-----
		// MIIEpAIBAAKCAQEA4e2D/qPN08pzTac+a8ZmlP1ziJOXk45CynMPtva0rtK/RB26
		// 7XC9wlRna4b3Ln8ew3q1ZcBjXwD4ppbTlmwAfQIaZTGJUgQbdsO9YA==
		// -----END RSA PRIVATE KEY-----
		// `,
		KeyPath: "/Users/username/.ssh/id_rsa",
		Port:    "22",
		Timeout: 60 * time.Second,
	}

	// Call Run method with command you want to run on remote server.
	stdout, stderr, done, err := ssh.Run("ls -al", 60)
	// Handle errors
	if err != nil {
		panic("Can't run remote command: " + err.Error())
	} else {
		fmt.Println("don is :", done, "stdout is :", stdout, ";   stderr is :", stderr)
	}

}

scp

See example/scp/scp.go

package main

import (
	"fmt"

	"github.com/appleboy/easyssh-proxy"
)

func main() {
	// Create MakeConfig instance with remote username, server address and path to private key.
	ssh := &easyssh.MakeConfig{
		User:     "appleboy",
		Server:   "example.com",
		Password: "123qwe",
		Port:     "22",
	}

	// Call Scp method with file you want to upload to remote server.
	// Please make sure the `tmp` floder exists.
	err := ssh.Scp("/root/source.csv", "/tmp/target.csv")

	// Handle errors
	if err != nil {
		panic("Can't run remote command: " + err.Error())
	} else {
		fmt.Println("success")
	}
}

SSH ProxyCommand

See example/proxy/proxy.go

	ssh := &easyssh.MakeConfig{
		User:    "drone-scp",
		Server:  "localhost",
		Port:    "22",
		KeyPath: "./tests/.ssh/id_rsa",
		Proxy: easyssh.DefaultConfig{
			User:    "drone-scp",
			Server:  "localhost",
			Port:    "22",
			KeyPath: "./tests/.ssh/id_rsa",
		},
	}

SSH Stream Log

See example/stream/stream.go

func main() {
	// Create MakeConfig instance with remote username, server address and path to private key.
	ssh := &easyssh.MakeConfig{
		Server:  "localhost",
		User:    "drone-scp",
		KeyPath: "./tests/.ssh/id_rsa",
		Port:    "22",
		Timeout: 60 * time.Second,
	}

	// Call Run method with command you want to run on remote server.
	stdoutChan, stderrChan, doneChan, errChan, err := ssh.Stream("for i in {1..5}; do echo ${i}; sleep 1; done; exit 2;", 60)
	// Handle errors
	if err != nil {
		panic("Can't run remote command: " + err.Error())
	} else {
		// read from the output channel until the done signal is passed
		isTimeout := true
	loop:
		for {
			select {
			case isTimeout = <-doneChan:
				break loop
			case outline := <-stdoutChan:
				fmt.Println("out:", outline)
			case errline := <-stderrChan:
				fmt.Println("err:", errline)
			case err = <-errChan:
			}
		}

		// get exit code or command error.
		if err != nil {
			fmt.Println("err: " + err.Error())
		}

		// command time out
		if !isTimeout {
			fmt.Println("Error: command timeout")
		}
	}
}