-
Notifications
You must be signed in to change notification settings - Fork 785
/
catalog_service.go
154 lines (132 loc) · 3.54 KB
/
catalog_service.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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package dependency
import (
"encoding/gob"
"fmt"
"log"
"net/url"
"regexp"
"github.com/pkg/errors"
)
var (
// Ensure implements
_ Dependency = (*CatalogServiceQuery)(nil)
// CatalogServiceQueryRe is the regular expression to use.
CatalogServiceQueryRe = regexp.MustCompile(`\A` + tagRe + serviceNameRe + dcRe + nearRe + `\z`)
)
func init() {
gob.Register([]*CatalogSnippet{})
}
// CatalogService is a catalog entry in Consul.
type CatalogService struct {
ID string
Node string
Address string
Datacenter string
TaggedAddresses map[string]string
NodeMeta map[string]string
ServiceID string
ServiceName string
ServiceAddress string
ServiceTags ServiceTags
ServiceMeta map[string]string
ServicePort int
}
// CatalogServiceQuery is the representation of a requested catalog services
// dependency from inside a template.
type CatalogServiceQuery struct {
stopCh chan struct{}
dc string
name string
near string
tag string
}
// NewCatalogServiceQuery parses a string into a CatalogServiceQuery.
func NewCatalogServiceQuery(s string) (*CatalogServiceQuery, error) {
if !CatalogServiceQueryRe.MatchString(s) {
return nil, fmt.Errorf("catalog.service: invalid format: %q", s)
}
m := regexpMatch(CatalogServiceQueryRe, s)
return &CatalogServiceQuery{
stopCh: make(chan struct{}, 1),
dc: m["dc"],
name: m["name"],
near: m["near"],
tag: m["tag"],
}, nil
}
// Fetch queries the Consul API defined by the given client and returns a slice
// of CatalogService objects.
func (d *CatalogServiceQuery) Fetch(clients *ClientSet, opts *QueryOptions) (interface{}, *ResponseMetadata, error) {
select {
case <-d.stopCh:
return nil, nil, ErrStopped
default:
}
opts = opts.Merge(&QueryOptions{
Datacenter: d.dc,
Near: d.near,
})
u := &url.URL{
Path: "/v1/catalog/service/" + d.name,
RawQuery: opts.String(),
}
if d.tag != "" {
q := u.Query()
q.Set("tag", d.tag)
u.RawQuery = q.Encode()
}
log.Printf("[TRACE] %s: GET %s", d, u)
entries, qm, err := clients.Consul().Catalog().Service(d.name, d.tag, opts.ToConsulOpts())
if err != nil {
return nil, nil, errors.Wrap(err, d.String())
}
log.Printf("[TRACE] %s: returned %d results", d, len(entries))
var list []*CatalogService
for _, s := range entries {
list = append(list, &CatalogService{
ID: s.ID,
Node: s.Node,
Address: s.Address,
Datacenter: s.Datacenter,
TaggedAddresses: s.TaggedAddresses,
NodeMeta: s.NodeMeta,
ServiceID: s.ServiceID,
ServiceName: s.ServiceName,
ServiceAddress: s.ServiceAddress,
ServiceTags: ServiceTags(deepCopyAndSortTags(s.ServiceTags)),
ServiceMeta: s.ServiceMeta,
ServicePort: s.ServicePort,
})
}
rm := &ResponseMetadata{
LastIndex: qm.LastIndex,
LastContact: qm.LastContact,
}
return list, rm, nil
}
// CanShare returns a boolean if this dependency is shareable.
func (d *CatalogServiceQuery) CanShare() bool {
return true
}
// String returns the human-friendly version of this dependency.
func (d *CatalogServiceQuery) String() string {
name := d.name
if d.tag != "" {
name = d.tag + "." + name
}
if d.dc != "" {
name = name + "@" + d.dc
}
if d.near != "" {
name = name + "~" + d.near
}
return fmt.Sprintf("catalog.service(%s)", name)
}
// Stop halts the dependency's fetch function.
func (d *CatalogServiceQuery) Stop() {
close(d.stopCh)
}
// Type returns the type of this dependency.
func (d *CatalogServiceQuery) Type() Type {
return TypeConsul
}