forked from criteo-forks/consul
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpeering.go
295 lines (245 loc) · 8.45 KB
/
peering.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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package api
import (
"context"
"fmt"
"time"
)
// PeeringState enumerates all the states a peering can be in
type PeeringState string
const (
// PeeringStateUndefined represents an unset value for PeeringState during
// writes.
PeeringStateUndefined PeeringState = "UNDEFINED"
// PeeringStatePending means the peering was created by generating a peering token.
// Peerings stay in a pending state until the peer uses the token to dial
// the local cluster.
PeeringStatePending PeeringState = "PENDING"
// PeeringStateEstablishing means the peering is being established from a peering token.
// This is the initial state for dialing peers.
PeeringStateEstablishing PeeringState = "ESTABLISHING"
// PeeringStateActive means that the peering connection is active and
// healthy.
PeeringStateActive PeeringState = "ACTIVE"
// PeeringStateFailing means the peering connection has been interrupted
// but has not yet been terminated.
PeeringStateFailing PeeringState = "FAILING"
// PeeringStateDeleting means a peering was marked for deletion and is in the process
// of being deleted.
PeeringStateDeleting PeeringState = "DELETING"
// PeeringStateTerminated means the peering relationship has been removed.
PeeringStateTerminated PeeringState = "TERMINATED"
)
type PeeringRemoteInfo struct {
// Partition is the remote peer's partition.
Partition string
// Datacenter is the remote peer's datacenter.
Datacenter string
Locality *Locality `json:",omitempty"`
}
// Locality identifies where a given entity is running.
type Locality struct {
// Region is region the zone belongs to.
Region string
// Zone is the zone the entity is running in.
Zone string
}
type Peering struct {
// ID is a datacenter-scoped UUID for the peering.
ID string
// Name is the local alias for the peering relationship.
Name string
// Partition is the local partition connecting to the peer.
Partition string `json:",omitempty"`
// DeletedAt is the time when the Peering was marked for deletion
DeletedAt *time.Time `json:",omitempty" alias:"deleted_at"`
// Meta is a mapping of some string value to any other string value
Meta map[string]string `json:",omitempty"`
// State is one of the valid PeeringState values to represent the status of
// peering relationship.
State PeeringState
// PeerID is the ID that our peer assigned to this peering. This ID is to
// be used when dialing the peer, so that it can know who dialed it.
PeerID string `json:",omitempty"`
// PeerCAPems contains all the CA certificates for the remote peer.
PeerCAPems []string `json:",omitempty"`
// PeerServerName is the name of the remote server as it relates to TLS.
PeerServerName string `json:",omitempty"`
// PeerServerAddresses contains all the connection addresses for the remote peer.
PeerServerAddresses []string `json:",omitempty"`
// StreamStatus contains information computed on read based on the state of the stream.
StreamStatus PeeringStreamStatus
// CreateIndex is the Raft index at which the Peering was created.
CreateIndex uint64
// ModifyIndex is the latest Raft index at which the Peering was modified.
ModifyIndex uint64
// Remote contains metadata for the remote peer.
Remote PeeringRemoteInfo
}
type PeeringStreamStatus struct {
// ImportedServices is the list of services imported from this peering.
ImportedServices []string
// ExportedServices is the list of services exported to this peering.
ExportedServices []string
// LastHeartbeat represents when the last heartbeat message was received.
LastHeartbeat *time.Time
// LastReceive represents when any message was last received, regardless of success or error.
LastReceive *time.Time
// LastSend represents when any message was last sent, regardless of success or error.
LastSend *time.Time
}
type PeeringReadResponse struct {
Peering *Peering
}
type PeeringGenerateTokenRequest struct {
// PeerName is the name of the remote peer.
PeerName string
// Partition to be peered.
Partition string `json:",omitempty"`
// Meta is a mapping of some string value to any other string value
Meta map[string]string `json:",omitempty"`
// ServerExternalAddresses is a list of addresses to put into the generated token. This could be used to specify
// load balancer(s) or external IPs to reach the servers from the dialing side, and will override any server
// addresses obtained from the "consul" service.
ServerExternalAddresses []string `json:",omitempty"`
}
type PeeringGenerateTokenResponse struct {
// PeeringToken is an opaque string provided to the remote peer for it to complete
// the peering initialization handshake.
PeeringToken string
}
type PeeringEstablishRequest struct {
// Name of the remote peer.
PeerName string
// The peering token returned from the peer's GenerateToken endpoint.
PeeringToken string `json:",omitempty"`
// Partition to be peered.
Partition string `json:",omitempty"`
// Meta is a mapping of some string value to any other string value
Meta map[string]string `json:",omitempty"`
}
type PeeringEstablishResponse struct {
}
type PeeringListRequest struct {
// future proofing in case we extend List functionality
}
type Peerings struct {
c *Client
}
// Peerings returns a handle to the operator endpoints.
func (c *Client) Peerings() *Peerings {
return &Peerings{c: c}
}
func (p *Peerings) Read(ctx context.Context, name string, q *QueryOptions) (*Peering, *QueryMeta, error) {
if name == "" {
return nil, nil, fmt.Errorf("peering name cannot be empty")
}
req := p.c.newRequest("GET", fmt.Sprintf("/v1/peering/%s", name))
req.setQueryOptions(q)
req.ctx = ctx
rtt, resp, err := p.c.doRequest(req)
if err != nil {
return nil, nil, err
}
defer closeResponseBody(resp)
found, resp, err := requireNotFoundOrOK(resp)
if err != nil {
return nil, nil, err
}
qm := &QueryMeta{}
parseQueryMeta(resp, qm)
qm.RequestTime = rtt
if !found {
return nil, qm, nil
}
var out Peering
if err := decodeBody(resp, &out); err != nil {
return nil, nil, err
}
return &out, qm, nil
}
func (p *Peerings) Delete(ctx context.Context, name string, q *WriteOptions) (*WriteMeta, error) {
if name == "" {
return nil, fmt.Errorf("peering name cannot be empty")
}
req := p.c.newRequest("DELETE", fmt.Sprintf("/v1/peering/%s", name))
req.setWriteOptions(q)
req.ctx = ctx
rtt, resp, err := p.c.doRequest(req)
if err != nil {
return nil, err
}
defer closeResponseBody(resp)
if err := requireOK(resp); err != nil {
return nil, err
}
wm := &WriteMeta{RequestTime: rtt}
return wm, nil
}
// TODO(peering): verify this is the ultimate signature we want
func (p *Peerings) GenerateToken(ctx context.Context, g PeeringGenerateTokenRequest, wq *WriteOptions) (*PeeringGenerateTokenResponse, *WriteMeta, error) {
if g.PeerName == "" {
return nil, nil, fmt.Errorf("peer name cannot be empty")
}
req := p.c.newRequest("POST", fmt.Sprint("/v1/peering/token"))
req.setWriteOptions(wq)
req.ctx = ctx
req.obj = g
rtt, resp, err := p.c.doRequest(req)
if err != nil {
return nil, nil, err
}
defer closeResponseBody(resp)
if err := requireOK(resp); err != nil {
return nil, nil, err
}
wm := &WriteMeta{RequestTime: rtt}
var out PeeringGenerateTokenResponse
if err := decodeBody(resp, &out); err != nil {
return nil, nil, err
}
return &out, wm, nil
}
// TODO(peering): verify this is the ultimate signature we want
func (p *Peerings) Establish(ctx context.Context, i PeeringEstablishRequest, wq *WriteOptions) (*PeeringEstablishResponse, *WriteMeta, error) {
req := p.c.newRequest("POST", fmt.Sprint("/v1/peering/establish"))
req.setWriteOptions(wq)
req.ctx = ctx
req.obj = i
rtt, resp, err := p.c.doRequest(req)
if err != nil {
return nil, nil, err
}
defer closeResponseBody(resp)
if err := requireOK(resp); err != nil {
return nil, nil, err
}
wm := &WriteMeta{RequestTime: rtt}
var out PeeringEstablishResponse
if err := decodeBody(resp, &out); err != nil {
return nil, nil, err
}
return &out, wm, nil
}
func (p *Peerings) List(ctx context.Context, q *QueryOptions) ([]*Peering, *QueryMeta, error) {
req := p.c.newRequest("GET", "/v1/peerings")
req.setQueryOptions(q)
req.ctx = ctx
rtt, resp, err := p.c.doRequest(req)
if err != nil {
return nil, nil, err
}
defer closeResponseBody(resp)
if err := requireOK(resp); err != nil {
return nil, nil, err
}
qm := &QueryMeta{}
parseQueryMeta(resp, qm)
qm.RequestTime = rtt
var out []*Peering
if err := decodeBody(resp, &out); err != nil {
return nil, nil, err
}
return out, qm, nil
}