diff --git a/command/agent/command.go b/command/agent/command.go index 4f049872f7..efeec1ceb1 100644 --- a/command/agent/command.go +++ b/command/agent/command.go @@ -203,6 +203,12 @@ func (c *Command) readConfig() *Config { if config.Server { mdbPath := filepath.Join(config.DataDir, "mdb") if _, err := os.Stat(mdbPath); !os.IsNotExist(err) { + if os.IsPermission(err) { + c.Ui.Error(fmt.Sprintf("CRITICAL: Permission denied for data folder at %q!", mdbPath)) + c.Ui.Error("Consul will refuse to boot without access to this directory.") + c.Ui.Error("Please correct permissions and try starting again.") + return nil + } c.Ui.Error(fmt.Sprintf("CRITICAL: Deprecated data folder found at %q!", mdbPath)) c.Ui.Error("Consul will refuse to boot with this directory present.") c.Ui.Error("See https://www.consul.io/docs/upgrade-specific.html for more information.") diff --git a/command/agent/command_test.go b/command/agent/command_test.go index 773a510d87..d04a8007b1 100644 --- a/command/agent/command_test.go +++ b/command/agent/command_test.go @@ -403,3 +403,29 @@ func TestProtectDataDir(t *testing.T) { t.Fatalf("expected mdb dir error, got: %s", out) } } + +func TestBadDataDirPermissions(t *testing.T) { + dir, err := ioutil.TempDir("", "consul") + if err != nil { + t.Fatalf("err: %v", err) + } + defer os.RemoveAll(dir) + + dataDir := filepath.Join(dir, "mdb") + if err := os.MkdirAll(dataDir, 0400); err != nil { + t.Fatalf("err: %v", err) + } + defer os.RemoveAll(dataDir) + + ui := new(cli.MockUi) + cmd := &Command{ + Ui: ui, + args: []string{"-data-dir=" + dataDir, "-server=true"}, + } + if conf := cmd.readConfig(); conf != nil { + t.Fatalf("Should fail with bad data directory permissions") + } + if out := ui.ErrorWriter.String(); !strings.Contains(out, "Permission denied") { + t.Fatalf("expected permission denied error, got: %s", out) + } +} diff --git a/command/agent/http_test.go b/command/agent/http_test.go index 1afabb0946..685f5cbd44 100644 --- a/command/agent/http_test.go +++ b/command/agent/http_test.go @@ -28,6 +28,9 @@ func makeHTTPServer(t *testing.T) (string, *HTTPServer) { } func makeHTTPServerWithConfig(t *testing.T, cb func(c *Config)) (string, *HTTPServer) { + configTry := 0 +RECONF: + configTry += 1 conf := nextConfig() if cb != nil { cb(conf) @@ -36,6 +39,9 @@ func makeHTTPServerWithConfig(t *testing.T, cb func(c *Config)) (string, *HTTPSe dir, agent := makeAgent(t, conf) servers, err := NewHTTPServers(agent, conf, agent.logOutput) if err != nil { + if configTry < 3 { + goto RECONF + } t.Fatalf("err: %v", err) } if len(servers) == 0 { diff --git a/command/agent/rpc_client_test.go b/command/agent/rpc_client_test.go index af1af23ea2..9217cf9533 100644 --- a/command/agent/rpc_client_test.go +++ b/command/agent/rpc_client_test.go @@ -3,8 +3,6 @@ package agent import ( "errors" "fmt" - "github.com/hashicorp/consul/testutil" - "github.com/hashicorp/serf/serf" "io" "io/ioutil" "net" @@ -14,6 +12,9 @@ import ( "strings" "testing" "time" + + "github.com/hashicorp/consul/testutil" + "github.com/hashicorp/serf/serf" ) type rpcParts struct { @@ -40,6 +41,9 @@ func testRPCClientWithConfig(t *testing.T, cb func(c *Config)) *rpcParts { lw := NewLogWriter(512) mult := io.MultiWriter(os.Stderr, lw) + configTry := 0 +RECONF: + configTry += 1 conf := nextConfig() cb(conf) @@ -50,6 +54,9 @@ func testRPCClientWithConfig(t *testing.T, cb func(c *Config)) *rpcParts { l, err := net.Listen(rpcAddr.Network(), rpcAddr.String()) if err != nil { + if configTry < 3 { + goto RECONF + } t.Fatalf("err: %s", err) } diff --git a/consul/client_test.go b/consul/client_test.go index 3e4d7706cc..b4d932b38b 100644 --- a/consul/client_test.go +++ b/consul/client_test.go @@ -212,7 +212,7 @@ func TestClient_RPC_Pool(t *testing.T) { t.Fatalf("err: %v", err) } if len(s1.LANMembers()) != 2 || len(c1.LANMembers()) != 2 { - t.Fatalf("bad len") + t.Fatalf("Server has %v of %v expected members; Client has %v of %v expected members.", len(s1.LANMembers()), 2, len(c1.LANMembers()), 2) } // Blast out a bunch of RPC requests at the same time to try to get