func (c *aclCache) lookupACL(id, authDC string) (acl.ACL, error) {
	// Check the cache for the ACL.
	var cached *aclCacheEntry
	raw, ok := c.acls.Get(id)
	if ok {
		cached = raw.(*aclCacheEntry)
	}

	// Check for live cache.
	if cached != nil && time.Now().Before(cached.Expires) {
		metrics.IncrCounter([]string{"consul", "acl", "cache_hit"}, 1)
		return cached.ACL, nil
	}
	metrics.IncrCounter([]string{"consul", "acl", "cache_miss"}, 1)

	// Attempt to refresh the policy from the ACL datacenter via an RPC.
	args := structs.ACLPolicyRequest{
		Datacenter: authDC,
		ACL:        id,
	}
	if cached != nil {
		args.ETag = cached.ETag
	}
	var reply structs.ACLPolicy
	err := c.rpc("ACL.GetPolicy", &args, &reply)
	if err == nil {
		return c.useACLPolicy(id, authDC, cached, &reply)
	}

	// Check for not-found, which will cause us to bail immediately. For any
	// other error we report it in the logs but can continue.
	if strings.Contains(err.Error(), aclNotFound) {
		return nil, errors.New(aclNotFound)
	}
	c.logger.Printf("[ERR] consul.acl: Failed to get policy from ACL datacenter: %v", err)

	// TODO (slackpad) - We could do a similar thing *within* the ACL
	// datacenter if the leader isn't available. We have a local state
	// store of the ACLs, so by populating the local member in this cache,
	// it would fall back to the state store if there was a leader loss and
	// the extend-cache policy was true. This feels subtle to explain and
	// configure, and leader blips should be paved over by cache already, so
	// we won't do this for now but should consider for the future. This is
	// a lot different than the replication story where you might be cut off
	// from the ACL datacenter for an extended period of time and need to
	// carry on operating with the full set of ACLs as they were known
	// before the partition.

	// At this point we might have an expired cache entry and we know that
	// there was a problem getting the ACL from the ACL datacenter. If a
	// local ACL fault function is registered to query replicated ACL data,
	// and the user's policy allows it, we will try locally before we give
	// up.
	if c.local != nil && c.config.ACLDownPolicy == "extend-cache" {
		parent, rules, err := c.local(id)
		if err != nil {
			// We don't make an exception here for ACLs that aren't
			// found locally. It seems more robust to use an expired
			// cached entry (if we have one) rather than ignore it
			// for the case that replication was a bit behind and
			// didn't have the ACL yet.
			c.logger.Printf("[DEBUG] consul.acl: Failed to get policy from replicated ACLs: %v", err)
			goto ACL_DOWN
		}

		policy, err := acl.Parse(rules)
		if err != nil {
			c.logger.Printf("[DEBUG] consul.acl: Failed to parse policy for replicated ACL: %v", err)
			goto ACL_DOWN
		}
		policy.ID = acl.RuleID(rules)

		// Fake up an ACL datacenter reply and inject it into the cache.
		// Note we use the local TTL here, so this'll be used for that
		// amount of time even once the ACL datacenter becomes available.
		metrics.IncrCounter([]string{"consul", "acl", "replication_hit"}, 1)
		reply.ETag = makeACLETag(parent, policy)
		reply.TTL = c.config.ACLTTL
		reply.Parent = parent
		reply.Policy = policy
		return c.useACLPolicy(id, authDC, cached, &reply)
	}

ACL_DOWN:
	// Unable to refresh, apply the down policy.
	switch c.config.ACLDownPolicy {
	case "allow":
		return acl.AllowAll(), nil
	case "extend-cache":
		if cached != nil {
			return cached.ACL, nil
		}
		fallthrough
	default:
		return acl.DenyAll(), nil
	}
}
// lookupACL is used when we are non-authoritative, and need to resolve an ACL.
lookupACL is used when we are non-authoritative, and need to resolve an ACL.
// lookupACL is used when we are non - authoritative and need to resolve an ACL .
func (c *aclCache) lookupACL(id, authDC string) (acl.ACL, error) {
	var cached *aclCacheEntry
	raw, ok := c.acls.Get(id)
	if ok {
		cached = raw.(*aclCacheEntry)
	}
	if cached != nil && time.Now().Before(cached.Expires) {
		metrics.IncrCounter([]string{"consul", "acl", "cache_hit"}, 1)
		return cached.ACL, nil
	}
	metrics.IncrCounter([]string{"consul", "acl", "cache_miss"}, 1)
	args := structs.ACLPolicyRequest{
		Datacenter: authDC,
		ACL:        id,
	}
	if cached != nil {
		args.ETag = cached.ETag
	}
	var reply structs.ACLPolicy
	err := c.rpc("ACL.GetPolicy", &args, &reply)
	if err == nil {
		return c.useACLPolicy(id, authDC, cached, &reply)
	}
	if strings.Contains(err.Error(), aclNotFound) {
		return nil, errors.New(aclNotFound)
	}
	c.logger.Printf("[ERR] consul.acl: Failed to get policy from ACL datacenter: %v", err)
	if c.local != nil && c.config.ACLDownPolicy == "extend-cache" {
		parent, rules, err := c.local(id)
		if err != nil {
			c.logger.Printf("[DEBUG] consul.acl: Failed to get policy from replicated ACLs: %v", err)
			goto ACL_DOWN
		}
		policy, err := acl.Parse(rules)
		if err != nil {
			c.logger.Printf("[DEBUG] consul.acl: Failed to parse policy for replicated ACL: %v", err)
			goto ACL_DOWN
		}
		policy.ID = acl.RuleID(rules)
		metrics.IncrCounter([]string{"consul", "acl", "replication_hit"}, 1)
		reply.ETag = makeACLETag(parent, policy)
		reply.TTL = c.config.ACLTTL
		reply.Parent = parent
		reply.Policy = policy
		return c.useACLPolicy(id, authDC, cached, &reply)
	}
ACL_DOWN:
	switch c.config.ACLDownPolicy {
	case "allow":
		return acl.AllowAll(), nil
	case "extend-cache":
		if cached != nil {
			return cached.ACL, nil
		}
		fallthrough
	default:
		return acl.DenyAll(), nil
	}
}
func ( c * aclCache ) lookupACL ( id , authDC string ) ( acl . ACL , error ) { var cached * aclCacheEntry raw , ok := c . acls . Get ( id ) if ok { cached = raw . ( * aclCacheEntry ) } if cached != nil && time . Now ( ) . Before ( cached . Expires ) { metrics . IncrCounter ( [ ] string { " " , " " , " " } , 1 ) return cached . ACL , nil } metrics . IncrCounter ( [ ] string { " " , " " , " " } , 1 ) args := structs . ACLPolicyRequest { Datacenter : authDC , ACL : id , } if cached != nil { args . ETag = cached . ETag } var reply structs . ACLPolicy err := c . rpc ( " " , & args , & reply ) if err == nil { return c . useACLPolicy ( id , authDC , cached , & reply ) } if strings . Contains ( err . Error ( ) , aclNotFound ) { return nil , errors . New ( aclNotFound ) } c . logger . Printf ( " " , err ) if c . local != nil && c . config . ACLDownPolicy == " " { parent , rules , err := c . local ( id ) if err != nil { c . logger . Printf ( " " , err ) goto ACL_DOWN } policy , err := acl . Parse ( rules ) if err != nil { c . logger . Printf ( " " , err ) goto ACL_DOWN } policy . ID = acl . RuleID ( rules ) metrics . IncrCounter ( [ ] string { " " , " " , " " } , 1 ) reply . ETag = makeACLETag ( parent , policy ) reply . TTL = c . config . ACLTTL reply . Parent = parent reply . Policy = policy return c . useACLPolicy ( id , authDC , cached , & reply ) } ACL_DOWN : switch c . config . ACLDownPolicy { case " " : return acl . AllowAll ( ) , nil case " " : if cached != nil { return cached . ACL , nil } fallthrough default : return acl . DenyAll ( ) , nil } }
lookupACL is used when we are non-authoritative, and need to resolve an ACL.
lookupACL is used when we are non - authoritative and need to resolve an ACL .
// Check the cache for the ACL. // Check for live cache. // Attempt to refresh the policy from the ACL datacenter via an RPC. // Check for not-found, which will cause us to bail immediately. For any // other error we report it in the logs but can continue. // TODO (slackpad) - We could do a similar thing *within* the ACL // datacenter if the leader isn't available. We have a local state // store of the ACLs, so by populating the local member in this cache, // it would fall back to the state store if there was a leader loss and // the extend-cache policy was true. This feels subtle to explain and // configure, and leader blips should be paved over by cache already, so // we won't do this for now but should consider for the future. This is // a lot different than the replication story where you might be cut off // from the ACL datacenter for an extended period of time and need to // carry on operating with the full set of ACLs as they were known // before the partition. // At this point we might have an expired cache entry and we know that // there was a problem getting the ACL from the ACL datacenter. If a // local ACL fault function is registered to query replicated ACL data, // and the user's policy allows it, we will try locally before we give // up. // We don't make an exception here for ACLs that aren't // found locally. It seems more robust to use an expired // cached entry (if we have one) rather than ignore it // for the case that replication was a bit behind and // didn't have the ACL yet. // Fake up an ACL datacenter reply and inject it into the cache. // Note we use the local TTL here, so this'll be used for that // amount of time even once the ACL datacenter becomes available. // Unable to refresh, apply the down policy.