consul: split ACL cache into a reusable struct
This commit is contained in:
parent
713f1781c8
commit
e04a23801e
|
@ -11,6 +11,7 @@ import (
|
|||
"github.com/armon/go-metrics"
|
||||
"github.com/hashicorp/consul/acl"
|
||||
"github.com/hashicorp/consul/consul/structs"
|
||||
"github.com/hashicorp/golang-lru"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -30,6 +31,9 @@ const (
|
|||
// anonymousToken is the token ID we re-write to if there
|
||||
// is no token ID provided
|
||||
anonymousToken = "anonymous"
|
||||
|
||||
// Maximum number of cached ACL entries
|
||||
aclCacheSize = 256
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -89,15 +93,57 @@ func (s *Server) resolveToken(id string) (acl.ACL, error) {
|
|||
}
|
||||
|
||||
// Use our non-authoritative cache
|
||||
return s.lookupACL(id, authDC)
|
||||
return s.aclCache.lookupACL(id, authDC)
|
||||
}
|
||||
|
||||
// rpcFn is used to make an RPC call to the client or server.
|
||||
type rpcFn func(string, interface{}, interface{}) error
|
||||
|
||||
// aclCache is used to cache ACL's and policies.
|
||||
type aclCache struct {
|
||||
config *Config
|
||||
logger *log.Logger
|
||||
|
||||
// acls is a non-authoritative ACL cache
|
||||
acls *lru.Cache
|
||||
|
||||
// aclPolicyCache is a policy cache
|
||||
policies *lru.Cache
|
||||
|
||||
// The RPC function used to talk to the client/server
|
||||
rpc rpcFn
|
||||
}
|
||||
|
||||
// newAclCache returns a new cache layer for ACLs and policies
|
||||
func newAclCache(conf *Config, logger *log.Logger, rpc rpcFn) (*aclCache, error) {
|
||||
var err error
|
||||
cache := &aclCache{
|
||||
config: conf,
|
||||
logger: logger,
|
||||
rpc: rpc,
|
||||
}
|
||||
|
||||
// Initialize the non-authoritative ACL cache
|
||||
cache.acls, err = lru.New(aclCacheSize)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to create ACL cache: %v", err)
|
||||
}
|
||||
|
||||
// Initialize the ACL policy cache
|
||||
cache.policies, err = lru.New(aclCacheSize)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to create ACL policy cache: %v", err)
|
||||
}
|
||||
|
||||
return cache, nil
|
||||
}
|
||||
|
||||
// lookupACL is used when we are non-authoritative, and need
|
||||
// to resolve an ACL
|
||||
func (s *Server) lookupACL(id, authDC string) (acl.ACL, error) {
|
||||
func (c *aclCache) lookupACL(id, authDC string) (acl.ACL, error) {
|
||||
// Check the cache for the ACL
|
||||
var cached *aclCacheEntry
|
||||
raw, ok := s.aclCache.Get(id)
|
||||
raw, ok := c.acls.Get(id)
|
||||
if ok {
|
||||
cached = raw.(*aclCacheEntry)
|
||||
}
|
||||
|
@ -119,22 +165,22 @@ func (s *Server) lookupACL(id, authDC string) (acl.ACL, error) {
|
|||
args.ETag = cached.ETag
|
||||
}
|
||||
var out structs.ACLPolicy
|
||||
err := s.RPC("ACL.GetPolicy", &args, &out)
|
||||
err := c.rpc("ACL.GetPolicy", &args, &out)
|
||||
|
||||
// Handle the happy path
|
||||
if err == nil {
|
||||
return s.useACLPolicy(id, authDC, cached, &out)
|
||||
return c.useACLPolicy(id, authDC, cached, &out)
|
||||
}
|
||||
|
||||
// Check for not-found
|
||||
if strings.Contains(err.Error(), aclNotFound) {
|
||||
return nil, errors.New(aclNotFound)
|
||||
} else {
|
||||
s.logger.Printf("[ERR] consul.acl: Failed to get policy for '%s': %v", id, err)
|
||||
c.logger.Printf("[ERR] consul.acl: Failed to get policy for '%s': %v", id, err)
|
||||
}
|
||||
|
||||
// Unable to refresh, apply the down policy
|
||||
switch s.config.ACLDownPolicy {
|
||||
switch c.config.ACLDownPolicy {
|
||||
case "allow":
|
||||
return acl.AllowAll(), nil
|
||||
case "extend-cache":
|
||||
|
@ -148,7 +194,7 @@ func (s *Server) lookupACL(id, authDC string) (acl.ACL, error) {
|
|||
}
|
||||
|
||||
// useACLPolicy handles an ACLPolicy response
|
||||
func (s *Server) useACLPolicy(id, authDC string, cached *aclCacheEntry, p *structs.ACLPolicy) (acl.ACL, error) {
|
||||
func (c *aclCache) useACLPolicy(id, authDC string, cached *aclCacheEntry, p *structs.ACLPolicy) (acl.ACL, error) {
|
||||
// Check if we can used the cached policy
|
||||
if cached != nil && cached.ETag == p.ETag {
|
||||
if p.TTL > 0 {
|
||||
|
@ -159,7 +205,7 @@ func (s *Server) useACLPolicy(id, authDC string, cached *aclCacheEntry, p *struc
|
|||
|
||||
// Check for a cached compiled policy
|
||||
var compiled acl.ACL
|
||||
raw, ok := s.aclPolicyCache.Get(p.ETag)
|
||||
raw, ok := c.policies.Get(p.ETag)
|
||||
if ok {
|
||||
compiled = raw.(acl.ACL)
|
||||
} else {
|
||||
|
@ -167,7 +213,7 @@ func (s *Server) useACLPolicy(id, authDC string, cached *aclCacheEntry, p *struc
|
|||
parent := acl.RootACL(p.Parent)
|
||||
if parent == nil {
|
||||
var err error
|
||||
parent, err = s.lookupACL(p.Parent, authDC)
|
||||
parent, err = c.lookupACL(p.Parent, authDC)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -180,7 +226,7 @@ func (s *Server) useACLPolicy(id, authDC string, cached *aclCacheEntry, p *struc
|
|||
}
|
||||
|
||||
// Cache the policy
|
||||
s.aclPolicyCache.Add(p.ETag, acl)
|
||||
c.policies.Add(p.ETag, acl)
|
||||
compiled = acl
|
||||
}
|
||||
|
||||
|
@ -192,7 +238,7 @@ func (s *Server) useACLPolicy(id, authDC string, cached *aclCacheEntry, p *struc
|
|||
if p.TTL > 0 {
|
||||
cached.Expires = time.Now().Add(p.TTL)
|
||||
}
|
||||
s.aclCache.Add(id, cached)
|
||||
c.acls.Add(id, cached)
|
||||
return compiled, nil
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue