1package dependency 2 3import ( 4 "fmt" 5 "log" 6 "net/url" 7 "regexp" 8 "strings" 9 10 "github.com/pkg/errors" 11) 12 13var ( 14 // Ensure implements 15 _ Dependency = (*KVKeysQuery)(nil) 16 17 // KVKeysQueryRe is the regular expression to use. 18 KVKeysQueryRe = regexp.MustCompile(`\A` + prefixRe + dcRe + `\z`) 19) 20 21// KVKeysQuery queries the KV store for a single key. 22type KVKeysQuery struct { 23 stopCh chan struct{} 24 25 dc string 26 prefix string 27} 28 29// NewKVKeysQuery parses a string into a dependency. 30func NewKVKeysQuery(s string) (*KVKeysQuery, error) { 31 if s != "" && !KVKeysQueryRe.MatchString(s) { 32 return nil, fmt.Errorf("kv.keys: invalid format: %q", s) 33 } 34 35 m := regexpMatch(KVKeysQueryRe, s) 36 return &KVKeysQuery{ 37 stopCh: make(chan struct{}, 1), 38 dc: m["dc"], 39 prefix: m["prefix"], 40 }, nil 41} 42 43// Fetch queries the Consul API defined by the given client. 44func (d *KVKeysQuery) Fetch(clients *ClientSet, opts *QueryOptions) (interface{}, *ResponseMetadata, error) { 45 select { 46 case <-d.stopCh: 47 return nil, nil, ErrStopped 48 default: 49 } 50 51 opts = opts.Merge(&QueryOptions{ 52 Datacenter: d.dc, 53 }) 54 55 log.Printf("[TRACE] %s: GET %s", d, &url.URL{ 56 Path: "/v1/kv/" + d.prefix, 57 RawQuery: opts.String(), 58 }) 59 60 list, qm, err := clients.Consul().KV().Keys(d.prefix, "", opts.ToConsulOpts()) 61 if err != nil { 62 return nil, nil, errors.Wrap(err, d.String()) 63 } 64 65 keys := make([]string, len(list)) 66 for i, v := range list { 67 v = strings.TrimPrefix(v, d.prefix) 68 v = strings.TrimLeft(v, "/") 69 keys[i] = v 70 } 71 72 log.Printf("[TRACE] %s: returned %d results", d, len(list)) 73 74 rm := &ResponseMetadata{ 75 LastIndex: qm.LastIndex, 76 LastContact: qm.LastContact, 77 } 78 79 return keys, rm, nil 80} 81 82// CanShare returns a boolean if this dependency is shareable. 83func (d *KVKeysQuery) CanShare() bool { 84 return true 85} 86 87// String returns the human-friendly version of this dependency. 88func (d *KVKeysQuery) String() string { 89 prefix := d.prefix 90 if d.dc != "" { 91 prefix = prefix + "@" + d.dc 92 } 93 return fmt.Sprintf("kv.keys(%s)", prefix) 94} 95 96// Stop halts the dependency's fetch function. 97func (d *KVKeysQuery) Stop() { 98 close(d.stopCh) 99} 100 101// Type returns the type of this dependency. 102func (d *KVKeysQuery) Type() Type { 103 return TypeConsul 104} 105