From 9b7c4eba24fba39a477f4f16c7314da037f082c4 Mon Sep 17 00:00:00 2001 From: Bo-Yi Wu Date: Sat, 4 Mar 2017 18:26:53 +0800 Subject: [PATCH] feat: Support proxy command. --- main.go | 46 ++++++++++ plugin.go | 20 ++++ plugin_test.go | 22 +++++ .../appleboy/easyssh-proxy/easyssh.go | 92 +++++++++++++++---- vendor/vendor.json | 10 +- 5 files changed, 165 insertions(+), 25 deletions(-) diff --git a/main.go b/main.go index 3711e3b..20d44a5 100644 --- a/main.go +++ b/main.go @@ -77,6 +77,43 @@ func main() { Name: "env-file", Usage: "source env file", }, + cli.StringFlag{ + Name: "proxy.ssh-key", + Usage: "private ssh key of proxy", + EnvVar: "PLUGIN_PROXY_SSH_KEY,PLUGIN_PROXY_KEY,PROXY_SSH_KEY", + }, + cli.StringFlag{ + Name: "proxy.key-path", + Usage: "ssh private key path of proxy", + EnvVar: "PLUGIN_PROXY_KEY_PATH,PROXY_SSH_KEY_PATH", + }, + cli.StringFlag{ + Name: "proxy.username,user", + Usage: "connect as user of proxy", + EnvVar: "PLUGIN_PROXY_USERNAME,PLUGIN_PROXY_USER,PROXY_SSH_USERNAME", + Value: "root", + }, + cli.StringFlag{ + Name: "proxy.password", + Usage: "user password of proxy", + EnvVar: "PLUGIN_PROXY_PASSWORD,PROXY_SSH_PASSWORD", + }, + cli.StringFlag{ + Name: "proxy.host", + Usage: "connect to host of proxy", + EnvVar: "PLUGIN_PROXY_HOST,PROXY_SSH_HOST", + }, + cli.StringFlag{ + Name: "proxy.port", + Usage: "connect to port of proxy", + EnvVar: "PLUGIN_PROXY_PORT,PROXY_SSH_PORT", + Value: "22", + }, + cli.DurationFlag{ + Name: "proxy.timeout", + Usage: "proxy connection timeout", + EnvVar: "PLUGIN_PROXY_TIMEOUT,PROXY_SSH_TIMEOUT", + }, } // Override a template @@ -131,6 +168,15 @@ func run(c *cli.Context) error { Timeout: c.Duration("timeout"), CommandTimeout: c.Int("command.timeout"), Script: c.StringSlice("script"), + Proxy: defaultConfig{ + Key: c.String("proxy.ssh-key"), + KeyPath: c.String("proxy.key-path"), + User: c.String("proxy.user"), + Password: c.String("proxy.password"), + Server: c.String("proxy.host"), + Port: c.String("proxy.port"), + Timeout: c.Duration("proxy.timeout"), + }, }, } diff --git a/plugin.go b/plugin.go index 2079b05..9d74469 100644 --- a/plugin.go +++ b/plugin.go @@ -19,6 +19,16 @@ const ( ) type ( + defaultConfig struct { + User string + Server string + Key string + KeyPath string + Port string + Password string + Timeout time.Duration + } + // Config for the plugin. Config struct { Key string @@ -30,6 +40,7 @@ type ( Timeout time.Duration CommandTimeout int Script []string + Proxy defaultConfig } // Plugin structure @@ -66,6 +77,15 @@ func (p Plugin) Exec() error { Key: p.Config.Key, KeyPath: p.Config.KeyPath, Timeout: p.Config.Timeout, + Proxy: defaultConfig{ + Server: p.Config.Proxy.Server, + User: p.Config.Proxy.User, + Password: p.Config.Proxy.Password, + Port: p.Config.Proxy.Port, + Key: p.Config.Proxy.Key, + KeyPath: p.Config.Proxy.KeyPath, + Timeout: p.Config.Proxy.Timeout, + }, } p.log(host, "commands: ", strings.Join(p.Config.Script, "\n")) diff --git a/plugin_test.go b/plugin_test.go index 8c125bb..154aee8 100644 --- a/plugin_test.go +++ b/plugin_test.go @@ -134,3 +134,25 @@ func TestSSHCommandNotFound(t *testing.T) { err := plugin.Exec() assert.NotNil(t, err) } + +func TestProxyCommand(t *testing.T) { + plugin := Plugin{ + Config: Config{ + Host: []string{"localhost"}, + UserName: "drone-scp", + Port: 22, + KeyPath: "./tests/.ssh/id_rsa", + Script: []string{"whoami"}, + CommandTimeout: 1, + Proxy: defaultConfig{ + Server: "localhost", + User: "drone-scp", + Port: "22", + KeyPath: "./tests/.ssh/id_rsa", + }, + }, + } + + err := plugin.Exec() + assert.Nil(t, err) +} diff --git a/vendor/github.com/appleboy/easyssh-proxy/easyssh.go b/vendor/github.com/appleboy/easyssh-proxy/easyssh.go index 27a074d..3f7aaeb 100644 --- a/vendor/github.com/appleboy/easyssh-proxy/easyssh.go +++ b/vendor/github.com/appleboy/easyssh-proxy/easyssh.go @@ -25,23 +25,44 @@ import ( // Port is SSH server port on remote machine. // Note: easyssh looking for private key in user's home directory (ex. /home/john + Key). // Then ensure your Key begins from '/' (ex. /.ssh/id_rsa) -type MakeConfig struct { - User string - Server string - Key string - KeyPath string - Port string - Password string - Timeout time.Duration -} +type ( + defaultConfig struct { + User string + Server string + Key string + KeyPath string + Port string + Password string + Timeout time.Duration + } -type sshConfig struct { - User string - Key string - KeyPath string - Password string - Timeout time.Duration -} + MakeConfig struct { + User string + Server string + Key string + KeyPath string + Port string + Password string + Timeout time.Duration + Proxy struct { + User string + Server string + Key string + KeyPath string + Port string + Password string + Timeout time.Duration + } + } + + 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") ) @@ -93,7 +114,10 @@ func getSSHConfig(config sshConfig) *ssh.ClientConfig { // connect to remote server using MakeConfig struct and returns *ssh.Session func (ssh_conf *MakeConfig) connect() (*ssh.Session, error) { - config := getSSHConfig(sshConfig{ + var client *ssh.Client + var err error + + targetConfig := getSSHConfig(sshConfig{ User: ssh_conf.User, Key: ssh_conf.Key, KeyPath: ssh_conf.KeyPath, @@ -101,9 +125,37 @@ func (ssh_conf *MakeConfig) connect() (*ssh.Session, error) { Timeout: ssh_conf.Timeout, }) - client, err := ssh.Dial("tcp", net.JoinHostPort(ssh_conf.Server, ssh_conf.Port), config) - if err != nil { - return nil, err + // Enable proxy command + if ssh_conf.Proxy.Server != "" { + proxyConfig := getSSHConfig(sshConfig{ + User: ssh_conf.Proxy.User, + Key: ssh_conf.Proxy.Key, + KeyPath: ssh_conf.Proxy.KeyPath, + Password: ssh_conf.Proxy.Password, + Timeout: ssh_conf.Proxy.Timeout, + }) + + proxyClient, err := ssh.Dial("tcp", net.JoinHostPort(ssh_conf.Proxy.Server, ssh_conf.Proxy.Port), proxyConfig) + if err != nil { + return nil, err + } + + conn, err := proxyClient.Dial("tcp", net.JoinHostPort(ssh_conf.Server, ssh_conf.Port)) + if err != nil { + return nil, err + } + + ncc, chans, reqs, err := ssh.NewClientConn(conn, net.JoinHostPort(ssh_conf.Server, ssh_conf.Port), targetConfig) + if err != nil { + return nil, err + } + + client = ssh.NewClient(ncc, chans, reqs) + } else { + client, err = ssh.Dial("tcp", net.JoinHostPort(ssh_conf.Server, ssh_conf.Port), targetConfig) + if err != nil { + return nil, err + } } session, err := client.NewSession() diff --git a/vendor/vendor.json b/vendor/vendor.json index e3abe61..82d9ad9 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -3,12 +3,12 @@ "ignore": "test", "package": [ { - "checksumSHA1": "NCdmzR+clcl2/1jUPn0vFeqjwjk=", + "checksumSHA1": "knoaYH97GvBuW65HyXhR0CQwEJ8=", "path": "github.com/appleboy/easyssh-proxy", - "revision": "89c61a4555c1578454f75ae406f4e3cdded275d2", - "revisionTime": "2017-03-04T06:27:13Z", - "version": "=1.0.0", - "versionExact": "1.0.0" + "revision": "438121ffb50f6f6de791bceb7046e74c1d818c3d", + "revisionTime": "2017-03-04T08:24:35Z", + "version": "=1.1.0", + "versionExact": "1.1.0" }, { "checksumSHA1": "dvabztWVQX8f6oMLRyv4dLH+TGY=",