/
errors.go
315 lines (270 loc) · 8.25 KB
/
errors.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
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
//
// (C) Copyright 2020-2022 Intel Corporation.
//
// SPDX-License-Identifier: BSD-2-Clause-Patent
//
package system
import (
"encoding/json"
"fmt"
"net"
"strings"
"github.com/google/uuid"
"github.com/pkg/errors"
"github.com/daos-stack/daos/src/control/build"
"github.com/daos-stack/daos/src/control/lib/ranklist"
)
var (
ErrEmptyGroupMap = errors.New("empty group map (all ranks excluded?)")
ErrRaftUnavail = errors.New("raft service unavailable (not started yet?)")
ErrUninitialized = errors.New("system is uninitialized (storage format required?)")
)
// IsNotReady is a convenience function for checking if an error
// indicates that the system is not ready to serve requests.
func IsNotReady(err error) bool {
return IsUninitialized(err) || IsUnavailable(err)
}
// IsUnavailable returns a boolean indicating whether or not the
// supplied error corresponds to some unavailability state.
func IsUnavailable(err error) bool {
if err == nil {
return false
}
return strings.Contains(errors.Cause(err).Error(), ErrRaftUnavail.Error())
}
// IsEmptyGroupMap returns a boolean indicating whether or not the
// supplied error corresponds to an empty system group map.
func IsEmptyGroupMap(err error) bool {
if err == nil {
return false
}
return strings.Contains(errors.Cause(err).Error(), ErrEmptyGroupMap.Error())
}
// IsUninitialized returns a boolean indicating whether or not the
// supplied error corresponds to an uninitialized system.
func IsUninitialized(err error) bool {
if err == nil {
return false
}
return strings.Contains(errors.Cause(err).Error(), ErrUninitialized.Error())
}
// ErrNotReplica indicates that a request was made to a control plane
// instance that is not a designated Management Service replica.
type ErrNotReplica struct {
Replicas []string
}
func (err *ErrNotReplica) Error() string {
return fmt.Sprintf("not a %s replica (try one of %s)",
build.ManagementServiceName, strings.Join(err.Replicas, ","))
}
// IsNotReplica returns a boolean indicating whether or not the
// supplied error is an instance of ErrNotReplica.
func IsNotReplica(err error) bool {
_, ok := errors.Cause(err).(*ErrNotReplica)
return ok
}
// ErrNotLeader indicates that a request was made to a control plane
// instance that is not the current Management Service Leader.
type ErrNotLeader struct {
LeaderHint string
Replicas []string
}
func (err *ErrNotLeader) Error() string {
return fmt.Sprintf("not the %s leader (try %s or one of %s)",
build.ManagementServiceName, err.LeaderHint, strings.Join(err.Replicas, ","))
}
// IsNotLeader returns a boolean indicating whether or not the
// supplied error is an instance of ErrNotLeader.
func IsNotLeader(err error) bool {
_, ok := errors.Cause(err).(*ErrNotLeader)
return ok
}
// ErrMemberExists indicates the failure of an operation that
// expected the given member to not exist.
type ErrMemberExists struct {
Rank *ranklist.Rank
UUID *uuid.UUID
}
func (err *ErrMemberExists) Error() string {
switch {
case err.Rank != nil:
return fmt.Sprintf("member with rank %d already exists", *err.Rank)
case err.UUID != nil:
return fmt.Sprintf("member with uuid %s already exists", *err.UUID)
default:
return "member already exists"
}
}
func ErrRankExists(r ranklist.Rank) *ErrMemberExists {
return &ErrMemberExists{Rank: &r}
}
func ErrUuidExists(u uuid.UUID) *ErrMemberExists {
return &ErrMemberExists{UUID: &u}
}
// IsMemberExists returns a boolean indicating whether or not the
// supplied error is an instance of ErrMemberExists.
func IsMemberExists(err error) bool {
_, ok := errors.Cause(err).(*ErrMemberExists)
return ok
}
// ErrJoinFailure indicates the failure of a Join request due
// to some structured error condition.
type ErrJoinFailure struct {
rankChanged bool
uuidChanged bool
isExcluded bool
newUUID *uuid.UUID
curUUID *uuid.UUID
newRank *ranklist.Rank
curRank *ranklist.Rank
}
func (err *ErrJoinFailure) Error() string {
switch {
case err.rankChanged:
return fmt.Sprintf("can't rejoin member with uuid %s: rank changed from %d -> %d", *err.curUUID, *err.curRank, *err.newRank)
case err.uuidChanged:
return fmt.Sprintf("can't rejoin member with rank %d: uuid changed from %s -> %s", *err.curRank, *err.curUUID, *err.newUUID)
case err.isExcluded:
return fmt.Sprintf("member %s (rank %d) has been administratively excluded", err.curUUID, *err.curRank)
default:
return "unknown join failure"
}
}
func ErrRankChanged(new, cur ranklist.Rank, uuid uuid.UUID) *ErrJoinFailure {
return &ErrJoinFailure{
rankChanged: true,
curUUID: &uuid,
newRank: &new,
curRank: &cur,
}
}
func ErrUuidChanged(new, cur uuid.UUID, rank ranklist.Rank) *ErrJoinFailure {
return &ErrJoinFailure{
uuidChanged: true,
newUUID: &new,
curUUID: &cur,
curRank: &rank,
}
}
func ErrAdminExcluded(uuid uuid.UUID, rank ranklist.Rank) *ErrJoinFailure {
return &ErrJoinFailure{
isExcluded: true,
curUUID: &uuid,
curRank: &rank,
}
}
// IsJoinFailure returns a boolean indicating whether or not the
// supplied error is an instance of ErrJoinFailure.
func IsJoinFailure(err error) bool {
_, ok := errors.Cause(err).(*ErrJoinFailure)
return ok
}
// ErrMemberNotFound indicates a failure to find a member with the
// given search criterion.
type ErrMemberNotFound struct {
byRank *ranklist.Rank
byUUID *uuid.UUID
byAddr *net.TCPAddr
}
func (err *ErrMemberNotFound) Error() string {
switch {
case err.byRank != nil:
return fmt.Sprintf("unable to find member with rank %d", *err.byRank)
case err.byUUID != nil:
return fmt.Sprintf("unable to find member with uuid %s", *err.byUUID)
case err.byAddr != nil:
return fmt.Sprintf("unable to find member with addr %s", err.byAddr)
default:
return "unable to find member"
}
}
// IsMemberNotFound returns a boolean indicating whether or not the
// supplied error is an instance of ErrMemberNotFound.
func IsMemberNotFound(err error) bool {
_, ok := errors.Cause(err).(*ErrMemberNotFound)
return ok
}
func ErrMemberRankNotFound(r ranklist.Rank) *ErrMemberNotFound {
return &ErrMemberNotFound{byRank: &r}
}
func ErrMemberUUIDNotFound(u uuid.UUID) *ErrMemberNotFound {
return &ErrMemberNotFound{byUUID: &u}
}
func ErrMemberAddrNotFound(a *net.TCPAddr) *ErrMemberNotFound {
return &ErrMemberNotFound{byAddr: a}
}
// ErrPoolNotFound indicates a failure to find a pool service with the
// given search criterion.
type ErrPoolNotFound struct {
byRank *ranklist.Rank
byUUID *uuid.UUID
byLabel *string
}
func (err *ErrPoolNotFound) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
Rank *ranklist.Rank
UUID *uuid.UUID
Label *string
}{
Rank: err.byRank,
UUID: err.byUUID,
Label: err.byLabel,
})
}
func (err *ErrPoolNotFound) UnmarshalJSON(data []byte) error {
if err == nil {
return nil
}
var tmp struct {
Rank *ranklist.Rank
UUID *uuid.UUID
Label *string
}
if err := json.Unmarshal(data, &tmp); err != nil {
return err
}
err.byRank = tmp.Rank
err.byUUID = tmp.UUID
err.byLabel = tmp.Label
return nil
}
func (err *ErrPoolNotFound) Error() string {
switch {
case err.byRank != nil:
return fmt.Sprintf("unable to find pool service with rank %d", *err.byRank)
case err.byUUID != nil:
return fmt.Sprintf("unable to find pool service with uuid %s", *err.byUUID)
case err.byLabel != nil:
return fmt.Sprintf("unable to find pool service with label %q", *err.byLabel)
default:
return "unable to find pool service"
}
}
// IsPoolNotFound returns a boolean indicating whether or not the
// supplied error is an instance of ErrPoolNotFound.
func IsPoolNotFound(err error) bool {
_, ok := errors.Cause(err).(*ErrPoolNotFound)
return ok
}
func ErrPoolRankNotFound(r ranklist.Rank) *ErrPoolNotFound {
return &ErrPoolNotFound{byRank: &r}
}
func ErrPoolUUIDNotFound(u uuid.UUID) *ErrPoolNotFound {
return &ErrPoolNotFound{byUUID: &u}
}
func ErrPoolLabelNotFound(l string) *ErrPoolNotFound {
return &ErrPoolNotFound{byLabel: &l}
}
type errSystemAttrNotFound struct {
key string
}
func (err *errSystemAttrNotFound) Error() string {
return fmt.Sprintf("unable to find system attribute with key %q", err.key)
}
func ErrSystemAttrNotFound(key string) *errSystemAttrNotFound {
return &errSystemAttrNotFound{key: key}
}
func IsErrSystemAttrNotFound(err error) bool {
_, ok := errors.Cause(err).(*errSystemAttrNotFound)
return ok
}