Make cubbyhole local instead of replicated. (#2397)

This doesn't really change behavior, just what it looks like in the UX.
However, it does make tests more complicated. Most were fixed by adding
a sorting function, which is generally useful anyways.
This commit is contained in:
Jeff Mitchell
2017-02-18 13:51:05 -05:00
committed by GitHub
parent 476446e24d
commit a4a27e7c3a
7 changed files with 55 additions and 47 deletions

View File

@@ -99,7 +99,7 @@ func TestSysMounts_headerAuth(t *testing.T) {
"default_lease_ttl": json.Number("0"), "default_lease_ttl": json.Number("0"),
"max_lease_ttl": json.Number("0"), "max_lease_ttl": json.Number("0"),
}, },
"local": false, "local": true,
}, },
}, },
"secret/": map[string]interface{}{ "secret/": map[string]interface{}{
@@ -127,7 +127,7 @@ func TestSysMounts_headerAuth(t *testing.T) {
"default_lease_ttl": json.Number("0"), "default_lease_ttl": json.Number("0"),
"max_lease_ttl": json.Number("0"), "max_lease_ttl": json.Number("0"),
}, },
"local": false, "local": true,
}, },
} }
testResponseStatus(t, resp, 200) testResponseStatus(t, resp, 200)

View File

@@ -51,7 +51,7 @@ func TestSysMounts(t *testing.T) {
"default_lease_ttl": json.Number("0"), "default_lease_ttl": json.Number("0"),
"max_lease_ttl": json.Number("0"), "max_lease_ttl": json.Number("0"),
}, },
"local": false, "local": true,
}, },
}, },
"secret/": map[string]interface{}{ "secret/": map[string]interface{}{
@@ -79,7 +79,7 @@ func TestSysMounts(t *testing.T) {
"default_lease_ttl": json.Number("0"), "default_lease_ttl": json.Number("0"),
"max_lease_ttl": json.Number("0"), "max_lease_ttl": json.Number("0"),
}, },
"local": false, "local": true,
}, },
} }
testResponseStatus(t, resp, 200) testResponseStatus(t, resp, 200)
@@ -147,7 +147,7 @@ func TestSysMount(t *testing.T) {
"default_lease_ttl": json.Number("0"), "default_lease_ttl": json.Number("0"),
"max_lease_ttl": json.Number("0"), "max_lease_ttl": json.Number("0"),
}, },
"local": false, "local": true,
}, },
}, },
"foo/": map[string]interface{}{ "foo/": map[string]interface{}{
@@ -184,7 +184,7 @@ func TestSysMount(t *testing.T) {
"default_lease_ttl": json.Number("0"), "default_lease_ttl": json.Number("0"),
"max_lease_ttl": json.Number("0"), "max_lease_ttl": json.Number("0"),
}, },
"local": false, "local": true,
}, },
} }
testResponseStatus(t, resp, 200) testResponseStatus(t, resp, 200)
@@ -274,7 +274,7 @@ func TestSysRemount(t *testing.T) {
"default_lease_ttl": json.Number("0"), "default_lease_ttl": json.Number("0"),
"max_lease_ttl": json.Number("0"), "max_lease_ttl": json.Number("0"),
}, },
"local": false, "local": true,
}, },
}, },
"bar/": map[string]interface{}{ "bar/": map[string]interface{}{
@@ -311,7 +311,7 @@ func TestSysRemount(t *testing.T) {
"default_lease_ttl": json.Number("0"), "default_lease_ttl": json.Number("0"),
"max_lease_ttl": json.Number("0"), "max_lease_ttl": json.Number("0"),
}, },
"local": false, "local": true,
}, },
} }
testResponseStatus(t, resp, 200) testResponseStatus(t, resp, 200)
@@ -373,7 +373,7 @@ func TestSysUnmount(t *testing.T) {
"default_lease_ttl": json.Number("0"), "default_lease_ttl": json.Number("0"),
"max_lease_ttl": json.Number("0"), "max_lease_ttl": json.Number("0"),
}, },
"local": false, "local": true,
}, },
}, },
"secret/": map[string]interface{}{ "secret/": map[string]interface{}{
@@ -401,7 +401,7 @@ func TestSysUnmount(t *testing.T) {
"default_lease_ttl": json.Number("0"), "default_lease_ttl": json.Number("0"),
"max_lease_ttl": json.Number("0"), "max_lease_ttl": json.Number("0"),
}, },
"local": false, "local": true,
}, },
} }
testResponseStatus(t, resp, 200) testResponseStatus(t, resp, 200)
@@ -469,7 +469,7 @@ func TestSysTuneMount(t *testing.T) {
"default_lease_ttl": json.Number("0"), "default_lease_ttl": json.Number("0"),
"max_lease_ttl": json.Number("0"), "max_lease_ttl": json.Number("0"),
}, },
"local": false, "local": true,
}, },
}, },
"foo/": map[string]interface{}{ "foo/": map[string]interface{}{
@@ -506,7 +506,7 @@ func TestSysTuneMount(t *testing.T) {
"default_lease_ttl": json.Number("0"), "default_lease_ttl": json.Number("0"),
"max_lease_ttl": json.Number("0"), "max_lease_ttl": json.Number("0"),
}, },
"local": false, "local": true,
}, },
} }
testResponseStatus(t, resp, 200) testResponseStatus(t, resp, 200)
@@ -595,7 +595,7 @@ func TestSysTuneMount(t *testing.T) {
"default_lease_ttl": json.Number("0"), "default_lease_ttl": json.Number("0"),
"max_lease_ttl": json.Number("0"), "max_lease_ttl": json.Number("0"),
}, },
"local": false, "local": true,
}, },
}, },
"foo/": map[string]interface{}{ "foo/": map[string]interface{}{
@@ -632,7 +632,7 @@ func TestSysTuneMount(t *testing.T) {
"default_lease_ttl": json.Number("0"), "default_lease_ttl": json.Number("0"),
"max_lease_ttl": json.Number("0"), "max_lease_ttl": json.Number("0"),
}, },
"local": false, "local": true,
}, },
} }

