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 package state
import ( import (
"encoding/binary"
"fmt" "fmt"
"time" "time"
@ -11,54 +10,6 @@ import (
pbacl "github.com/hashicorp/consul/proto/pbacl" 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 // ACLTokens is used when saving a snapshot
func (s *Snapshot) ACLTokens() (memdb.ResultIterator, error) { func (s *Snapshot) ACLTokens() (memdb.ResultIterator, error) {
iter, err := s.tx.Get(tableACLTokens, "id") 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 { func (s *Store) expiresIndexName(local bool) string {
if local { 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 // ACLTokenDeleteBySecret is used to remove an existing ACL from the state store. If

View File

@ -22,6 +22,8 @@ const (
indexAuthMethod = "authmethod" indexAuthMethod = "authmethod"
indexLocality = "locality" indexLocality = "locality"
indexName = "name" indexName = "name"
indexExpiresGlobal = "expires-global"
indexExpiresLocal = "expires-local"
) )
func tokensTableSchema() *memdb.TableSchema { func tokensTableSchema() *memdb.TableSchema {
@ -84,17 +86,23 @@ func tokensTableSchema() *memdb.TableSchema {
writeIndex: writeIndex(indexLocalFromACLToken), writeIndex: writeIndex(indexLocalFromACLToken),
}, },
}, },
"expires-global": { indexExpiresGlobal: {
Name: "expires-global", Name: indexExpiresGlobal,
AllowMissing: true, AllowMissing: true,
Unique: false, Unique: false,
Indexer: &TokenExpirationIndex{LocalFilter: false}, Indexer: indexerSingle{
readIndex: readIndex(indexFromTimeQuery),
writeIndex: writeIndex(indexExpiresGlobalFromACLToken),
}, },
"expires-local": { },
Name: "expires-local", indexExpiresLocal: {
Name: indexExpiresLocal,
AllowMissing: true, AllowMissing: true,
Unique: false, 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 //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) b.Bool(p.Local)
return b.Bytes(), nil 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", Name: "global",
AllowMissing: true, AllowMissing: true,
Unique: false, Unique: false,
Indexer: &TokenExpirationIndex{LocalFilter: false}, Indexer: indexerSingle{
readIndex: readIndex(indexFromTimeQuery),
writeIndex: writeIndex(indexExpiresGlobalFromACLToken),
},
} }
localIndex := &memdb.IndexSchema{ localIndex := &memdb.IndexSchema{
Name: "local", Name: "local",
AllowMissing: true, AllowMissing: true,
Unique: false, Unique: false,
Indexer: &TokenExpirationIndex{LocalFilter: true}, Indexer: indexerSingle{
readIndex: readIndex(indexFromTimeQuery),
writeIndex: writeIndex(indexExpiresLocalFromACLToken),
},
} }
schema := &memdb.DBSchema{ schema := &memdb.DBSchema{
Tables: map[string]*memdb.TableSchema{ Tables: map[string]*memdb.TableSchema{

View File

@ -5,6 +5,9 @@ import (
"encoding/binary" "encoding/binary"
"errors" "errors"
"fmt" "fmt"
"time"
"github.com/hashicorp/consul/agent/structs"
) )
// indexerSingle implements both memdb.Indexer and memdb.SingleIndexer. It may // 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) { func (b *indexBuilder) Bool(v bool) {
b.Raw([]byte{intFromBool(v)}) 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)
}