From f8ee86065d33f0245d1ad64e40feb4076f1a207d Mon Sep 17 00:00:00 2001
From: Alex Dadgar <alex.dadgar@gmail.com>
Date: Tue, 16 May 2017 12:59:58 -0400
Subject: [PATCH] Fix Vault Client panic when given nonexistant role

The Vault API returns a nil secret and nil error when reading an object
that doesn't exist. The old code assumed an error would be returned and
thus will panic when trying to validate a non-existant role.
---
 nomad/vault.go      |  3 +++
 nomad/vault_test.go | 39 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 42 insertions(+)

diff --git a/nomad/vault.go b/nomad/vault.go
index 93624b932a5..0d14ebe5cae 100644
--- a/nomad/vault.go
+++ b/nomad/vault.go
@@ -782,6 +782,9 @@ func (v *vaultClient) validateRole(role string) error {
 	if err != nil {
 		return fmt.Errorf("failed to lookup role %q: %v", role, err)
 	}
+	if rsecret == nil {
+		return fmt.Errorf("Role %q does not exist", role)
+	}
 
 	// Read and parse the fields
 	var data struct {
diff --git a/nomad/vault_test.go b/nomad/vault_test.go
index b874230b42a..0e0c2b64c53 100644
--- a/nomad/vault_test.go
+++ b/nomad/vault_test.go
@@ -247,6 +247,45 @@ func TestVaultClient_ValidateRole(t *testing.T) {
 	}
 }
 
+func TestVaultClient_ValidateRole_NonExistant(t *testing.T) {
+	v := testutil.NewTestVault(t).Start()
+	defer v.Stop()
+
+	v.Config.Token = defaultTestVaultWhitelistRoleAndToken(v, t, 5)
+	v.Config.Token = v.RootToken
+	logger := log.New(os.Stderr, "", log.LstdFlags)
+	v.Config.ConnectionRetryIntv = 100 * time.Millisecond
+	v.Config.Role = "test-nonexistant"
+	client, err := NewVaultClient(v.Config, logger, nil)
+	if err != nil {
+		t.Fatalf("failed to build vault client: %v", err)
+	}
+	defer client.Stop()
+
+	// Wait for an error
+	var conn bool
+	var connErr error
+	testutil.WaitForResult(func() (bool, error) {
+		conn, connErr = client.ConnectionEstablished()
+		if conn {
+			return false, fmt.Errorf("Should not connect")
+		}
+
+		if connErr == nil {
+			return false, fmt.Errorf("expect an error")
+		}
+
+		return true, nil
+	}, func(err error) {
+		t.Fatalf("bad: %v", err)
+	})
+
+	errStr := connErr.Error()
+	if !strings.Contains(errStr, "does not exist") {
+		t.Fatalf("Expect orphan error")
+	}
+}
+
 func TestVaultClient_ValidateToken(t *testing.T) {
 	v := testutil.NewTestVault(t).Start()
 	defer v.Stop()