-
Notifications
You must be signed in to change notification settings - Fork 12
/
error.go
185 lines (167 loc) · 4.24 KB
/
error.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
package ovirtsdk
import (
"bytes"
"errors"
"fmt"
"net/http"
)
type baseError struct {
// Code contains the HTTP status code that caused this error.
Code int
// Msg contains the text message that should be printed to the user.
Msg string
}
// Error returns the error string.
func (b *baseError) Error() string {
return b.Msg
}
// AuthError indicates that an authentication or authorization
// problem happened, like incorrect user name, incorrect password, or
// missing permissions.
type AuthError struct {
baseError
}
// Conflict error indicates that the operation failed because of a conflict.
// For example, another operation blocks the operation from being executed.
type ConflictError struct {
baseError
}
// NotFoundError indicates that an object can't be found.
type NotFoundError struct {
baseError
}
// ResponseParseError indicates that the response from the oVirt Engine could not be parsed.
type ResponseParseError struct {
baseError
cause error
body []byte
}
// Unwrap returns the root cause of this error.
func (r *ResponseParseError) Unwrap() error {
return r.cause
}
// Body returns the HTTP response body that caused the parse error.
func (r *ResponseParseError) Body() []byte {
return r.body
}
// CheckFault takes a failed HTTP response (non-200) and extracts the fault from it.
func CheckFault(resBytes []byte, response *http.Response) error {
// Process empty response body
if len(resBytes) == 0 {
return BuildError(response, nil)
}
reader := NewXMLReader(resBytes)
fault, err := XMLFaultReadOne(reader, nil, "")
if err != nil {
return &ResponseParseError{
baseError{
Code: response.StatusCode,
Msg: fmt.Sprintf(
"failed to parse oVirt Engine fault response: %s (%v)",
resBytes,
err,
),
},
err,
resBytes,
}
}
if fault != nil || response.StatusCode >= 400 {
return BuildError(response, fault)
}
return errors.New("unknown error")
}
// CheckAction checks if response contains an Action instance
func CheckAction(resBytes []byte, response *http.Response) (*Action, error) {
// Process empty response body
if len(resBytes) == 0 {
return nil, BuildError(response, nil)
}
var tagNotMatchError XMLTagNotMatchError
faultreader := NewXMLReader(resBytes)
fault, err := XMLFaultReadOne(faultreader, nil, "")
if err != nil {
// If the tag mismatches, return the err
if !errors.As(err, &tagNotMatchError) {
return nil, &ResponseParseError{
baseError{
Code: response.StatusCode,
Msg: fmt.Sprintf(
"failed to parse oVirt Engine response: %s (%v)",
resBytes,
err,
),
},
err,
resBytes,
}
}
}
if fault != nil {
return nil, BuildError(response, fault)
}
actionreader := NewXMLReader(resBytes)
action, err := XMLActionReadOne(actionreader, nil, "")
if err != nil {
// If the tag mismatches, return the err
if errors.As(err, &tagNotMatchError) {
return nil, err
}
}
if action != nil {
if afault, ok := action.Fault(); ok {
return nil, BuildError(response, afault)
}
return action, nil
}
return nil, nil
}
// BuildError constructs error
func BuildError(response *http.Response, fault *Fault) error {
var buffer bytes.Buffer
if fault != nil {
if reason, ok := fault.Reason(); ok {
if buffer.Len() > 0 {
buffer.WriteString(" ")
}
buffer.WriteString(fmt.Sprintf("Fault reason is \"%s\".", reason))
}
if detail, ok := fault.Detail(); ok {
if buffer.Len() > 0 {
buffer.WriteString(" ")
}
buffer.WriteString(fmt.Sprintf("Fault detail is \"%s\".", detail))
}
}
if response != nil {
if buffer.Len() > 0 {
buffer.WriteString(" ")
}
buffer.WriteString(fmt.Sprintf("HTTP response code is \"%d\".", response.StatusCode))
buffer.WriteString(" ")
buffer.WriteString(fmt.Sprintf("HTTP response message is \"%s\".", response.Status))
if Contains(response.StatusCode, []int{401, 403}) {
return &AuthError{
baseError{
response.StatusCode,
buffer.String(),
},
}
} else if response.StatusCode == 404 {
return &NotFoundError{
baseError{
response.StatusCode,
buffer.String(),
},
}
} else if response.StatusCode == 409 {
return &ConflictError{
baseError{
response.StatusCode,
buffer.String(),
},
}
}
}
return errors.New(buffer.String())
}