2021-03-16 18:22:21 +00:00
|
|
|
package consul
|
|
|
|
|
|
|
|
import (
|
|
|
|
"sort"
|
2021-06-07 15:54:33 +00:00
|
|
|
"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
|
2021-03-16 18:22:21 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// 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
|
2021-06-07 15:54:33 +00:00
|
|
|
agentAPI AgentAPI
|
|
|
|
|
|
|
|
lock sync.Mutex
|
|
|
|
enabled bool // namespaces requires Ent + Namespaces feature
|
|
|
|
updated time.Time // memoize response for a while
|
2021-03-16 18:22:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewNamespacesClient returns a NamespacesClient backed by a NamespaceAPI.
|
2021-06-07 15:54:33 +00:00
|
|
|
func NewNamespacesClient(namespacesAPI NamespaceAPI, agentAPI AgentAPI) *NamespacesClient {
|
2021-03-16 18:22:21 +00:00
|
|
|
return &NamespacesClient{
|
|
|
|
namespacesAPI: namespacesAPI,
|
2021-06-07 15:54:33 +00:00
|
|
|
agentAPI: agentAPI,
|
2021-03-16 18:22:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-07 15:54:33 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2021-06-07 20:22:26 +00:00
|
|
|
ns.enabled = Namespaces(self)
|
2021-06-07 15:54:33 +00:00
|
|
|
ns.updated = now
|
|
|
|
return ns.enabled
|
|
|
|
}
|
|
|
|
|
2021-03-16 18:22:21 +00:00
|
|
|
// List returns a list of Consul Namespaces.
|
|
|
|
//
|
2021-06-07 15:54:33 +00:00
|
|
|
// TODO(shoenig): return empty string instead of "default" when namespaces are not
|
|
|
|
// enabled. (Coming in followup PR).
|
2021-03-16 18:22:21 +00:00
|
|
|
func (ns *NamespacesClient) List() ([]string, error) {
|
2021-06-07 15:54:33 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2021-03-16 18:22:21 +00:00
|
|
|
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
|
|
|
|
}
|