errors.go 14.2 KB
Newer Older
1 2
package gophercloud

3 4 5 6
import (
	"fmt"
	"strings"
)
7 8 9

// BaseError is an error type that all other error types embed.
type BaseError struct {
10 11
	DefaultErrString string
	Info             string
12 13
}

14
func (e BaseError) Error() string {
15 16 17 18 19 20 21 22 23
	e.DefaultErrString = "An error occurred while executing a Gophercloud request."
	return e.choseErrString()
}

func (e BaseError) choseErrString() string {
	if e.Info != "" {
		return e.Info
	}
	return e.DefaultErrString
24 25
}

26 27 28
// ErrMissingInput is the error when input is required in a particular
// situation but not provided by the user
type ErrMissingInput struct {
29
	BaseError
30 31 32
	Argument string
}

33
func (e ErrMissingInput) Error() string {
34 35
	e.DefaultErrString = fmt.Sprintf("Missing input for argument [%s]", e.Argument)
	return e.choseErrString()
36 37
}

38 39 40 41 42 43 44
// ErrInvalidInput is an error type used for most non-HTTP Gophercloud errors.
type ErrInvalidInput struct {
	ErrMissingInput
	Value interface{}
}

func (e ErrInvalidInput) Error() string {
45 46
	e.DefaultErrString = fmt.Sprintf("Invalid input provided for argument [%s]: [%+v]", e.Argument, e.Value)
	return e.choseErrString()
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
// ErrMissingEnvironmentVariable is the error when environment variable is required
// in a particular situation but not provided by the user
type ErrMissingEnvironmentVariable struct {
	BaseError
	EnvironmentVariable string
}

func (e ErrMissingEnvironmentVariable) Error() string {
	e.DefaultErrString = fmt.Sprintf("Missing environment variable [%s]", e.EnvironmentVariable)
	return e.choseErrString()
}

// ErrMissingAnyoneOfEnvironmentVariables is the error when anyone of the environment variables
// is required in a particular situation but not provided by the user
type ErrMissingAnyoneOfEnvironmentVariables struct {
	BaseError
	EnvironmentVariables []string
}

func (e ErrMissingAnyoneOfEnvironmentVariables) Error() string {
	e.DefaultErrString = fmt.Sprintf(
		"Missing one of the following environment variables [%s]",
		strings.Join(e.EnvironmentVariables, ", "),
	)
	return e.choseErrString()
}

76 77 78
// ErrUnexpectedResponseCode is returned by the Request method when a response code other than
// those listed in OkCodes is encountered.
type ErrUnexpectedResponseCode struct {
79
	BaseError
80 81 82 83 84 85 86
	URL      string
	Method   string
	Expected []int
	Actual   int
	Body     []byte
}

87 88
func (e ErrUnexpectedResponseCode) Error() string {
	e.DefaultErrString = fmt.Sprintf(
89
		"Expected HTTP response code %v when accessing [%s %s], but got %d instead\n%s",
90
		e.Expected, e.Method, e.URL, e.Actual, e.Body,
91
	)
92
	return e.choseErrString()
93 94
}

95
// ErrDefault400 is the default error type returned on a 400 HTTP response code.
96
type ErrDefault400 struct {
97
	ErrUnexpectedResponseCode
98
}
99 100

// ErrDefault401 is the default error type returned on a 401 HTTP response code.
101
type ErrDefault401 struct {
102
	ErrUnexpectedResponseCode
103
}
104

105 106 107 108 109
// ErrDefault403 is the default error type returned on a 403 HTTP response code.
type ErrDefault403 struct {
	ErrUnexpectedResponseCode
}

110
// ErrDefault404 is the default error type returned on a 404 HTTP response code.
111
type ErrDefault404 struct {
112
	ErrUnexpectedResponseCode
113
}
114 115

// ErrDefault405 is the default error type returned on a 405 HTTP response code.
116
type ErrDefault405 struct {
117
	ErrUnexpectedResponseCode
118
}
119 120

// ErrDefault408 is the default error type returned on a 408 HTTP response code.
121
type ErrDefault408 struct {
122
	ErrUnexpectedResponseCode
123
}
124 125

// ErrDefault429 is the default error type returned on a 429 HTTP response code.
126
type ErrDefault429 struct {
127
	ErrUnexpectedResponseCode
128
}
129 130

// ErrDefault500 is the default error type returned on a 500 HTTP response code.
131
type ErrDefault500 struct {
132
	ErrUnexpectedResponseCode
133
}
134 135

// ErrDefault503 is the default error type returned on a 503 HTTP response code.
136
type ErrDefault503 struct {
137
	ErrUnexpectedResponseCode
138 139 140
}

func (e ErrDefault400) Error() string {
141 142 143 144 145
	e.DefaultErrString = fmt.Sprintf(
		"Bad request with: [%s %s], error message: %s",
		e.Method, e.URL, e.Body,
	)
	return e.choseErrString()
146 147 148 149
}
func (e ErrDefault401) Error() string {
	return "Authentication failed"
}
150 151 152 153 154 155 156
func (e ErrDefault403) Error() string {
	e.DefaultErrString = fmt.Sprintf(
		"Request forbidden: [%s %s], error message: %s",
		e.Method, e.URL, e.Body,
	)
	return e.choseErrString()
}
157 158 159 160 161 162 163 164 165 166
func (e ErrDefault404) Error() string {
	return "Resource not found"
}
func (e ErrDefault405) Error() string {
	return "Method not allowed"
}
func (e ErrDefault408) Error() string {
	return "The server timed out waiting for the request"
}
func (e ErrDefault429) Error() string {
167 168
	return "Too many requests have been sent in a given amount of time. Pause" +
		" requests, wait up to one minute, and try again."
169 170 171 172 173
}
func (e ErrDefault500) Error() string {
	return "Internal Server Error"
}
func (e ErrDefault503) Error() string {
174 175
	return "The service is currently unable to handle the request due to a temporary" +
		" overloading or maintenance. This is a temporary condition. Try again later."
176 177 178 179 180
}

// Err400er is the interface resource error types implement to override the error message
// from a 400 error.
type Err400er interface {
181
	Error400(ErrUnexpectedResponseCode) error
182 183 184 185 186
}

// Err401er is the interface resource error types implement to override the error message
// from a 401 error.
type Err401er interface {
187
	Error401(ErrUnexpectedResponseCode) error
188 189
}

190 191 192 193 194 195
// Err403er is the interface resource error types implement to override the error message
// from a 403 error.
type Err403er interface {
	Error403(ErrUnexpectedResponseCode) error
}

196 197 198
// Err404er is the interface resource error types implement to override the error message
// from a 404 error.
type Err404er interface {
199
	Error404(ErrUnexpectedResponseCode) error
200 201 202 203 204
}

// Err405er is the interface resource error types implement to override the error message
// from a 405 error.
type Err405er interface {
205
	Error405(ErrUnexpectedResponseCode) error
206 207 208 209 210
}

// Err408er is the interface resource error types implement to override the error message
// from a 408 error.
type Err408er interface {
211
	Error408(ErrUnexpectedResponseCode) error
212 213 214 215 216
}

// Err429er is the interface resource error types implement to override the error message
// from a 429 error.
type Err429er interface {
217
	Error429(ErrUnexpectedResponseCode) error
218 219 220 221 222
}

// Err500er is the interface resource error types implement to override the error message
// from a 500 error.
type Err500er interface {
223
	Error500(ErrUnexpectedResponseCode) error
224 225 226 227 228
}

// Err503er is the interface resource error types implement to override the error message
// from a 503 error.
type Err503er interface {
229
	Error503(ErrUnexpectedResponseCode) error
230 231
}

232
// ErrTimeOut is the error type returned when an operations times out.
233
type ErrTimeOut struct {
234
	BaseError
235 236
}

237
func (e ErrTimeOut) Error() string {
238 239
	e.DefaultErrString = "A time out occurred"
	return e.choseErrString()
240 241
}

242
// ErrUnableToReauthenticate is the error type returned when reauthentication fails.
243
type ErrUnableToReauthenticate struct {
244
	BaseError
245
	ErrOriginal error
246 247
}

248
func (e ErrUnableToReauthenticate) Error() string {
249 250
	e.DefaultErrString = fmt.Sprintf("Unable to re-authenticate: %s", e.ErrOriginal)
	return e.choseErrString()
251 252
}

253 254
// ErrErrorAfterReauthentication is the error type returned when reauthentication
// succeeds, but an error occurs afterword (usually an HTTP error).
255
type ErrErrorAfterReauthentication struct {
256
	BaseError
257
	ErrOriginal error
258 259
}

260
func (e ErrErrorAfterReauthentication) Error() string {
261 262
	e.DefaultErrString = fmt.Sprintf("Successfully re-authenticated, but got error executing request: %s", e.ErrOriginal)
	return e.choseErrString()
263 264 265 266 267 268 269
}

// ErrServiceNotFound is returned when no service in a service catalog matches
// the provided EndpointOpts. This is generally returned by provider service
// factory methods like "NewComputeV2()" and can mean that a service is not
// enabled for your account.
type ErrServiceNotFound struct {
270
	BaseError
271 272
}

273
func (e ErrServiceNotFound) Error() string {
274 275
	e.DefaultErrString = "No suitable service could be found in the service catalog."
	return e.choseErrString()
276 277 278 279 280 281 282
}

// ErrEndpointNotFound is returned when no available endpoints match the
// provided EndpointOpts. This is also generally returned by provider service
// factory methods, and usually indicates that a region was specified
// incorrectly.
type ErrEndpointNotFound struct {
283
	BaseError
284 285
}

286
func (e ErrEndpointNotFound) Error() string {
287 288
	e.DefaultErrString = "No suitable endpoint could be found in the service catalog."
	return e.choseErrString()
289
}
290 291 292 293

// ErrResourceNotFound is the error when trying to retrieve a resource's
// ID by name and the resource doesn't exist.
type ErrResourceNotFound struct {
294
	BaseError
295
	Name         string
296 297 298
	ResourceType string
}

299
func (e ErrResourceNotFound) Error() string {
300 301
	e.DefaultErrString = fmt.Sprintf("Unable to find %s with name %s", e.ResourceType, e.Name)
	return e.choseErrString()
302 303 304 305 306
}

// ErrMultipleResourcesFound is the error when trying to retrieve a resource's
// ID by name and multiple resources have the user-provided name.
type ErrMultipleResourcesFound struct {
307
	BaseError
308 309 310 311 312
	Name         string
	Count        int
	ResourceType string
}

313
func (e ErrMultipleResourcesFound) Error() string {
314 315
	e.DefaultErrString = fmt.Sprintf("Found %d %ss matching %s", e.Count, e.ResourceType, e.Name)
	return e.choseErrString()
316
}
Jon Perritt's avatar
Jon Perritt committed
317 318 319 320 321 322 323 324 325

// ErrUnexpectedType is the error when an unexpected type is encountered
type ErrUnexpectedType struct {
	BaseError
	Expected string
	Actual   string
}

func (e ErrUnexpectedType) Error() string {
326 327
	e.DefaultErrString = fmt.Sprintf("Expected %s but got %s", e.Expected, e.Actual)
	return e.choseErrString()
Jon Perritt's avatar
Jon Perritt committed
328
}
329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453

func unacceptedAttributeErr(attribute string) string {
	return fmt.Sprintf("The base Identity V3 API does not accept authentication by %s", attribute)
}

func redundantWithTokenErr(attribute string) string {
	return fmt.Sprintf("%s may not be provided when authenticating with a TokenID", attribute)
}

func redundantWithUserID(attribute string) string {
	return fmt.Sprintf("%s may not be provided when authenticating with a UserID", attribute)
}

// ErrAPIKeyProvided indicates that an APIKey was provided but can't be used.
type ErrAPIKeyProvided struct{ BaseError }

func (e ErrAPIKeyProvided) Error() string {
	return unacceptedAttributeErr("APIKey")
}

// ErrTenantIDProvided indicates that a TenantID was provided but can't be used.
type ErrTenantIDProvided struct{ BaseError }

func (e ErrTenantIDProvided) Error() string {
	return unacceptedAttributeErr("TenantID")
}

// ErrTenantNameProvided indicates that a TenantName was provided but can't be used.
type ErrTenantNameProvided struct{ BaseError }

func (e ErrTenantNameProvided) Error() string {
	return unacceptedAttributeErr("TenantName")
}

// ErrUsernameWithToken indicates that a Username was provided, but token authentication is being used instead.
type ErrUsernameWithToken struct{ BaseError }

func (e ErrUsernameWithToken) Error() string {
	return redundantWithTokenErr("Username")
}

// ErrUserIDWithToken indicates that a UserID was provided, but token authentication is being used instead.
type ErrUserIDWithToken struct{ BaseError }

func (e ErrUserIDWithToken) Error() string {
	return redundantWithTokenErr("UserID")
}

// ErrDomainIDWithToken indicates that a DomainID was provided, but token authentication is being used instead.
type ErrDomainIDWithToken struct{ BaseError }

func (e ErrDomainIDWithToken) Error() string {
	return redundantWithTokenErr("DomainID")
}

// ErrDomainNameWithToken indicates that a DomainName was provided, but token authentication is being used instead.s
type ErrDomainNameWithToken struct{ BaseError }

func (e ErrDomainNameWithToken) Error() string {
	return redundantWithTokenErr("DomainName")
}

// ErrUsernameOrUserID indicates that neither username nor userID are specified, or both are at once.
type ErrUsernameOrUserID struct{ BaseError }

func (e ErrUsernameOrUserID) Error() string {
	return "Exactly one of Username and UserID must be provided for password authentication"
}

// ErrDomainIDWithUserID indicates that a DomainID was provided, but unnecessary because a UserID is being used.
type ErrDomainIDWithUserID struct{ BaseError }

func (e ErrDomainIDWithUserID) Error() string {
	return redundantWithUserID("DomainID")
}

// ErrDomainNameWithUserID indicates that a DomainName was provided, but unnecessary because a UserID is being used.
type ErrDomainNameWithUserID struct{ BaseError }

func (e ErrDomainNameWithUserID) Error() string {
	return redundantWithUserID("DomainName")
}

// ErrDomainIDOrDomainName indicates that a username was provided, but no domain to scope it.
// It may also indicate that both a DomainID and a DomainName were provided at once.
type ErrDomainIDOrDomainName struct{ BaseError }

func (e ErrDomainIDOrDomainName) Error() string {
	return "You must provide exactly one of DomainID or DomainName to authenticate by Username"
}

// ErrMissingPassword indicates that no password was provided and no token is available.
type ErrMissingPassword struct{ BaseError }

func (e ErrMissingPassword) Error() string {
	return "You must provide a password to authenticate"
}

// ErrScopeDomainIDOrDomainName indicates that a domain ID or Name was required in a Scope, but not present.
type ErrScopeDomainIDOrDomainName struct{ BaseError }

func (e ErrScopeDomainIDOrDomainName) Error() string {
	return "You must provide exactly one of DomainID or DomainName in a Scope with ProjectName"
}

// ErrScopeProjectIDOrProjectName indicates that both a ProjectID and a ProjectName were provided in a Scope.
type ErrScopeProjectIDOrProjectName struct{ BaseError }

func (e ErrScopeProjectIDOrProjectName) Error() string {
	return "You must provide at most one of ProjectID or ProjectName in a Scope"
}

// ErrScopeProjectIDAlone indicates that a ProjectID was provided with other constraints in a Scope.
type ErrScopeProjectIDAlone struct{ BaseError }

func (e ErrScopeProjectIDAlone) Error() string {
	return "ProjectID must be supplied alone in a Scope"
}

// ErrScopeEmpty indicates that no credentials were provided in a Scope.
type ErrScopeEmpty struct{ BaseError }

func (e ErrScopeEmpty) Error() string {
	return "You must provide either a Project or Domain in a Scope"
}
454 455 456 457 458 459 460

// ErrAppCredMissingSecret indicates that no Application Credential Secret was provided with Application Credential ID or Name
type ErrAppCredMissingSecret struct{ BaseError }

func (e ErrAppCredMissingSecret) Error() string {
	return "You must provide an Application Credential Secret"
}