464 lines
11 KiB
Go
464 lines
11 KiB
Go
package state
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/hashicorp/go-memdb"
|
|
)
|
|
|
|
// schemaFn is an interface function used to create and return
|
|
// new memdb schema structs for constructing an in-memory db.
|
|
type schemaFn func() *memdb.TableSchema
|
|
|
|
// stateStoreSchema is used to return the combined schema for
|
|
// the state store.
|
|
func stateStoreSchema() *memdb.DBSchema {
|
|
// Create the root DB schema
|
|
db := &memdb.DBSchema{
|
|
Tables: make(map[string]*memdb.TableSchema),
|
|
}
|
|
|
|
// Collect the needed schemas
|
|
schemas := []schemaFn{
|
|
indexTableSchema,
|
|
nodesTableSchema,
|
|
servicesTableSchema,
|
|
checksTableSchema,
|
|
kvsTableSchema,
|
|
tombstonesTableSchema,
|
|
sessionsTableSchema,
|
|
sessionChecksTableSchema,
|
|
aclsTableSchema,
|
|
aclsBootstrapTableSchema,
|
|
coordinatesTableSchema,
|
|
preparedQueriesTableSchema,
|
|
autopilotConfigTableSchema,
|
|
}
|
|
|
|
// Add the tables to the root schema
|
|
for _, fn := range schemas {
|
|
schema := fn()
|
|
if _, ok := db.Tables[schema.Name]; ok {
|
|
panic(fmt.Sprintf("duplicate table name: %s", schema.Name))
|
|
}
|
|
db.Tables[schema.Name] = schema
|
|
}
|
|
return db
|
|
}
|
|
|
|
// indexTableSchema returns a new table schema used for
|
|
// tracking various indexes for the Raft log.
|
|
func indexTableSchema() *memdb.TableSchema {
|
|
return &memdb.TableSchema{
|
|
Name: "index",
|
|
Indexes: map[string]*memdb.IndexSchema{
|
|
"id": &memdb.IndexSchema{
|
|
Name: "id",
|
|
AllowMissing: false,
|
|
Unique: true,
|
|
Indexer: &memdb.StringFieldIndex{
|
|
Field: "Key",
|
|
Lowercase: true,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
// 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": &memdb.IndexSchema{
|
|
Name: "id",
|
|
AllowMissing: false,
|
|
Unique: true,
|
|
Indexer: &memdb.StringFieldIndex{
|
|
Field: "Node",
|
|
Lowercase: true,
|
|
},
|
|
},
|
|
"uuid": &memdb.IndexSchema{
|
|
Name: "uuid",
|
|
AllowMissing: true,
|
|
Unique: true,
|
|
Indexer: &memdb.UUIDFieldIndex{
|
|
Field: "ID",
|
|
},
|
|
},
|
|
"meta": &memdb.IndexSchema{
|
|
Name: "meta",
|
|
AllowMissing: true,
|
|
Unique: false,
|
|
Indexer: &memdb.StringMapFieldIndex{
|
|
Field: "Meta",
|
|
Lowercase: false,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
// servicesTableSchema returns a new TableSchema used to
|
|
// store information about services.
|
|
func servicesTableSchema() *memdb.TableSchema {
|
|
return &memdb.TableSchema{
|
|
Name: "services",
|
|
Indexes: map[string]*memdb.IndexSchema{
|
|
"id": &memdb.IndexSchema{
|
|
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": &memdb.IndexSchema{
|
|
Name: "node",
|
|
AllowMissing: false,
|
|
Unique: false,
|
|
Indexer: &memdb.StringFieldIndex{
|
|
Field: "Node",
|
|
Lowercase: true,
|
|
},
|
|
},
|
|
"service": &memdb.IndexSchema{
|
|
Name: "service",
|
|
AllowMissing: true,
|
|
Unique: false,
|
|
Indexer: &memdb.StringFieldIndex{
|
|
Field: "ServiceName",
|
|
Lowercase: true,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
// 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": &memdb.IndexSchema{
|
|
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": &memdb.IndexSchema{
|
|
Name: "status",
|
|
AllowMissing: false,
|
|
Unique: false,
|
|
Indexer: &memdb.StringFieldIndex{
|
|
Field: "Status",
|
|
Lowercase: false,
|
|
},
|
|
},
|
|
"service": &memdb.IndexSchema{
|
|
Name: "service",
|
|
AllowMissing: true,
|
|
Unique: false,
|
|
Indexer: &memdb.StringFieldIndex{
|
|
Field: "ServiceName",
|
|
Lowercase: true,
|
|
},
|
|
},
|
|
"node": &memdb.IndexSchema{
|
|
Name: "node",
|
|
AllowMissing: true,
|
|
Unique: false,
|
|
Indexer: &memdb.StringFieldIndex{
|
|
Field: "Node",
|
|
Lowercase: true,
|
|
},
|
|
},
|
|
"node_service_check": &memdb.IndexSchema{
|
|
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": &memdb.IndexSchema{
|
|
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,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
// kvsTableSchema returns a new table schema used for storing
|
|
// key/value data from consul's kv store.
|
|
func kvsTableSchema() *memdb.TableSchema {
|
|
return &memdb.TableSchema{
|
|
Name: "kvs",
|
|
Indexes: map[string]*memdb.IndexSchema{
|
|
"id": &memdb.IndexSchema{
|
|
Name: "id",
|
|
AllowMissing: false,
|
|
Unique: true,
|
|
Indexer: &memdb.StringFieldIndex{
|
|
Field: "Key",
|
|
Lowercase: false,
|
|
},
|
|
},
|
|
"session": &memdb.IndexSchema{
|
|
Name: "session",
|
|
AllowMissing: true,
|
|
Unique: false,
|
|
Indexer: &memdb.UUIDFieldIndex{
|
|
Field: "Session",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
// tombstonesTableSchema returns a new table schema used for
|
|
// storing tombstones during KV delete operations to prevent
|
|
// the index from sliding backwards.
|
|
func tombstonesTableSchema() *memdb.TableSchema {
|
|
return &memdb.TableSchema{
|
|
Name: "tombstones",
|
|
Indexes: map[string]*memdb.IndexSchema{
|
|
"id": &memdb.IndexSchema{
|
|
Name: "id",
|
|
AllowMissing: false,
|
|
Unique: true,
|
|
Indexer: &memdb.StringFieldIndex{
|
|
Field: "Key",
|
|
Lowercase: false,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
// sessionsTableSchema returns a new TableSchema used for
|
|
// storing session information.
|
|
func sessionsTableSchema() *memdb.TableSchema {
|
|
return &memdb.TableSchema{
|
|
Name: "sessions",
|
|
Indexes: map[string]*memdb.IndexSchema{
|
|
"id": &memdb.IndexSchema{
|
|
Name: "id",
|
|
AllowMissing: false,
|
|
Unique: true,
|
|
Indexer: &memdb.UUIDFieldIndex{
|
|
Field: "ID",
|
|
},
|
|
},
|
|
"node": &memdb.IndexSchema{
|
|
Name: "node",
|
|
AllowMissing: false,
|
|
Unique: false,
|
|
Indexer: &memdb.StringFieldIndex{
|
|
Field: "Node",
|
|
Lowercase: true,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
// sessionChecksTableSchema returns a new table schema used
|
|
// for storing session checks.
|
|
func sessionChecksTableSchema() *memdb.TableSchema {
|
|
return &memdb.TableSchema{
|
|
Name: "session_checks",
|
|
Indexes: map[string]*memdb.IndexSchema{
|
|
"id": &memdb.IndexSchema{
|
|
Name: "id",
|
|
AllowMissing: false,
|
|
Unique: true,
|
|
Indexer: &memdb.CompoundIndex{
|
|
Indexes: []memdb.Indexer{
|
|
&memdb.StringFieldIndex{
|
|
Field: "Node",
|
|
Lowercase: true,
|
|
},
|
|
&memdb.StringFieldIndex{
|
|
Field: "CheckID",
|
|
Lowercase: true,
|
|
},
|
|
&memdb.UUIDFieldIndex{
|
|
Field: "Session",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
"node_check": &memdb.IndexSchema{
|
|
Name: "node_check",
|
|
AllowMissing: false,
|
|
Unique: false,
|
|
Indexer: &memdb.CompoundIndex{
|
|
Indexes: []memdb.Indexer{
|
|
&memdb.StringFieldIndex{
|
|
Field: "Node",
|
|
Lowercase: true,
|
|
},
|
|
&memdb.StringFieldIndex{
|
|
Field: "CheckID",
|
|
Lowercase: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
"session": &memdb.IndexSchema{
|
|
Name: "session",
|
|
AllowMissing: false,
|
|
Unique: false,
|
|
Indexer: &memdb.UUIDFieldIndex{
|
|
Field: "Session",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
// coordinatesTableSchema returns a new table schema used for storing
|
|
// network coordinates.
|
|
func coordinatesTableSchema() *memdb.TableSchema {
|
|
return &memdb.TableSchema{
|
|
Name: "coordinates",
|
|
Indexes: map[string]*memdb.IndexSchema{
|
|
"id": &memdb.IndexSchema{
|
|
Name: "id",
|
|
AllowMissing: false,
|
|
Unique: true,
|
|
Indexer: &memdb.CompoundIndex{
|
|
// AllowMissing is required since we allow
|
|
// Segment to be an empty string.
|
|
AllowMissing: true,
|
|
Indexes: []memdb.Indexer{
|
|
&memdb.StringFieldIndex{
|
|
Field: "Node",
|
|
Lowercase: true,
|
|
},
|
|
&memdb.StringFieldIndex{
|
|
Field: "Segment",
|
|
Lowercase: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
"node": &memdb.IndexSchema{
|
|
Name: "node",
|
|
AllowMissing: false,
|
|
Unique: false,
|
|
Indexer: &memdb.StringFieldIndex{
|
|
Field: "Node",
|
|
Lowercase: true,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
// preparedQueriesTableSchema returns a new table schema used for storing
|
|
// prepared queries.
|
|
func preparedQueriesTableSchema() *memdb.TableSchema {
|
|
return &memdb.TableSchema{
|
|
Name: "prepared-queries",
|
|
Indexes: map[string]*memdb.IndexSchema{
|
|
"id": &memdb.IndexSchema{
|
|
Name: "id",
|
|
AllowMissing: false,
|
|
Unique: true,
|
|
Indexer: &memdb.UUIDFieldIndex{
|
|
Field: "ID",
|
|
},
|
|
},
|
|
"name": &memdb.IndexSchema{
|
|
Name: "name",
|
|
AllowMissing: true,
|
|
Unique: true,
|
|
Indexer: &memdb.StringFieldIndex{
|
|
Field: "Name",
|
|
Lowercase: true,
|
|
},
|
|
},
|
|
"template": &memdb.IndexSchema{
|
|
Name: "template",
|
|
AllowMissing: true,
|
|
Unique: true,
|
|
Indexer: &PreparedQueryIndex{},
|
|
},
|
|
"session": &memdb.IndexSchema{
|
|
Name: "session",
|
|
AllowMissing: true,
|
|
Unique: false,
|
|
Indexer: &memdb.UUIDFieldIndex{
|
|
Field: "Session",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
// autopilotConfigTableSchema returns a new table schema used for storing
|
|
// the autopilot configuration
|
|
func autopilotConfigTableSchema() *memdb.TableSchema {
|
|
return &memdb.TableSchema{
|
|
Name: "autopilot-config",
|
|
Indexes: map[string]*memdb.IndexSchema{
|
|
"id": &memdb.IndexSchema{
|
|
Name: "id",
|
|
AllowMissing: true,
|
|
Unique: true,
|
|
Indexer: &memdb.ConditionalIndex{
|
|
Conditional: func(obj interface{}) (bool, error) { return true, nil },
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|