func (m *ExpirationManager) deleteEntry(leaseID string) error {
	if err := m.idView.Delete(leaseID); err != nil {
		return fmt.Errorf("failed to delete lease entry: %v", err)
	}
	return nil
}
deleteEntry is used to delete a lease entry
package vault
import (
	"encoding/json"
	"fmt"
	"path"
	"strings"
	"sync"
	"time"
	"github.com/armon/go-metrics"
	log "github.com/mgutz/logxi/v1"
	"github.com/hashicorp/go-uuid"
	"github.com/hashicorp/vault/helper/jsonutil"
	"github.com/hashicorp/vault/logical"
)
const (
	expirationSubPath = "expire/"
	leaseViewPrefix = "id/"
	tokenViewPrefix = "token/"
	maxRevokeAttempts = 6
	revokeRetryBase = 10 * time.Second
	minRevokeDelay = 5 * time.Second
	maxLeaseTTL = 32 * 24 * time.Hour
	defaultLeaseTTL = maxLeaseTTL
)
type ExpirationManager struct {
	router     *Router
	idView     *BarrierView
	tokenView  *BarrierView
	tokenStore *TokenStore
	logger     log.Logger
	pending     map[string]*time.Timer
	pendingLock sync.Mutex
}
func NewExpirationManager(router *Router, view *BarrierView, ts *TokenStore, logger log.Logger) *ExpirationManager {
	if logger == nil {
		logger = log.New("expiration_manager")
	}
	exp := &ExpirationManager{
		router:     router,
		idView:     view.SubView(leaseViewPrefix),
		tokenView:  view.SubView(tokenViewPrefix),
		tokenStore: ts,
		logger:     logger,
		pending:    make(map[string]*time.Timer),
	}
	return exp
}
func (c *Core) setupExpiration() error {
	c.metricsMutex.Lock()
	defer c.metricsMutex.Unlock()
	view := c.systemBarrierView.SubView(expirationSubPath)
	mgr := NewExpirationManager(c.router, view, c.tokenStore, c.logger)
	c.expiration = mgr
	c.tokenStore.SetExpirationManager(mgr)
	if err := c.expiration.Restore(); err != nil {
		return fmt.Errorf("expiration state restore failed: %v", err)
	}
	return nil
}
func (c *Core) stopExpiration() error {
	if c.expiration != nil {
		if err := c.expiration.Stop(); err != nil {
			return err
		}
		c.metricsMutex.Lock()
		defer c.metricsMutex.Unlock()
		c.expiration = nil
	}
	return nil
}
func (m *ExpirationManager) Restore() error {
	m.pendingLock.Lock()
	defer m.pendingLock.Unlock()
	existing, err := CollectKeys(m.idView)
	if err != nil {
		return fmt.Errorf("failed to scan for leases: %v", err)
	}
	for _, leaseID := range existing {
		le, err := m.loadEntry(leaseID)
		if err != nil {
			return err
		}
		if le == nil {
			continue
		}
		if le.ExpireTime.IsZero() {
			continue
		}
		expires := le.ExpireTime.Sub(time.Now())
		if expires <= 0 {
			expires = minRevokeDelay
		}
		m.pending[le.LeaseID] = time.AfterFunc(expires, func() {
			m.expireID(le.LeaseID)
		})
	}
	if len(m.pending) > 0 {
		if m.logger.IsInfo() {
			m.logger.Info("expire: leases restored", "restored_lease_count", len(m.pending))
		}
	}
	return nil
}
func (m *ExpirationManager) Stop() error {
	m.pendingLock.Lock()
	for _, timer := range m.pending {
		timer.Stop()
	}
	m.pending = make(map[string]*time.Timer)
	m.pendingLock.Unlock()
	return nil
}
func (m *ExpirationManager) Revoke(leaseID string) error {
	defer metrics.MeasureSince([]string{"expire", "revoke"}, time.Now())
	return m.revokeCommon(leaseID, false, false)
}
func (m *ExpirationManager) revokeCommon(leaseID string, force, skipToken bool) error {
	defer metrics.MeasureSince([]string{"expire", "revoke-common"}, time.Now())
	le, err := m.loadEntry(leaseID)
	if err != nil {
		return err
	}
	if le == nil {
		return nil
	}
	if !skipToken || le.Auth == nil {
		if err := m.revokeEntry(le); err != nil {
			if !force {
				return err
			} else {
				if m.logger.IsWarn() {
					m.logger.Warn("revocation from the backend failed, but in force mode so ignoring", "error", err)
				}
			}
		}
	}
	if err := m.deleteEntry(leaseID); err != nil {
		return err
	}
	if le.Secret != nil {
		if err := m.removeIndexByToken(le.ClientToken, le.LeaseID); err != nil {
			return err
		}
	}
	m.pendingLock.Lock()
	if timer, ok := m.pending[leaseID]; ok {
		timer.Stop()
		delete(m.pending, leaseID)
	}
	m.pendingLock.Unlock()
	return nil
}
func (m *ExpirationManager) RevokeForce(prefix string) error {
	defer metrics.MeasureSince([]string{"expire", "revoke-force"}, time.Now())
	return m.revokePrefixCommon(prefix, true)
}
func (m *ExpirationManager) RevokePrefix(prefix string) error {
	defer metrics.MeasureSince([]string{"expire", "revoke-prefix"}, time.Now())
	return m.revokePrefixCommon(prefix, false)
}
func (m *ExpirationManager) RevokeByToken(te *TokenEntry) error {
	defer metrics.MeasureSince([]string{"expire", "revoke-by-token"}, time.Now())
	existing, err := m.lookupByToken(te.ID)
	if err != nil {
		return fmt.Errorf("failed to scan for leases: %v", err)
	}
	for idx, leaseID := range existing {
		if err := m.Revoke(leaseID); err != nil {
			return fmt.Errorf("failed to revoke '%s' (%d / %d): %v",
				leaseID, idx+1, len(existing), err)
		}
	}
	if te.Path != "" {
		tokenLeaseID := path.Join(te.Path, m.tokenStore.SaltID(te.ID))
		return m.revokeCommon(tokenLeaseID, false, true)
	}
	return nil
}
func (m *ExpirationManager) revokePrefixCommon(prefix string, force bool) error {
	if !strings.HasSuffix(prefix, "/") {
		prefix = prefix + "/"
	}
	sub := m.idView.SubView(prefix)
	existing, err := CollectKeys(sub)
	if err != nil {
		return fmt.Errorf("failed to scan for leases: %v", err)
	}
	for idx, suffix := range existing {
		leaseID := prefix + suffix
		if err := m.revokeCommon(leaseID, force, false); err != nil {
			return fmt.Errorf("failed to revoke '%s' (%d / %d): %v",
				leaseID, idx+1, len(existing), err)
		}
	}
	return nil
}
func (m *ExpirationManager) Renew(leaseID string, increment time.Duration) (*logical.Response, error) {
	defer metrics.MeasureSince([]string{"expire", "renew"}, time.Now())
	le, err := m.loadEntry(leaseID)
	if err != nil {
		return nil, err
	}
	if err := le.renewable(); err != nil {
		return nil, err
	}
	resp, err := m.renewEntry(le, increment)
	if err != nil {
		return nil, err
	}
	if resp == nil || resp.Secret == nil || !resp.Secret.LeaseEnabled() {
		return resp, nil
	}
	if err := resp.Secret.Validate(); err != nil {
		return nil, err
	}
	resp.Secret.LeaseID = leaseID
	le.Data = resp.Data
	le.Secret = resp.Secret
	le.ExpireTime = resp.Secret.ExpirationTime()
	le.LastRenewalTime = time.Now()
	if err := m.persistEntry(le); err != nil {
		return nil, err
	}
	m.updatePending(le, resp.Secret.LeaseTotal())
	return resp, nil
}
func (m *ExpirationManager) RenewToken(req *logical.Request, source string, token string,
	increment time.Duration) (*logical.Response, error) {
	defer metrics.MeasureSince([]string{"expire", "renew-token"}, time.Now())
	leaseID := path.Join(source, m.tokenStore.SaltID(token))
	le, err := m.loadEntry(leaseID)
	if err != nil {
		return nil, err
	}
	if err := le.renewable(); err != nil {
		return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest
	}
	resp, err := m.renewAuthEntry(req, le, increment)
	if err != nil {
		return nil, err
	}
	if resp == nil {
		return nil, nil
	}
	if resp.IsError() {
		return &logical.Response{
			Data: resp.Data,
		}, nil
	}
	if resp.Auth == nil || !resp.Auth.LeaseEnabled() {
		return &logical.Response{
			Auth: resp.Auth,
		}, nil
	}
	resp.Auth.ClientToken = token
	resp.Auth.Increment = 0
	le.Auth = resp.Auth
	le.ExpireTime = resp.Auth.ExpirationTime()
	le.LastRenewalTime = time.Now()
	if err := m.persistEntry(le); err != nil {
		return nil, err
	}
	m.updatePending(le, resp.Auth.LeaseTotal())
	return &logical.Response{
		Auth: resp.Auth,
	}, nil
}
func (m *ExpirationManager) Register(req *logical.Request, resp *logical.Response) (string, error) {
	defer metrics.MeasureSince([]string{"expire", "register"}, time.Now())
	if resp == nil || resp.Secret == nil {
		return "", nil
	}
	if err := resp.Secret.Validate(); err != nil {
		return "", err
	}
	leaseUUID, err := uuid.GenerateUUID()
	if err != nil {
		return "", err
	}
	le := leaseEntry{
		LeaseID:     path.Join(req.Path, leaseUUID),
		ClientToken: req.ClientToken,
		Path:        req.Path,
		Data:        resp.Data,
		Secret:      resp.Secret,
		IssueTime:   time.Now(),
		ExpireTime:  resp.Secret.ExpirationTime(),
	}
	if err := m.persistEntry(&le); err != nil {
		return "", err
	}
	if err := m.createIndexByToken(le.ClientToken, le.LeaseID); err != nil {
		return "", err
	}
	m.updatePending(&le, resp.Secret.LeaseTotal())
	return le.LeaseID, nil
}
func (m *ExpirationManager) RegisterAuth(source string, auth *logical.Auth) error {
	defer metrics.MeasureSince([]string{"expire", "register-auth"}, time.Now())
	le := leaseEntry{
		LeaseID:     path.Join(source, m.tokenStore.SaltID(auth.ClientToken)),
		ClientToken: auth.ClientToken,
		Auth:        auth,
		Path:        source,
		IssueTime:   time.Now(),
		ExpireTime:  auth.ExpirationTime(),
	}
	if err := m.persistEntry(&le); err != nil {
		return err
	}
	m.updatePending(&le, auth.LeaseTotal())
	return nil
}
func (m *ExpirationManager) FetchLeaseTimesByToken(source, token string) (*leaseEntry, error) {
	defer metrics.MeasureSince([]string{"expire", "fetch-lease-times-by-token"}, time.Now())
	leaseID := path.Join(source, m.tokenStore.SaltID(token))
	return m.FetchLeaseTimes(leaseID)
}
func (m *ExpirationManager) FetchLeaseTimes(leaseID string) (*leaseEntry, error) {
	defer metrics.MeasureSince([]string{"expire", "fetch-lease-times"}, time.Now())
	le, err := m.loadEntry(leaseID)
	if err != nil {
		return nil, err
	}
	if le == nil {
		return nil, nil
	}
	ret := &leaseEntry{
		IssueTime:       le.IssueTime,
		ExpireTime:      le.ExpireTime,
		LastRenewalTime: le.LastRenewalTime,
	}
	if le.Secret != nil {
		ret.Secret = &logical.Secret{}
		ret.Secret.Renewable = le.Secret.Renewable
		ret.Secret.TTL = le.Secret.TTL
	}
	if le.Auth != nil {
		ret.Auth = &logical.Auth{}
		ret.Auth.Renewable = le.Auth.Renewable
		ret.Auth.TTL = le.Auth.TTL
	}
	return ret, nil
}
func (m *ExpirationManager) updatePending(le *leaseEntry, leaseTotal time.Duration) {
	m.pendingLock.Lock()
	defer m.pendingLock.Unlock()
	timer, ok := m.pending[le.LeaseID]
	if !ok && leaseTotal > 0 {
		timer := time.AfterFunc(leaseTotal, func() {
			m.expireID(le.LeaseID)
		})
		m.pending[le.LeaseID] = timer
		return
	}
	if ok && leaseTotal == 0 {
		timer.Stop()
		delete(m.pending, le.LeaseID)
		return
	}
	if ok && leaseTotal > 0 {
		timer.Reset(leaseTotal)
	}
}
func (m *ExpirationManager) expireID(leaseID string) {
	m.pendingLock.Lock()
	delete(m.pending, leaseID)
	m.pendingLock.Unlock()
	for attempt := uint(0); attempt < maxRevokeAttempts; attempt++ {
		err := m.Revoke(leaseID)
		if err == nil {
			if m.logger.IsInfo() {
				m.logger.Info("expire: revoked lease", "lease_id", leaseID)
			}
			return
		}
		m.logger.Error("expire: failed to revoke lease", "lease_id", leaseID, "error", err)
		time.Sleep((1 << attempt) * revokeRetryBase)
	}
	m.logger.Error("expire: maximum revoke attempts reached", "lease_id", leaseID)
}
func (m *ExpirationManager) revokeEntry(le *leaseEntry) error {
	if le.Auth != nil {
		if err := m.tokenStore.RevokeTree(le.Auth.ClientToken); err != nil {
			return fmt.Errorf("failed to revoke token: %v", err)
		}
		return nil
	}
	resp, err := m.router.Route(logical.RevokeRequest(
		le.Path, le.Secret, le.Data))
	if err != nil || (resp != nil && resp.IsError()) {
		return fmt.Errorf("failed to revoke entry: resp:%#v err:%s", resp, err)
	}
	return nil
}
func (m *ExpirationManager) renewEntry(le *leaseEntry, increment time.Duration) (*logical.Response, error) {
	secret := *le.Secret
	secret.IssueTime = le.IssueTime
	secret.Increment = increment
	secret.LeaseID = ""
	req := logical.RenewRequest(le.Path, &secret, le.Data)
	resp, err := m.router.Route(req)
	if err != nil || (resp != nil && resp.IsError()) {
		return nil, fmt.Errorf("failed to renew entry: resp:%#v err:%s", resp, err)
	}
	return resp, nil
}
func (m *ExpirationManager) renewAuthEntry(req *logical.Request, le *leaseEntry, increment time.Duration) (*logical.Response, error) {
	auth := *le.Auth
	auth.IssueTime = le.IssueTime
	auth.Increment = increment
	if strings.HasPrefix(le.Path, "auth/token/") {
		auth.ClientToken = le.ClientToken
	} else {
		auth.ClientToken = ""
	}
	authReq := logical.RenewAuthRequest(le.Path, &auth, nil)
	authReq.Connection = req.Connection
	resp, err := m.router.Route(authReq)
	if err != nil {
		return nil, fmt.Errorf("failed to renew entry: %v", err)
	}
	return resp, nil
}
func (m *ExpirationManager) loadEntry(leaseID string) (*leaseEntry, error) {
	out, err := m.idView.Get(leaseID)
	if err != nil {
		return nil, fmt.Errorf("failed to read lease entry: %v", err)
	}
	if out == nil {
		return nil, nil
	}
	le, err := decodeLeaseEntry(out.Value)
	if err != nil {
		return nil, fmt.Errorf("failed to decode lease entry: %v", err)
	}
	return le, nil
}
func (m *ExpirationManager) persistEntry(le *leaseEntry) error {
	buf, err := le.encode()
	if err != nil {
		return fmt.Errorf("failed to encode lease entry: %v", err)
	}
	ent := logical.StorageEntry{
		Key:   le.LeaseID,
		Value: buf,
	}
	if err := m.idView.Put(&ent); err != nil {
		return fmt.Errorf("failed to persist lease entry: %v", err)
	}
	return nil
}