Add config types and state store table

This commit is contained in:
Kyle Havlovitz 2019-03-19 10:06:46 -07:00
parent 73f79ac599
commit 53913461db
2 changed files with 202 additions and 0 deletions

View File

@ -0,0 +1,127 @@
package state
import (
"fmt"
"github.com/hashicorp/consul/agent/structs"
memdb "github.com/hashicorp/go-memdb"
)
const (
configTableName = "configurations"
)
// configTableSchema returns a new table schema used to store global service
// and proxy configurations.
func configTableSchema() *memdb.TableSchema {
return &memdb.TableSchema{
Name: configTableName,
Indexes: map[string]*memdb.IndexSchema{
"id": &memdb.IndexSchema{
Name: "id",
AllowMissing: false,
Unique: true,
Indexer: &memdb.CompoundIndex{
Indexes: []memdb.Indexer{
&memdb.StringFieldIndex{
Field: "Kind",
Lowercase: true,
},
&memdb.StringFieldIndex{
Field: "Name",
Lowercase: true,
},
},
},
},
},
}
}
func init() {
registerSchema(configTableSchema)
}
// Configurations is used to pull all the configurations for the snapshot.
func (s *Snapshot) Configurations() ([]structs.Configuration, error) {
ixns, err := s.tx.Get(configTableName, "id")
if err != nil {
return nil, err
}
var ret []structs.Configuration
for wrapped := ixns.Next(); wrapped != nil; wrapped = ixns.Next() {
ret = append(ret, wrapped.(structs.Configuration))
}
return ret, nil
}
// Configuration is used when restoring from a snapshot.
func (s *Restore) Configuration(c structs.Configuration) error {
// Insert
if err := s.tx.Insert(configTableName, c); err != nil {
return fmt.Errorf("failed restoring configuration object: %s", err)
}
if err := indexUpdateMaxTxn(s.tx, c.ModifyIndex, configTableName); err != nil {
return fmt.Errorf("failed updating index: %s", err)
}
return nil
}
// EnsureConfiguration is called to upsert creation of a given configuration.
func (s *Store) EnsureConfiguration(idx uint64, conf structs.Configuration) error {
tx := s.db.Txn(true)
defer tx.Abort()
// Does it make sense to validate here? We do this for service meta in the state store
// but could also do this in RPC endpoint. More version compatibility that way?
if err := conf.Validate(); err != nil {
return fmt.Errorf("failed validating config: %v", err)
}
// Check for existing configuration.
existing, err := tx.First("configurations", "id", conf.GetKind(), conf.GetName())
if err != nil {
return fmt.Errorf("failed configuration lookup: %s", err)
}
if existing != nil {
conf.CreateIndex = serviceNode.CreateIndex
conf.ModifyIndex = serviceNode.ModifyIndex
} else {
conf.CreateIndex = idx
}
conf.ModifyIndex = idx
// Insert the configuration and update the index
if err := tx.Insert("configurations", conf); err != nil {
return fmt.Errorf("failed inserting service: %s", err)
}
if err := tx.Insert("index", &IndexEntry{"configurations", idx}); err != nil {
return fmt.Errorf("failed updating index: %s", err)
}
tx.Commit()
return nil
}
// Configuration is called to get a given configuration.
func (s *Store) Configuration(idx uint64, kind structs.ConfigurationKind, name string) (structs.Configuration, error) {
tx := s.db.Txn(true)
defer tx.Abort()
// Get the existing configuration.
existing, err := tx.First("configurations", "id", kind, name)
if err != nil {
return nil, fmt.Errorf("failed configuration lookup: %s", err)
}
conf, ok := existing.(structs.Configuration)
if !ok {
return nil, fmt.Errorf("configuration %q (%s) is an invalid type: %T", name, kind, conf)
}
return conf, nil
}

View File

@ -0,0 +1,75 @@
package structs
type ConfigurationKind string
const (
ServiceDefaults ConfigurationKind = "service-defaults"
ProxyDefaults ConfigurationKind = "proxy-defaults"
)
// Should this be an interface or a switch on the existing config types?
type Configuration interface {
GetKind() ConfigurationKind
GetName() string
Validate() error
}
// ServiceConfiguration is the top-level struct for the configuration of a service
// across the entire cluster.
type ServiceConfiguration struct {
Kind ConfigurationKind
Name string
Protocol string
Connect ConnectConfiguration
ServiceDefinitionDefaults ServiceDefinitionDefaults
RaftIndex
}
func (s *ServiceConfiguration) GetKind() ConfigurationKind {
return ServiceDefaults
}
type ConnectConfiguration struct {
SidecarProxy bool
}
type ServiceDefinitionDefaults struct {
EnableTagOverride bool
// Non script/docker checks only
Check *HealthCheck
Checks HealthChecks
// Kind is allowed to accommodate non-sidecar proxies but it will be an error
// if they also set Connect.DestinationServiceID since sidecars are
// configured via their associated service's config.
Kind ServiceKind
// Only DestinationServiceName and Config are supported.
Proxy ConnectProxyConfig
Connect ServiceConnect
Weights Weights
// DisableDirectDiscovery is a field that marks the service instance as
// not discoverable. This is useful in two cases:
// 1. Truly headless services like job workers that still need Connect
// sidecars to connect to upstreams.
// 2. Connect applications that expose services only through their sidecar
// and so discovery of their IP/port is meaningless since they can't be
// connected to by that means.
DisableDirectDiscovery bool
}
// ProxyConfiguration is the top-level struct for global proxy configuration defaults.
type ProxyConfiguration struct {
Kind ConfigurationKind
Name string
ProxyConfig ConnectProxyConfig
}
func (p *ProxyConfiguration) GetKind() ConfigurationKind {
return ProxyDefaults
}