Understand local when persisting mount tables, to avoid invalidations when not necessary (#2427)
This commit is contained in:
parent
70bfdb5ae9
commit
a585f709d3
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue