Make memdb indexers generic (#13558)

We have many indexer functions in Consul which take interface{} and type assert before building the index. We can use generics to get rid of the initial plumbing and pass around functions with better defined signatures. This has two benefits: 1) Less verbosity; 2) Developers can parse the argument types to memdb schemas without having to introspect the function for the type assertion.
This commit is contained in:
Chris S. Kim 2022-06-23 11:07:19 -04:00 committed by GitHub
parent dc19b9f46f
commit aaf3c051f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 303 additions and 524 deletions

View File

@ -7,7 +7,7 @@ import (
"fmt" "fmt"
"strings" "strings"
memdb "github.com/hashicorp/go-memdb" "github.com/hashicorp/go-memdb"
"github.com/hashicorp/consul/acl" "github.com/hashicorp/consul/acl"
"github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/agent/structs"
@ -209,18 +209,13 @@ func (s *Store) ACLAuthMethodUpsertValidateEnterprise(method *structs.ACLAuthMet
return nil return nil
} }
func indexAuthMethodFromACLToken(raw interface{}) ([]byte, error) { func indexAuthMethodFromACLToken(t *structs.ACLToken) ([]byte, error) {
p, ok := raw.(*structs.ACLToken) if t.AuthMethod == "" {
if !ok {
return nil, fmt.Errorf("unexpected type %T for structs.ACLToken index", raw)
}
if p.AuthMethod == "" {
return nil, errMissingValueForIndex return nil, errMissingValueForIndex
} }
var b indexBuilder var b indexBuilder
b.String(strings.ToLower(p.AuthMethod)) b.String(strings.ToLower(t.AuthMethod))
return b.Bytes(), nil return b.Bytes(), nil
} }

View File