View File

@@ -16,12 +16,6 @@ func CubbyholeBackendFactory(conf *logical.BackendConfig) (logical.Backend, erro
b.Backend = &framework.Backend{ b.Backend = &framework.Backend{
Help: strings.TrimSpace(cubbyholeHelp), Help: strings.TrimSpace(cubbyholeHelp),
PathsSpecial: &logical.Paths{
LocalStorage: []string{
"*",
},
},
Paths: []*framework.Path{ Paths: []*framework.Path{
&framework.Path{ &framework.Path{
Pattern: ".*", Pattern: ".*",

View File

@@ -10,18 +10,6 @@ import (
"github.com/hashicorp/vault/logical" "github.com/hashicorp/vault/logical"
) )
func TestCubbyholeBackend_RootPaths(t *testing.T) {
b := testCubbyholeBackend()
expected := []string{
"*",
}
actual := b.SpecialPaths().LocalStorage
if !reflect.DeepEqual(actual, expected) {
t.Fatalf("bad: %#v", actual)
}
}
func TestCubbyholeBackend_Write(t *testing.T) { func TestCubbyholeBackend_Write(t *testing.T) {
b := testCubbyholeBackend() b := testCubbyholeBackend()
req := logical.TestRequest(t, logical.UpdateOperation, "foo") req := logical.TestRequest(t, logical.UpdateOperation, "foo")

View File

@@ -70,7 +70,7 @@ func TestSystemBackend_mounts(t *testing.T) {
"default_lease_ttl": resp.Data["cubbyhole/"].(map[string]interface{})["config"].(map[string]interface{})["default_lease_ttl"].(int64), "default_lease_ttl": resp.Data["cubbyhole/"].(map[string]interface{})["config"].(map[string]interface{})["default_lease_ttl"].(int64),
"max_lease_ttl": resp.Data["cubbyhole/"].(map[string]interface{})["config"].(map[string]interface{})["max_lease_ttl"].(int64), "max_lease_ttl": resp.Data["cubbyhole/"].(map[string]interface{})["config"].(map[string]interface{})["max_lease_ttl"].(int64),
}, },
"local": false, "local": true,
}, },
} }
if !reflect.DeepEqual(resp.Data, exp) { if !reflect.DeepEqual(resp.Data, exp) {

View File

@@ -5,6 +5,7 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"sort"
"strings" "strings"
"time" "time"
@@ -119,6 +120,15 @@ func (t *MountTable) remove(path string) *MountEntry {
return nil return nil
} }
// sortEntriesByPath sorts the entries in the table by path and returns the
// table; this is useful for tests
func (t *MountTable) sortEntriesByPath() *MountTable {
sort.Slice(t.Entries, func(i, j int) bool {
return t.Entries[i].Path < t.Entries[j].Path
})
return t
}
// MountEntry is used to represent a mount table entry // MountEntry is used to represent a mount table entry
type MountEntry struct { type MountEntry struct {
Table string `json:"table"` // The table it belongs to Table string `json:"table"` // The table it belongs to
@@ -733,6 +743,7 @@ func requiredMountTable() *MountTable {
Type: "cubbyhole", Type: "cubbyhole",
Description: "per-token private secret storage", Description: "per-token private secret storage",
UUID: cubbyholeUUID, UUID: cubbyholeUUID,
Local: true,
} }
sysUUID, err := uuid.GenerateUUID() sysUUID, err := uuid.GenerateUUID()

View File

@@ -37,7 +37,7 @@ func TestCore_DefaultMountTable(t *testing.T) {
} }
// Verify matching mount tables // Verify matching mount tables
if !reflect.DeepEqual(c.mounts, c2.mounts) { if !reflect.DeepEqual(c.mounts.sortEntriesByPath(), c2.mounts.sortEntriesByPath()) {
t.Fatalf("mismatch: %v %v", c.mounts, c2.mounts) t.Fatalf("mismatch: %v %v", c.mounts, c2.mounts)
} }
} }
@@ -78,7 +78,7 @@ func TestCore_Mount(t *testing.T) {
} }
// Verify matching mount tables // Verify matching mount tables
if !reflect.DeepEqual(c.mounts, c2.mounts) { if !reflect.DeepEqual(c.mounts.sortEntriesByPath(), c2.mounts.sortEntriesByPath()) {
t.Fatalf("mismatch: %v %v", c.mounts, c2.mounts) t.Fatalf("mismatch: %v %v", c.mounts, c2.mounts)
} }
} }
@@ -127,8 +127,8 @@ func TestCore_Mount_Local(t *testing.T) {
if err := jsonutil.DecodeJSON(rawLocal.Value, localMountsTable); err != nil { if err := jsonutil.DecodeJSON(rawLocal.Value, localMountsTable); err != nil {
t.Fatal(err) t.Fatal(err)
} }
if len(localMountsTable.Entries) > 0 { if len(localMountsTable.Entries) != 1 || localMountsTable.Entries[0].Type != "cubbyhole" {
t.Fatalf("expected no entries in local mount table, got %#v", localMountsTable) t.Fatalf("expected only cubbyhole entry in local mount table, got %#v", localMountsTable)
} }
c.mounts.Entries[1].Local = true c.mounts.Entries[1].Local = true
@@ -147,7 +147,11 @@ func TestCore_Mount_Local(t *testing.T) {
if err := jsonutil.DecodeJSON(rawLocal.Value, localMountsTable); err != nil { if err := jsonutil.DecodeJSON(rawLocal.Value, localMountsTable); err != nil {
t.Fatal(err) t.Fatal(err)
} }
if len(localMountsTable.Entries) != 1 { // This requires some explanation: because we're directly munging the mount
// table, the table initially when core unseals contains cubbyhole as per
// above, but then we overwrite it with our own table with one local entry,
// so we should now only expect the noop2 entry
if len(localMountsTable.Entries) != 1 || localMountsTable.Entries[0].Path != "noop2/" {
t.Fatalf("expected one entry in local mount table, got %#v", localMountsTable) t.Fatalf("expected one entry in local mount table, got %#v", localMountsTable)
} }
@@ -204,7 +208,7 @@ func TestCore_Unmount(t *testing.T) {
} }
// Verify matching mount tables // Verify matching mount tables
if !reflect.DeepEqual(c.mounts, c2.mounts) { if !reflect.DeepEqual(c.mounts.sortEntriesByPath(), c2.mounts.sortEntriesByPath()) {
t.Fatalf("mismatch: %v %v", c.mounts, c2.mounts) t.Fatalf("mismatch: %v %v", c.mounts, c2.mounts)
} }
} }
@@ -483,6 +487,17 @@ func testCore_MountTable_UpgradeToTyped_Common(
mt = c.auth mt = c.auth
} }
// We filter out local entries here since the logic is rather dumb
// (straight JSON comparison) and doesn't seal well with the separate
// locations
newEntries := mt.Entries[:0]
for _, entry := range mt.Entries {
if !entry.Local {
newEntries = append(newEntries, entry)
}
}
mt.Entries = newEntries
// Save the expected table // Save the expected table
goodJson, err := json.Marshal(mt) goodJson, err := json.Marshal(mt)
if err != nil { if err != nil {
@@ -577,22 +592,23 @@ func verifyDefaultTable(t *testing.T, table *MountTable) {
if len(table.Entries) != 3 { if len(table.Entries) != 3 {
t.Fatalf("bad: %v", table.Entries) t.Fatalf("bad: %v", table.Entries)
} }
table.sortEntriesByPath()
for idx, entry := range table.Entries { for idx, entry := range table.Entries {
switch idx { switch idx {
case 0: case 0:
if entry.Path != "secret/" {
t.Fatalf("bad: %v", entry)
}
if entry.Type != "generic" {
t.Fatalf("bad: %v", entry)
}
case 1:
if entry.Path != "cubbyhole/" { if entry.Path != "cubbyhole/" {
t.Fatalf("bad: %v", entry) t.Fatalf("bad: %v", entry)
} }
if entry.Type != "cubbyhole" { if entry.Type != "cubbyhole" {
t.Fatalf("bad: %v", entry) t.Fatalf("bad: %v", entry)
} }
case 1:
if entry.Path != "secret/" {
t.Fatalf("bad: %v", entry)
}
if entry.Type != "generic" {
t.Fatalf("bad: %v", entry)
}
case 2: case 2:
if entry.Path != "sys/" { if entry.Path != "sys/" {
t.Fatalf("bad: %v", entry) t.Fatalf("bad: %v", entry)
@@ -611,5 +627,4 @@ func verifyDefaultTable(t *testing.T, table *MountTable) {
t.Fatalf("bad: %v", entry) t.Fatalf("bad: %v", entry)
} }
} }
} }