convert expiration indexed in ACLToken table to use `indexerSingle` (#11018)

* move intFromBool to be available for oss

* add expiry indexes

* remove dead code: `TokenExpirationIndex`

* fix remove indexer `TokenExpirationIndex`

* fix rebase issue
This commit is contained in:
Dhia Ayachi 2021-09-13 14:37:16 -04:00 committed by GitHub
parent 1f23bdf388
commit 4992218676
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 96 additions and 65 deletions

View File

@ -1,7 +1,6 @@
package state
import (
"encoding/binary"
"fmt"
"time"
@ -11,54 +10,6 @@ import (
pbacl "github.com/hashicorp/consul/proto/pbacl"
)
type TokenExpirationIndex struct {
LocalFilter bool
}
func (s *TokenExpirationIndex) encodeTime(t time.Time) []byte {
val := t.Unix()
buf := make([]byte, 8)
binary.BigEndian.PutUint64(buf, uint64(val))
return buf
}
func (s *TokenExpirationIndex) FromObject(obj interface{}) (bool, []byte, error) {
token, ok := obj.(*structs.ACLToken)
if !ok {
return false, nil, fmt.Errorf("object is not an ACLToken")
}
if s.LocalFilter != token.Local {
return false, nil, nil
}
if !token.HasExpirationTime() {
return false, nil, nil
}
if token.ExpirationTime.Unix() < 0 {
return false, nil, fmt.Errorf("token expiration time cannot be before the unix epoch: %s", token.ExpirationTime)
}
buf := s.encodeTime(*token.ExpirationTime)
return true, buf, nil
}
func (s *TokenExpirationIndex) FromArgs(args ...interface{}) ([]byte, error) {
if len(args) != 1 {
return nil, fmt.Errorf("must provide only a single argument")
}
arg, ok := args[0].(time.Time)
if !ok {
return nil, fmt.Errorf("argument must be a time.Time: %#v", args[0])
}
if arg.Unix() < 0 {
return nil, fmt.Errorf("argument must be a time.Time after the unix epoch: %s", args[0])
}
buf := s.encodeTime(arg)
return buf, nil
}
// ACLTokens is used when saving a snapshot
func (s *Snapshot) ACLTokens() (memdb.ResultIterator, error) {
iter, err := s.tx.Get(tableACLTokens, "id")
@ -850,9 +801,9 @@ func (s *Store) ACLTokenListExpired(local bool, asOf time.Time, max int) (struct
func (s *Store) expiresIndexName(local bool) string {
if local {
return "expires-local"
return indexExpiresLocal
}
return "expires-global"
return indexExpiresGlobal
}
// ACLTokenDeleteBySecret is used to remove an existing ACL from the state store. If

View File

@ -16,12 +16,14 @@ const (
tableACLBindingRules = "acl-binding-rules"
tableACLAuthMethods = "acl-auth-methods"
indexAccessor = "accessor"
indexPolicies = "policies"
indexRoles = "roles"
indexAuthMethod = "authmethod"
indexLocality = "locality"
indexName = "name"
indexAccessor = "accessor"
indexPolicies = "policies"
indexRoles = "roles"
indexAuthMethod = "authmethod"
indexLocality = "locality"
indexName = "name"
indexExpiresGlobal = "expires-global"
indexExpiresLocal = "expires-local"
)
func tokensTableSchema() *memdb.TableSchema {
@ -84,17 +86,23 @@ func tokensTableSchema() *memdb.TableSchema {
writeIndex: writeIndex(indexLocalFromACLToken),
},
},
"expires-global": {
Name: "expires-global",
indexExpiresGlobal: {
Name: indexExpiresGlobal,
AllowMissing: true,
Unique: false,
Indexer: &TokenExpirationIndex{LocalFilter: false},
Indexer: indexerSingle{
readIndex: readIndex(indexFromTimeQuery),
writeIndex: writeIndex(indexExpiresGlobalFromACLToken),
},
},
"expires-local": {
Name: "expires-local",
indexExpiresLocal: {
Name: indexExpiresLocal,
AllowMissing: true,
Unique: false,
Indexer: &TokenExpirationIndex{LocalFilter: true},
Indexer: indexerSingle{
readIndex: readIndex(indexFromTimeQuery),
writeIndex: writeIndex(indexExpiresLocalFromACLToken),
},
},
//DEPRECATED (ACL-Legacy-Compat) - This index is only needed while we support upgrading v1 to v2 acls
@ -423,3 +431,42 @@ func indexLocalFromACLToken(raw interface{}) ([]byte, error) {
b.Bool(p.Local)
return b.Bytes(), nil
}
func indexFromTimeQuery(arg interface{}) ([]byte, error) {
p, ok := arg.(*TimeQuery)
if !ok {
return nil, fmt.Errorf("unexpected type %T for TimeQuery index", arg)
}
var b indexBuilder
b.Time(p.Value)
return b.Bytes(), nil
}
func indexExpiresLocalFromACLToken(raw interface{}) ([]byte, error) {
return indexExpiresFromACLToken(raw, true)
}
func indexExpiresGlobalFromACLToken(raw interface{}) ([]byte, error) {
return indexExpiresFromACLToken(raw, false)
}
func indexExpiresFromACLToken(raw interface{}, local bool) ([]byte, error) {
p, ok := raw.(*structs.ACLToken)
if !ok {
return nil, fmt.Errorf("unexpected type %T for structs.ACLToken index", raw)
}
if p.Local != local {
return nil, errMissingValueForIndex
}
if !p.HasExpirationTime() {
return nil, errMissingValueForIndex
}
if p.ExpirationTime.Unix() < 0 {
return nil, fmt.Errorf("token expiration time cannot be before the unix epoch: %s", p.ExpirationTime)
}
var b indexBuilder
b.Time(*p.ExpirationTime)
return b.Bytes(), nil
}

View File

@ -3819,13 +3819,19 @@ func TestTokenPoliciesIndex(t *testing.T) {
Name: "global",
AllowMissing: true,
Unique: false,
Indexer: &TokenExpirationIndex{LocalFilter: false},
Indexer: indexerSingle{
readIndex: readIndex(indexFromTimeQuery),
writeIndex: writeIndex(indexExpiresGlobalFromACLToken),
},
}
localIndex := &memdb.IndexSchema{
Name: "local",
AllowMissing: true,
Unique: false,
Indexer: &TokenExpirationIndex{LocalFilter: true},
Indexer: indexerSingle{
readIndex: readIndex(indexFromTimeQuery),
writeIndex: writeIndex(indexExpiresLocalFromACLToken),
},
}
schema := &memdb.DBSchema{
Tables: map[string]*memdb.TableSchema{

View File

@ -5,6 +5,9 @@ import (
"encoding/binary"
"errors"
"fmt"
"time"
"github.com/hashicorp/consul/agent/structs"
)
// indexerSingle implements both memdb.Indexer and memdb.SingleIndexer. It may
@ -137,3 +140,27 @@ func (b *indexBuilder) Bytes() []byte {
func (b *indexBuilder) Bool(v bool) {
b.Raw([]byte{intFromBool(v)})
}
type TimeQuery struct {
Value time.Time
structs.EnterpriseMeta
}
// NamespaceOrDefault exists because structs.EnterpriseMeta uses a pointer
// receiver for this method. Remove once that is fixed.
func (q TimeQuery) NamespaceOrDefault() string {
return q.EnterpriseMeta.NamespaceOrDefault()
}
// PartitionOrDefault exists because structs.EnterpriseMeta uses a pointer
// receiver for this method. Remove once that is fixed.
func (q TimeQuery) PartitionOrDefault() string {
return q.EnterpriseMeta.PartitionOrDefault()
}
func (b *indexBuilder) Time(t time.Time) {
val := t.Unix()
buf := make([]byte, 8)
binary.BigEndian.PutUint64(buf, uint64(val))
(*bytes.Buffer)(b).Write(buf)
}