Various refactoring to clean up code organization

Brought to you by: Dept of 2nd thoughts before pushing enter on `git push`
This commit is contained in:
Sean Chittenden 2016-04-23 19:53:21 -07:00
parent 53f9cea87c
commit 60006f550f
5 changed files with 169 additions and 137 deletions

View File

@ -203,9 +203,6 @@ func (c *ServerCommand) Run(args []string) int {
if envAA := os.Getenv("VAULT_ADVERTISE_ADDR"); envAA != "" {
coreConfig.AdvertiseAddr = envAA
if consulBackend, ok := (backend).(*physical.ConsulBackend); ok {
consulBackend.UpdateAdvertiseAddr(envAA)
}
}
// Attempt to detect the advertise address, if possible
@ -223,9 +220,6 @@ func (c *ServerCommand) Run(args []string) int {
c.Ui.Error("Failed to detect advertise address.")
} else {
coreConfig.AdvertiseAddr = advertise
if consulBackend, ok := (backend).(*physical.ConsulBackend); ok {
consulBackend.UpdateAdvertiseAddr(advertise)
}
}
}
@ -296,6 +290,11 @@ func (c *ServerCommand) Run(args []string) int {
if coreConfig.HAPhysical != nil {
sd, ok := coreConfig.HAPhysical.(physical.ServiceDiscovery)
if ok {
if err := sd.UpdateAdvertiseAddr(coreConfig.AdvertiseAddr); err != nil {
c.Ui.Error(fmt.Sprintf("Error configuring service discovery: %v", err))
return 1
}
if err := sd.RunServiceDiscovery(c.ShutdownCh); err != nil {
c.Ui.Error(fmt.Sprintf("Error initializing service discovery: %v", err))
return 1

View File

@ -44,21 +44,23 @@ const (
// prefix within Consul. It is used for most production situations as
// it allows Vault to run on multiple machines in a highly-available manner.
type ConsulBackend struct {
path string
client *api.Client
kv *api.KV
permitPool *PermitPool
serviceLock sync.RWMutex
service *api.AgentServiceRegistration
sealedCheck *api.AgentCheckRegistration
advertiseAddr string
consulClientConf *api.Config
serviceName string
running bool
active bool
sealed bool
checkTimeout time.Duration
checkTimer *time.Timer
path string
client *api.Client
kv *api.KV
permitPool *PermitPool
serviceLock sync.RWMutex
service *api.AgentServiceRegistration
sealedCheck *api.AgentCheckRegistration
advertiseHost string
advertisePort int
consulClientConf *api.Config
serviceName string
running bool
active bool
sealed bool
disableRegistration bool
checkTimeout time.Duration
checkTimer *time.Timer
}
// newConsulBackend constructs a Consul backend using the given API client
@ -78,6 +80,17 @@ func newConsulBackend(conf map[string]string) (Backend, error) {
path = strings.TrimPrefix(path, "/")
}
// Allow admins to disable consul integration
disableReg, ok := conf["disable_registration"]
var disableRegistration bool
if ok && disableReg != "" {
b, err := strconv.ParseBool(disableReg)
if err != nil {
return nil, errwrap.Wrapf("failed parsing disable_registration parameter: {{err}}", err)
}
disableRegistration = b
}
// Get the service name to advertise in Consul
service, ok := conf["service"]
if !ok {
@ -141,14 +154,15 @@ func newConsulBackend(conf map[string]string) (Backend, error) {
// Setup the backend
c := &ConsulBackend{
path: path,
client: client,
kv: client.KV(),
permitPool: NewPermitPool(maxParInt),
consulClientConf: consulConf,
serviceName: service,
checkTimeout: checkTimeout,
checkTimer: time.NewTimer(checkTimeout),
path: path,
client: client,
kv: client.KV(),
permitPool: NewPermitPool(maxParInt),
consulClientConf: consulConf,
serviceName: service,
checkTimeout: checkTimeout,
checkTimer: time.NewTimer(checkTimeout),
disableRegistration: disableRegistration,
}
return c, nil
}
@ -160,21 +174,13 @@ func (c *ConsulBackend) UpdateAdvertiseAddr(addr string) error {
return fmt.Errorf("service registration unable to update advertise address, backend already running")
}
url, err := url.Parse(addr)
host, port, err := parseAdvertiseAddr(addr)
if err != nil {
return errwrap.Wrapf(fmt.Sprintf(`updating advertise address failed to parse URL "%v": {{err}}`, addr), err)
return errwrap.Wrapf(fmt.Sprintf(`failed to parse advertise address "%v": {{err}}`, addr), err)
}
_, portStr, err := net.SplitHostPort(url.Host)
if err != nil {
return errwrap.Wrapf(fmt.Sprintf(`updating advertise address failed to find a host:port in advertise address "%v": {{err}}`, url.Host), err)
}
_, err = strconv.ParseInt(portStr, 10, 0)
if err != nil {
return errwrap.Wrapf(fmt.Sprintf(`updating advertise address failed to parse port "%v": {{err}}`, portStr), err)
}
c.advertiseAddr = addr
c.advertiseHost = host
c.advertisePort = int(port)
return nil
}
@ -197,10 +203,12 @@ func (c *ConsulBackend) AdvertiseActive(active bool) error {
return nil
}
c.service.Tags = serviceTags(active)
agent := c.client.Agent()
if err := agent.ServiceRegister(c.service); err != nil {
return errwrap.Wrapf("service registration failed: {{err}}", err)
if !c.disableRegistration {
c.service.Tags = serviceTags(active)
agent := c.client.Agent()
if err := agent.ServiceRegister(c.service); err != nil {
return errwrap.Wrapf("service registration failed: {{err}}", err)
}
}
// Save a cached copy of the active state: no way to query Core
@ -219,8 +227,10 @@ func (c *ConsulBackend) AdvertiseSealed(sealed bool) error {
return nil
}
// Push a TTL check immediately to update the state
c.runCheck()
if !c.disableRegistration {
// Push a TTL check immediately to update the state
c.runCheck()
}
return nil
}
@ -229,35 +239,22 @@ func (c *ConsulBackend) RunServiceDiscovery(shutdownCh ShutdownChannel) (err err
c.serviceLock.Lock()
defer c.serviceLock.Unlock()
if c.disableRegistration {
return nil
}
if c.running {
return fmt.Errorf("service registration routine already running")
}
url, err := url.Parse(c.advertiseAddr)
if err != nil {
return errwrap.Wrapf(fmt.Sprintf(`service registration failed to parse URL "%v": {{err}}`, c.advertiseAddr), err)
}
host, portStr, err := net.SplitHostPort(url.Host)
if err != nil {
return errwrap.Wrapf(fmt.Sprintf(`service registration failed to find a host:port in advertise address "%v": {{err}}`, url.Host), err)
}
port, err := strconv.ParseInt(portStr, 10, 0)
if err != nil {
return errwrap.Wrapf(fmt.Sprintf(`service registration failed to parse port "%v": {{err}}`, portStr), err)
}
serviceID, err := c.serviceID()
if err != nil {
return err
}
serviceID := c.serviceID()
c.service = &api.AgentServiceRegistration{
ID: serviceID,
Name: c.serviceName,
Tags: serviceTags(c.active),
Port: int(port),
Address: host,
Port: c.advertisePort,
Address: c.advertiseHost,
EnableTagOverride: false,
}
@ -351,22 +348,31 @@ func (c *ConsulBackend) checkID() string {
// serviceID returns the Vault ServiceID for use in Consul. Assume at least
// a read lock is held.
func (c *ConsulBackend) serviceID() (string, error) {
url, err := url.Parse(c.advertiseAddr)
if err != nil {
return "", errwrap.Wrapf(fmt.Sprintf(`service registration failed to parse URL "%v": {{err}}`, c.advertiseAddr), err)
func (c *ConsulBackend) serviceID() string {
return fmt.Sprintf("%s:%s:%d", c.serviceName, c.advertiseHost, c.advertisePort)
}
func parseAdvertiseAddr(addr string) (host string, port int, err error) {
if addr == "" {
return "", -1, fmt.Errorf("advertise address must not be empty")
}
host, portStr, err := net.SplitHostPort(url.Host)
url, err := url.Parse(addr)
if err != nil {
return "", errwrap.Wrapf(fmt.Sprintf(`service registration failed to find a host:port in advertise address "%v": {{err}}`, url.Host), err)
}
port, err := strconv.ParseInt(portStr, 10, 0)
if err != nil {
return "", errwrap.Wrapf(fmt.Sprintf(`service registration failed to parse port "%v": {{err}}`, portStr), err)
return "", -2, errwrap.Wrapf(fmt.Sprintf(`failed to parse advertise URL "%v": {{err}}`, addr), err)
}
return fmt.Sprintf("%s:%s:%d", c.serviceName, host, int(port)), nil
var portStr string
host, portStr, err = net.SplitHostPort(url.Host)
if err != nil {
return "", -3, errwrap.Wrapf(fmt.Sprintf(`failed to find a host:port in advertise address "%v": {{err}}`, url.Host), err)
}
portNum, err := strconv.ParseInt(portStr, 10, 0)
if err != nil || portNum < 1 || portNum > 65535 {
return "", -4, errwrap.Wrapf(fmt.Sprintf(`failed to parse valid port "%v": {{err}}`, portStr), err)
}
return host, int(portNum), nil
}
func setupTLSConfig(conf map[string]string) (*tls.Config, error) {

View File

@ -86,67 +86,81 @@ func testConsul_testConsulBackend(t *testing.T) {
func TestConsul_newConsulBackend(t *testing.T) {
tests := []struct {
Name string
Config map[string]string
Fail bool
checkTimeout time.Duration
path string
service string
address string
scheme string
token string
max_parallel int
name string
consulConfig map[string]string
fail bool
advertiseAddr string
checkTimeout time.Duration
path string
service string
address string
scheme string
token string
max_parallel int
disableReg bool
}{
{
Name: "Valid default config",
Config: map[string]string{},
checkTimeout: 5 * time.Second,
path: "vault",
service: "vault",
address: "127.0.0.1",
scheme: "http",
token: "",
max_parallel: 4,
name: "Valid default config",
consulConfig: map[string]string{},
checkTimeout: 5 * time.Second,
advertiseAddr: "http://127.0.0.1:8200",
path: "vault/",
service: "vault",
address: "127.0.0.1:8500",
scheme: "http",
token: "",
max_parallel: 4,
disableReg: false,
},
{
Name: "Valid modified config",
Config: map[string]string{
"path": "seaTech/",
"service": "astronomy",
"check_timeout": "6s",
"address": "127.0.0.2",
"scheme": "https",
"token": "deadbeef-cafeefac-deadc0de-feedface",
"max_parallel": "4",
name: "Valid modified config",
consulConfig: map[string]string{
"path": "seaTech/",
"service": "astronomy",
"advertiseAddr": "http://127.0.0.2:8200",
"check_timeout": "6s",
"address": "127.0.0.2",
"scheme": "https",
"token": "deadbeef-cafeefac-deadc0de-feedface",
"max_parallel": "4",
"disable_registration": "false",
},
checkTimeout: 6 * time.Second,
path: "seaTech/",
service: "astronomy",
address: "127.0.0.2",
scheme: "https",
token: "deadbeef-cafeefac-deadc0de-feedface",
max_parallel: 4,
checkTimeout: 6 * time.Second,
path: "seaTech/",
service: "astronomy",
advertiseAddr: "http://127.0.0.2:8200",
address: "127.0.0.2",
scheme: "https",
token: "deadbeef-cafeefac-deadc0de-feedface",
max_parallel: 4,
},
{
Name: "check timeout too short",
Fail: true,
Config: map[string]string{
name: "check timeout too short",
fail: true,
consulConfig: map[string]string{
"check_timeout": "99ms",
},
},
}
for _, test := range tests {
be, err := newConsulBackend(test.Config)
if test.Fail && err == nil {
t.Fatalf("Expected config %s to fail", test.Name)
} else if !test.Fail && err != nil {
t.Fatalf("Expected config %s to not fail: %v", test.Name, err)
be, err := newConsulBackend(test.consulConfig)
if test.fail {
if err == nil {
t.Fatalf(`Expected config "%s" to fail`, test.name)
} else {
continue
}
} else if !test.fail && err != nil {
t.Fatalf("Expected config %s to not fail: %v", test.name, err)
}
c, ok := be.(*ConsulBackend)
if !ok {
t.Fatalf("Expected ConsulBackend")
t.Fatalf("Expected ConsulBackend: %s", test.name)
}
if err := c.UpdateAdvertiseAddr(test.advertiseAddr); err != nil {
t.Fatalf("bad: %v", err)
}
if test.checkTimeout != c.checkTimeout {
@ -154,7 +168,7 @@ func TestConsul_newConsulBackend(t *testing.T) {
}
if test.path != c.path {
t.Errorf("bad: %v != %v", test.path, c.path)
t.Errorf("bad: %s %v != %v", test.name, test.path, c.path)
}
if test.service != c.serviceName {
@ -162,7 +176,7 @@ func TestConsul_newConsulBackend(t *testing.T) {
}
if test.address != c.consulClientConf.Address {
t.Errorf("bad: %v != %v", test.address, c.consulClientConf.Address)
t.Errorf("bad: %s %v != %v", test.name, test.address, c.consulClientConf.Address)
}
if test.scheme != c.consulClientConf.Scheme {
@ -206,14 +220,20 @@ func TestConsul_serviceTags(t *testing.T) {
func TestConsul_UpdateAdvertiseAddr(t *testing.T) {
tests := []struct {
addr string
host string
port int
pass bool
}{
{
addr: "http://127.0.0.1:8200/",
host: "127.0.0.1",
port: 8200,
pass: true,
},
{
addr: "http://127.0.0.1:8200",
host: "127.0.0.1",
port: 8200,
pass: true,
},
{
@ -244,8 +264,12 @@ func TestConsul_UpdateAdvertiseAddr(t *testing.T) {
}
}
if c.advertiseAddr != test.addr {
t.Fatalf("bad: %v != %v", c.advertiseAddr, test.addr)
if c.advertiseHost != test.host {
t.Fatalf("bad: %v != %v", c.advertiseHost, test.host)
}
if c.advertisePort != test.port {
t.Fatalf("bad: %v != %v", c.advertisePort, test.port)
}
}
}
@ -330,21 +354,25 @@ func TestConsul_checkID(t *testing.T) {
func TestConsul_serviceID(t *testing.T) {
passingTests := []struct {
name string
advertiseAddr string
serviceName string
expected string
}{
{
name: "valid host w/o slash",
advertiseAddr: "http://127.0.0.1:8200",
serviceName: "sea-tech-astronomy",
expected: "sea-tech-astronomy:127.0.0.1:8200",
},
{
name: "valid host w/ slash",
advertiseAddr: "http://127.0.0.1:8200/",
serviceName: "sea-tech-astronomy",
expected: "sea-tech-astronomy:127.0.0.1:8200",
},
{
name: "valid https host w/ slash",
advertiseAddr: "https://127.0.0.1:8200/",
serviceName: "sea-tech-astronomy",
expected: "sea-tech-astronomy:127.0.0.1:8200",
@ -357,14 +385,10 @@ func TestConsul_serviceID(t *testing.T) {
})
if err := c.UpdateAdvertiseAddr(test.advertiseAddr); err != nil {
t.Fatalf("bad: %v", err)
}
serviceID, err := c.serviceID()
if err != nil {
t.Fatalf("bad: %v", err)
t.Fatalf("bad: %s %v", test.name, err)
}
serviceID := c.serviceID()
if serviceID != test.expected {
t.Fatalf("bad: %v != %v", serviceID, test.expected)
}

View File

@ -43,11 +43,6 @@ type HABackend interface {
type AdvertiseDetect interface {
// DetectHostAddr is used to detect the host address
DetectHostAddr() (string, error)
// UpdateAdvertiseAddr allows for a non-Running backend to update the
// advertise address. HABackends may want to present a different
// address that wasn't available when a Backend was created.
UpdateAdvertiseAddr(addr string) error
}
// ServiceDiscovery is an optional interface that an HABackend can implement.
@ -65,6 +60,11 @@ type ServiceDiscovery interface {
// Run executes any background service discovery tasks until the
// shutdown channel is closed.
RunServiceDiscovery(ShutdownChannel) error
// UpdateAdvertiseAddr allows for a non-Running backend to update the
// advertise address. HABackends may want to present a different
// address that wasn't available when a Backend was created.
UpdateAdvertiseAddr(addr string) error
}
type Lock interface {

View File

@ -200,6 +200,9 @@ For Consul, the following options are supported:
* `scheme` (optional) - "http" or "https" for talking to Consul.
* `disable_registration` (optional) - If true, then Vault will not register
itself with Vault. Defaults to "false".
* `token` (optional) - An access token to use to write data to Consul.
* `max_parallel` (optional) - The maximum number of connections to Consul;