mirror of
https://github.com/status-im/consul.git
synced 2025-02-16 23:57:07 +00:00
Merge pull request #9420 from hashicorp/dnephin/reduce-duplicate-in-catalog-schema
state: reduce interface for Enterprise schema
This commit is contained in:
commit
48112e6298
@ -28,191 +28,6 @@ const (
|
|||||||
serviceLastExtinctionIndexName = "service_last_extinction"
|
serviceLastExtinctionIndexName = "service_last_extinction"
|
||||||
)
|
)
|
||||||
|
|
||||||
// nodesTableSchema returns a new table schema used for storing node
|
|
||||||
// information.
|
|
||||||
func nodesTableSchema() *memdb.TableSchema {
|
|
||||||
return &memdb.TableSchema{
|
|
||||||
Name: "nodes",
|
|
||||||
Indexes: map[string]*memdb.IndexSchema{
|
|
||||||
"id": {
|
|
||||||
Name: "id",
|
|
||||||
AllowMissing: false,
|
|
||||||
Unique: true,
|
|
||||||
Indexer: &memdb.StringFieldIndex{
|
|
||||||
Field: "Node",
|
|
||||||
Lowercase: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"uuid": {
|
|
||||||
Name: "uuid",
|
|
||||||
AllowMissing: true,
|
|
||||||
Unique: true,
|
|
||||||
Indexer: &memdb.UUIDFieldIndex{
|
|
||||||
Field: "ID",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"meta": {
|
|
||||||
Name: "meta",
|
|
||||||
AllowMissing: true,
|
|
||||||
Unique: false,
|
|
||||||
Indexer: &memdb.StringMapFieldIndex{
|
|
||||||
Field: "Meta",
|
|
||||||
Lowercase: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// gatewayServicesTableNameSchema returns a new table schema used to store information
|
|
||||||
// about services associated with terminating gateways.
|
|
||||||
func gatewayServicesTableNameSchema() *memdb.TableSchema {
|
|
||||||
return &memdb.TableSchema{
|
|
||||||
Name: gatewayServicesTableName,
|
|
||||||
Indexes: map[string]*memdb.IndexSchema{
|
|
||||||
"id": {
|
|
||||||
Name: "id",
|
|
||||||
AllowMissing: false,
|
|
||||||
Unique: true,
|
|
||||||
Indexer: &memdb.CompoundIndex{
|
|
||||||
Indexes: []memdb.Indexer{
|
|
||||||
&ServiceNameIndex{
|
|
||||||
Field: "Gateway",
|
|
||||||
},
|
|
||||||
&ServiceNameIndex{
|
|
||||||
Field: "Service",
|
|
||||||
},
|
|
||||||
&memdb.IntFieldIndex{
|
|
||||||
Field: "Port",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"gateway": {
|
|
||||||
Name: "gateway",
|
|
||||||
AllowMissing: false,
|
|
||||||
Unique: false,
|
|
||||||
Indexer: &ServiceNameIndex{
|
|
||||||
Field: "Gateway",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"service": {
|
|
||||||
Name: "service",
|
|
||||||
AllowMissing: true,
|
|
||||||
Unique: false,
|
|
||||||
Indexer: &ServiceNameIndex{
|
|
||||||
Field: "Service",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// topologyTableNameSchema returns a new table schema used to store information
|
|
||||||
// relating upstream and downstream services
|
|
||||||
func topologyTableNameSchema() *memdb.TableSchema {
|
|
||||||
return &memdb.TableSchema{
|
|
||||||
Name: topologyTableName,
|
|
||||||
Indexes: map[string]*memdb.IndexSchema{
|
|
||||||
"id": {
|
|
||||||
Name: "id",
|
|
||||||
AllowMissing: false,
|
|
||||||
Unique: true,
|
|
||||||
Indexer: &memdb.CompoundIndex{
|
|
||||||
Indexes: []memdb.Indexer{
|
|
||||||
&ServiceNameIndex{
|
|
||||||
Field: "Upstream",
|
|
||||||
},
|
|
||||||
&ServiceNameIndex{
|
|
||||||
Field: "Downstream",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"upstream": {
|
|
||||||
Name: "upstream",
|
|
||||||
AllowMissing: true,
|
|
||||||
Unique: false,
|
|
||||||
Indexer: &ServiceNameIndex{
|
|
||||||
Field: "Upstream",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"downstream": {
|
|
||||||
Name: "downstream",
|
|
||||||
AllowMissing: false,
|
|
||||||
Unique: false,
|
|
||||||
Indexer: &ServiceNameIndex{
|
|
||||||
Field: "Downstream",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type ServiceNameIndex struct {
|
|
||||||
Field string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (index *ServiceNameIndex) FromObject(obj interface{}) (bool, []byte, error) {
|
|
||||||
v := reflect.ValueOf(obj)
|
|
||||||
v = reflect.Indirect(v) // Dereference the pointer if any
|
|
||||||
|
|
||||||
fv := v.FieldByName(index.Field)
|
|
||||||
isPtr := fv.Kind() == reflect.Ptr
|
|
||||||
fv = reflect.Indirect(fv)
|
|
||||||
if !isPtr && !fv.IsValid() || !fv.CanInterface() {
|
|
||||||
return false, nil,
|
|
||||||
fmt.Errorf("field '%s' for %#v is invalid %v ", index.Field, obj, isPtr)
|
|
||||||
}
|
|
||||||
|
|
||||||
name, ok := fv.Interface().(structs.ServiceName)
|
|
||||||
if !ok {
|
|
||||||
return false, nil, fmt.Errorf("Field 'ServiceName' is not of type structs.ServiceName")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enforce lowercase and add null character as terminator
|
|
||||||
id := strings.ToLower(name.String()) + "\x00"
|
|
||||||
|
|
||||||
return true, []byte(id), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (index *ServiceNameIndex) FromArgs(args ...interface{}) ([]byte, error) {
|
|
||||||
if len(args) != 1 {
|
|
||||||
return nil, fmt.Errorf("must provide only a single argument")
|
|
||||||
}
|
|
||||||
name, ok := args[0].(structs.ServiceName)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("argument must be of type structs.ServiceName: %#v", args[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enforce lowercase and add null character as terminator
|
|
||||||
id := strings.ToLower(name.String()) + "\x00"
|
|
||||||
|
|
||||||
return []byte(strings.ToLower(id)), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (index *ServiceNameIndex) PrefixFromArgs(args ...interface{}) ([]byte, error) {
|
|
||||||
val, err := index.FromArgs(args...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Strip the null terminator, the rest is a prefix
|
|
||||||
n := len(val)
|
|
||||||
if n > 0 {
|
|
||||||
return val[:n-1], nil
|
|
||||||
}
|
|
||||||
return val, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
registerSchema(nodesTableSchema)
|
|
||||||
registerSchema(servicesTableSchema)
|
|
||||||
registerSchema(checksTableSchema)
|
|
||||||
registerSchema(gatewayServicesTableNameSchema)
|
|
||||||
registerSchema(topologyTableNameSchema)
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// minUUIDLookupLen is used as a minimum length of a node name required before
|
// minUUIDLookupLen is used as a minimum length of a node name required before
|
||||||
// we test to see if the name is actually a UUID and perform an ID-based node
|
// we test to see if the name is actually a UUID and perform an ID-based node
|
||||||
|
@ -5,154 +5,12 @@ package state
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/hashicorp/consul/agent/structs"
|
|
||||||
memdb "github.com/hashicorp/go-memdb"
|
memdb "github.com/hashicorp/go-memdb"
|
||||||
|
|
||||||
|
"github.com/hashicorp/consul/agent/structs"
|
||||||
)
|
)
|
||||||
|
|
||||||
// servicesTableSchema returns a new table schema used to store information
|
func withEnterpriseSchema(_ *memdb.DBSchema) {}
|
||||||
// about services.
|
|
||||||
func servicesTableSchema() *memdb.TableSchema {
|
|
||||||
return &memdb.TableSchema{
|
|
||||||
Name: "services",
|
|
||||||
Indexes: map[string]*memdb.IndexSchema{
|
|
||||||
"id": {
|
|
||||||
Name: "id",
|
|
||||||
AllowMissing: false,
|
|
||||||
Unique: true,
|
|
||||||
Indexer: &memdb.CompoundIndex{
|
|
||||||
Indexes: []memdb.Indexer{
|
|
||||||
&memdb.StringFieldIndex{
|
|
||||||
Field: "Node",
|
|
||||||
Lowercase: true,
|
|
||||||
},
|
|
||||||
&memdb.StringFieldIndex{
|
|
||||||
Field: "ServiceID",
|
|
||||||
Lowercase: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"node": {
|
|
||||||
Name: "node",
|
|
||||||
AllowMissing: false,
|
|
||||||
Unique: false,
|
|
||||||
Indexer: &memdb.StringFieldIndex{
|
|
||||||
Field: "Node",
|
|
||||||
Lowercase: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"service": {
|
|
||||||
Name: "service",
|
|
||||||
AllowMissing: true,
|
|
||||||
Unique: false,
|
|
||||||
Indexer: &memdb.StringFieldIndex{
|
|
||||||
Field: "ServiceName",
|
|
||||||
Lowercase: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"connect": {
|
|
||||||
Name: "connect",
|
|
||||||
AllowMissing: true,
|
|
||||||
Unique: false,
|
|
||||||
Indexer: &IndexConnectService{},
|
|
||||||
},
|
|
||||||
"kind": {
|
|
||||||
Name: "kind",
|
|
||||||
AllowMissing: false,
|
|
||||||
Unique: false,
|
|
||||||
Indexer: &IndexServiceKind{},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// checksTableSchema returns a new table schema used for storing and indexing
|
|
||||||
// health check information. Health checks have a number of different attributes
|
|
||||||
// we want to filter by, so this table is a bit more complex.
|
|
||||||
func checksTableSchema() *memdb.TableSchema {
|
|
||||||
return &memdb.TableSchema{
|
|
||||||
Name: "checks",
|
|
||||||
Indexes: map[string]*memdb.IndexSchema{
|
|
||||||
"id": {
|
|
||||||
Name: "id",
|
|
||||||
AllowMissing: false,
|
|
||||||
Unique: true,
|
|
||||||
Indexer: &memdb.CompoundIndex{
|
|
||||||
Indexes: []memdb.Indexer{
|
|
||||||
&memdb.StringFieldIndex{
|
|
||||||
Field: "Node",
|
|
||||||
Lowercase: true,
|
|
||||||
},
|
|
||||||
&memdb.StringFieldIndex{
|
|
||||||
Field: "CheckID",
|
|
||||||
Lowercase: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
Name: "status",
|
|
||||||
AllowMissing: false,
|
|
||||||
Unique: false,
|
|
||||||
Indexer: &memdb.StringFieldIndex{
|
|
||||||
Field: "Status",
|
|
||||||
Lowercase: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"service": {
|
|
||||||
Name: "service",
|
|
||||||
AllowMissing: true,
|
|
||||||
Unique: false,
|
|
||||||
Indexer: &memdb.StringFieldIndex{
|
|
||||||
Field: "ServiceName",
|
|
||||||
Lowercase: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"node": {
|
|
||||||
Name: "node",
|
|
||||||
AllowMissing: true,
|
|
||||||
Unique: false,
|
|
||||||
Indexer: &memdb.StringFieldIndex{
|
|
||||||
Field: "Node",
|
|
||||||
Lowercase: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"node_service_check": {
|
|
||||||
Name: "node_service_check",
|
|
||||||
AllowMissing: true,
|
|
||||||
Unique: false,
|
|
||||||
Indexer: &memdb.CompoundIndex{
|
|
||||||
Indexes: []memdb.Indexer{
|
|
||||||
&memdb.StringFieldIndex{
|
|
||||||
Field: "Node",
|
|
||||||
Lowercase: true,
|
|
||||||
},
|
|
||||||
&memdb.FieldSetIndex{
|
|
||||||
Field: "ServiceID",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"node_service": {
|
|
||||||
Name: "node_service",
|
|
||||||
AllowMissing: true,
|
|
||||||
Unique: false,
|
|
||||||
Indexer: &memdb.CompoundIndex{
|
|
||||||
Indexes: []memdb.Indexer{
|
|
||||||
&memdb.StringFieldIndex{
|
|
||||||
Field: "Node",
|
|
||||||
Lowercase: true,
|
|
||||||
},
|
|
||||||
&memdb.StringFieldIndex{
|
|
||||||
Field: "ServiceID",
|
|
||||||
Lowercase: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func serviceIndexName(name string, _ *structs.EnterpriseMeta) string {
|
func serviceIndexName(name string, _ *structs.EnterpriseMeta) string {
|
||||||
return fmt.Sprintf("service.%s", name)
|
return fmt.Sprintf("service.%s", name)
|
||||||
|
355
agent/consul/state/catalog_schema.go
Normal file
355
agent/consul/state/catalog_schema.go
Normal file
@ -0,0 +1,355 @@
|
|||||||
|
package state
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/hashicorp/go-memdb"
|
||||||
|
|
||||||
|
"github.com/hashicorp/consul/agent/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
tableNodes = "nodes"
|
||||||
|
tableServices = "services"
|
||||||
|
tableChecks = "checks"
|
||||||
|
|
||||||
|
indexID = "id"
|
||||||
|
indexServiceName = "service"
|
||||||
|
indexConnect = "connect"
|
||||||
|
indexKind = "kind"
|
||||||
|
indexStatus = "status"
|
||||||
|
indexNodeServiceCheck = "node_service_check"
|
||||||
|
indexNodeService = "node_service"
|
||||||
|
)
|
||||||
|
|
||||||
|
// nodesTableSchema returns a new table schema used for storing node
|
||||||
|
// information.
|
||||||
|
func nodesTableSchema() *memdb.TableSchema {
|
||||||
|
return &memdb.TableSchema{
|
||||||
|
Name: tableNodes,
|
||||||
|
Indexes: map[string]*memdb.IndexSchema{
|
||||||
|
"id": {
|
||||||
|
Name: "id",
|
||||||
|
AllowMissing: false,
|
||||||
|
Unique: true,
|
||||||
|
Indexer: &memdb.StringFieldIndex{
|
||||||
|
Field: "Node",
|
||||||
|
Lowercase: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"uuid": {
|
||||||
|
Name: "uuid",
|
||||||
|
AllowMissing: true,
|
||||||
|
Unique: true,
|
||||||
|
Indexer: &memdb.UUIDFieldIndex{
|
||||||
|
Field: "ID",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"meta": {
|
||||||
|
Name: "meta",
|
||||||
|
AllowMissing: true,
|
||||||
|
Unique: false,
|
||||||
|
Indexer: &memdb.StringMapFieldIndex{
|
||||||
|
Field: "Meta",
|
||||||
|
Lowercase: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// servicesTableSchema returns a new table schema used to store information
|
||||||
|
// about services.
|
||||||
|
func servicesTableSchema() *memdb.TableSchema {
|
||||||
|
return &memdb.TableSchema{
|
||||||
|
Name: tableServices,
|
||||||
|
Indexes: map[string]*memdb.IndexSchema{
|
||||||
|
indexID: {
|
||||||
|
Name: indexID,
|
||||||
|
AllowMissing: false,
|
||||||
|
Unique: true,
|
||||||
|
Indexer: &memdb.CompoundIndex{
|
||||||
|
Indexes: []memdb.Indexer{
|
||||||
|
&memdb.StringFieldIndex{
|
||||||
|
Field: "Node",
|
||||||
|
Lowercase: true,
|
||||||
|
},
|
||||||
|
&memdb.StringFieldIndex{
|
||||||
|
Field: "ServiceID",
|
||||||
|
Lowercase: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"node": {
|
||||||
|
Name: "node",
|
||||||
|
AllowMissing: false,
|
||||||
|
Unique: false,
|
||||||
|
Indexer: &memdb.StringFieldIndex{
|
||||||
|
Field: "Node",
|
||||||
|
Lowercase: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
indexServiceName: {
|
||||||
|
Name: indexServiceName,
|
||||||
|
AllowMissing: true,
|
||||||
|
Unique: false,
|
||||||
|
Indexer: &memdb.StringFieldIndex{
|
||||||
|
Field: "ServiceName",
|
||||||
|
Lowercase: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
indexConnect: {
|
||||||
|
Name: indexConnect,
|
||||||
|
AllowMissing: true,
|
||||||
|
Unique: false,
|
||||||
|
Indexer: &IndexConnectService{},
|
||||||
|
},
|
||||||
|
indexKind: {
|
||||||
|
Name: indexKind,
|
||||||
|
AllowMissing: false,
|
||||||
|
Unique: false,
|
||||||
|
Indexer: &IndexServiceKind{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// checksTableSchema returns a new table schema used for storing and indexing
|
||||||
|
// health check information. Health checks have a number of different attributes
|
||||||
|
// we want to filter by, so this table is a bit more complex.
|
||||||
|
func checksTableSchema() *memdb.TableSchema {
|
||||||
|
return &memdb.TableSchema{
|
||||||
|
Name: tableChecks,
|
||||||
|
Indexes: map[string]*memdb.IndexSchema{
|
||||||
|
indexID: {
|
||||||
|
Name: indexID,
|
||||||
|
AllowMissing: false,
|
||||||
|
Unique: true,
|
||||||
|
Indexer: &memdb.CompoundIndex{
|
||||||
|
Indexes: []memdb.Indexer{
|
||||||
|
&memdb.StringFieldIndex{
|
||||||
|
Field: "Node",
|
||||||
|
Lowercase: true,
|
||||||
|
},
|
||||||
|
&memdb.StringFieldIndex{
|
||||||
|
Field: "CheckID",
|
||||||
|
Lowercase: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
indexStatus: {
|
||||||
|
Name: indexStatus,
|
||||||
|
AllowMissing: false,
|
||||||
|
Unique: false,
|
||||||
|
Indexer: &memdb.StringFieldIndex{
|
||||||
|
Field: "Status",
|
||||||
|
Lowercase: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
indexServiceName: {
|
||||||
|
Name: indexServiceName,
|
||||||
|
AllowMissing: true,
|
||||||
|
Unique: false,
|
||||||
|
Indexer: &memdb.StringFieldIndex{
|
||||||
|
Field: "ServiceName",
|
||||||
|
Lowercase: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"node": {
|
||||||
|
Name: "node",
|
||||||
|
AllowMissing: true,
|
||||||
|
Unique: false,
|
||||||
|
Indexer: &memdb.StringFieldIndex{
|
||||||
|
Field: "Node",
|
||||||
|
Lowercase: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
indexNodeServiceCheck: {
|
||||||
|
Name: indexNodeServiceCheck,
|
||||||
|
AllowMissing: true,
|
||||||
|
Unique: false,
|
||||||
|
Indexer: &memdb.CompoundIndex{
|
||||||
|
Indexes: []memdb.Indexer{
|
||||||
|
&memdb.StringFieldIndex{
|
||||||
|
Field: "Node",
|
||||||
|
Lowercase: true,
|
||||||
|
},
|
||||||
|
&memdb.FieldSetIndex{
|
||||||
|
Field: "ServiceID",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
indexNodeService: {
|
||||||
|
Name: indexNodeService,
|
||||||
|
AllowMissing: true,
|
||||||
|
Unique: false,
|
||||||
|
Indexer: &memdb.CompoundIndex{
|
||||||
|
Indexes: []memdb.Indexer{
|
||||||
|
&memdb.StringFieldIndex{
|
||||||
|
Field: "Node",
|
||||||
|
Lowercase: true,
|
||||||
|
},
|
||||||
|
&memdb.StringFieldIndex{
|
||||||
|
Field: "ServiceID",
|
||||||
|
Lowercase: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// gatewayServicesTableNameSchema returns a new table schema used to store information
|
||||||
|
// about services associated with terminating gateways.
|
||||||
|
func gatewayServicesTableNameSchema() *memdb.TableSchema {
|
||||||
|
return &memdb.TableSchema{
|
||||||
|
Name: gatewayServicesTableName,
|
||||||
|
Indexes: map[string]*memdb.IndexSchema{
|
||||||
|
"id": {
|
||||||
|
Name: "id",
|
||||||
|
AllowMissing: false,
|
||||||
|
Unique: true,
|
||||||
|
Indexer: &memdb.CompoundIndex{
|
||||||
|
Indexes: []memdb.Indexer{
|
||||||
|
&ServiceNameIndex{
|
||||||
|
Field: "Gateway",
|
||||||
|
},
|
||||||
|
&ServiceNameIndex{
|
||||||
|
Field: "Service",
|
||||||
|
},
|
||||||
|
&memdb.IntFieldIndex{
|
||||||
|
Field: "Port",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"gateway": {
|
||||||
|
Name: "gateway",
|
||||||
|
AllowMissing: false,
|
||||||
|
Unique: false,
|
||||||
|
Indexer: &ServiceNameIndex{
|
||||||
|
Field: "Gateway",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"service": {
|
||||||
|
Name: "service",
|
||||||
|
AllowMissing: true,
|
||||||
|
Unique: false,
|
||||||
|
Indexer: &ServiceNameIndex{
|
||||||
|
Field: "Service",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// topologyTableNameSchema returns a new table schema used to store information
|
||||||
|
// relating upstream and downstream services
|
||||||
|
func topologyTableNameSchema() *memdb.TableSchema {
|
||||||
|
return &memdb.TableSchema{
|
||||||
|
Name: topologyTableName,
|
||||||
|
Indexes: map[string]*memdb.IndexSchema{
|
||||||
|
"id": {
|
||||||
|
Name: "id",
|
||||||
|
AllowMissing: false,
|
||||||
|
Unique: true,
|
||||||
|
Indexer: &memdb.CompoundIndex{
|
||||||
|
Indexes: []memdb.Indexer{
|
||||||
|
&ServiceNameIndex{
|
||||||
|
Field: "Upstream",
|
||||||
|
},
|
||||||
|
&ServiceNameIndex{
|
||||||
|
Field: "Downstream",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"upstream": {
|
||||||
|
Name: "upstream",
|
||||||
|
AllowMissing: true,
|
||||||
|
Unique: false,
|
||||||
|
Indexer: &ServiceNameIndex{
|
||||||
|
Field: "Upstream",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"downstream": {
|
||||||
|
Name: "downstream",
|
||||||
|
AllowMissing: false,
|
||||||
|
Unique: false,
|
||||||
|
Indexer: &ServiceNameIndex{
|
||||||
|
Field: "Downstream",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceNameIndex struct {
|
||||||
|
Field string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (index *ServiceNameIndex) FromObject(obj interface{}) (bool, []byte, error) {
|
||||||
|
v := reflect.ValueOf(obj)
|
||||||
|
v = reflect.Indirect(v) // Dereference the pointer if any
|
||||||
|
|
||||||
|
fv := v.FieldByName(index.Field)
|
||||||
|
isPtr := fv.Kind() == reflect.Ptr
|
||||||
|
fv = reflect.Indirect(fv)
|
||||||
|
if !isPtr && !fv.IsValid() || !fv.CanInterface() {
|
||||||
|
return false, nil,
|
||||||
|
fmt.Errorf("field '%s' for %#v is invalid %v ", index.Field, obj, isPtr)
|
||||||
|
}
|
||||||
|
|
||||||
|
name, ok := fv.Interface().(structs.ServiceName)
|
||||||
|
if !ok {
|
||||||
|
return false, nil, fmt.Errorf("Field 'ServiceName' is not of type structs.ServiceName")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enforce lowercase and add null character as terminator
|
||||||
|
id := strings.ToLower(name.String()) + "\x00"
|
||||||
|
|
||||||
|
return true, []byte(id), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (index *ServiceNameIndex) FromArgs(args ...interface{}) ([]byte, error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
return nil, fmt.Errorf("must provide only a single argument")
|
||||||
|
}
|
||||||
|
name, ok := args[0].(structs.ServiceName)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("argument must be of type structs.ServiceName: %#v", args[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enforce lowercase and add null character as terminator
|
||||||
|
id := strings.ToLower(name.String()) + "\x00"
|
||||||
|
|
||||||
|
return []byte(strings.ToLower(id)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (index *ServiceNameIndex) PrefixFromArgs(args ...interface{}) ([]byte, error) {
|
||||||
|
val, err := index.FromArgs(args...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strip the null terminator, the rest is a prefix
|
||||||
|
n := len(val)
|
||||||
|
if n > 0 {
|
||||||
|
return val[:n-1], nil
|
||||||
|
}
|
||||||
|
return val, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
registerSchema(nodesTableSchema)
|
||||||
|
registerSchema(servicesTableSchema)
|
||||||
|
registerSchema(checksTableSchema)
|
||||||
|
registerSchema(gatewayServicesTableNameSchema)
|
||||||
|
registerSchema(topologyTableNameSchema)
|
||||||
|
}
|
@ -35,6 +35,7 @@ func stateStoreSchema() *memdb.DBSchema {
|
|||||||
}
|
}
|
||||||
db.Tables[schema.Name] = schema
|
db.Tables[schema.Name] = schema
|
||||||
}
|
}
|
||||||
|
withEnterpriseSchema(db)
|
||||||
return db
|
return db
|
||||||
}
|
}
|
||||||
|
|
||||||
|
5
agent/consul/state/schema_oss_test.go
Normal file
5
agent/consul/state/schema_oss_test.go
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
// +build !consulent
|
||||||
|
|
||||||
|
package state
|
||||||
|
|
||||||
|
var stateStoreSchemaExpected = "TestStateStoreSchema.golden"
|
@ -1,17 +1,100 @@
|
|||||||
package state
|
package state
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"runtime"
|
||||||
|
"sort"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/hashicorp/go-memdb"
|
"github.com/hashicorp/go-memdb"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/hashicorp/consul/internal/testing/golden"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestStateStore_Schema(t *testing.T) {
|
func TestStateStoreSchema(t *testing.T) {
|
||||||
// First call the schema creation
|
|
||||||
schema := stateStoreSchema()
|
schema := stateStoreSchema()
|
||||||
|
require.NoError(t, schema.Validate())
|
||||||
|
|
||||||
// Try to initialize a new memdb using the schema
|
_, err := memdb.NewMemDB(schema)
|
||||||
if _, err := memdb.NewMemDB(schema); err != nil {
|
require.NoError(t, err)
|
||||||
t.Fatalf("err: %s", err)
|
|
||||||
|
actual, err := repr(schema)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
expected := golden.Get(t, actual, stateStoreSchemaExpected)
|
||||||
|
require.Equal(t, expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
func repr(schema *memdb.DBSchema) (string, error) {
|
||||||
|
tables := make([]string, 0, len(schema.Tables))
|
||||||
|
for name := range schema.Tables {
|
||||||
|
tables = append(tables, name)
|
||||||
|
}
|
||||||
|
sort.Strings(tables)
|
||||||
|
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
for _, name := range tables {
|
||||||
|
fmt.Fprintf(buf, "table=%v\n", name)
|
||||||
|
|
||||||
|
indexes := indexNames(schema.Tables[name])
|
||||||
|
for _, i := range indexes {
|
||||||
|
index := schema.Tables[name].Indexes[i]
|
||||||
|
fmt.Fprintf(buf, " index=%v", i)
|
||||||
|
if index.Unique {
|
||||||
|
buf.WriteString(" unique")
|
||||||
|
}
|
||||||
|
if index.AllowMissing {
|
||||||
|
buf.WriteString(" allow-missing")
|
||||||
|
}
|
||||||
|
buf.WriteString("\n")
|
||||||
|
buf.WriteString(" indexer=")
|
||||||
|
formatIndexer(buf, index.Indexer)
|
||||||
|
buf.WriteString("\n")
|
||||||
|
}
|
||||||
|
buf.WriteString("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func formatIndexer(buf *bytes.Buffer, indexer memdb.Indexer) {
|
||||||
|
v := reflect.Indirect(reflect.ValueOf(indexer))
|
||||||
|
typ := v.Type()
|
||||||
|
buf.WriteString(typ.PkgPath() + "." + typ.Name())
|
||||||
|
for i := 0; i < typ.NumField(); i++ {
|
||||||
|
fmt.Fprintf(buf, " %v=", typ.Field(i).Name)
|
||||||
|
|
||||||
|
field := v.Field(i)
|
||||||
|
switch typ.Field(i).Type.Kind() {
|
||||||
|
case reflect.Slice:
|
||||||
|
buf.WriteString("[")
|
||||||
|
for j := 0; j < field.Len(); j++ {
|
||||||
|
if j != 0 {
|
||||||
|
buf.WriteString(", ")
|
||||||
|
}
|
||||||
|
// TODO: handle other types of slices
|
||||||
|
formatIndexer(buf, v.Field(i).Index(j).Interface().(memdb.Indexer))
|
||||||
|
}
|
||||||
|
buf.WriteString("]")
|
||||||
|
case reflect.Func:
|
||||||
|
// Functions are printed as pointer addresses, which change frequently.
|
||||||
|
// Instead use the name.
|
||||||
|
buf.WriteString(runtime.FuncForPC(field.Pointer()).Name())
|
||||||
|
default:
|
||||||
|
fmt.Fprintf(buf, "%v", field)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func indexNames(table *memdb.TableSchema) []string {
|
||||||
|
indexes := make([]string, 0, len(table.Indexes))
|
||||||
|
for name := range table.Indexes {
|
||||||
|
indexes = append(indexes, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Strings(indexes)
|
||||||
|
return indexes
|
||||||
|
}
|
||||||
|
188
agent/consul/state/testdata/TestStateStoreSchema.golden
vendored
Normal file
188
agent/consul/state/testdata/TestStateStoreSchema.golden
vendored
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
table=acl-auth-methods
|
||||||
|
index=id unique
|
||||||
|
indexer=github.com/hashicorp/go-memdb.StringFieldIndex Field=Name Lowercase=true
|
||||||
|
|
||||||
|
table=acl-binding-rules
|
||||||
|
index=authmethod
|
||||||
|
indexer=github.com/hashicorp/go-memdb.StringFieldIndex Field=AuthMethod Lowercase=true
|
||||||
|
index=id unique
|
||||||
|
indexer=github.com/hashicorp/go-memdb.UUIDFieldIndex Field=ID
|
||||||
|
|
||||||
|
table=acl-policies
|
||||||
|
index=id unique
|
||||||
|
indexer=github.com/hashicorp/go-memdb.UUIDFieldIndex Field=ID
|
||||||
|
index=name unique
|
||||||
|
indexer=github.com/hashicorp/go-memdb.StringFieldIndex Field=Name Lowercase=true
|
||||||
|
|
||||||
|
table=acl-roles
|
||||||
|
index=id unique
|
||||||
|
indexer=github.com/hashicorp/go-memdb.UUIDFieldIndex Field=ID
|
||||||
|
index=name unique
|
||||||
|
indexer=github.com/hashicorp/go-memdb.StringFieldIndex Field=Name Lowercase=true
|
||||||
|
index=policies allow-missing
|
||||||
|
indexer=github.com/hashicorp/consul/agent/consul/state.RolePoliciesIndex
|
||||||
|
|
||||||
|
table=acl-tokens
|
||||||
|
index=accessor unique allow-missing
|
||||||
|
indexer=github.com/hashicorp/go-memdb.UUIDFieldIndex Field=AccessorID
|
||||||
|
index=authmethod allow-missing
|
||||||
|
indexer=github.com/hashicorp/go-memdb.StringFieldIndex Field=AuthMethod Lowercase=false
|
||||||
|
index=expires-global allow-missing
|
||||||
|
indexer=github.com/hashicorp/consul/agent/consul/state.TokenExpirationIndex LocalFilter=false
|
||||||
|
index=expires-local allow-missing
|
||||||
|
indexer=github.com/hashicorp/consul/agent/consul/state.TokenExpirationIndex LocalFilter=true
|
||||||
|
index=id unique
|
||||||
|
indexer=github.com/hashicorp/go-memdb.StringFieldIndex Field=SecretID Lowercase=false
|
||||||
|
index=local
|
||||||
|
indexer=github.com/hashicorp/go-memdb.ConditionalIndex Conditional=github.com/hashicorp/consul/agent/consul/state.tokensTableSchema.func1
|
||||||
|
index=needs-upgrade
|
||||||
|
indexer=github.com/hashicorp/go-memdb.ConditionalIndex Conditional=github.com/hashicorp/consul/agent/consul/state.tokensTableSchema.func2
|
||||||
|
index=policies allow-missing
|
||||||
|
indexer=github.com/hashicorp/consul/agent/consul/state.TokenPoliciesIndex
|
||||||
|
index=roles allow-missing
|
||||||
|
indexer=github.com/hashicorp/consul/agent/consul/state.TokenRolesIndex
|
||||||
|
|
||||||
|
table=autopilot-config
|
||||||
|
index=id unique allow-missing
|
||||||
|
indexer=github.com/hashicorp/go-memdb.ConditionalIndex Conditional=github.com/hashicorp/consul/agent/consul/state.autopilotConfigTableSchema.func1
|
||||||
|
|
||||||
|
table=checks
|
||||||
|
index=id unique
|
||||||
|
indexer=github.com/hashicorp/go-memdb.CompoundIndex Indexes=[github.com/hashicorp/go-memdb.StringFieldIndex Field=Node Lowercase=true, github.com/hashicorp/go-memdb.StringFieldIndex Field=CheckID Lowercase=true] AllowMissing=false
|
||||||
|
index=node allow-missing
|
||||||
|
indexer=github.com/hashicorp/go-memdb.StringFieldIndex Field=Node Lowercase=true
|
||||||
|
index=node_service allow-missing
|
||||||
|
indexer=github.com/hashicorp/go-memdb.CompoundIndex Indexes=[github.com/hashicorp/go-memdb.StringFieldIndex Field=Node Lowercase=true, github.com/hashicorp/go-memdb.StringFieldIndex Field=ServiceID Lowercase=true] AllowMissing=false
|
||||||
|
index=node_service_check allow-missing
|
||||||
|
indexer=github.com/hashicorp/go-memdb.CompoundIndex Indexes=[github.com/hashicorp/go-memdb.StringFieldIndex Field=Node Lowercase=true, github.com/hashicorp/go-memdb.FieldSetIndex Field=ServiceID] AllowMissing=false
|
||||||
|
index=service allow-missing
|
||||||
|
indexer=github.com/hashicorp/go-memdb.StringFieldIndex Field=ServiceName Lowercase=true
|
||||||
|
index=status
|
||||||
|
indexer=github.com/hashicorp/go-memdb.StringFieldIndex Field=Status Lowercase=false
|
||||||
|
|
||||||
|
table=config-entries
|
||||||
|
index=id unique
|
||||||
|
indexer=github.com/hashicorp/go-memdb.CompoundIndex Indexes=[github.com/hashicorp/go-memdb.StringFieldIndex Field=Kind Lowercase=true, github.com/hashicorp/go-memdb.StringFieldIndex Field=Name Lowercase=true] AllowMissing=false
|
||||||
|
index=intention-legacy-id unique allow-missing
|
||||||
|
indexer=github.com/hashicorp/consul/agent/consul/state.ServiceIntentionLegacyIDIndex uuidFieldIndex={}
|
||||||
|
index=intention-source allow-missing
|
||||||
|
indexer=github.com/hashicorp/consul/agent/consul/state.ServiceIntentionSourceIndex
|
||||||
|
index=kind
|
||||||
|
indexer=github.com/hashicorp/go-memdb.StringFieldIndex Field=Kind Lowercase=true
|
||||||
|
index=link allow-missing
|
||||||
|
indexer=github.com/hashicorp/consul/agent/consul/state.ConfigEntryLinkIndex
|
||||||
|
|
||||||
|
table=connect-ca-builtin
|
||||||
|
index=id unique
|
||||||
|
indexer=github.com/hashicorp/go-memdb.StringFieldIndex Field=ID Lowercase=false
|
||||||
|
|
||||||
|
table=connect-ca-config
|
||||||
|
index=id unique allow-missing
|
||||||
|
indexer=github.com/hashicorp/go-memdb.ConditionalIndex Conditional=github.com/hashicorp/consul/agent/consul/state.caConfigTableSchema.func1
|
||||||
|
|
||||||
|
table=connect-ca-roots
|
||||||
|
index=id unique
|
||||||
|
indexer=github.com/hashicorp/go-memdb.StringFieldIndex Field=ID Lowercase=false
|
||||||
|
|
||||||
|
table=connect-intentions
|
||||||
|
index=destination allow-missing
|
||||||
|
indexer=github.com/hashicorp/go-memdb.CompoundIndex Indexes=[github.com/hashicorp/go-memdb.StringFieldIndex Field=DestinationNS Lowercase=true, github.com/hashicorp/go-memdb.StringFieldIndex Field=DestinationName Lowercase=true] AllowMissing=false
|
||||||
|
index=id unique
|
||||||
|
indexer=github.com/hashicorp/go-memdb.UUIDFieldIndex Field=ID
|
||||||
|
index=source allow-missing
|
||||||
|
indexer=github.com/hashicorp/go-memdb.CompoundIndex Indexes=[github.com/hashicorp/go-memdb.StringFieldIndex Field=SourceNS Lowercase=true, github.com/hashicorp/go-memdb.StringFieldIndex Field=SourceName Lowercase=true] AllowMissing=false
|
||||||
|
index=source_destination unique allow-missing
|
||||||
|
indexer=github.com/hashicorp/go-memdb.CompoundIndex Indexes=[github.com/hashicorp/go-memdb.StringFieldIndex Field=SourceNS Lowercase=true, github.com/hashicorp/go-memdb.StringFieldIndex Field=SourceName Lowercase=true, github.com/hashicorp/go-memdb.StringFieldIndex Field=DestinationNS Lowercase=true, github.com/hashicorp/go-memdb.StringFieldIndex Field=DestinationName Lowercase=true] AllowMissing=false
|
||||||
|
|
||||||
|
table=coordinates
|
||||||
|
index=id unique
|
||||||
|
indexer=github.com/hashicorp/go-memdb.CompoundIndex Indexes=[github.com/hashicorp/go-memdb.StringFieldIndex Field=Node Lowercase=true, github.com/hashicorp/go-memdb.StringFieldIndex Field=Segment Lowercase=true] AllowMissing=true
|
||||||
|
index=node
|
||||||
|
indexer=github.com/hashicorp/go-memdb.StringFieldIndex Field=Node Lowercase=true
|
||||||
|
|
||||||
|
table=federation-states
|
||||||
|
index=id unique
|
||||||
|
indexer=github.com/hashicorp/go-memdb.StringFieldIndex Field=Datacenter Lowercase=true
|
||||||
|
|
||||||
|
table=gateway-services
|
||||||
|
index=gateway
|
||||||
|
indexer=github.com/hashicorp/consul/agent/consul/state.ServiceNameIndex Field=Gateway
|
||||||
|
index=id unique
|
||||||
|
indexer=github.com/hashicorp/go-memdb.CompoundIndex Indexes=[github.com/hashicorp/consul/agent/consul/state.ServiceNameIndex Field=Gateway, github.com/hashicorp/consul/agent/consul/state.ServiceNameIndex Field=Service, github.com/hashicorp/go-memdb.IntFieldIndex Field=Port] AllowMissing=false
|
||||||
|
index=service allow-missing
|
||||||
|
indexer=github.com/hashicorp/consul/agent/consul/state.ServiceNameIndex Field=Service
|
||||||
|
|
||||||
|
table=index
|
||||||
|
index=id unique
|
||||||
|
indexer=github.com/hashicorp/go-memdb.StringFieldIndex Field=Key Lowercase=true
|
||||||
|
|
||||||
|
table=kvs
|
||||||
|
index=id unique
|
||||||
|
indexer=github.com/hashicorp/go-memdb.StringFieldIndex Field=Key Lowercase=false
|
||||||
|
index=session allow-missing
|
||||||
|
indexer=github.com/hashicorp/go-memdb.UUIDFieldIndex Field=Session
|
||||||
|
|
||||||
|
table=mesh-topology
|
||||||
|
index=downstream
|
||||||
|
indexer=github.com/hashicorp/consul/agent/consul/state.ServiceNameIndex Field=Downstream
|
||||||
|
index=id unique
|
||||||
|
indexer=github.com/hashicorp/go-memdb.CompoundIndex Indexes=[github.com/hashicorp/consul/agent/consul/state.ServiceNameIndex Field=Upstream, github.com/hashicorp/consul/agent/consul/state.ServiceNameIndex Field=Downstream] AllowMissing=false
|
||||||
|
index=upstream allow-missing
|
||||||
|
indexer=github.com/hashicorp/consul/agent/consul/state.ServiceNameIndex Field=Upstream
|
||||||
|
|
||||||
|
table=nodes
|
||||||
|
index=id unique
|
||||||
|
indexer=github.com/hashicorp/go-memdb.StringFieldIndex Field=Node Lowercase=true
|
||||||
|
index=meta allow-missing
|
||||||
|
indexer=github.com/hashicorp/go-memdb.StringMapFieldIndex Field=Meta Lowercase=false
|
||||||
|
index=uuid unique allow-missing
|
||||||
|
indexer=github.com/hashicorp/go-memdb.UUIDFieldIndex Field=ID
|
||||||
|
|
||||||
|
table=prepared-queries
|
||||||
|
index=id unique
|
||||||
|
indexer=github.com/hashicorp/go-memdb.UUIDFieldIndex Field=ID
|
||||||
|
index=name unique allow-missing
|
||||||
|
indexer=github.com/hashicorp/go-memdb.StringFieldIndex Field=Name Lowercase=true
|
||||||
|
index=session allow-missing
|
||||||
|
indexer=github.com/hashicorp/go-memdb.UUIDFieldIndex Field=Session
|
||||||
|
index=template unique allow-missing
|
||||||
|
indexer=github.com/hashicorp/consul/agent/consul/state.PreparedQueryIndex
|
||||||
|
|
||||||
|
table=services
|
||||||
|
index=connect allow-missing
|
||||||
|
indexer=github.com/hashicorp/consul/agent/consul/state.IndexConnectService
|
||||||
|
index=id unique
|
||||||
|
indexer=github.com/hashicorp/go-memdb.CompoundIndex Indexes=[github.com/hashicorp/go-memdb.StringFieldIndex Field=Node Lowercase=true, github.com/hashicorp/go-memdb.StringFieldIndex Field=ServiceID Lowercase=true] AllowMissing=false
|
||||||
|
index=kind
|
||||||
|
indexer=github.com/hashicorp/consul/agent/consul/state.IndexServiceKind
|
||||||
|
index=node
|
||||||
|
indexer=github.com/hashicorp/go-memdb.StringFieldIndex Field=Node Lowercase=true
|
||||||
|
index=service allow-missing
|
||||||
|
indexer=github.com/hashicorp/go-memdb.StringFieldIndex Field=ServiceName Lowercase=true
|
||||||
|
|
||||||
|
table=session_checks
|
||||||
|
index=id unique
|
||||||
|
indexer=github.com/hashicorp/go-memdb.CompoundIndex Indexes=[github.com/hashicorp/go-memdb.StringFieldIndex Field=Node Lowercase=true, github.com/hashicorp/consul/agent/consul/state.CheckIDIndex, github.com/hashicorp/go-memdb.UUIDFieldIndex Field=Session] AllowMissing=false
|
||||||
|
index=node_check
|
||||||
|
indexer=github.com/hashicorp/go-memdb.CompoundIndex Indexes=[github.com/hashicorp/go-memdb.StringFieldIndex Field=Node Lowercase=true, github.com/hashicorp/consul/agent/consul/state.CheckIDIndex] AllowMissing=false
|
||||||
|
index=session
|
||||||
|
indexer=github.com/hashicorp/go-memdb.UUIDFieldIndex Field=Session
|
||||||
|
|
||||||
|
table=sessions
|
||||||
|
index=id unique
|
||||||
|
indexer=github.com/hashicorp/go-memdb.UUIDFieldIndex Field=ID
|
||||||
|
index=node
|
||||||
|
indexer=github.com/hashicorp/go-memdb.StringFieldIndex Field=Node Lowercase=true
|
||||||
|
|
||||||
|
table=system-metadata
|
||||||
|
index=id unique
|
||||||
|
indexer=github.com/hashicorp/go-memdb.StringFieldIndex Field=Key Lowercase=true
|
||||||
|
|
||||||
|
table=tombstones
|
||||||
|
index=id unique
|
||||||
|
indexer=github.com/hashicorp/go-memdb.StringFieldIndex Field=Key Lowercase=false
|
||||||
|
|
||||||
|
table=usage
|
||||||
|
index=id unique
|
||||||
|
indexer=github.com/hashicorp/go-memdb.StringFieldIndex Field=ID Lowercase=true
|
||||||
|
|
36
internal/testing/golden/golden.go
Normal file
36
internal/testing/golden/golden.go
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package golden
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
// update allows golden files to be updated based on the current output.
|
||||||
|
var update = flag.Bool("update", false, "update golden files")
|
||||||
|
|
||||||
|
// Get reads the expected value from the file at filename and returns the value.
|
||||||
|
// filename is relative to the ./testdata directory.
|
||||||
|
//
|
||||||
|
// If the `-update` flag is used with `go test`, the golden file will be updated
|
||||||
|
// to the value of actual.
|
||||||
|
func Get(t *testing.T, actual, filename string) string {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
path := filepath.Join("testdata", filename)
|
||||||
|
if *update {
|
||||||
|
if dir := filepath.Dir(path); dir != "." {
|
||||||
|
require.NoError(t, os.MkdirAll(dir, 0755))
|
||||||
|
}
|
||||||
|
err := ioutil.WriteFile(path, []byte(actual), 0644)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected, err := ioutil.ReadFile(path)
|
||||||
|
require.NoError(t, err)
|
||||||
|
return string(expected)
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user