-
Notifications
You must be signed in to change notification settings - Fork 782
/
catalog_services.go
128 lines (103 loc) · 2.89 KB
/
catalog_services.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package dependency
import (
"encoding/gob"
"fmt"
"log"
"net/url"
"regexp"
"sort"
"github.com/pkg/errors"
)
var (
// Ensure implements
_ Dependency = (*CatalogServicesQuery)(nil)
// CatalogServicesQueryRe is the regular expression to use for CatalogNodesQuery.
CatalogServicesQueryRe = regexp.MustCompile(`\A` + dcRe + `\z`)
)
func init() {
gob.Register([]*CatalogSnippet{})
}
// CatalogSnippet is a catalog entry in Consul.
type CatalogSnippet struct {
Name string
Tags ServiceTags
}
// CatalogServicesQuery is the representation of a requested catalog service
// dependency from inside a template.
type CatalogServicesQuery struct {
stopCh chan struct{}
dc string
}
// NewCatalogServicesQuery parses a string of the format @dc.
func NewCatalogServicesQuery(s string) (*CatalogServicesQuery, error) {
if !CatalogServicesQueryRe.MatchString(s) {
return nil, fmt.Errorf("catalog.services: invalid format: %q", s)
}
m := regexpMatch(CatalogServicesQueryRe, s)
return &CatalogServicesQuery{
dc: m["dc"],
}, nil
}
// Fetch queries the Consul API defined by the given client and returns a slice
// of CatalogService objects.
func (d *CatalogServicesQuery) Fetch(clients *ClientSet, opts *QueryOptions) (interface{}, *ResponseMetadata, error) {
select {
case <-d.stopCh:
return nil, nil, ErrStopped
default:
}
opts = opts.Merge(&QueryOptions{
Datacenter: d.dc,
})
log.Printf("[TRACE] %s: GET %s", d, &url.URL{
Path: "/v1/catalog/services",
RawQuery: opts.String(),
})
entries, qm, err := clients.Consul().Catalog().Services(opts.ToConsulOpts())
if err != nil {
return nil, nil, errors.Wrap(err, d.String())
}
log.Printf("[TRACE] %s: returned %d results", d, len(entries))
var catalogServices []*CatalogSnippet
for name, tags := range entries {
catalogServices = append(catalogServices, &CatalogSnippet{
Name: name,
Tags: ServiceTags(deepCopyAndSortTags(tags)),
})
}
sort.Stable(ByName(catalogServices))
rm := &ResponseMetadata{
LastIndex: qm.LastIndex,
LastContact: qm.LastContact,
}
return catalogServices, rm, nil
}
// CanShare returns a boolean if this dependency is shareable.
func (d *CatalogServicesQuery) CanShare() bool {
return true
}
// String returns the human-friendly version of this dependency.
func (d *CatalogServicesQuery) String() string {
if d.dc != "" {
return fmt.Sprintf("catalog.services(@%s)", d.dc)
}
return "catalog.services"
}
// Stop halts the dependency's fetch function.
func (d *CatalogServicesQuery) Stop() {
close(d.stopCh)
}
// Type returns the type of this dependency.
func (d *CatalogServicesQuery) Type() Type {
return TypeConsul
}
// ByName is a sortable slice of CatalogService structs.
type ByName []*CatalogSnippet
func (s ByName) Len() int { return len(s) }
func (s ByName) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s ByName) Less(i, j int) bool {
if s[i].Name <= s[j].Name {
return true
}
return false
}