github.com/hernad/nomad@v1.6.112/command/agent/consul/namespaces_client.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package consul 5 6 import ( 7 "sort" 8 "sync" 9 "time" 10 11 "github.com/hashicorp/consul/api" 12 ) 13 14 const ( 15 // namespaceEnabledCacheTTL is how long to cache the response from Consul 16 // /v1/agent/self API, which is used to determine whether namespaces are 17 // available. 18 namespaceEnabledCacheTTL = 1 * time.Minute 19 ) 20 21 // NamespacesClient is a wrapper for the Consul NamespacesAPI, that is used to 22 // deal with Consul OSS vs Consul Enterprise behavior in listing namespaces. 23 type NamespacesClient struct { 24 namespacesAPI NamespaceAPI 25 agentAPI AgentAPI 26 27 lock sync.Mutex 28 enabled bool // namespaces requires Ent + Namespaces feature 29 updated time.Time // memoize response for a while 30 } 31 32 // NewNamespacesClient returns a NamespacesClient backed by a NamespaceAPI. 33 func NewNamespacesClient(namespacesAPI NamespaceAPI, agentAPI AgentAPI) *NamespacesClient { 34 return &NamespacesClient{ 35 namespacesAPI: namespacesAPI, 36 agentAPI: agentAPI, 37 } 38 } 39 40 func stale(updated, now time.Time) bool { 41 return now.After(updated.Add(namespaceEnabledCacheTTL)) 42 } 43 44 func (ns *NamespacesClient) allowable(now time.Time) bool { 45 ns.lock.Lock() 46 defer ns.lock.Unlock() 47 48 if !stale(ns.updated, now) { 49 return ns.enabled 50 } 51 52 self, err := ns.agentAPI.Self() 53 if err != nil { 54 return ns.enabled 55 } 56 57 sku, ok := SKU(self) 58 if !ok { 59 return ns.enabled 60 } 61 62 if sku != "ent" { 63 ns.enabled = false 64 ns.updated = now 65 return ns.enabled 66 } 67 68 ns.enabled = Namespaces(self) 69 ns.updated = now 70 return ns.enabled 71 } 72 73 // List returns a list of Consul Namespaces. 74 func (ns *NamespacesClient) List() ([]string, error) { 75 if !ns.allowable(time.Now()) { 76 // TODO(shoenig): lets return the empty string instead, that way we do not 77 // need to normalize at call sites later on 78 return []string{"default"}, nil 79 } 80 81 qo := &api.QueryOptions{ 82 AllowStale: true, 83 } 84 namespaces, _, err := ns.namespacesAPI.List(qo) 85 if err != nil { 86 return nil, err 87 } 88 89 result := make([]string, 0, len(namespaces)) 90 for _, namespace := range namespaces { 91 result = append(result, namespace.Name) 92 } 93 sort.Strings(result) 94 return result, nil 95 }