Understand local when persisting mount tables, to avoid invalidations when not necessary (#2427)

This commit is contained in:
Jeff Mitchell 2017-03-02 14:37:59 -05:00 committed by GitHub
parent 70bfdb5ae9
commit a585f709d3
8 changed files with 125 additions and 104 deletions

View File

@ -90,7 +90,7 @@ func (c *Core) enableAudit(entry *MountEntry) error {
newTable := c.audit.shallowClone()
newTable.Entries = append(newTable.Entries, entry)
if err := c.persistAudit(newTable); err != nil {
if err := c.persistAudit(newTable, entry.Local); err != nil {
return errors.New("failed to update audit table")
}
@ -132,7 +132,7 @@ func (c *Core) disableAudit(path string) (bool, error) {
}
// Update the audit table
if err := c.persistAudit(newTable); err != nil {
if err := c.persistAudit(newTable, entry.Local); err != nil {
return true, errors.New("failed to update audit table")
}
@ -200,23 +200,21 @@ func (c *Core) loadAudits() error {
}
}
if needPersist {
return c.persistAudit(c.audit)
if !needPersist {
return nil
}
return nil
} else {
c.audit = defaultAuditTable()
}
// Create and persist the default audit table
c.audit = defaultAuditTable()
if err := c.persistAudit(c.audit); err != nil {
if err := c.persistAudit(c.audit, false); err != nil {
return errLoadAuditFailed
}
return nil
}
// persistAudit is used to persist the audit table after modification
func (c *Core) persistAudit(table *MountTable) error {
func (c *Core) persistAudit(table *MountTable, localOnly bool) error {
if table.Type != auditTableType {
c.logger.Error("core: given table to persist has wrong type", "actual_type", table.Type, "expected_type", auditTableType)
return fmt.Errorf("invalid table type given, not persisting")
@ -245,33 +243,35 @@ func (c *Core) persistAudit(table *MountTable) error {
}
}
// Marshal the table
compressedBytes, err := jsonutil.EncodeJSONAndCompress(nonLocalAudit, nil)
if err != nil {
c.logger.Error("core: failed to encode and/or compress audit table", "error", err)
return err
}
if !localOnly {
// Marshal the table
compressedBytes, err := jsonutil.EncodeJSONAndCompress(nonLocalAudit, nil)
if err != nil {
c.logger.Error("core: failed to encode and/or compress audit table", "error", err)
return err
}
// Create an entry
entry := &Entry{
Key: coreAuditConfigPath,
Value: compressedBytes,
}
// Create an entry
entry := &Entry{
Key: coreAuditConfigPath,
Value: compressedBytes,
}
// Write to the physical backend
if err := c.barrier.Put(entry); err != nil {
c.logger.Error("core: failed to persist audit table", "error", err)
return err
// Write to the physical backend
if err := c.barrier.Put(entry); err != nil {
c.logger.Error("core: failed to persist audit table", "error", err)
return err
}
}
// Repeat with local audit
compressedBytes, err = jsonutil.EncodeJSONAndCompress(localAudit, nil)
compressedBytes, err := jsonutil.EncodeJSONAndCompress(localAudit, nil)
if err != nil {
c.logger.Error("core: failed to encode and/or compress local audit table", "error", err)
return err
}
entry = &Entry{
entry := &Entry{
Key: coreLocalAuditConfigPath,
Value: compressedBytes,
}

View File

@ -220,7 +220,7 @@ func TestCore_EnableAudit_Local(t *testing.T) {
}
c.audit.Entries[1].Local = true
if err := c.persistAudit(c.audit); err != nil {
if err := c.persistAudit(c.audit, false); err != nil {
t.Fatal(err)
}

View File

@ -99,7 +99,7 @@ func (c *Core) enableCredential(entry *MountEntry) error {
// Update the auth table
newTable := c.auth.shallowClone()
newTable.Entries = append(newTable.Entries, entry)
if err := c.persistAuth(newTable); err != nil {
if err := c.persistAuth(newTable, entry.Local); err != nil {
return errors.New("failed to update auth table")
}
@ -180,10 +180,14 @@ func (c *Core) removeCredEntry(path string) error {
// Taint the entry from the auth table
newTable := c.auth.shallowClone()
newTable.remove(path)
entry := newTable.remove(path)
if entry == nil {
c.logger.Error("core: nil entry found removing entry in auth table", "path", path)
return logical.CodedError(500, "failed to remove entry in auth table")
}
// Update the auth table
if err := c.persistAuth(newTable); err != nil {
if err := c.persistAuth(newTable, entry.Local); err != nil {
return errors.New("failed to update auth table")
}
@ -200,15 +204,15 @@ func (c *Core) taintCredEntry(path string) error {
// Taint the entry from the auth table
// We do this on the original since setting the taint operates
// on the entries which a shallow clone shares anyways
found := c.auth.setTaint(path, true)
entry := c.auth.setTaint(path, true)
// Ensure there was a match
if !found {
if entry == nil {
return fmt.Errorf("no matching backend")
}
// Update the auth table
if err := c.persistAuth(c.auth); err != nil {
if err := c.persistAuth(c.auth, entry.Local); err != nil {
return errors.New("failed to update auth table")
}
@ -268,16 +272,14 @@ func (c *Core) loadCredentials() error {
}
}
if needPersist {
return c.persistAuth(c.auth)
if !needPersist {
return nil
}
return nil
} else {
c.auth = defaultAuthTable()
}
// Create and persist the default auth table
c.auth = defaultAuthTable()
if err := c.persistAuth(c.auth); err != nil {
if err := c.persistAuth(c.auth, false); err != nil {
c.logger.Error("core: failed to persist auth table", "error", err)
return errLoadAuthFailed
}
@ -285,7 +287,7 @@ func (c *Core) loadCredentials() error {
}
// persistAuth is used to persist the auth table after modification
func (c *Core) persistAuth(table *MountTable) error {
func (c *Core) persistAuth(table *MountTable, localOnly bool) error {
if table.Type != credentialTableType {
c.logger.Error("core: given table to persist has wrong type", "actual_type", table.Type, "expected_type", credentialTableType)
return fmt.Errorf("invalid table type given, not persisting")
@ -314,33 +316,35 @@ func (c *Core) persistAuth(table *MountTable) error {
}
}
// Marshal the table
compressedBytes, err := jsonutil.EncodeJSONAndCompress(nonLocalAuth, nil)
if err != nil {
c.logger.Error("core: failed to encode and/or compress auth table", "error", err)
return err
}
if !localOnly {
// Marshal the table
compressedBytes, err := jsonutil.EncodeJSONAndCompress(nonLocalAuth, nil)
if err != nil {
c.logger.Error("core: failed to encode and/or compress auth table", "error", err)
return err
}
// Create an entry
entry := &Entry{
Key: coreAuthConfigPath,
Value: compressedBytes,
}
// Create an entry
entry := &Entry{
Key: coreAuthConfigPath,
Value: compressedBytes,
}
// Write to the physical backend
if err := c.barrier.Put(entry); err != nil {
c.logger.Error("core: failed to persist auth table", "error", err)
return err
// Write to the physical backend
if err := c.barrier.Put(entry); err != nil {
c.logger.Error("core: failed to persist auth table", "error", err)
return err
}
}
// Repeat with local auth
compressedBytes, err = jsonutil.EncodeJSONAndCompress(localAuth, nil)
compressedBytes, err := jsonutil.EncodeJSONAndCompress(localAuth, nil)
if err != nil {
c.logger.Error("core: failed to encode and/or compress local auth table", "error", err)
return err
}
entry = &Entry{
entry := &Entry{
Key: coreLocalAuthConfigPath,
Value: compressedBytes,
}
@ -411,7 +415,7 @@ func (c *Core) setupCredentials() error {
}
if persistNeeded {
return c.persistAuth(c.auth)
return c.persistAuth(c.auth, false)
}
return nil

View File

@ -135,7 +135,7 @@ func TestCore_EnableCredential_Local(t *testing.T) {
}
c.auth.Entries[1].Local = true
if err := c.persistAuth(c.auth); err != nil {
if err := c.persistAuth(c.auth, false); err != nil {
t.Fatal(err)
}

View File

@ -1246,7 +1246,7 @@ func (b *SystemBackend) handleTuneWriteCommon(
lock.Lock()
defer lock.Unlock()
if err := b.tuneMountTTLs(path, &mountEntry.Config, newDefault, newMax); err != nil {
if err := b.tuneMountTTLs(path, mountEntry, newDefault, newMax); err != nil {
b.Backend.Logger().Error("sys: tuning failed", "path", path, "error", err)
return handleError(err)
}

View File

@ -7,7 +7,9 @@ import (
)
// tuneMount is used to set config on a mount point
func (b *SystemBackend) tuneMountTTLs(path string, meConfig *MountConfig, newDefault, newMax *time.Duration) error {
func (b *SystemBackend) tuneMountTTLs(path string, me *MountEntry, newDefault, newMax *time.Duration) error {
meConfig := &me.Config
if newDefault == nil && newMax == nil {
return nil
}
@ -65,9 +67,9 @@ func (b *SystemBackend) tuneMountTTLs(path string, meConfig *MountConfig, newDef
var err error
switch {
case strings.HasPrefix(path, "auth/"):
err = b.Core.persistAuth(b.Core.auth)
err = b.Core.persistAuth(b.Core.auth, me.Local)
default:
err = b.Core.persistMounts(b.Core.mounts)
err = b.Core.persistMounts(b.Core.mounts, me.Local)
}
if err != nil {
meConfig.MaxLeaseTTL = origMax

View File

@ -95,15 +95,15 @@ func (t *MountTable) Hash() ([]byte, error) {
}
// setTaint is used to set the taint on given entry
func (t *MountTable) setTaint(path string, value bool) bool {
func (t *MountTable) setTaint(path string, value bool) *MountEntry {
n := len(t.Entries)
for i := 0; i < n; i++ {
if t.Entries[i].Path == path {
t.Entries[i].Tainted = value
return true
return t.Entries[i]
}
}
return false
return nil
}
// remove is used to remove a given path entry; returns the entry that was
@ -221,7 +221,7 @@ func (c *Core) mount(entry *MountEntry) error {
newTable := c.mounts.shallowClone()
newTable.Entries = append(newTable.Entries, entry)
if err := c.persistMounts(newTable); err != nil {
if err := c.persistMounts(newTable, entry.Local); err != nil {
c.logger.Error("core: failed to update mount table", "error", err)
return logical.CodedError(500, "failed to update mount table")
}
@ -315,7 +315,11 @@ func (c *Core) removeMountEntry(path string) error {
// Remove the entry from the mount table
newTable := c.mounts.shallowClone()
newTable.remove(path)
entry := newTable.remove(path)
if entry == nil {
c.logger.Error("core: nil entry found removing entry in mounts table", "path", path)
return logical.CodedError(500, "failed to remove entry in mounts table")
}
// When unmounting all entries the JSON code will load back up from storage
// as a nil slice, which kills tests...just set it nil explicitly
@ -324,9 +328,9 @@ func (c *Core) removeMountEntry(path string) error {
}
// Update the mount table
if err := c.persistMounts(newTable); err != nil {
c.logger.Error("core: failed to update mount table", "error", err)
return logical.CodedError(500, "failed to update mount table")
if err := c.persistMounts(newTable, entry.Local); err != nil {
c.logger.Error("core: failed to remove entry from mounts table", "error", err)
return logical.CodedError(500, "failed to remove entry from mounts table")
}
c.mounts = newTable
@ -340,12 +344,16 @@ func (c *Core) taintMountEntry(path string) error {
// As modifying the taint of an entry affects shallow clones,
// we simply use the original
c.mounts.setTaint(path, true)
entry := c.mounts.setTaint(path, true)
if entry == nil {
c.logger.Error("core: nil entry found tainting entry in mounts table", "path", path)
return logical.CodedError(500, "failed to taint entry in mounts table")
}
// Update the mount table
if err := c.persistMounts(c.mounts); err != nil {
c.logger.Error("core: failed to update mount table", "error", err)
return logical.CodedError(500, "failed to update mount table")
if err := c.persistMounts(c.mounts, entry.Local); err != nil {
c.logger.Error("core: failed to taint entry in mounts table", "error", err)
return logical.CodedError(500, "failed to taint entry in mounts table")
}
return nil
@ -408,13 +416,18 @@ func (c *Core) remount(src, dst string) error {
}
}
if ent == nil {
c.logger.Error("core: failed to find entry in mounts table")
return logical.CodedError(500, "failed to find entry in mounts table")
}
// Update the mount table
if err := c.persistMounts(c.mounts); err != nil {
if err := c.persistMounts(c.mounts, ent.Local); err != nil {
ent.Path = src
ent.Tainted = true
c.mountsLock.Unlock()
c.logger.Error("core: failed to update mount table", "error", err)
return logical.CodedError(500, "failed to update mount table")
c.logger.Error("core: failed to update mounts table", "error", err)
return logical.CodedError(500, "failed to update mounts table")
}
c.mountsLock.Unlock()
@ -520,7 +533,7 @@ func (c *Core) loadMounts() error {
c.mounts = defaultMountTable()
}
if err := c.persistMounts(c.mounts); err != nil {
if err := c.persistMounts(c.mounts, false); err != nil {
c.logger.Error("core: failed to persist mount table", "error", err)
return errLoadMountsFailed
}
@ -528,7 +541,7 @@ func (c *Core) loadMounts() error {
}
// persistMounts is used to persist the mount table after modification
func (c *Core) persistMounts(table *MountTable) error {
func (c *Core) persistMounts(table *MountTable, localOnly bool) error {
if table.Type != mountTableType {
c.logger.Error("core: given table to persist has wrong type", "actual_type", table.Type, "expected_type", mountTableType)
return fmt.Errorf("invalid table type given, not persisting")
@ -557,33 +570,35 @@ func (c *Core) persistMounts(table *MountTable) error {
}
}
// Encode the mount table into JSON and compress it (lzw).
compressedBytes, err := jsonutil.EncodeJSONAndCompress(nonLocalMounts, nil)
if err != nil {
c.logger.Error("core: failed to encode and/or compress the mount table", "error", err)
return err
}
if !localOnly {
// Encode the mount table into JSON and compress it (lzw).
compressedBytes, err := jsonutil.EncodeJSONAndCompress(nonLocalMounts, nil)
if err != nil {
c.logger.Error("core: failed to encode and/or compress the mount table", "error", err)
return err
}
// Create an entry
entry := &Entry{
Key: coreMountConfigPath,
Value: compressedBytes,
}
// Create an entry
entry := &Entry{
Key: coreMountConfigPath,
Value: compressedBytes,
}
// Write to the physical backend
if err := c.barrier.Put(entry); err != nil {
c.logger.Error("core: failed to persist mount table", "error", err)
return err
// Write to the physical backend
if err := c.barrier.Put(entry); err != nil {
c.logger.Error("core: failed to persist mount table", "error", err)
return err
}
}
// Repeat with local mounts
compressedBytes, err = jsonutil.EncodeJSONAndCompress(localMounts, nil)
compressedBytes, err := jsonutil.EncodeJSONAndCompress(localMounts, nil)
if err != nil {
c.logger.Error("core: failed to encode and/or compress the local mount table", "error", err)
return err
}
entry = &Entry{
entry := &Entry{
Key: coreLocalMountConfigPath,
Value: compressedBytes,
}

View File

@ -132,7 +132,7 @@ func TestCore_Mount_Local(t *testing.T) {
}
c.mounts.Entries[1].Local = true
if err := c.persistMounts(c.mounts); err != nil {
if err := c.persistMounts(c.mounts, false); err != nil {
t.Fatal(err)
}
@ -527,7 +527,7 @@ func testCore_MountTable_UpgradeToTyped_Common(
t.Fatal(err)
}
var persistFunc func(*MountTable) error
var persistFunc func(*MountTable, bool) error
// It should load successfully and be upgraded and persisted
switch testType {
@ -570,19 +570,19 @@ func testCore_MountTable_UpgradeToTyped_Common(
// Now try saving invalid versions
origTableType := mt.Type
mt.Type = "foo"
if err := persistFunc(mt); err == nil {
if err := persistFunc(mt, false); err == nil {
t.Fatal("expected error")
}
if len(mt.Entries) > 0 {
mt.Type = origTableType
mt.Entries[0].Table = "bar"
if err := persistFunc(mt); err == nil {
if err := persistFunc(mt, false); err == nil {
t.Fatal("expected error")
}
mt.Entries[0].Table = mt.Type
if err := persistFunc(mt); err != nil {
if err := persistFunc(mt, false); err != nil {
t.Fatal(err)
}
}