open-nomad/command/agent/consul/namespaces_client.go

91 lines
2.1 KiB
Go

package consul
import (
"sort"
"sync"
"time"
)
const (
// namespaceEnabledCacheTTL is how long to cache the response from Consul
// /v1/agent/self API, which is used to determine whether namespaces are
// available.
namespaceEnabledCacheTTL = 1 * time.Minute
)
// NamespacesClient is a wrapper for the Consul NamespacesAPI, that is used to
// deal with Consul OSS vs Consul Enterprise behavior in listing namespaces.
type NamespacesClient struct {
namespacesAPI NamespaceAPI
agentAPI AgentAPI
lock sync.Mutex
enabled bool // namespaces requires Ent + Namespaces feature
updated time.Time // memoize response for a while
}
// NewNamespacesClient returns a NamespacesClient backed by a NamespaceAPI.
func NewNamespacesClient(namespacesAPI NamespaceAPI, agentAPI AgentAPI) *NamespacesClient {
return &NamespacesClient{
namespacesAPI: namespacesAPI,
agentAPI: agentAPI,
}
}
func stale(updated, now time.Time) bool {
return now.After(updated.Add(namespaceEnabledCacheTTL))
}
func (ns *NamespacesClient) allowable(now time.Time) bool {
ns.lock.Lock()
defer ns.lock.Unlock()
if !stale(ns.updated, now) {
return ns.enabled
}
self, err := ns.agentAPI.Self()
if err != nil {
return ns.enabled
}
sku, ok := SKU(self)
if !ok {
return ns.enabled
}
if sku != "ent" {
ns.enabled = false
ns.updated = now
return ns.enabled
}
ns.enabled = Namespaces(self)
ns.updated = now
return ns.enabled
}
// List returns a list of Consul Namespaces.
//
// TODO(shoenig): return empty string instead of "default" when namespaces are not
// enabled. (Coming in followup PR).
func (ns *NamespacesClient) List() ([]string, error) {
if !ns.allowable(time.Now()) {
// TODO(shoenig): lets return the empty string instead, that way we do not
// need to normalize at call sites later on
return []string{"default"}, nil
}
namespaces, _, err := ns.namespacesAPI.List(nil)
if err != nil {
return nil, err
}
result := make([]string, 0, len(namespaces))
for _, namespace := range namespaces {
result = append(result, namespace.Name)
}
sort.Strings(result)
return result, nil
}