1package dependency 2 3import ( 4 "fmt" 5 "log" 6 "net/url" 7 "regexp" 8 9 "github.com/pkg/errors" 10) 11 12var ( 13 // Ensure implements 14 _ Dependency = (*KVGetQuery)(nil) 15 16 // KVGetQueryRe is the regular expression to use. 17 KVGetQueryRe = regexp.MustCompile(`\A` + keyRe + dcRe + `\z`) 18) 19 20// KVGetQuery queries the KV store for a single key. 21type KVGetQuery struct { 22 stopCh chan struct{} 23 24 dc string 25 key string 26 block bool 27} 28 29// NewKVGetQuery parses a string into a dependency. 30func NewKVGetQuery(s string) (*KVGetQuery, error) { 31 if s != "" && !KVGetQueryRe.MatchString(s) { 32 return nil, fmt.Errorf("kv.get: invalid format: %q", s) 33 } 34 35 m := regexpMatch(KVGetQueryRe, s) 36 return &KVGetQuery{ 37 stopCh: make(chan struct{}, 1), 38 dc: m["dc"], 39 key: m["key"], 40 }, nil 41} 42 43// Fetch queries the Consul API defined by the given client. 44func (d *KVGetQuery) 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.key, 57 RawQuery: opts.String(), 58 }) 59 60 pair, qm, err := clients.Consul().KV().Get(d.key, opts.ToConsulOpts()) 61 if err != nil { 62 return nil, nil, errors.Wrap(err, d.String()) 63 } 64 65 rm := &ResponseMetadata{ 66 LastIndex: qm.LastIndex, 67 LastContact: qm.LastContact, 68 Block: d.block, 69 } 70 71 if pair == nil { 72 log.Printf("[TRACE] %s: returned nil", d) 73 return nil, rm, nil 74 } 75 76 value := string(pair.Value) 77 log.Printf("[TRACE] %s: returned %q", d, value) 78 return value, rm, nil 79} 80 81// EnableBlocking turns this into a blocking KV query. 82func (d *KVGetQuery) EnableBlocking() { 83 d.block = true 84} 85 86// CanShare returns a boolean if this dependency is shareable. 87func (d *KVGetQuery) CanShare() bool { 88 return true 89} 90 91// String returns the human-friendly version of this dependency. 92func (d *KVGetQuery) String() string { 93 key := d.key 94 if d.dc != "" { 95 key = key + "@" + d.dc 96 } 97 98 if d.block { 99 return fmt.Sprintf("kv.block(%s)", key) 100 } 101 return fmt.Sprintf("kv.get(%s)", key) 102} 103 104// Stop halts the dependency's fetch function. 105func (d *KVGetQuery) Stop() { 106 close(d.stopCh) 107} 108 109// Type returns the type of this dependency. 110func (d *KVGetQuery) Type() Type { 111 return TypeConsul 112} 113