135 lines
2.9 KiB
Go
135 lines
2.9 KiB
Go
package dependency
|
|
|
|
import (
|
|
"encoding/gob"
|
|
"errors"
|
|
"fmt"
|
|
"log"
|
|
"regexp"
|
|
"strings"
|
|
)
|
|
|
|
func init() {
|
|
gob.Register([]*KeyPair{})
|
|
}
|
|
|
|
// KeyPair is a simple Key-Value pair
|
|
type KeyPair struct {
|
|
Path string
|
|
Key string
|
|
Value string
|
|
|
|
// Lesser-used, but still valuable keys from api.KV
|
|
CreateIndex uint64
|
|
ModifyIndex uint64
|
|
LockIndex uint64
|
|
Flags uint64
|
|
Session string
|
|
}
|
|
|
|
// StoreKeyPrefix is the representation of a requested key dependency
|
|
// from inside a template.
|
|
type StoreKeyPrefix struct {
|
|
rawKey string
|
|
Prefix string
|
|
DataCenter string
|
|
}
|
|
|
|
// Fetch queries the Consul API defined by the given client and returns a slice
|
|
// of KeyPair objects
|
|
func (d *StoreKeyPrefix) Fetch(clients *ClientSet, opts *QueryOptions) (interface{}, *ResponseMetadata, error) {
|
|
if opts == nil {
|
|
opts = &QueryOptions{}
|
|
}
|
|
|
|
consulOpts := opts.consulQueryOptions()
|
|
if d.DataCenter != "" {
|
|
consulOpts.Datacenter = d.DataCenter
|
|
}
|
|
|
|
log.Printf("[DEBUG] (%s) querying Consul with %+v", d.Display(), consulOpts)
|
|
|
|
consul, err := clients.Consul()
|
|
if err != nil {
|
|
return nil, nil, fmt.Errorf("store key prefix: error getting client: %s", err)
|
|
}
|
|
|
|
store := consul.KV()
|
|
prefixes, qm, err := store.List(d.Prefix, consulOpts)
|
|
if err != nil {
|
|
return nil, nil, fmt.Errorf("store key prefix: error fetching: %s", err)
|
|
}
|
|
|
|
log.Printf("[DEBUG] (%s) Consul returned %d key pairs", d.Display(), len(prefixes))
|
|
|
|
keyPairs := make([]*KeyPair, 0, len(prefixes))
|
|
for _, pair := range prefixes {
|
|
key := strings.TrimPrefix(pair.Key, d.Prefix)
|
|
key = strings.TrimLeft(key, "/")
|
|
|
|
keyPairs = append(keyPairs, &KeyPair{
|
|
Path: pair.Key,
|
|
Key: key,
|
|
Value: string(pair.Value),
|
|
CreateIndex: pair.CreateIndex,
|
|
ModifyIndex: pair.ModifyIndex,
|
|
LockIndex: pair.LockIndex,
|
|
Flags: pair.Flags,
|
|
Session: pair.Session,
|
|
})
|
|
}
|
|
|
|
rm := &ResponseMetadata{
|
|
LastIndex: qm.LastIndex,
|
|
LastContact: qm.LastContact,
|
|
}
|
|
|
|
return keyPairs, rm, nil
|
|
}
|
|
|
|
func (d *StoreKeyPrefix) CanShare() bool {
|
|
return true
|
|
}
|
|
|
|
func (d *StoreKeyPrefix) HashCode() string {
|
|
return fmt.Sprintf("StoreKeyPrefix|%s", d.rawKey)
|
|
}
|
|
|
|
func (d *StoreKeyPrefix) Display() string {
|
|
return fmt.Sprintf(`"storeKeyPrefix(%s)"`, d.rawKey)
|
|
}
|
|
|
|
// ParseStoreKeyPrefix parses a string of the format a(/b(/c...))
|
|
func ParseStoreKeyPrefix(s string) (*StoreKeyPrefix, error) {
|
|
// a(/b(/c))(@datacenter)
|
|
re := regexp.MustCompile(`\A` +
|
|
`(?P<prefix>[[:word:]\.\:\-\/]+)?` +
|
|
`(@(?P<datacenter>[[:word:]\.\-]+))?` +
|
|
`\z`)
|
|
names := re.SubexpNames()
|
|
match := re.FindAllStringSubmatch(s, -1)
|
|
|
|
if len(match) == 0 {
|
|
return nil, errors.New("invalid key prefix dependency format")
|
|
}
|
|
|
|
r := match[0]
|
|
|
|
m := map[string]string{}
|
|
for i, n := range r {
|
|
if names[i] != "" {
|
|
m[names[i]] = n
|
|
}
|
|
}
|
|
|
|
prefix, datacenter := m["prefix"], m["datacenter"]
|
|
|
|
kpd := &StoreKeyPrefix{
|
|
rawKey: s,
|
|
Prefix: prefix,
|
|
DataCenter: datacenter,
|
|
}
|
|
|
|
return kpd, nil
|
|
}
|