Browse Source

etcdctl: return exitcode 2 if can't connect to any peers

Anthony Romano 10 years ago
parent
commit
4477ef636e
1 changed files with 37 additions and 1 deletions
  1. 37 1
      etcdctl/command/util.go

+ 37 - 1
etcdctl/command/util.go

@@ -19,10 +19,12 @@ import (
 	"fmt"
 	"fmt"
 	"io"
 	"io"
 	"io/ioutil"
 	"io/ioutil"
+	"net"
 	"net/http"
 	"net/http"
 	"net/url"
 	"net/url"
 	"os"
 	"os"
 	"strings"
 	"strings"
+	"syscall"
 	"time"
 	"time"
 
 
 	"github.com/coreos/etcd/Godeps/_workspace/src/github.com/bgentry/speakeasy"
 	"github.com/coreos/etcd/Godeps/_workspace/src/github.com/bgentry/speakeasy"
@@ -211,11 +213,19 @@ func mustNewClient(c *cli.Context) client.Client {
 				handleError(ExitServerError, err)
 				handleError(ExitServerError, err)
 			}
 			}
 
 
+			if isConnectionError(err) {
+				handleError(ExitBadConnection, err)
+			}
+
 			// fail-back to try sync cluster with peer API. this is for making etcdctl work with etcd 0.4.x.
 			// fail-back to try sync cluster with peer API. this is for making etcdctl work with etcd 0.4.x.
 			// TODO: remove this when we deprecate the support for etcd 0.4.
 			// TODO: remove this when we deprecate the support for etcd 0.4.
 			eps, serr := syncWithPeerAPI(c, ctx, hc.Endpoints())
 			eps, serr := syncWithPeerAPI(c, ctx, hc.Endpoints())
 			if serr != nil {
 			if serr != nil {
-				handleError(ExitServerError, serr)
+				if isConnectionError(serr) {
+					handleError(ExitBadConnection, serr)
+				} else {
+					handleError(ExitServerError, serr)
+				}
 			}
 			}
 			err = hc.SetEndpoints(eps)
 			err = hc.SetEndpoints(eps)
 			if err != nil {
 			if err != nil {
@@ -234,6 +244,32 @@ func mustNewClient(c *cli.Context) client.Client {
 	return hc
 	return hc
 }
 }
 
 
+func isConnectionError(err error) bool {
+	switch t := err.(type) {
+	case *client.ClusterError:
+		for _, cerr := range t.Errors {
+			if !isConnectionError(cerr) {
+				return false
+			}
+		}
+		return true
+	case *net.OpError:
+		if t.Op == "dial" || t.Op == "read" {
+			return true
+		}
+		return isConnectionError(t.Err)
+	case net.Error:
+		if t.Timeout() {
+			return true
+		}
+	case syscall.Errno:
+		if t == syscall.ECONNREFUSED {
+			return true
+		}
+	}
+	return false
+}
+
 func mustNewClientNoSync(c *cli.Context) client.Client {
 func mustNewClientNoSync(c *cli.Context) client.Client {
 	hc, err := newClient(c)
 	hc, err := newClient(c)
 	if err != nil {
 	if err != nil {