mirror of
https://github.com/appleboy/drone-ssh.git
synced 2025-05-09 18:23:21 +08:00
Merge b40bfc56ce
into 6c0b475c15
This commit is contained in:
commit
d8eac07970
6
main.go
6
main.go
@ -71,6 +71,11 @@ func main() {
|
|||||||
EnvVar: "PLUGIN_PORT,SSH_PORT",
|
EnvVar: "PLUGIN_PORT,SSH_PORT",
|
||||||
Value: 22,
|
Value: 22,
|
||||||
},
|
},
|
||||||
|
cli.DurationFlag{
|
||||||
|
Name: "retry-timeout",
|
||||||
|
Usage: "connection retry timeout",
|
||||||
|
EnvVar: "PLUGIN_RETRY_TIMEOUT",
|
||||||
|
},
|
||||||
cli.BoolFlag{
|
cli.BoolFlag{
|
||||||
Name: "sync",
|
Name: "sync",
|
||||||
Usage: "sync mode",
|
Usage: "sync mode",
|
||||||
@ -194,6 +199,7 @@ func run(c *cli.Context) error {
|
|||||||
Password: c.String("password"),
|
Password: c.String("password"),
|
||||||
Host: c.StringSlice("host"),
|
Host: c.StringSlice("host"),
|
||||||
Port: c.Int("port"),
|
Port: c.Int("port"),
|
||||||
|
RetryTimeout: c.Duration("retry-timeout"),
|
||||||
Timeout: c.Duration("timeout"),
|
Timeout: c.Duration("timeout"),
|
||||||
CommandTimeout: c.Int("command.timeout"),
|
CommandTimeout: c.Int("command.timeout"),
|
||||||
Script: c.StringSlice("script"),
|
Script: c.StringSlice("script"),
|
||||||
|
35
plugin.go
35
plugin.go
@ -10,6 +10,7 @@ import (
|
|||||||
|
|
||||||
"github.com/appleboy/easyssh-proxy"
|
"github.com/appleboy/easyssh-proxy"
|
||||||
"io"
|
"io"
|
||||||
|
"net"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -29,6 +30,7 @@ type (
|
|||||||
Host []string
|
Host []string
|
||||||
Port int
|
Port int
|
||||||
Timeout time.Duration
|
Timeout time.Duration
|
||||||
|
RetryTimeout time.Duration
|
||||||
CommandTimeout int
|
CommandTimeout int
|
||||||
Script []string
|
Script []string
|
||||||
Secrets []string
|
Secrets []string
|
||||||
@ -90,7 +92,7 @@ func (p Plugin) exec(host string, wg *sync.WaitGroup, errChannel chan error) {
|
|||||||
p.log(host, "======END======")
|
p.log(host, "======END======")
|
||||||
}
|
}
|
||||||
|
|
||||||
stdoutChan, stderrChan, doneChan, errChan, err := ssh.Stream(strings.Join(p.Config.Script, "\n"), p.Config.CommandTimeout)
|
stdoutChan, stderrChan, doneChan, errChan, err := retryStream(ssh, p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errChannel <- err
|
errChannel <- err
|
||||||
} else {
|
} else {
|
||||||
@ -179,3 +181,34 @@ func (p Plugin) Exec() error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func retryStream(ssh *easyssh.MakeConfig, p Plugin) (<-chan string, <-chan string, <-chan bool, <-chan error, error) {
|
||||||
|
var (
|
||||||
|
timeout = time.After(p.Config.RetryTimeout)
|
||||||
|
wait = time.Second
|
||||||
|
)
|
||||||
|
|
||||||
|
for {
|
||||||
|
stdoutChan, stderrChan, doneChan, errChan, err := ssh.Stream(strings.Join(p.Config.Script, "\n"), p.Config.CommandTimeout)
|
||||||
|
|
||||||
|
// If there was no error, return all channels
|
||||||
|
if err == nil {
|
||||||
|
return stdoutChan, stderrChan, doneChan, errChan, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the error was not a net.OpError, return that error
|
||||||
|
if _, ok := err.(*net.OpError); !ok {
|
||||||
|
return nil, nil, nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-timeout:
|
||||||
|
return nil, nil, nil, nil, err
|
||||||
|
case <-time.After(wait):
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// Double our back-off time
|
||||||
|
wait *= 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -8,6 +8,8 @@ import (
|
|||||||
"github.com/appleboy/easyssh-proxy"
|
"github.com/appleboy/easyssh-proxy"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMissingHostOrUser(t *testing.T) {
|
func TestMissingHostOrUser(t *testing.T) {
|
||||||
@ -457,6 +459,56 @@ func TestEnvOutput(t *testing.T) {
|
|||||||
assert.Equal(t, unindent(expected), unindent(buffer.String()))
|
assert.Equal(t, unindent(expected), unindent(buffer.String()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestConnectTimeoutRetry tests that when a network error occurs, the connect
|
||||||
|
// is retried until it either succeeds or the configured timeout is hit.
|
||||||
|
func TestConnectTimeoutRetry(t *testing.T) {
|
||||||
|
start := time.Now()
|
||||||
|
|
||||||
|
plugin := Plugin{
|
||||||
|
Config: Config{
|
||||||
|
Host: []string{"localhost"},
|
||||||
|
UserName: "drone-scp",
|
||||||
|
Port: 2200,
|
||||||
|
KeyPath: "./tests/.ssh/id_rsa",
|
||||||
|
Script: []string{"exit"},
|
||||||
|
RetryTimeout: 15 * time.Second,
|
||||||
|
Sync: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := plugin.Exec()
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
|
||||||
|
end := time.Now()
|
||||||
|
assert.WithinDuration(t, start.Local().Add(15*time.Second), end, 2*time.Second)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestConnectTimeoutRetry tests that when a non-network error occurs, the connect
|
||||||
|
// is not retried and instead returns the error immediately.
|
||||||
|
func TestConnectTimeoutImmediate(t *testing.T) {
|
||||||
|
start := time.Now()
|
||||||
|
|
||||||
|
plugin := Plugin{
|
||||||
|
Config: Config{
|
||||||
|
Host: []string{"localhost"},
|
||||||
|
UserName: "drone-scp",
|
||||||
|
Port: 22,
|
||||||
|
Key: "",
|
||||||
|
Script: []string{"exit"},
|
||||||
|
RetryTimeout: 60 * time.Second,
|
||||||
|
Sync: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := plugin.Exec()
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
|
||||||
|
end := time.Now()
|
||||||
|
assert.WithinDuration(t, start.Local().Add(time.Second), end, 2*time.Second)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func unindent(text string) string {
|
func unindent(text string) string {
|
||||||
return strings.TrimSpace(strings.Replace(text, "\t", "", -1))
|
return strings.TrimSpace(strings.Replace(text, "\t", "", -1))
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user