-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy patherrors.go
More file actions
228 lines (199 loc) · 7.06 KB
/
errors.go
File metadata and controls
228 lines (199 loc) · 7.06 KB
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
package deis
import (
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
"strings"
)
const (
// formatErrUnknown is used to create an dynamic error if no error matches
formatErrUnknown = "Unknown Error (%d): %s"
// fieldReqMsg is API error stating a field is required.
fieldReqMsg = "This field is required."
invalidUserMsg = "Enter a valid username. This value may contain only letters, numbers and @/./+/-/_ characters."
failedLoginMsg = "Unable to log in with provided credentials."
invalidAppNameMsg = "App name can only contain a-z (lowercase), 0-9 and hypens"
invalidNameMsg = "Can only contain a-z (lowercase), 0-9 and hypens"
invalidCertMsg = "Could not load certificate"
invalidPodMsg = "does not exist in application"
invalidDomainMsg = "Hostname does not look valid."
invalidVersionMsg = "version cannot be below 0"
invalidKeyMsg = "Key contains invalid base64 chars"
duplicateUserMsg = "A user with that username already exists."
invalidEmailMsg = "Enter a valid email address."
invalidTagMsg = "No nodes matched the provided labels"
)
var (
// ErrNotFound is returned when the server returns a 404.
ErrNotFound = errors.New("Not Found")
// ErrServerError is returned when the server returns a 500.
ErrServerError = errors.New("Internal Server Error")
// ErrMethodNotAllowed is thrown when using a unsupposrted method.
// This should not come up unless there in an bug in the SDK.
ErrMethodNotAllowed = errors.New("Method Not Allowed")
// ErrInvalidUsername is returned when the user specifies an invalid or missing username.
ErrInvalidUsername = errors.New(invalidUserMsg)
// ErrDuplicateUsername is returned when trying to register a user that already exists.
ErrDuplicateUsername = errors.New(duplicateUserMsg)
// ErrMissingPassword is returned when a password is not sent with the request.
ErrMissingPassword = errors.New("A Password is required")
// ErrLogin is returned when the api cannot login fails with provided username and password
ErrLogin = errors.New(failedLoginMsg)
// ErrUnauthorized is given when the API returns a 401.
ErrUnauthorized = errors.New("Unauthorized: Missing or Invalid Token")
// ErrInvalidAppName is returned when the user specifies an invalid app name.
ErrInvalidAppName = errors.New(invalidAppNameMsg)
// ErrConflict is returned when the API returns a 409.
ErrConflict = errors.New("This action could not be completed due to a conflict.")
// ErrForbidden is returned when the API returns a 403.
ErrForbidden = errors.New("You do not have permission to perform this action.")
// ErrMissingKey is returned when a key is not sent with the request.
ErrMissingKey = errors.New("A key is required")
// ErrInvalidName is returned when a name is invalid or missing.
ErrInvalidName = errors.New(invalidNameMsg)
// ErrInvalidCertificate is returned when a certififate is missing or invalid
ErrInvalidCertificate = errors.New(invalidCertMsg)
// ErrPodNotFound is returned when a pod type is not Found
ErrPodNotFound = errors.New("Pod not found in application")
// ErrInvalidDomain is returned when a domain is missing or invalid
ErrInvalidDomain = errors.New(invalidDomainMsg)
// ErrInvalidImage is returned when a image is missing or invalid
ErrInvalidImage = errors.New("The given image is invalid")
// ErrInvalidVersion is returned when a version is invalid
ErrInvalidVersion = errors.New("The given version is invalid")
// ErrMissingID is returned when a ID is missing
ErrMissingID = errors.New("An id is required")
// ErrInvalidEmail is returned when a user gives an invalid email.
ErrInvalidEmail = errors.New(invalidEmailMsg)
// ErrTagNotFound is returned when no node can be found that matches the tag
ErrTagNotFound = errors.New(invalidTagMsg)
)
func checkForErrors(res *http.Response) error {
if res.StatusCode >= 200 && res.StatusCode < 400 {
return nil
}
// Fix json.Decoder bug in <go1.7
defer func() {
io.Copy(ioutil.Discard, res.Body)
res.Body.Close()
}()
switch res.StatusCode {
case 400:
bodyMap := make(map[string]interface{})
if err := json.NewDecoder(res.Body).Decode(&bodyMap); err != nil {
return unknownError(res.StatusCode, err)
}
if scanResponse(bodyMap, "username", []string{fieldReqMsg, invalidUserMsg}, true) {
return ErrInvalidUsername
}
if scanResponse(bodyMap, "username", []string{duplicateUserMsg}, true) {
return ErrDuplicateUsername
}
if scanResponse(bodyMap, "password", []string{fieldReqMsg}, true) {
return ErrMissingPassword
}
if scanResponse(bodyMap, "non_field_errors", []string{failedLoginMsg}, true) {
return ErrLogin
}
if scanResponse(bodyMap, "id", []string{invalidAppNameMsg}, true) {
return ErrInvalidAppName
}
if scanResponse(bodyMap, "key", []string{fieldReqMsg}, true) {
return ErrMissingKey
}
if scanResponse(bodyMap, "public", []string{fieldReqMsg, invalidKeyMsg}, true) {
return ErrMissingKey
}
if scanResponse(bodyMap, "certificate", []string{fieldReqMsg, invalidCertMsg}, false) {
return ErrInvalidCertificate
}
if scanResponse(bodyMap, "name", []string{fieldReqMsg, invalidNameMsg}, true) {
return ErrInvalidName
}
if scanResponse(bodyMap, "domain", []string{invalidDomainMsg}, true) {
return ErrInvalidDomain
}
if scanResponse(bodyMap, "image", []string{fieldReqMsg}, true) {
return ErrInvalidImage
}
if scanResponse(bodyMap, "id", []string{fieldReqMsg}, true) {
return ErrMissingID
}
if scanResponse(bodyMap, "email", []string{invalidEmailMsg}, true) {
return ErrInvalidEmail
}
if v, ok := bodyMap["detail"].(string); ok {
if strings.Contains(v, invalidPodMsg) {
return ErrPodNotFound
}
if strings.Contains(v, invalidVersionMsg) {
return ErrInvalidVersion
}
if strings.Contains(v, invalidTagMsg) {
return ErrTagNotFound
}
}
return unknownError(res.StatusCode, bodyMap)
case 401:
return ErrUnauthorized
case 403:
return ErrForbidden
case 404:
return ErrNotFound
case 405:
return ErrMethodNotAllowed
case 409:
return ErrConflict
case 500:
return ErrServerError
default:
out, err := ioutil.ReadAll(res.Body)
if err != nil {
return unknownError(res.StatusCode, err)
}
return unknownError(res.StatusCode, out)
}
}
func arrayContents(m map[string]interface{}, field string) []string {
if v, ok := m[field]; ok {
if a, ok := v.([]interface{}); ok {
sa := []string{}
for _, i := range a {
if s, ok := i.(string); ok {
sa = append(sa, s)
}
}
return sa
}
}
return []string{}
}
func arrayContains(search string, completeMatch bool, array []string) bool {
for _, element := range array {
if completeMatch {
if element == search {
return true
}
} else {
if strings.Contains(element, search) {
return true
}
}
}
return false
}
func unknownError(sc int, k interface{}) error {
return fmt.Errorf(formatErrUnknown, sc, k)
}
func scanResponse(
body map[string]interface{}, field string, errMsgs []string, completeMatch bool) bool {
for _, msg := range errMsgs {
if arrayContains(msg, completeMatch, arrayContents(body, field)) {
return true
}
}
return false
}