@ -6,7 +6,6 @@ import (
"github.com/hashicorp/go-memdb" "github.com/hashicorp/go-memdb"
"github.com/hashicorp/consul/acl"
"github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/agent/structs"
) )
@ -36,18 +35,18 @@ func tokensTableSchema() *memdb.TableSchema {
// DEPRECATED (ACL-Legacy-Compat) - we should not AllowMissing here once legacy compat is removed // DEPRECATED (ACL-Legacy-Compat) - we should not AllowMissing here once legacy compat is removed
AllowMissing: true, AllowMissing: true,
Unique: true, Unique: true,
Indexer: indexerSingle{ Indexer: indexerSingle[string, *structs.ACLToken]{
readIndex: readIndex(indexFromUUIDString), readIndex: indexFromUUIDString,
writeIndex: writeIndex(indexAccessorIDFromACLToken), writeIndex: indexAccessorIDFromACLToken,
}, },
}, },
indexID: { indexID: {
Name: indexID, Name: indexID,
AllowMissing: false, AllowMissing: false,
Unique: true, Unique: true,
Indexer: indexerSingle{ Indexer: indexerSingle[string, *structs.ACLToken]{
readIndex: readIndex(indexFromStringCaseSensitive), readIndex: indexFromStringCaseSensitive,
writeIndex: writeIndex(indexSecretIDFromACLToken), writeIndex: indexSecretIDFromACLToken,
}, },
}, },
indexPolicies: { indexPolicies: {
@ -55,58 +54,58 @@ func tokensTableSchema() *memdb.TableSchema {
// Need to allow missing for the anonymous token // Need to allow missing for the anonymous token
AllowMissing: true, AllowMissing: true,
Unique: false, Unique: false,
Indexer: indexerMulti{ Indexer: indexerMulti[Query, *structs.ACLToken]{
readIndex: readIndex(indexFromUUIDQuery), readIndex: indexFromUUIDQuery,
writeIndexMulti: writeIndexMulti(indexPoliciesFromACLToken), writeIndexMulti: indexPoliciesFromACLToken,
}, },
}, },
indexRoles: { indexRoles: {
Name: indexRoles, Name: indexRoles,
AllowMissing: true, AllowMissing: true,
Unique: false, Unique: false,
Indexer: indexerMulti{ Indexer: indexerMulti[Query, *structs.ACLToken]{
readIndex: readIndex(indexFromUUIDQuery), readIndex: indexFromUUIDQuery,
writeIndexMulti: writeIndexMulti(indexRolesFromACLToken), writeIndexMulti: indexRolesFromACLToken,
}, },
}, },
indexAuthMethod: { indexAuthMethod: {
Name: indexAuthMethod, Name: indexAuthMethod,
AllowMissing: true, AllowMissing: true,
Unique: false, Unique: false,
Indexer: indexerSingle{ Indexer: indexerSingle[AuthMethodQuery, *structs.ACLToken]{
readIndex: readIndex(indexFromAuthMethodQuery), readIndex: indexFromAuthMethodQuery,
writeIndex: writeIndex(indexAuthMethodFromACLToken), writeIndex: indexAuthMethodFromACLToken,
}, },
}, },
indexLocality: { indexLocality: {
Name: indexLocality, Name: indexLocality,
AllowMissing: false, AllowMissing: false,
Unique: false, Unique: false,
Indexer: indexerSingle{ Indexer: indexerSingle[BoolQuery, *structs.ACLToken]{
readIndex: readIndex(indexFromBoolQuery), readIndex: indexFromBoolQuery,
writeIndex: writeIndex(indexLocalFromACLToken), writeIndex: indexLocalFromACLToken,
}, },
}, },
indexExpiresGlobal: { indexExpiresGlobal: {
Name: indexExpiresGlobal, Name: indexExpiresGlobal,
AllowMissing: true, AllowMissing: true,
Unique: false, Unique: false,
Indexer: indexerSingle{ Indexer: indexerSingle[*TimeQuery, *structs.ACLToken]{
readIndex: readIndex(indexFromTimeQuery), readIndex: indexFromTimeQuery,
writeIndex: writeIndex(indexExpiresGlobalFromACLToken), writeIndex: indexExpiresGlobalFromACLToken,
}, },
}, },
indexExpiresLocal: { indexExpiresLocal: {
Name: indexExpiresLocal, Name: indexExpiresLocal,
AllowMissing: true, AllowMissing: true,
Unique: false, Unique: false,
Indexer: indexerSingle{ Indexer: indexerSingle[*TimeQuery, *structs.ACLToken]{
readIndex: readIndex(indexFromTimeQuery), readIndex: indexFromTimeQuery,
writeIndex: writeIndex(indexExpiresLocalFromACLToken), 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
// This table indexes all the ACL tokens that do not have an AccessorID // This table indexes all the ACL tokens that do not have an AccessorID
// TODO(ACL-Legacy-Compat): remove in phase 2 // TODO(ACL-Legacy-Compat): remove in phase 2
"needs-upgrade": { "needs-upgrade": {
@ -142,7 +141,7 @@ func policiesTableSchema() *memdb.TableSchema {
Name: indexName, Name: indexName,
AllowMissing: false, AllowMissing: false,
Unique: true, Unique: true,
Indexer: indexerSingleWithPrefix{ Indexer: indexerSingleWithPrefix[Query, *structs.ACLPolicy, any]{
readIndex: indexFromQuery, readIndex: indexFromQuery,
writeIndex: indexNameFromACLPolicy, writeIndex: indexNameFromACLPolicy,
prefixIndex: prefixIndexFromQuery, prefixIndex: prefixIndexFromQuery,
@ -152,12 +151,7 @@ func policiesTableSchema() *memdb.TableSchema {
} }
} }
func indexNameFromACLPolicy(raw interface{}) ([]byte, error) { func indexNameFromACLPolicy(p *structs.ACLPolicy) ([]byte, error) {
p, ok := raw.(*structs.ACLPolicy)
if !ok {
return nil, fmt.Errorf("unexpected type %T for structs.ACLPolicy index", raw)
}
if p.Name == "" { if p.Name == "" {
return nil, errMissingValueForIndex return nil, errMissingValueForIndex
} }
@ -183,7 +177,7 @@ func rolesTableSchema() *memdb.TableSchema {
Name: indexName, Name: indexName,
AllowMissing: false, AllowMissing: false,
Unique: true, Unique: true,
Indexer: indexerSingleWithPrefix{ Indexer: indexerSingleWithPrefix[Query, *structs.ACLRole, any]{
readIndex: indexFromQuery, readIndex: indexFromQuery,
writeIndex: indexNameFromACLRole, writeIndex: indexNameFromACLRole,
prefixIndex: prefixIndexFromQuery, prefixIndex: prefixIndexFromQuery,
@ -194,7 +188,7 @@ func rolesTableSchema() *memdb.TableSchema {
// Need to allow missing for the anonymous token // Need to allow missing for the anonymous token
AllowMissing: true, AllowMissing: true,
Unique: false, Unique: false,
Indexer: indexerMulti{ Indexer: indexerMulti[Query, *structs.ACLRole]{
readIndex: indexFromUUIDQuery, readIndex: indexFromUUIDQuery,
writeIndexMulti: multiIndexPolicyFromACLRole, writeIndexMulti: multiIndexPolicyFromACLRole,
}, },
@ -203,75 +197,43 @@ func rolesTableSchema() *memdb.TableSchema {
} }
} }
func indexNameFromACLRole(raw interface{}) ([]byte, error) { func indexNameFromACLRole(r *structs.ACLRole) ([]byte, error) {
p, ok := raw.(*structs.ACLRole) if r.Name == "" {
if !ok {
return nil, fmt.Errorf("unexpected type %T for structs.ACLRole index", raw)
}
if p.Name == "" {
return nil, errMissingValueForIndex return nil, errMissingValueForIndex
} }
var b indexBuilder var b indexBuilder
b.String(strings.ToLower(p.Name)) b.String(strings.ToLower(r.Name))
return b.Bytes(), nil return b.Bytes(), nil
} }
func indexFromUUIDQuery(raw interface{}) ([]byte, error) { func indexFromUUIDQuery(q Query) ([]byte, error) {
q, ok := raw.(Query)
if !ok {
return nil, fmt.Errorf("unexpected type %T for UUIDQuery index", raw)
}
return uuidStringToBytes(q.Value) return uuidStringToBytes(q.Value)
} }
func prefixIndexFromUUIDQuery(arg interface{}) ([]byte, error) { func prefixIndexFromUUIDWithPeerQuery(q Query) ([]byte, error) {
switch v := arg.(type) { var b indexBuilder
case *acl.EnterpriseMeta: peername := q.PeerOrEmpty()
return nil, nil if peername == "" {
case acl.EnterpriseMeta: b.String(structs.LocalPeerKeyword)
return nil, nil } else {
case Query: b.String(strings.ToLower(peername))
return variableLengthUUIDStringToBytes(v.Value)
} }
uuidBytes, err := variableLengthUUIDStringToBytes(q.Value)
return nil, fmt.Errorf("unexpected type %T for Query prefix index", arg) if err != nil {
return nil, err
}
return append(b.Bytes(), uuidBytes...), nil
} }
func prefixIndexFromUUIDWithPeerQuery(arg interface{}) ([]byte, error) { func multiIndexPolicyFromACLRole(r *structs.ACLRole) ([][]byte, error) {
switch v := arg.(type) { count := len(r.Policies)
case Query:
var b indexBuilder
peername := v.PeerOrEmpty()
if peername == "" {
b.String(structs.LocalPeerKeyword)
} else {
b.String(strings.ToLower(peername))
}
uuidBytes, err := variableLengthUUIDStringToBytes(v.Value)
if err != nil {
return nil, err
}
return append(b.Bytes(), uuidBytes...), nil
}
return nil, fmt.Errorf("unexpected type %T for Query prefix index", arg)
}
func multiIndexPolicyFromACLRole(raw interface{}) ([][]byte, error) {
role, ok := raw.(*structs.ACLRole)
if !ok {
return nil, fmt.Errorf("unexpected type %T for structs.ACLRole index", raw)
}
count := len(role.Policies)
if count == 0 { if count == 0 {
return nil, errMissingValueForIndex return nil, errMissingValueForIndex
} }
vals := make([][]byte, 0, count) vals := make([][]byte, 0, count)
for _, link := range role.Policies { for _, link := range r.Policies {
v, err := uuidStringToBytes(link.ID) v, err := uuidStringToBytes(link.ID)
if err != nil { if err != nil {
return nil, err return nil, err
@ -290,16 +252,16 @@ func bindingRulesTableSchema() *memdb.TableSchema {
Name: indexID, Name: indexID,
AllowMissing: false, AllowMissing: false,
Unique: true, Unique: true,
Indexer: indexerSingle{ Indexer: indexerSingle[string, *structs.ACLBindingRule]{
readIndex: readIndex(indexFromUUIDString), readIndex: indexFromUUIDString,
writeIndex: writeIndex(indexIDFromACLBindingRule), writeIndex: indexIDFromACLBindingRule,
}, },
}, },
indexAuthMethod: { indexAuthMethod: {
Name: indexAuthMethod, Name: indexAuthMethod,
AllowMissing: false, AllowMissing: false,
Unique: false, Unique: false,
Indexer: indexerSingle{ Indexer: indexerSingle[Query, *structs.ACLBindingRule]{
readIndex: indexFromQuery, readIndex: indexFromQuery,
writeIndex: indexAuthMethodFromACLBindingRule, writeIndex: indexAuthMethodFromACLBindingRule,
}, },
@ -308,12 +270,8 @@ func bindingRulesTableSchema() *memdb.TableSchema {
} }
} }
func indexIDFromACLBindingRule(raw interface{}) ([]byte, error) { func indexIDFromACLBindingRule(r *structs.ACLBindingRule) ([]byte, error) {
p, ok := raw.(*structs.ACLBindingRule) vv, err := uuidStringToBytes(r.ID)
if !ok {
return nil, fmt.Errorf("unexpected type %T for structs.ACLBindingRule index", raw)
}
vv, err := uuidStringToBytes(p.ID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -321,27 +279,18 @@ func indexIDFromACLBindingRule(raw interface{}) ([]byte, error) {
return vv, err return vv, err
} }
func indexAuthMethodFromACLBindingRule(raw interface{}) ([]byte, error) { func indexAuthMethodFromACLBindingRule(r *structs.ACLBindingRule) ([]byte, error) {
p, ok := raw.(*structs.ACLBindingRule) if r.AuthMethod == "" {
if !ok {
return nil, fmt.Errorf("unexpected type %T for structs.ACLBindingRule index", raw)
}
if p.AuthMethod == "" {
return nil, errMissingValueForIndex return nil, errMissingValueForIndex
} }
var b indexBuilder var b indexBuilder
b.String(strings.ToLower(p.AuthMethod)) b.String(strings.ToLower(r.AuthMethod))
return b.Bytes(), nil return b.Bytes(), nil
} }
func indexFromUUIDString(raw interface{}) ([]byte, error) { func indexFromUUIDString(raw string) ([]byte, error) {
index, ok := raw.(string) uuid, err := uuidStringToBytes(raw)
if !ok {
return nil, fmt.Errorf("unexpected type %T for UUID string index", raw)
}
uuid, err := uuidStringToBytes(index)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -350,17 +299,12 @@ func indexFromUUIDString(raw interface{}) ([]byte, error) {
return b.Bytes(), nil return b.Bytes(), nil
} }
func indexAccessorIDFromACLToken(raw interface{}) ([]byte, error) { func indexAccessorIDFromACLToken(t *structs.ACLToken) ([]byte, error) {
p, ok := raw.(*structs.ACLToken) if t.AccessorID == "" {
if !ok {
return nil, fmt.Errorf("unexpected type %T for structs.ACLToken index", raw)
}
if p.AccessorID == "" {
return nil, errMissingValueForIndex return nil, errMissingValueForIndex
} }
uuid, err := uuidStringToBytes(p.AccessorID) uuid, err := uuidStringToBytes(t.AccessorID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -369,37 +313,23 @@ func indexAccessorIDFromACLToken(raw interface{}) ([]byte, error) {
return b.Bytes(), nil return b.Bytes(), nil
} }
func indexSecretIDFromACLToken(raw interface{}) ([]byte, error) { func indexSecretIDFromACLToken(t *structs.ACLToken) ([]byte, error) {
p, ok := raw.(*structs.ACLToken) if t.SecretID == "" {
if !ok {
return nil, fmt.Errorf("unexpected type %T for structs.ACLToken index", raw)
}
if p.SecretID == "" {
return nil, errMissingValueForIndex return nil, errMissingValueForIndex
} }
var b indexBuilder var b indexBuilder
b.String(p.SecretID) b.String(t.SecretID)
return b.Bytes(), nil return b.Bytes(), nil
} }
func indexFromStringCaseSensitive(raw interface{}) ([]byte, error) { func indexFromStringCaseSensitive(s string) ([]byte, error) {
q, ok := raw.(string)
if !ok {
return nil, fmt.Errorf("unexpected type %T for string prefix query", raw)
}
var b indexBuilder var b indexBuilder
b.String(q) b.String(s)
return b.Bytes(), nil return b.Bytes(), nil
} }
func indexPoliciesFromACLToken(raw interface{}) ([][]byte, error) { func indexPoliciesFromACLToken(token *structs.ACLToken) ([][]byte, error) {
token, ok := raw.(*structs.ACLToken)
if !ok {
return nil, fmt.Errorf("unexpected type %T for structs.ACLToken index", raw)
}
links := token.Policies links := token.Policies
numLinks := len(links) numLinks := len(links)
@ -420,11 +350,7 @@ func indexPoliciesFromACLToken(raw interface{}) ([][]byte, error) {
return vals, nil return vals, nil
} }
func indexRolesFromACLToken(raw interface{}) ([][]byte, error) { func indexRolesFromACLToken(token *structs.ACLToken) ([][]byte, error) {
token, ok := raw.(*structs.ACLToken)
if !ok {
return nil, fmt.Errorf("unexpected type %T for structs.ACLToken index", raw)
}
links := token.Roles links := token.Roles
numLinks := len(links) numLinks := len(links)
@ -445,63 +371,45 @@ func indexRolesFromACLToken(raw interface{}) ([][]byte, error) {
return vals, nil return vals, nil
} }
func indexFromBoolQuery(raw interface{}) ([]byte, error) { func indexFromBoolQuery(q BoolQuery) ([]byte, error) {
q, ok := raw.(BoolQuery)
if !ok {
return nil, fmt.Errorf("unexpected type %T for BoolQuery index", raw)
}
var b indexBuilder var b indexBuilder
b.Bool(q.Value) b.Bool(q.Value)
return b.Bytes(), nil return b.Bytes(), nil
} }
func indexLocalFromACLToken(raw interface{}) ([]byte, error) { func indexLocalFromACLToken(token *structs.ACLToken) ([]byte, error) {
p, ok := raw.(*structs.ACLToken)
if !ok {
return nil, fmt.Errorf("unexpected type %T for structs.ACLPolicy index", raw)
}
var b indexBuilder var b indexBuilder
b.Bool(p.Local) b.Bool(token.Local)
return b.Bytes(), nil return b.Bytes(), nil
} }
func indexFromTimeQuery(arg interface{}) ([]byte, error) { func indexFromTimeQuery(q *TimeQuery) ([]byte, error) {
p, ok := arg.(*TimeQuery)
if !ok {
return nil, fmt.Errorf("unexpected type %T for TimeQuery index", arg)
}
var b indexBuilder var b indexBuilder
b.Time(p.Value) b.Time(q.Value)
return b.Bytes(), nil return b.Bytes(), nil
} }
func indexExpiresLocalFromACLToken(raw interface{}) ([]byte, error) { func indexExpiresLocalFromACLToken(token *structs.ACLToken) ([]byte, error) {
return indexExpiresFromACLToken(raw, true) return indexExpiresFromACLToken(token, true)
} }
func indexExpiresGlobalFromACLToken(raw interface{}) ([]byte, error) { func indexExpiresGlobalFromACLToken(token *structs.ACLToken) ([]byte, error) {
return indexExpiresFromACLToken(raw, false) return indexExpiresFromACLToken(token, false)
} }
func indexExpiresFromACLToken(raw interface{}, local bool) ([]byte, error) { func indexExpiresFromACLToken(t *structs.ACLToken, local bool) ([]byte, error) {
p, ok := raw.(*structs.ACLToken) if t.Local != local {
if !ok {
return nil, fmt.Errorf("unexpected type %T for structs.ACLToken index", raw)
}
if p.Local != local {
return nil, errMissingValueForIndex return nil, errMissingValueForIndex
} }
if !p.HasExpirationTime() { if !t.HasExpirationTime() {
return nil, errMissingValueForIndex return nil, errMissingValueForIndex
} }
if p.ExpirationTime.Unix() < 0 { if t.ExpirationTime.Unix() < 0 {
return nil, fmt.Errorf("token expiration time cannot be before the unix epoch: %s", p.ExpirationTime) return nil, fmt.Errorf("token expiration time cannot be before the unix epoch: %s", t.ExpirationTime)
} }
var b indexBuilder var b indexBuilder
b.Time(*p.ExpirationTime) b.Time(*t.ExpirationTime)
return b.Bytes(), nil return b.Bytes(), nil
} }
@ -513,7 +421,7 @@ func authMethodsTableSchema() *memdb.TableSchema {
Name: indexID, Name: indexID,
AllowMissing: false, AllowMissing: false,
Unique: true, Unique: true,
Indexer: indexerSingle{ Indexer: indexerSingle[Query, *structs.ACLAuthMethod]{
readIndex: indexFromQuery, readIndex: indexFromQuery,
writeIndex: indexNameFromACLAuthMethod, writeIndex: indexNameFromACLAuthMethod,
}, },
@ -522,17 +430,12 @@ func authMethodsTableSchema() *memdb.TableSchema {
} }
} }
func indexNameFromACLAuthMethod(raw interface{}) ([]byte, error) { func indexNameFromACLAuthMethod(m *structs.ACLAuthMethod) ([]byte, error) {
p, ok := raw.(*structs.ACLAuthMethod) if m.Name == "" {
if !ok {
return nil, fmt.Errorf("unexpected type %T for structs.ACLAuthMethod index", raw)
}
if p.Name == "" {
return nil, errMissingValueForIndex return nil, errMissingValueForIndex
} }
var b indexBuilder var b indexBuilder
b.String(strings.ToLower(p.Name)) b.String(strings.ToLower(m.Name))
return b.Bytes(), nil return b.Bytes(), nil
} }

View File

@ -7,14 +7,14 @@ import (
"testing" "testing"
"time" "time"
memdb "github.com/hashicorp/go-memdb" "github.com/hashicorp/go-memdb"
"github.com/hashicorp/go-uuid" "github.com/hashicorp/go-uuid"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/hashicorp/consul/acl" "github.com/hashicorp/consul/acl"
"github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/agent/structs"
"github.com/hashicorp/consul/lib" "github.com/hashicorp/consul/lib"
pbacl "github.com/hashicorp/consul/proto/pbacl" "github.com/hashicorp/consul/proto/pbacl"
) )
const ( const (
@ -3702,18 +3702,18 @@ func TestTokenPoliciesIndex(t *testing.T) {
Name: "global", Name: "global",
AllowMissing: true, AllowMissing: true,
Unique: false, Unique: false,
Indexer: indexerSingle{ Indexer: indexerSingle[*TimeQuery, *structs.ACLToken]{
readIndex: readIndex(indexFromTimeQuery), readIndex: indexFromTimeQuery,
writeIndex: writeIndex(indexExpiresGlobalFromACLToken), writeIndex: indexExpiresGlobalFromACLToken,
}, },
} }
localIndex := &memdb.IndexSchema{ localIndex := &memdb.IndexSchema{
Name: "local", Name: "local",
AllowMissing: true, AllowMissing: true,
Unique: false, Unique: false,
Indexer: indexerSingle{ Indexer: indexerSingle[*TimeQuery, *structs.ACLToken]{
readIndex: readIndex(indexFromTimeQuery), readIndex: indexFromTimeQuery,
writeIndex: writeIndex(indexExpiresLocalFromACLToken), writeIndex: indexExpiresLocalFromACLToken,
}, },
} }
schema := &memdb.DBSchema{ schema := &memdb.DBSchema{

View File

@ -47,7 +47,7 @@ func nodesTableSchema() *memdb.TableSchema {
Name: indexID, Name: indexID,
AllowMissing: false, AllowMissing: false,
Unique: true, Unique: true,
Indexer: indexerSingleWithPrefix{ Indexer: indexerSingleWithPrefix[Query, *structs.Node, any]{
readIndex: indexWithPeerName(indexFromQuery), readIndex: indexWithPeerName(indexFromQuery),
writeIndex: indexWithPeerName(indexFromNode), writeIndex: indexWithPeerName(indexFromNode),
prefixIndex: prefixIndexFromQueryWithPeer, prefixIndex: prefixIndexFromQueryWithPeer,
@ -57,7 +57,7 @@ func nodesTableSchema() *memdb.TableSchema {
Name: indexUUID, Name: indexUUID,
AllowMissing: true, AllowMissing: true,
Unique: true, Unique: true,
Indexer: indexerSingleWithPrefix{ Indexer: indexerSingleWithPrefix[Query, *structs.Node, Query]{
readIndex: indexWithPeerName(indexFromUUIDQuery), readIndex: indexWithPeerName(indexFromUUIDQuery),
writeIndex: indexWithPeerName(indexIDFromNode), writeIndex: indexWithPeerName(indexIDFromNode),
prefixIndex: prefixIndexFromUUIDWithPeerQuery, prefixIndex: prefixIndexFromUUIDWithPeerQuery,
@ -67,7 +67,7 @@ func nodesTableSchema() *memdb.TableSchema {
Name: indexMeta, Name: indexMeta,
AllowMissing: true, AllowMissing: true,
Unique: false, Unique: false,
Indexer: indexerMulti{ Indexer: indexerMulti[KeyValueQuery, *structs.Node]{
readIndex: indexWithPeerName(indexFromKeyValueQuery), readIndex: indexWithPeerName(indexFromKeyValueQuery),
writeIndexMulti: multiIndexWithPeerName(indexMetaFromNode), writeIndexMulti: multiIndexWithPeerName(indexMetaFromNode),
}, },
@ -76,12 +76,7 @@ func nodesTableSchema() *memdb.TableSchema {
} }
} }
func indexFromNode(raw interface{}) ([]byte, error) { func indexFromNode(n *structs.Node) ([]byte, error) {
n, ok := raw.(*structs.Node)
if !ok {
return nil, fmt.Errorf("unexpected type %T for structs.Node index", raw)
}
if n.Node == "" { if n.Node == "" {
return nil, errMissingValueForIndex return nil, errMissingValueForIndex
} }
@ -91,12 +86,7 @@ func indexFromNode(raw interface{}) ([]byte, error) {
return b.Bytes(), nil return b.Bytes(), nil
} }
func indexIDFromNode(raw interface{}) ([]byte, error) { func indexIDFromNode(n *structs.Node) ([]byte, error) {
n, ok := raw.(*structs.Node)
if !ok {
return nil, fmt.Errorf("unexpected type %T for structs.Node index", raw)
}
if n.ID == "" { if n.ID == "" {
return nil, errMissingValueForIndex return nil, errMissingValueForIndex
} }
@ -109,12 +99,7 @@ func indexIDFromNode(raw interface{}) ([]byte, error) {
return v, nil return v, nil
} }
func indexMetaFromNode(raw interface{}) ([][]byte, error) { func indexMetaFromNode(n *structs.Node) ([][]byte, error) {
n, ok := raw.(*structs.Node)
if !ok {
return nil, fmt.Errorf("unexpected type %T for structs.Node index", raw)
}
// NOTE: this is case-sensitive! // NOTE: this is case-sensitive!
vals := make([][]byte, 0, len(n.Meta)) vals := make([][]byte, 0, len(n.Meta))
@ -145,7 +130,7 @@ func servicesTableSchema() *memdb.TableSchema {
Name: indexID, Name: indexID,
AllowMissing: false, AllowMissing: false,
Unique: true, Unique: true,
Indexer: indexerSingleWithPrefix{ Indexer: indexerSingleWithPrefix[NodeServiceQuery, *structs.ServiceNode, any]{
readIndex: indexWithPeerName(indexFromNodeServiceQuery), readIndex: indexWithPeerName(indexFromNodeServiceQuery),
writeIndex: indexWithPeerName(indexFromServiceNode), writeIndex: indexWithPeerName(indexFromServiceNode),
prefixIndex: prefixIndexFromQueryWithPeer, prefixIndex: prefixIndexFromQueryWithPeer,
@ -155,7 +140,7 @@ func servicesTableSchema() *memdb.TableSchema {
Name: indexNode, Name: indexNode,
AllowMissing: false, AllowMissing: false,
Unique: false, Unique: false,
Indexer: indexerSingle{ Indexer: indexerSingle[Query, nodeIdentifier]{
readIndex: indexWithPeerName(indexFromQuery), readIndex: indexWithPeerName(indexFromQuery),
writeIndex: indexWithPeerName(indexFromNodeIdentity), writeIndex: indexWithPeerName(indexFromNodeIdentity),
}, },
@ -164,7 +149,7 @@ func servicesTableSchema() *memdb.TableSchema {
Name: indexService, Name: indexService,
AllowMissing: true, AllowMissing: true,
Unique: false, Unique: false,
Indexer: indexerSingle{ Indexer: indexerSingle[Query, *structs.ServiceNode]{
readIndex: indexWithPeerName(indexFromQuery), readIndex: indexWithPeerName(indexFromQuery),
writeIndex: indexWithPeerName(indexServiceNameFromServiceNode), writeIndex: indexWithPeerName(indexServiceNameFromServiceNode),
}, },
@ -173,7 +158,7 @@ func servicesTableSchema() *memdb.TableSchema {
Name: indexConnect, Name: indexConnect,
AllowMissing: true, AllowMissing: true,
Unique: false, Unique: false,
Indexer: indexerSingle{ Indexer: indexerSingle[Query, *structs.ServiceNode]{
readIndex: indexWithPeerName(indexFromQuery), readIndex: indexWithPeerName(indexFromQuery),
writeIndex: indexWithPeerName(indexConnectNameFromServiceNode), writeIndex: indexWithPeerName(indexConnectNameFromServiceNode),
}, },
@ -182,7 +167,7 @@ func servicesTableSchema() *memdb.TableSchema {
Name: indexKind, Name: indexKind,
AllowMissing: false, AllowMissing: false,
Unique: false, Unique: false,
Indexer: indexerSingle{ Indexer: indexerSingle[Query, *structs.ServiceNode]{
readIndex: indexWithPeerName(indexFromQuery), readIndex: indexWithPeerName(indexFromQuery),
writeIndex: indexWithPeerName(indexKindFromServiceNode), writeIndex: indexWithPeerName(indexKindFromServiceNode),
}, },
@ -191,24 +176,14 @@ func servicesTableSchema() *memdb.TableSchema {
} }
} }
func indexFromNodeServiceQuery(arg interface{}) ([]byte, error) { func indexFromNodeServiceQuery(q NodeServiceQuery) ([]byte, error) {
q, ok := arg.(NodeServiceQuery)
if !ok {
return nil, fmt.Errorf("unexpected type %T for NodeServiceQuery index", arg)
}
var b indexBuilder var b indexBuilder
b.String(strings.ToLower(q.Node)) b.String(strings.ToLower(q.Node))
b.String(strings.ToLower(q.Service)) b.String(strings.ToLower(q.Service))
return b.Bytes(), nil return b.Bytes(), nil
} }
func indexFromServiceNode(raw interface{}) ([]byte, error) { func indexFromServiceNode(n *structs.ServiceNode) ([]byte, error) {
n, ok := raw.(*structs.ServiceNode)
if !ok {
return nil, fmt.Errorf("unexpected type %T for structs.ServiceNode index", raw)
}
if n.Node == "" { if n.Node == "" {
return nil, errMissingValueForIndex return nil, errMissingValueForIndex
} }
@ -219,14 +194,17 @@ func indexFromServiceNode(raw interface{}) ([]byte, error) {
return b.Bytes(), nil return b.Bytes(), nil
} }
func indexFromNodeIdentity(raw interface{}) ([]byte, error) { type nodeIdentifier interface {
n, ok := raw.(interface { partitionIndexable
NodeIdentity() structs.Identity peerIndexable
})
if !ok {
return nil, fmt.Errorf("unexpected type %T for index, type must provide NodeIdentity()", raw)
}
NodeIdentity() structs.Identity
}
var _ nodeIdentifier = (*structs.HealthCheck)(nil)
var _ nodeIdentifier = (*structs.ServiceNode)(nil)
func indexFromNodeIdentity(n nodeIdentifier) ([]byte, error) {
id := n.NodeIdentity() id := n.NodeIdentity()
if id.ID == "" { if id.ID == "" {
return nil, errMissingValueForIndex return nil, errMissingValueForIndex
@ -237,12 +215,7 @@ func indexFromNodeIdentity(raw interface{}) ([]byte, error) {
return b.Bytes(), nil return b.Bytes(), nil
} }
func indexServiceNameFromServiceNode(raw interface{}) ([]byte, error) { func indexServiceNameFromServiceNode(n *structs.ServiceNode) ([]byte, error) {
n, ok := raw.(*structs.ServiceNode)
if !ok {
return nil, fmt.Errorf("unexpected type %T for structs.ServiceNode index", raw)
}
if n.Node == "" { if n.Node == "" {
return nil, errMissingValueForIndex return nil, errMissingValueForIndex
} }
@ -252,12 +225,7 @@ func indexServiceNameFromServiceNode(raw interface{}) ([]byte, error) {
return b.Bytes(), nil return b.Bytes(), nil
} }
func indexConnectNameFromServiceNode(raw interface{}) ([]byte, error) { func indexConnectNameFromServiceNode(n *structs.ServiceNode) ([]byte, error) {
n, ok := raw.(*structs.ServiceNode)
if !ok {
return nil, fmt.Errorf("unexpected type %T for structs.ServiceNode index", raw)
}
name, ok := connectNameFromServiceNode(n) name, ok := connectNameFromServiceNode(n)
if !ok { if !ok {
return nil, errMissingValueForIndex return nil, errMissingValueForIndex
@ -284,33 +252,23 @@ func connectNameFromServiceNode(sn *structs.ServiceNode) (string, bool) {
} }
} }
func indexKindFromServiceNode(raw interface{}) ([]byte, error) { func indexKindFromServiceNode(n *structs.ServiceNode) ([]byte, error) {
n, ok := raw.(*structs.ServiceNode)
if !ok {
return nil, fmt.Errorf("unexpected type %T for structs.ServiceNode index", raw)
}
var b indexBuilder var b indexBuilder
b.String(strings.ToLower(string(n.ServiceKind))) b.String(strings.ToLower(string(n.ServiceKind)))
return b.Bytes(), nil return b.Bytes(), nil
} }
// indexWithPeerName adds peer name to the index. // indexWithPeerName adds peer name to the index.
func indexWithPeerName( func indexWithPeerName[T peerIndexable](
fn func(interface{}) ([]byte, error), fn func(T) ([]byte, error),
) func(interface{}) ([]byte, error) { ) func(T) ([]byte, error) {
return func(raw interface{}) ([]byte, error) { return func(e T) ([]byte, error) {
v, err := fn(raw) v, err := fn(e)
if err != nil { if err != nil {
return nil, err return nil, err
} }
n, ok := raw.(peerIndexable) peername := e.PeerOrEmpty()
if !ok {
return nil, fmt.Errorf("type must be peerIndexable: %T", raw)
}
peername := n.PeerOrEmpty()
if peername == "" { if peername == "" {
peername = structs.LocalPeerKeyword peername = structs.LocalPeerKeyword
} }
@ -322,20 +280,20 @@ func indexWithPeerName(
} }
// multiIndexWithPeerName adds peer name to multiple indices, and returns multiple indices. // multiIndexWithPeerName adds peer name to multiple indices, and returns multiple indices.
func multiIndexWithPeerName( func multiIndexWithPeerName[T any](
fn func(interface{}) ([][]byte, error), fn func(T) ([][]byte, error),
) func(interface{}) ([][]byte, error) { ) func(T) ([][]byte, error) {
return func(raw interface{}) ([][]byte, error) { return func(raw T) ([][]byte, error) {
n, ok := any(raw).(peerIndexable)
if !ok {
return nil, fmt.Errorf("type must be peerIndexable: %T", raw)
}
results, err := fn(raw) results, err := fn(raw)
if err != nil { if err != nil {
return nil, err return nil, err
} }
n, ok := raw.(peerIndexable)
if !ok {
return nil, fmt.Errorf("type must be peerIndexable: %T", raw)
}
peername := n.PeerOrEmpty() peername := n.PeerOrEmpty()
if peername == "" { if peername == "" {
peername = structs.LocalPeerKeyword peername = structs.LocalPeerKeyword
@ -361,7 +319,7 @@ func checksTableSchema() *memdb.TableSchema {
Name: indexID, Name: indexID,
AllowMissing: false, AllowMissing: false,
Unique: true, Unique: true,
Indexer: indexerSingleWithPrefix{ Indexer: indexerSingleWithPrefix[NodeCheckQuery, *structs.HealthCheck, any]{
readIndex: indexWithPeerName(indexFromNodeCheckQuery), readIndex: indexWithPeerName(indexFromNodeCheckQuery),
writeIndex: indexWithPeerName(indexFromHealthCheck), writeIndex: indexWithPeerName(indexFromHealthCheck),
prefixIndex: prefixIndexFromQueryWithPeer, prefixIndex: prefixIndexFromQueryWithPeer,
@ -371,7 +329,7 @@ func checksTableSchema() *memdb.TableSchema {
Name: indexStatus, Name: indexStatus,
AllowMissing: false, AllowMissing: false,
Unique: false, Unique: false,
Indexer: indexerSingle{ Indexer: indexerSingle[Query, *structs.HealthCheck]{
readIndex: indexWithPeerName(indexFromQuery), readIndex: indexWithPeerName(indexFromQuery),
writeIndex: indexWithPeerName(indexStatusFromHealthCheck), writeIndex: indexWithPeerName(indexStatusFromHealthCheck),
}, },
@ -380,7 +338,7 @@ func checksTableSchema() *memdb.TableSchema {
Name: indexService, Name: indexService,
AllowMissing: true, AllowMissing: true,
Unique: false, Unique: false,
Indexer: indexerSingle{ Indexer: indexerSingle[Query, *structs.HealthCheck]{
readIndex: indexWithPeerName(indexFromQuery), readIndex: indexWithPeerName(indexFromQuery),
writeIndex: indexWithPeerName(indexServiceNameFromHealthCheck), writeIndex: indexWithPeerName(indexServiceNameFromHealthCheck),
}, },
@ -389,7 +347,7 @@ func checksTableSchema() *memdb.TableSchema {
Name: indexNode, Name: indexNode,
AllowMissing: true, AllowMissing: true,
Unique: false, Unique: false,
Indexer: indexerSingle{ Indexer: indexerSingle[Query, nodeIdentifier]{
readIndex: indexWithPeerName(indexFromQuery), readIndex: indexWithPeerName(indexFromQuery),
writeIndex: indexWithPeerName(indexFromNodeIdentity), writeIndex: indexWithPeerName(indexFromNodeIdentity),
}, },
@ -398,7 +356,7 @@ func checksTableSchema() *memdb.TableSchema {
Name: indexNodeService, Name: indexNodeService,
AllowMissing: true, AllowMissing: true,
Unique: false, Unique: false,
Indexer: indexerSingle{ Indexer: indexerSingle[NodeServiceQuery, *structs.HealthCheck]{
readIndex: indexWithPeerName(indexFromNodeServiceQuery), readIndex: indexWithPeerName(indexFromNodeServiceQuery),
writeIndex: indexWithPeerName(indexNodeServiceFromHealthCheck), writeIndex: indexWithPeerName(indexNodeServiceFromHealthCheck),
}, },
@ -407,28 +365,18 @@ func checksTableSchema() *memdb.TableSchema {
} }
} }
func indexFromNodeCheckQuery(raw interface{}) ([]byte, error) { func indexFromNodeCheckQuery(q NodeCheckQuery) ([]byte, error) {
hc, ok := raw.(NodeCheckQuery) if q.Node == "" || q.CheckID == "" {
if !ok {
return nil, fmt.Errorf("unexpected type %T for NodeCheckQuery index", raw)
}
if hc.Node == "" || hc.CheckID == "" {
return nil, errMissingValueForIndex return nil, errMissingValueForIndex
} }
var b indexBuilder var b indexBuilder
b.String(strings.ToLower(hc.Node)) b.String(strings.ToLower(q.Node))
b.String(strings.ToLower(hc.CheckID)) b.String(strings.ToLower(q.CheckID))
return b.Bytes(), nil return b.Bytes(), nil
} }
func indexFromHealthCheck(raw interface{}) ([]byte, error) { func indexFromHealthCheck(hc *structs.HealthCheck) ([]byte, error) {
hc, ok := raw.(*structs.HealthCheck)
if !ok {
return nil, fmt.Errorf("unexpected type %T for structs.HealthCheck index", raw)
}
if hc.Node == "" || hc.CheckID == "" { if hc.Node == "" || hc.CheckID == "" {
return nil, errMissingValueForIndex return nil, errMissingValueForIndex
} }
@ -439,12 +387,7 @@ func indexFromHealthCheck(raw interface{}) ([]byte, error) {
return b.Bytes(), nil return b.Bytes(), nil
} }
func indexNodeServiceFromHealthCheck(raw interface{}) ([]byte, error) { func indexNodeServiceFromHealthCheck(hc *structs.HealthCheck) ([]byte, error) {
hc, ok := raw.(*structs.HealthCheck)
if !ok {
return nil, fmt.Errorf("unexpected type %T for structs.HealthCheck index", raw)
}
if hc.Node == "" { if hc.Node == "" {
return nil, errMissingValueForIndex return nil, errMissingValueForIndex
} }
@ -455,12 +398,7 @@ func indexNodeServiceFromHealthCheck(raw interface{}) ([]byte, error) {
return b.Bytes(), nil return b.Bytes(), nil
} }
func indexStatusFromHealthCheck(raw interface{}) ([]byte, error) { func indexStatusFromHealthCheck(hc *structs.HealthCheck) ([]byte, error) {
hc, ok := raw.(*structs.HealthCheck)
if !ok {
return nil, fmt.Errorf("unexpected type %T for structs.HealthCheck index", raw)
}
if hc.Status == "" { if hc.Status == "" {
return nil, errMissingValueForIndex return nil, errMissingValueForIndex
} }
@ -470,12 +408,7 @@ func indexStatusFromHealthCheck(raw interface{}) ([]byte, error) {
return b.Bytes(), nil return b.Bytes(), nil
} }
func indexServiceNameFromHealthCheck(raw interface{}) ([]byte, error) { func indexServiceNameFromHealthCheck(hc *structs.HealthCheck) ([]byte, error) {
hc, ok := raw.(*structs.HealthCheck)
if !ok {
return nil, fmt.Errorf("unexpected type %T for structs.HealthCheck index", raw)
}
if hc.ServiceName == "" { if hc.ServiceName == "" {
return nil, errMissingValueForIndex return nil, errMissingValueForIndex
} }
@ -761,7 +694,7 @@ func kindServiceNameTableSchema() *memdb.TableSchema {
Name: indexID, Name: indexID,
AllowMissing: false, AllowMissing: false,
Unique: true, Unique: true,
Indexer: indexerSingle{ Indexer: indexerSingle[any, any]{
readIndex: indexFromKindServiceName, readIndex: indexFromKindServiceName,
writeIndex: indexFromKindServiceName, writeIndex: indexFromKindServiceName,
}, },
@ -770,7 +703,7 @@ func kindServiceNameTableSchema() *memdb.TableSchema {
Name: indexKind, Name: indexKind,
AllowMissing: false, AllowMissing: false,
Unique: false, Unique: false,
Indexer: indexerSingle{ Indexer: indexerSingle[enterpriseIndexable, enterpriseIndexable]{
readIndex: indexFromKindServiceNameKindOnly, readIndex: indexFromKindServiceNameKindOnly,
writeIndex: indexFromKindServiceNameKindOnly, writeIndex: indexFromKindServiceNameKindOnly,
}, },
@ -798,7 +731,7 @@ func (q KindServiceNameQuery) PartitionOrDefault() string {
return q.EnterpriseMeta.PartitionOrDefault() return q.EnterpriseMeta.PartitionOrDefault()
} }
func indexFromKindServiceNameKindOnly(raw interface{}) ([]byte, error) { func indexFromKindServiceNameKindOnly(raw enterpriseIndexable) ([]byte, error) {
switch x := raw.(type) { switch x := raw.(type) {
case *KindServiceName: case *KindServiceName:
var b indexBuilder var b indexBuilder

View File

@ -1,7 +1,6 @@
package state package state
import ( import (
"fmt"
"strings" "strings"
"github.com/hashicorp/go-memdb" "github.com/hashicorp/go-memdb"
@ -27,7 +26,7 @@ func configTableSchema() *memdb.TableSchema {
Name: indexID, Name: indexID,
AllowMissing: false, AllowMissing: false,
Unique: true, Unique: true,
Indexer: indexerSingleWithPrefix{ Indexer: indexerSingleWithPrefix[any, structs.ConfigEntry, any]{
readIndex: indexFromConfigEntryKindName, readIndex: indexFromConfigEntryKindName,
writeIndex: indexFromConfigEntry, writeIndex: indexFromConfigEntry,
prefixIndex: indexFromConfigEntryKindName, prefixIndex: indexFromConfigEntryKindName,
@ -55,12 +54,30 @@ func configTableSchema() *memdb.TableSchema {
} }
} }
func indexFromConfigEntry(raw interface{}) ([]byte, error) { // configEntryIndexable is required because while structs.ConfigEntry
c, ok := raw.(structs.ConfigEntry) // has a GetEnterpriseMeta method, it does not directly expose the
if !ok { // required NamespaceOrDefault and PartitionOrDefault methods of
return nil, fmt.Errorf("type must be structs.ConfigEntry: %T", raw) // enterpriseIndexable.
} //
// Config entries that embed *acl.EnterpriseMeta will automatically
// implement this interface.
type configEntryIndexable interface {
structs.ConfigEntry
enterpriseIndexable
}
var _ configEntryIndexable = (*structs.ExportedServicesConfigEntry)(nil)
var _ configEntryIndexable = (*structs.IngressGatewayConfigEntry)(nil)
var _ configEntryIndexable = (*structs.MeshConfigEntry)(nil)
var _ configEntryIndexable = (*structs.ProxyConfigEntry)(nil)
var _ configEntryIndexable = (*structs.ServiceConfigEntry)(nil)
var _ configEntryIndexable = (*structs.ServiceIntentionsConfigEntry)(nil)
var _ configEntryIndexable = (*structs.ServiceResolverConfigEntry)(nil)
var _ configEntryIndexable = (*structs.ServiceRouterConfigEntry)(nil)
var _ configEntryIndexable = (*structs.ServiceSplitterConfigEntry)(nil)
var _ configEntryIndexable = (*structs.TerminatingGatewayConfigEntry)(nil)
func indexFromConfigEntry(c structs.ConfigEntry) ([]byte, error) {
if c.GetName() == "" || c.GetKind() == "" { if c.GetName() == "" || c.GetKind() == "" {
return nil, errMissingValueForIndex return nil, errMissingValueForIndex
} }
@ -73,12 +90,7 @@ func indexFromConfigEntry(raw interface{}) ([]byte, error) {
// indexKindFromConfigEntry indexes kinds without a namespace for any config // indexKindFromConfigEntry indexes kinds without a namespace for any config
// entries that span all namespaces. // entries that span all namespaces.
func indexKindFromConfigEntry(raw interface{}) ([]byte, error) { func indexKindFromConfigEntry(c configEntryIndexable) ([]byte, error) {
c, ok := raw.(structs.ConfigEntry)
if !ok {
return nil, fmt.Errorf("type must be structs.ConfigEntry: %T", raw)
}
if c.GetKind() == "" { if c.GetKind() == "" {
return nil, errMissingValueForIndex return nil, errMissingValueForIndex
} }

View File

@ -13,12 +13,7 @@ import (
const tableCoordinates = "coordinates" const tableCoordinates = "coordinates"
func indexFromCoordinate(raw interface{}) ([]byte, error) { func indexFromCoordinate(c *structs.Coordinate) ([]byte, error) {
c, ok := raw.(*structs.Coordinate)
if !ok {
return nil, fmt.Errorf("unexpected type %T for structs.Coordinate index", raw)
}
if c.Node == "" { if c.Node == "" {
return nil, errMissingValueForIndex return nil, errMissingValueForIndex
} }
@ -29,12 +24,7 @@ func indexFromCoordinate(raw interface{}) ([]byte, error) {
return b.Bytes(), nil return b.Bytes(), nil
} }
func indexNodeFromCoordinate(raw interface{}) ([]byte, error) { func indexNodeFromCoordinate(c *structs.Coordinate) ([]byte, error) {
c, ok := raw.(*structs.Coordinate)
if !ok {
return nil, fmt.Errorf("unexpected type %T for structs.Coordinate index", raw)
}
if c.Node == "" { if c.Node == "" {
return nil, errMissingValueForIndex return nil, errMissingValueForIndex
} }
@ -44,12 +34,7 @@ func indexNodeFromCoordinate(raw interface{}) ([]byte, error) {
return b.Bytes(), nil return b.Bytes(), nil
} }
func indexFromCoordinateQuery(raw interface{}) ([]byte, error) { func indexFromCoordinateQuery(q CoordinateQuery) ([]byte, error) {
q, ok := raw.(CoordinateQuery)
if !ok {
return nil, fmt.Errorf("unexpected type %T for CoordinateQuery index", raw)
}
if q.Node == "" { if q.Node == "" {
return nil, errMissingValueForIndex return nil, errMissingValueForIndex
} }
@ -80,7 +65,7 @@ func coordinatesTableSchema() *memdb.TableSchema {
Name: indexID, Name: indexID,
AllowMissing: false, AllowMissing: false,
Unique: true, Unique: true,
Indexer: indexerSingleWithPrefix{ Indexer: indexerSingleWithPrefix[CoordinateQuery, *structs.Coordinate, any]{
readIndex: indexFromCoordinateQuery, readIndex: indexFromCoordinateQuery,
writeIndex: indexFromCoordinate, writeIndex: indexFromCoordinate,
prefixIndex: prefixIndexFromQueryNoNamespace, prefixIndex: prefixIndexFromQueryNoNamespace,
@ -90,7 +75,7 @@ func coordinatesTableSchema() *memdb.TableSchema {
Name: indexNode, Name: indexNode,
AllowMissing: false, AllowMissing: false,
Unique: false, Unique: false,
Indexer: indexerSingle{ Indexer: indexerSingle[Query, *structs.Coordinate]{
readIndex: indexFromQuery, readIndex: indexFromQuery,
writeIndex: indexNodeFromCoordinate, writeIndex: indexNodeFromCoordinate,
}, },

View File

@ -15,32 +15,42 @@ import (
// indexerSingle implements both memdb.Indexer and memdb.SingleIndexer. It may // indexerSingle implements both memdb.Indexer and memdb.SingleIndexer. It may
// be used in a memdb.IndexSchema to specify functions that generate the index // be used in a memdb.IndexSchema to specify functions that generate the index
// value for memdb.Txn operations. // value for memdb.Txn operations.
type indexerSingle struct { //
// R represents the type used to generate the read index.
// W represents the type used to generate the write index.
type indexerSingle[R, W any] struct {
// readIndex is used by memdb for Txn.Get, Txn.First, and other operations // readIndex is used by memdb for Txn.Get, Txn.First, and other operations
// that read data. // that read data.
readIndex readIndex[R]
// writeIndex is used by memdb for Txn.Insert, Txn.Delete, for operations // writeIndex is used by memdb for Txn.Insert, Txn.Delete, for operations
// that write data to the index. // that write data to the index.
writeIndex writeIndex[W]
} }
// indexerMulti implements both memdb.Indexer and memdb.MultiIndexer. It may // indexerMulti implements both memdb.Indexer and memdb.MultiIndexer. It may
// be used in a memdb.IndexSchema to specify functions that generate the index // be used in a memdb.IndexSchema to specify functions that generate the index
// value for memdb.Txn operations. // value for memdb.Txn operations.
type indexerMulti struct { //
// R represents the type used to generate the read index.
// W represents the type used to generate the write index.
type indexerMulti[R, W any] struct {
// readIndex is used by memdb for Txn.Get, Txn.First, and other operations // readIndex is used by memdb for Txn.Get, Txn.First, and other operations
// that read data. // that read data.
readIndex readIndex[R]
// writeIndexMulti is used by memdb for Txn.Insert, Txn.Delete, for operations // writeIndexMulti is used by memdb for Txn.Insert, Txn.Delete, for operations
// that write data to the index. // that write data to the index.
writeIndexMulti writeIndexMulti[W]
} }
// indexerSingleWithPrefix is a indexerSingle which also supports prefix queries. // indexerSingleWithPrefix is a indexerSingle which also supports prefix queries.
type indexerSingleWithPrefix struct { //
readIndex // R represents the type used to generate the read index.
writeIndex // W represents the type used to generate the write index.
prefixIndex // P represents the type used to generate the prefix index.
type indexerSingleWithPrefix[R, W, P any] struct {
readIndex[R]
writeIndex[W]
prefixIndex[P]
} }
// readIndex implements memdb.Indexer. It exists so that a function can be used // readIndex implements memdb.Indexer. It exists so that a function can be used
@ -48,13 +58,18 @@ type indexerSingleWithPrefix struct {
// //
// Unlike memdb.Indexer, a readIndex function accepts only a single argument. To // Unlike memdb.Indexer, a readIndex function accepts only a single argument. To
// generate an index from multiple values, use a struct type with multiple fields. // generate an index from multiple values, use a struct type with multiple fields.
type readIndex func(arg interface{}) ([]byte, error) type readIndex[R any] func(arg R) ([]byte, error)
func (f readIndex) FromArgs(args ...interface{}) ([]byte, error) { func (f readIndex[R]) FromArgs(args ...interface{}) ([]byte, error) {
if len(args) != 1 { if len(args) != 1 {
return nil, fmt.Errorf("index supports only a single arg") return nil, fmt.Errorf("index supports only a single arg")
} }
return f(args[0]) arg, ok := args[0].(R)
if !ok {
var typ R
return nil, fmt.Errorf("unexpected type %T, does not implement %T", args[0], typ)
}
return f(arg)
} }
var errMissingValueForIndex = fmt.Errorf("object is missing a value for this index") var errMissingValueForIndex = fmt.Errorf("object is missing a value for this index")
@ -65,10 +80,15 @@ var errMissingValueForIndex = fmt.Errorf("object is missing a value for this ind
// Instead of a bool return value, writeIndex expects errMissingValueForIndex to // Instead of a bool return value, writeIndex expects errMissingValueForIndex to
// indicate that an index could not be build for the object. It will translate // indicate that an index could not be build for the object. It will translate
// this error into a false value to satisfy the memdb.SingleIndexer interface. // this error into a false value to satisfy the memdb.SingleIndexer interface.
type writeIndex func(raw interface{}) ([]byte, error) type writeIndex[W any] func(raw W) ([]byte, error)
func (f writeIndex) FromObject(raw interface{}) (bool, []byte, error) { func (f writeIndex[W]) FromObject(raw interface{}) (bool, []byte, error) {
v, err := f(raw) obj, ok := raw.(W)
if !ok {
var typ W
return false, nil, fmt.Errorf("unexpected type %T, does not implement %T", raw, typ)
}
v, err := f(obj)
if errors.Is(err, errMissingValueForIndex) { if errors.Is(err, errMissingValueForIndex) {
return false, nil, nil return false, nil, nil
} }
@ -81,10 +101,15 @@ func (f writeIndex) FromObject(raw interface{}) (bool, []byte, error) {
// Instead of a bool return value, writeIndexMulti expects errMissingValueForIndex to // Instead of a bool return value, writeIndexMulti expects errMissingValueForIndex to
// indicate that an index could not be build for the object. It will translate // indicate that an index could not be build for the object. It will translate
// this error into a false value to satisfy the memdb.MultiIndexer interface. // this error into a false value to satisfy the memdb.MultiIndexer interface.
type writeIndexMulti func(raw interface{}) ([][]byte, error) type writeIndexMulti[W any] func(raw W) ([][]byte, error)
func (f writeIndexMulti) FromObject(raw interface{}) (bool, [][]byte, error) { func (f writeIndexMulti[W]) FromObject(raw interface{}) (bool, [][]byte, error) {
v, err := f(raw) obj, ok := raw.(W)
if !ok {
var typ W
return false, nil, fmt.Errorf("unexpected type %T, does not implement %T", raw, typ)
}
v, err := f(obj)
if errors.Is(err, errMissingValueForIndex) { if errors.Is(err, errMissingValueForIndex) {
return false, nil, nil return false, nil, nil
} }
@ -93,13 +118,18 @@ func (f writeIndexMulti) FromObject(raw interface{}) (bool, [][]byte, error) {
// prefixIndex implements memdb.PrefixIndexer. It exists so that a function // prefixIndex implements memdb.PrefixIndexer. It exists so that a function
// can be used to provide this interface. // can be used to provide this interface.
type prefixIndex func(args interface{}) ([]byte, error) type prefixIndex[P any] func(args P) ([]byte, error)
func (f prefixIndex) PrefixFromArgs(args ...interface{}) ([]byte, error) { func (f prefixIndex[P]) PrefixFromArgs(args ...interface{}) ([]byte, error) {
if len(args) != 1 { if len(args) != 1 {
return nil, fmt.Errorf("index supports only a single arg") return nil, fmt.Errorf("index supports only a single arg")
} }
return f(args[0]) arg, ok := args[0].(P)
if !ok {
var typ P
return nil, fmt.Errorf("unexpected type %T, does not implement %T", args[0], typ)
}
return f(arg)
} }
const null = "\x00" const null = "\x00"
@ -159,12 +189,7 @@ var _ singleValueID = (*Query)(nil)
var _ singleValueID = (*structs.Session)(nil) var _ singleValueID = (*structs.Session)(nil)
// indexFromIDValue creates an index key from any struct that implements singleValueID // indexFromIDValue creates an index key from any struct that implements singleValueID
func indexFromIDValueLowerCase(raw interface{}) ([]byte, error) { func indexFromIDValueLowerCase(e singleValueID) ([]byte, error) {
e, ok := raw.(singleValueID)
if !ok {
return nil, fmt.Errorf("unexpected type %T, does not implement singleValueID", raw)
}
v := strings.ToLower(e.IDValue()) v := strings.ToLower(e.IDValue())
if v == "" { if v == "" {
return nil, errMissingValueForIndex return nil, errMissingValueForIndex
@ -176,11 +201,7 @@ func indexFromIDValueLowerCase(raw interface{}) ([]byte, error) {
} }
// indexFromIDValue creates an index key from any struct that implements singleValueID // indexFromIDValue creates an index key from any struct that implements singleValueID
func indexFromMultiValueID(raw interface{}) ([]byte, error) { func indexFromMultiValueID(e multiValueID) ([]byte, error) {
e, ok := raw.(multiValueID)
if !ok {
return nil, fmt.Errorf("unexpected type %T, does not implement multiValueID", raw)
}
var b indexBuilder var b indexBuilder
for _, v := range e.IDValue() { for _, v := range e.IDValue() {
if v == "" { if v == "" {

View File

@ -41,12 +41,7 @@ func kvsTableSchema() *memdb.TableSchema {
} }
// indexFromIDValue creates an index key from any struct that implements singleValueID // indexFromIDValue creates an index key from any struct that implements singleValueID
func indexFromIDValue(raw interface{}) ([]byte, error) { func indexFromIDValue(e singleValueID) ([]byte, error) {
e, ok := raw.(singleValueID)
if !ok {
return nil, fmt.Errorf("unexpected type %T, does not implement singleValueID", raw)
}
v := e.IDValue() v := e.IDValue()
if v == "" { if v == "" {
return nil, errMissingValueForIndex return nil, errMissingValueForIndex

View File

@ -13,11 +13,11 @@ import (
"github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/agent/structs"
) )
func kvsIndexer() indexerSingleWithPrefix { func kvsIndexer() indexerSingleWithPrefix[singleValueID, singleValueID, any] {
return indexerSingleWithPrefix{ return indexerSingleWithPrefix[singleValueID, singleValueID, any]{
readIndex: readIndex(indexFromIDValue), readIndex: indexFromIDValue,
writeIndex: writeIndex(indexFromIDValue), writeIndex: indexFromIDValue,
prefixIndex: prefixIndex(prefixIndexForIDValue), prefixIndex: prefixIndexForIDValue,
} }
} }

View File

@ -27,16 +27,16 @@ func peeringTableSchema() *memdb.TableSchema {
Name: indexID, Name: indexID,
AllowMissing: false, AllowMissing: false,
Unique: true, Unique: true,
Indexer: indexerSingle{ Indexer: indexerSingle[string, *pbpeering.Peering]{
readIndex: readIndex(indexFromUUIDString), readIndex: indexFromUUIDString,
writeIndex: writeIndex(indexIDFromPeering), writeIndex: indexIDFromPeering,
}, },
}, },
indexName: { indexName: {
Name: indexName, Name: indexName,
AllowMissing: false, AllowMissing: false,
Unique: true, Unique: true,
Indexer: indexerSingleWithPrefix{ Indexer: indexerSingleWithPrefix[Query, *pbpeering.Peering, any]{
readIndex: indexPeeringFromQuery, readIndex: indexPeeringFromQuery,
writeIndex: indexFromPeering, writeIndex: indexFromPeering,
prefixIndex: prefixIndexFromQueryNoNamespace, prefixIndex: prefixIndexFromQueryNoNamespace,
@ -46,7 +46,7 @@ func peeringTableSchema() *memdb.TableSchema {
Name: indexDeleted, Name: indexDeleted,
AllowMissing: false, AllowMissing: false,
Unique: false, Unique: false,
Indexer: indexerSingle{ Indexer: indexerSingle[BoolQuery, *pbpeering.Peering]{
readIndex: indexDeletedFromBoolQuery, readIndex: indexDeletedFromBoolQuery,
writeIndex: indexDeletedFromPeering, writeIndex: indexDeletedFromPeering,
}, },
@ -63,7 +63,7 @@ func peeringTrustBundlesTableSchema() *memdb.TableSchema {
Name: indexID, Name: indexID,
AllowMissing: false, AllowMissing: false,
Unique: true, Unique: true,
Indexer: indexerSingleWithPrefix{ Indexer: indexerSingleWithPrefix[Query, *pbpeering.PeeringTrustBundle, any]{
readIndex: indexPeeringFromQuery, // same as peering table since we'll use the query.Value readIndex: indexPeeringFromQuery, // same as peering table since we'll use the query.Value
writeIndex: indexFromPeeringTrustBundle, writeIndex: indexFromPeeringTrustBundle,
prefixIndex: prefixIndexFromQueryNoNamespace, prefixIndex: prefixIndexFromQueryNoNamespace,
@ -73,12 +73,7 @@ func peeringTrustBundlesTableSchema() *memdb.TableSchema {
} }
} }
func indexIDFromPeering(raw interface{}) ([]byte, error) { func indexIDFromPeering(p *pbpeering.Peering) ([]byte, error) {
p, ok := raw.(*pbpeering.Peering)
if !ok {
return nil, fmt.Errorf("unexpected type %T for pbpeering.Peering index", raw)
}
if p.ID == "" { if p.ID == "" {
return nil, errMissingValueForIndex return nil, errMissingValueForIndex
} }
@ -92,12 +87,7 @@ func indexIDFromPeering(raw interface{}) ([]byte, error) {
return b.Bytes(), nil return b.Bytes(), nil
} }
func indexDeletedFromPeering(raw interface{}) ([]byte, error) { func indexDeletedFromPeering(p *pbpeering.Peering) ([]byte, error) {
p, ok := raw.(*pbpeering.Peering)
if !ok {
return nil, fmt.Errorf("unexpected type %T for *pbpeering.Peering index", raw)
}
var b indexBuilder var b indexBuilder
b.Bool(!p.IsActive()) b.Bool(!p.IsActive())
return b.Bytes(), nil return b.Bytes(), nil

View File

@ -10,23 +10,13 @@ import (
"github.com/hashicorp/consul/proto/pbpeering" "github.com/hashicorp/consul/proto/pbpeering"
) )
func indexPeeringFromQuery(raw interface{}) ([]byte, error) { func indexPeeringFromQuery(q Query) ([]byte, error) {
q, ok := raw.(Query)
if !ok {
return nil, fmt.Errorf("unexpected type %T for Query index", raw)
}
var b indexBuilder var b indexBuilder
b.String(strings.ToLower(q.Value)) b.String(strings.ToLower(q.Value))
return b.Bytes(), nil return b.Bytes(), nil
} }
func indexFromPeering(raw interface{}) ([]byte, error) { func indexFromPeering(p *pbpeering.Peering) ([]byte, error) {
p, ok := raw.(*pbpeering.Peering)
if !ok {
return nil, fmt.Errorf("unexpected type %T for structs.Peering index", raw)
}
if p.Name == "" { if p.Name == "" {
return nil, errMissingValueForIndex return nil, errMissingValueForIndex
} }
@ -36,12 +26,7 @@ func indexFromPeering(raw interface{}) ([]byte, error) {
return b.Bytes(), nil return b.Bytes(), nil
} }
func indexFromPeeringTrustBundle(raw interface{}) ([]byte, error) { func indexFromPeeringTrustBundle(ptb *pbpeering.PeeringTrustBundle) ([]byte, error) {
ptb, ok := raw.(*pbpeering.PeeringTrustBundle)
if !ok {
return nil, fmt.Errorf("unexpected type %T for pbpeering.PeeringTrustBundle index", raw)
}
if ptb.PeerName == "" { if ptb.PeerName == "" {
return nil, errMissingValueForIndex return nil, errMissingValueForIndex
} }

View File

@ -60,12 +60,7 @@ func (q MultiQuery) PartitionOrDefault() string {
// indexFromQuery builds an index key where Query.Value is lowercase, and is // indexFromQuery builds an index key where Query.Value is lowercase, and is
// a required value. // a required value.
func indexFromQuery(arg interface{}) ([]byte, error) { func indexFromQuery(q Query) ([]byte, error) {
q, ok := arg.(Query)
if !ok {
return nil, fmt.Errorf("unexpected type %T for Query index", arg)
}
var b indexBuilder var b indexBuilder
b.String(strings.ToLower(q.Value)) b.String(strings.ToLower(q.Value))
return b.Bytes(), nil return b.Bytes(), nil
@ -164,12 +159,8 @@ func (q KeyValueQuery) PartitionOrDefault() string {
return q.EnterpriseMeta.PartitionOrDefault() return q.EnterpriseMeta.PartitionOrDefault()
} }
func indexFromKeyValueQuery(arg interface{}) ([]byte, error) { func indexFromKeyValueQuery(q KeyValueQuery) ([]byte, error) {
// NOTE: this is case-sensitive! // NOTE: this is case-sensitive!
q, ok := arg.(KeyValueQuery)
if !ok {
return nil, fmt.Errorf("unexpected type %T for Query index", arg)
}
var b indexBuilder var b indexBuilder
b.String(q.Key) b.String(q.Key)

View File

@ -11,7 +11,7 @@ import (
"github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/agent/structs"
) )
func prefixIndexFromQuery(arg interface{}) ([]byte, error) { func prefixIndexFromQuery(arg any) ([]byte, error) {
var b indexBuilder var b indexBuilder
switch v := arg.(type) { switch v := arg.(type) {
case *acl.EnterpriseMeta: case *acl.EnterpriseMeta:
@ -29,7 +29,7 @@ func prefixIndexFromQuery(arg interface{}) ([]byte, error) {
return nil, fmt.Errorf("unexpected type %T for Query prefix index", arg) return nil, fmt.Errorf("unexpected type %T for Query prefix index", arg)
} }
func prefixIndexFromQueryWithPeer(arg interface{}) ([]byte, error) { func prefixIndexFromQueryWithPeer(arg any) ([]byte, error) {
var b indexBuilder var b indexBuilder
switch v := arg.(type) { switch v := arg.(type) {
case *acl.EnterpriseMeta: case *acl.EnterpriseMeta:
@ -58,12 +58,7 @@ func prefixIndexFromQueryNoNamespace(arg interface{}) ([]byte, error) {
// indexFromAuthMethodQuery builds an index key where Query.Value is lowercase, and is // indexFromAuthMethodQuery builds an index key where Query.Value is lowercase, and is
// a required value. // a required value.
func indexFromAuthMethodQuery(arg interface{}) ([]byte, error) { func indexFromAuthMethodQuery(q AuthMethodQuery) ([]byte, error) {
q, ok := arg.(AuthMethodQuery)
if !ok {
return nil, fmt.Errorf("unexpected type %T for Query index", arg)
}
var b indexBuilder var b indexBuilder
b.String(strings.ToLower(q.Value)) b.String(strings.ToLower(q.Value))
return b.Bytes(), nil return b.Bytes(), nil

View File

@ -84,7 +84,7 @@ func indexTableSchema() *memdb.TableSchema {
Name: indexID, Name: indexID,
AllowMissing: false, AllowMissing: false,
Unique: true, Unique: true,
Indexer: indexerSingle{ Indexer: indexerSingle[string, *IndexEntry]{
readIndex: indexFromString, readIndex: indexFromString,
writeIndex: indexNameFromIndexEntry, writeIndex: indexNameFromIndexEntry,
}, },
@ -93,39 +93,37 @@ func indexTableSchema() *memdb.TableSchema {
} }
} }
func indexNameFromIndexEntry(raw interface{}) ([]byte, error) { func indexNameFromIndexEntry(e *IndexEntry) ([]byte, error) {
p, ok := raw.(*IndexEntry) if e.Key == "" {
if !ok {
return nil, fmt.Errorf("unexpected type %T for IndexEntry index", raw)
}
if p.Key == "" {
return nil, errMissingValueForIndex return nil, errMissingValueForIndex
} }
var b indexBuilder var b indexBuilder
b.String(strings.ToLower(p.Key)) b.String(strings.ToLower(e.Key))
return b.Bytes(), nil return b.Bytes(), nil
} }
func indexFromString(raw interface{}) ([]byte, error) { func indexFromString(s string) ([]byte, error) {
q, ok := raw.(string)
if !ok {
return nil, fmt.Errorf("unexpected type %T for string prefix query", raw)
}
var b indexBuilder var b indexBuilder
b.String(strings.ToLower(q)) b.String(strings.ToLower(s))
return b.Bytes(), nil return b.Bytes(), nil
} }
func indexDeletedFromBoolQuery(raw interface{}) ([]byte, error) { func indexDeletedFromBoolQuery(q BoolQuery) ([]byte, error) {
q, ok := raw.(BoolQuery)
if !ok {
return nil, fmt.Errorf("unexpected type %T for BoolQuery index", raw)
}
var b indexBuilder var b indexBuilder
b.Bool(q.Value) b.Bool(q.Value)
return b.Bytes(), nil return b.Bytes(), nil
} }
type enterpriseIndexable interface {
partitionIndexable
namespaceIndexable
}
type partitionIndexable interface {
PartitionOrDefault() string
}
type namespaceIndexable interface {
NamespaceOrDefault() string
}

View File

@ -19,12 +19,7 @@ const (
indexNodeCheck = "node_check" indexNodeCheck = "node_check"
) )
func indexFromSession(raw interface{}) ([]byte, error) { func indexFromSession(e *structs.Session) ([]byte, error) {
e, ok := raw.(*structs.Session)
if !ok {
return nil, fmt.Errorf("unexpected type %T, does not implement *structs.Session", raw)
}
v := strings.ToLower(e.ID) v := strings.ToLower(e.ID)
if v == "" { if v == "" {
return nil, errMissingValueForIndex return nil, errMissingValueForIndex
@ -86,12 +81,7 @@ func sessionChecksTableSchema() *memdb.TableSchema {
} }
// indexNodeFromSession creates an index key from *structs.Session // indexNodeFromSession creates an index key from *structs.Session
func indexNodeFromSession(raw interface{}) ([]byte, error) { func indexNodeFromSession(e *structs.Session) ([]byte, error) {
e, ok := raw.(*structs.Session)
if !ok {
return nil, fmt.Errorf("unexpected type %T, does not implement *structs.Session", raw)
}
v := strings.ToLower(e.Node) v := strings.ToLower(e.Node)
if v == "" { if v == "" {
return nil, errMissingValueForIndex return nil, errMissingValueForIndex
@ -103,12 +93,7 @@ func indexNodeFromSession(raw interface{}) ([]byte, error) {
} }
// indexFromNodeCheckIDSession creates an index key from sessionCheck // indexFromNodeCheckIDSession creates an index key from sessionCheck
func indexFromNodeCheckIDSession(raw interface{}) ([]byte, error) { func indexFromNodeCheckIDSession(e *sessionCheck) ([]byte, error) {
e, ok := raw.(*sessionCheck)
if !ok {
return nil, fmt.Errorf("unexpected type %T, does not implement sessionCheck", raw)
}
var b indexBuilder var b indexBuilder
v := strings.ToLower(e.Node) v := strings.ToLower(e.Node)
if v == "" { if v == "" {
@ -132,12 +117,7 @@ func indexFromNodeCheckIDSession(raw interface{}) ([]byte, error) {
} }
// indexSessionCheckFromSession creates an index key from sessionCheck // indexSessionCheckFromSession creates an index key from sessionCheck
func indexSessionCheckFromSession(raw interface{}) ([]byte, error) { func indexSessionCheckFromSession(e *sessionCheck) ([]byte, error) {
e, ok := raw.(*sessionCheck)
if !ok {
return nil, fmt.Errorf("unexpected type %T, does not implement *sessionCheck", raw)
}
var b indexBuilder var b indexBuilder
v := strings.ToLower(e.Session) v := strings.ToLower(e.Session)
if v == "" { if v == "" {

View File

@ -14,48 +14,44 @@ import (
"github.com/hashicorp/consul/api" "github.com/hashicorp/consul/api"
) )
func sessionIndexer() indexerSingleWithPrefix { func sessionIndexer() indexerSingleWithPrefix[Query, *structs.Session, any] {
return indexerSingleWithPrefix{ return indexerSingleWithPrefix[Query, *structs.Session, any]{
readIndex: readIndex(indexFromQuery), readIndex: indexFromQuery,
writeIndex: writeIndex(indexFromSession), writeIndex: indexFromSession,
prefixIndex: prefixIndex(prefixIndexFromQuery), prefixIndex: prefixIndexFromQuery,
} }
} }
func nodeSessionsIndexer() indexerSingle { func nodeSessionsIndexer() indexerSingle[singleValueID, *structs.Session] {
return indexerSingle{ return indexerSingle[singleValueID, *structs.Session]{
readIndex: readIndex(indexFromIDValueLowerCase), readIndex: indexFromIDValueLowerCase,
writeIndex: writeIndex(indexNodeFromSession), writeIndex: indexNodeFromSession,
} }
} }
func idCheckIndexer() indexerSingle { func idCheckIndexer() indexerSingle[*sessionCheck, *sessionCheck] {
return indexerSingle{ return indexerSingle[*sessionCheck, *sessionCheck]{
readIndex: indexFromNodeCheckIDSession, readIndex: indexFromNodeCheckIDSession,
writeIndex: indexFromNodeCheckIDSession, writeIndex: indexFromNodeCheckIDSession,
} }
} }
func sessionCheckIndexer() indexerSingle { func sessionCheckIndexer() indexerSingle[Query, *sessionCheck] {
return indexerSingle{ return indexerSingle[Query, *sessionCheck]{
readIndex: indexFromQuery, readIndex: indexFromQuery,
writeIndex: indexSessionCheckFromSession, writeIndex: indexSessionCheckFromSession,
} }
} }
func nodeChecksIndexer() indexerSingle { func nodeChecksIndexer() indexerSingle[multiValueID, *sessionCheck] {
return indexerSingle{ return indexerSingle[multiValueID, *sessionCheck]{
readIndex: indexFromMultiValueID, readIndex: indexFromMultiValueID,
writeIndex: indexFromNodeCheckID, writeIndex: indexFromNodeCheckID,
} }
} }
// indexFromNodeCheckID creates an index key from a sessionCheck structure // indexFromNodeCheckID creates an index key from a sessionCheck structure
func indexFromNodeCheckID(raw interface{}) ([]byte, error) { func indexFromNodeCheckID(e *sessionCheck) ([]byte, error) {
e, ok := raw.(*sessionCheck)
if !ok {
return nil, fmt.Errorf("unexpected type %T, does not implement *structs.Session", raw)
}
var b indexBuilder var b indexBuilder
v := strings.ToLower(e.Node) v := strings.ToLower(e.Node)
if v == "" { if v == "" {