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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,6 @@
package state
import (
"fmt"
"strings"
"github.com/hashicorp/go-memdb"
@ -27,7 +26,7 @@ func configTableSchema() *memdb.TableSchema {
Name: indexID,
AllowMissing: false,
Unique: true,
Indexer: indexerSingleWithPrefix{
Indexer: indexerSingleWithPrefix[any, structs.ConfigEntry, any]{
readIndex: indexFromConfigEntryKindName,
writeIndex: indexFromConfigEntry,
prefixIndex: indexFromConfigEntryKindName,
@ -55,12 +54,30 @@ func configTableSchema() *memdb.TableSchema {
}
}
func indexFromConfigEntry(raw interface{}) ([]byte, error) {
c, ok := raw.(structs.ConfigEntry)
if !ok {
return nil, fmt.Errorf("type must be structs.ConfigEntry: %T", raw)
}
// configEntryIndexable is required because while structs.ConfigEntry
// has a GetEnterpriseMeta method, it does not directly expose the
// required NamespaceOrDefault and PartitionOrDefault methods of
// 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() == "" {
return nil, errMissingValueForIndex
}
@ -73,12 +90,7 @@ func indexFromConfigEntry(raw interface{}) ([]byte, error) {
// indexKindFromConfigEntry indexes kinds without a namespace for any config
// entries that span all namespaces.
func indexKindFromConfigEntry(raw interface{}) ([]byte, error) {
c, ok := raw.(structs.ConfigEntry)
if !ok {
return nil, fmt.Errorf("type must be structs.ConfigEntry: %T", raw)
}
func indexKindFromConfigEntry(c configEntryIndexable) ([]byte, error) {
if c.GetKind() == "" {
return nil, errMissingValueForIndex
}

View File

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

View File

@ -15,32 +15,42 @@ import (
// indexerSingle implements both memdb.Indexer and memdb.SingleIndexer. It may
// be used in a memdb.IndexSchema to specify functions that generate the index
// 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
// that read data.
readIndex
readIndex[R]
// writeIndex is used by memdb for Txn.Insert, Txn.Delete, for operations
// that write data to the index.
writeIndex
writeIndex[W]
}
// indexerMulti implements both memdb.Indexer and memdb.MultiIndexer. It may
// be used in a memdb.IndexSchema to specify functions that generate the index
// 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
// that read data.
readIndex
readIndex[R]
// writeIndexMulti is used by memdb for Txn.Insert, Txn.Delete, for operations
// that write data to the index.
writeIndexMulti
writeIndexMulti[W]
}
// indexerSingleWithPrefix is a indexerSingle which also supports prefix queries.
type indexerSingleWithPrefix struct {
readIndex
writeIndex
prefixIndex
//
// R represents the type used to generate the read index.
// W represents the type used to generate the write index.
// 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
@ -48,13 +58,18 @@ type indexerSingleWithPrefix struct {
//
// 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.
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 {
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")
@ -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
// 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.
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) {
v, err := f(raw)
func (f writeIndex[W]) FromObject(raw interface{}) (bool, []byte, error) {
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) {
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
// 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.
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) {
v, err := f(raw)
func (f writeIndexMulti[W]) FromObject(raw interface{}) (bool, [][]byte, error) {
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) {
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
// 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 {
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"
@ -159,12 +189,7 @@ var _ singleValueID = (*Query)(nil)
var _ singleValueID = (*structs.Session)(nil)
// indexFromIDValue creates an index key from any struct that implements singleValueID
func indexFromIDValueLowerCase(raw interface{}) ([]byte, error) {
e, ok := raw.(singleValueID)
if !ok {
return nil, fmt.Errorf("unexpected type %T, does not implement singleValueID", raw)
}
func indexFromIDValueLowerCase(e singleValueID) ([]byte, error) {
v := strings.ToLower(e.IDValue())
if v == "" {
return nil, errMissingValueForIndex
@ -176,11 +201,7 @@ func indexFromIDValueLowerCase(raw interface{}) ([]byte, error) {
}
// indexFromIDValue creates an index key from any struct that implements singleValueID
func indexFromMultiValueID(raw interface{}) ([]byte, error) {
e, ok := raw.(multiValueID)
if !ok {
return nil, fmt.Errorf("unexpected type %T, does not implement multiValueID", raw)
}
func indexFromMultiValueID(e multiValueID) ([]byte, error) {
var b indexBuilder
for _, v := range e.IDValue() {
if v == "" {

View File

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

View File

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

View File

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

View File

@ -10,23 +10,13 @@ import (
"github.com/hashicorp/consul/proto/pbpeering"
)
func indexPeeringFromQuery(raw interface{}) ([]byte, error) {
q, ok := raw.(Query)
if !ok {
return nil, fmt.Errorf("unexpected type %T for Query index", raw)
}
func indexPeeringFromQuery(q Query) ([]byte, error) {
var b indexBuilder
b.String(strings.ToLower(q.Value))
return b.Bytes(), nil
}
func indexFromPeering(raw interface{}) ([]byte, error) {
p, ok := raw.(*pbpeering.Peering)
if !ok {
return nil, fmt.Errorf("unexpected type %T for structs.Peering index", raw)
}
func indexFromPeering(p *pbpeering.Peering) ([]byte, error) {
if p.Name == "" {
return nil, errMissingValueForIndex
}
@ -36,12 +26,7 @@ func indexFromPeering(raw interface{}) ([]byte, error) {
return b.Bytes(), nil
}
func indexFromPeeringTrustBundle(raw interface{}) ([]byte, error) {
ptb, ok := raw.(*pbpeering.PeeringTrustBundle)
if !ok {
return nil, fmt.Errorf("unexpected type %T for pbpeering.PeeringTrustBundle index", raw)
}
func indexFromPeeringTrustBundle(ptb *pbpeering.PeeringTrustBundle) ([]byte, error) {
if ptb.PeerName == "" {
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
// a required value.
func indexFromQuery(arg interface{}) ([]byte, error) {
q, ok := arg.(Query)
if !ok {
return nil, fmt.Errorf("unexpected type %T for Query index", arg)
}
func indexFromQuery(q Query) ([]byte, error) {
var b indexBuilder
b.String(strings.ToLower(q.Value))
return b.Bytes(), nil
@ -164,12 +159,8 @@ func (q KeyValueQuery) PartitionOrDefault() string {
return q.EnterpriseMeta.PartitionOrDefault()
}
func indexFromKeyValueQuery(arg interface{}) ([]byte, error) {
func indexFromKeyValueQuery(q KeyValueQuery) ([]byte, error) {
// 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
b.String(q.Key)

View File

@ -11,7 +11,7 @@ import (
"github.com/hashicorp/consul/agent/structs"
)
func prefixIndexFromQuery(arg interface{}) ([]byte, error) {
func prefixIndexFromQuery(arg any) ([]byte, error) {
var b indexBuilder
switch v := arg.(type) {
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)
}
func prefixIndexFromQueryWithPeer(arg interface{}) ([]byte, error) {
func prefixIndexFromQueryWithPeer(arg any) ([]byte, error) {
var b indexBuilder
switch v := arg.(type) {
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
// a required value.
func indexFromAuthMethodQuery(arg interface{}) ([]byte, error) {
q, ok := arg.(AuthMethodQuery)
if !ok {
return nil, fmt.Errorf("unexpected type %T for Query index", arg)
}
func indexFromAuthMethodQuery(q AuthMethodQuery) ([]byte, error) {
var b indexBuilder
b.String(strings.ToLower(q.Value))
return b.Bytes(), nil

View File

@ -84,7 +84,7 @@ func indexTableSchema() *memdb.TableSchema {
Name: indexID,
AllowMissing: false,
Unique: true,
Indexer: indexerSingle{
Indexer: indexerSingle[string, *IndexEntry]{
readIndex: indexFromString,
writeIndex: indexNameFromIndexEntry,
},
@ -93,39 +93,37 @@ func indexTableSchema() *memdb.TableSchema {
}
}
func indexNameFromIndexEntry(raw interface{}) ([]byte, error) {
p, ok := raw.(*IndexEntry)
if !ok {
return nil, fmt.Errorf("unexpected type %T for IndexEntry index", raw)
}
if p.Key == "" {
func indexNameFromIndexEntry(e *IndexEntry) ([]byte, error) {
if e.Key == "" {
return nil, errMissingValueForIndex
}
var b indexBuilder
b.String(strings.ToLower(p.Key))
b.String(strings.ToLower(e.Key))
return b.Bytes(), nil
}
func indexFromString(raw interface{}) ([]byte, error) {
q, ok := raw.(string)
if !ok {
return nil, fmt.Errorf("unexpected type %T for string prefix query", raw)
}
func indexFromString(s string) ([]byte, error) {
var b indexBuilder
b.String(strings.ToLower(q))
b.String(strings.ToLower(s))
return b.Bytes(), nil
}
func indexDeletedFromBoolQuery(raw interface{}) ([]byte, error) {
q, ok := raw.(BoolQuery)
if !ok {
return nil, fmt.Errorf("unexpected type %T for BoolQuery index", raw)
}
func indexDeletedFromBoolQuery(q BoolQuery) ([]byte, error) {
var b indexBuilder
b.Bool(q.Value)
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"
)
func indexFromSession(raw interface{}) ([]byte, error) {
e, ok := raw.(*structs.Session)
if !ok {
return nil, fmt.Errorf("unexpected type %T, does not implement *structs.Session", raw)
}
func indexFromSession(e *structs.Session) ([]byte, error) {
v := strings.ToLower(e.ID)
if v == "" {
return nil, errMissingValueForIndex
@ -86,12 +81,7 @@ func sessionChecksTableSchema() *memdb.TableSchema {
}
// indexNodeFromSession creates an index key from *structs.Session
func indexNodeFromSession(raw interface{}) ([]byte, error) {
e, ok := raw.(*structs.Session)
if !ok {
return nil, fmt.Errorf("unexpected type %T, does not implement *structs.Session", raw)
}
func indexNodeFromSession(e *structs.Session) ([]byte, error) {
v := strings.ToLower(e.Node)
if v == "" {
return nil, errMissingValueForIndex
@ -103,12 +93,7 @@ func indexNodeFromSession(raw interface{}) ([]byte, error) {
}
// indexFromNodeCheckIDSession creates an index key from sessionCheck
func indexFromNodeCheckIDSession(raw interface{}) ([]byte, error) {
e, ok := raw.(*sessionCheck)
if !ok {
return nil, fmt.Errorf("unexpected type %T, does not implement sessionCheck", raw)
}
func indexFromNodeCheckIDSession(e *sessionCheck) ([]byte, error) {
var b indexBuilder
v := strings.ToLower(e.Node)
if v == "" {
@ -132,12 +117,7 @@ func indexFromNodeCheckIDSession(raw interface{}) ([]byte, error) {
}
// indexSessionCheckFromSession creates an index key from sessionCheck
func indexSessionCheckFromSession(raw interface{}) ([]byte, error) {
e, ok := raw.(*sessionCheck)
if !ok {
return nil, fmt.Errorf("unexpected type %T, does not implement *sessionCheck", raw)
}
func indexSessionCheckFromSession(e *sessionCheck) ([]byte, error) {
var b indexBuilder
v := strings.ToLower(e.Session)
if v == "" {

View File

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