Merge pull request #9834 from cjcullen/fwfix

Fix crashes in ssh-tunnel code.
This commit is contained in:
Brendan Burns
2015-06-15 20:25:32 -07:00
2 changed files with 53 additions and 23 deletions

View File

@@ -32,9 +32,30 @@ import (
"time"
"github.com/golang/glog"
"github.com/prometheus/client_golang/prometheus"
"golang.org/x/crypto/ssh"
)
var (
tunnelOpenCounter = prometheus.NewCounter(
prometheus.CounterOpts{
Name: "ssh_tunnel_open_count",
Help: "Counter of ssh tunnel total open attempts",
},
)
tunnelOpenFailCounter = prometheus.NewCounter(
prometheus.CounterOpts{
Name: "ssh_tunnel_open_fail_count",
Help: "Counter of ssh tunnel failed open attempts",
},
)
)
func init() {
prometheus.MustRegister(tunnelOpenCounter)
prometheus.MustRegister(tunnelOpenFailCounter)
}
// TODO: Unit tests for this code, we can spin up a test SSH server with instructions here:
// https://godoc.org/golang.org/x/crypto/ssh#ServerConn
type SSHTunnel struct {
@@ -83,7 +104,9 @@ func makeSSHTunnel(user string, signer ssh.Signer, host string) (*SSHTunnel, err
func (s *SSHTunnel) Open() error {
var err error
s.client, err = ssh.Dial("tcp", net.JoinHostPort(s.Host, s.SSHPort), s.Config)
tunnelOpenCounter.Inc()
if err != nil {
tunnelOpenFailCounter.Inc()
return err
}
return nil
@@ -97,6 +120,9 @@ func (s *SSHTunnel) Dial(network, address string) (net.Conn, error) {
}
func (s *SSHTunnel) tunnel(conn net.Conn, remoteHost, remotePort string) error {
if s.client == nil {
return errors.New("tunnel is not opened.")
}
tunnel, err := s.client.Dial("tcp", net.JoinHostPort(remoteHost, remotePort))
if err != nil {
return err
@@ -107,6 +133,9 @@ func (s *SSHTunnel) tunnel(conn net.Conn, remoteHost, remotePort string) error {
}
func (s *SSHTunnel) Close() error {
if s.client == nil {
return errors.New("Cannot close tunnel. Tunnel was not opened.")
}
if err := s.client.Close(); err != nil {
return err
}
@@ -196,9 +225,14 @@ func MakeSSHTunnels(user, keyfile string, addresses []string) (SSHTunnelList, er
func (l SSHTunnelList) Open() error {
for ix := range l {
if err := l[ix].Tunnel.Open(); err != nil {
return err
// Remove a failed Open from the list.
glog.Errorf("Failed to open tunnel %v: %v", l[ix], err)
l = append(l[:ix], l[ix+1:]...)
}
}
if len(l) == 0 {
return errors.New("Failed to open any tunnels.")
}
return nil
}
@@ -209,6 +243,7 @@ func (l SSHTunnelList) Close() {
for ix := range l {
entry := l[ix]
go func() {
defer HandleCrash()
time.Sleep(1 * time.Minute)
if err := entry.Tunnel.Close(); err != nil {
glog.Errorf("Failed to close tunnel %v: %v", entry, err)