1package gophercloud 2 3import ( 4 "fmt" 5 "net/http" 6 "strings" 7) 8 9// BaseError is an error type that all other error types embed. 10type BaseError struct { 11 DefaultErrString string 12 Info string 13} 14 15func (e BaseError) Error() string { 16 e.DefaultErrString = "An error occurred while executing a Gophercloud request." 17 return e.choseErrString() 18} 19 20func (e BaseError) choseErrString() string { 21 if e.Info != "" { 22 return e.Info 23 } 24 return e.DefaultErrString 25} 26 27// ErrMissingInput is the error when input is required in a particular 28// situation but not provided by the user 29type ErrMissingInput struct { 30 BaseError 31 Argument string 32} 33 34func (e ErrMissingInput) Error() string { 35 e.DefaultErrString = fmt.Sprintf("Missing input for argument [%s]", e.Argument) 36 return e.choseErrString() 37} 38 39// ErrInvalidInput is an error type used for most non-HTTP Gophercloud errors. 40type ErrInvalidInput struct { 41 ErrMissingInput 42 Value interface{} 43} 44 45func (e ErrInvalidInput) Error() string { 46 e.DefaultErrString = fmt.Sprintf("Invalid input provided for argument [%s]: [%+v]", e.Argument, e.Value) 47 return e.choseErrString() 48} 49 50// ErrMissingEnvironmentVariable is the error when environment variable is required 51// in a particular situation but not provided by the user 52type ErrMissingEnvironmentVariable struct { 53 BaseError 54 EnvironmentVariable string 55} 56 57func (e ErrMissingEnvironmentVariable) Error() string { 58 e.DefaultErrString = fmt.Sprintf("Missing environment variable [%s]", e.EnvironmentVariable) 59 return e.choseErrString() 60} 61 62// ErrMissingAnyoneOfEnvironmentVariables is the error when anyone of the environment variables 63// is required in a particular situation but not provided by the user 64type ErrMissingAnyoneOfEnvironmentVariables struct { 65 BaseError 66 EnvironmentVariables []string 67} 68 69func (e ErrMissingAnyoneOfEnvironmentVariables) Error() string { 70 e.DefaultErrString = fmt.Sprintf( 71 "Missing one of the following environment variables [%s]", 72 strings.Join(e.EnvironmentVariables, ", "), 73 ) 74 return e.choseErrString() 75} 76 77// ErrUnexpectedResponseCode is returned by the Request method when a response code other than 78// those listed in OkCodes is encountered. 79type ErrUnexpectedResponseCode struct { 80 BaseError 81 URL string 82 Method string 83 Expected []int 84 Actual int 85 Body []byte 86 ResponseHeader http.Header 87} 88 89func (e ErrUnexpectedResponseCode) Error() string { 90 e.DefaultErrString = fmt.Sprintf( 91 "Expected HTTP response code %v when accessing [%s %s], but got %d instead\n%s", 92 e.Expected, e.Method, e.URL, e.Actual, e.Body, 93 ) 94 return e.choseErrString() 95} 96 97// GetStatusCode returns the actual status code of the error. 98func (e ErrUnexpectedResponseCode) GetStatusCode() int { 99 return e.Actual 100} 101 102// StatusCodeError is a convenience interface to easily allow access to the 103// status code field of the various ErrDefault* types. 104// 105// By using this interface, you only have to make a single type cast of 106// the returned error to err.(StatusCodeError) and then call GetStatusCode() 107// instead of having a large switch statement checking for each of the 108// ErrDefault* types. 109type StatusCodeError interface { 110 Error() string 111 GetStatusCode() int 112} 113 114// ErrDefault400 is the default error type returned on a 400 HTTP response code. 115type ErrDefault400 struct { 116 ErrUnexpectedResponseCode 117} 118 119// ErrDefault401 is the default error type returned on a 401 HTTP response code. 120type ErrDefault401 struct { 121 ErrUnexpectedResponseCode 122} 123 124// ErrDefault403 is the default error type returned on a 403 HTTP response code. 125type ErrDefault403 struct { 126 ErrUnexpectedResponseCode 127} 128 129// ErrDefault404 is the default error type returned on a 404 HTTP response code. 130type ErrDefault404 struct { 131 ErrUnexpectedResponseCode 132} 133 134// ErrDefault405 is the default error type returned on a 405 HTTP response code. 135type ErrDefault405 struct { 136 ErrUnexpectedResponseCode 137} 138 139// ErrDefault408 is the default error type returned on a 408 HTTP response code. 140type ErrDefault408 struct { 141 ErrUnexpectedResponseCode 142} 143 144// ErrDefault409 is the default error type returned on a 409 HTTP response code. 145type ErrDefault409 struct { 146 ErrUnexpectedResponseCode 147} 148 149// ErrDefault429 is the default error type returned on a 429 HTTP response code. 150type ErrDefault429 struct { 151 ErrUnexpectedResponseCode 152} 153 154// ErrDefault500 is the default error type returned on a 500 HTTP response code. 155type ErrDefault500 struct { 156 ErrUnexpectedResponseCode 157} 158 159// ErrDefault503 is the default error type returned on a 503 HTTP response code. 160type ErrDefault503 struct { 161 ErrUnexpectedResponseCode 162} 163 164func (e ErrDefault400) Error() string { 165 e.DefaultErrString = fmt.Sprintf( 166 "Bad request with: [%s %s], error message: %s", 167 e.Method, e.URL, e.Body, 168 ) 169 return e.choseErrString() 170} 171func (e ErrDefault401) Error() string { 172 return "Authentication failed" 173} 174func (e ErrDefault403) Error() string { 175 e.DefaultErrString = fmt.Sprintf( 176 "Request forbidden: [%s %s], error message: %s", 177 e.Method, e.URL, e.Body, 178 ) 179 return e.choseErrString() 180} 181func (e ErrDefault404) Error() string { 182 return "Resource not found" 183} 184func (e ErrDefault405) Error() string { 185 return "Method not allowed" 186} 187func (e ErrDefault408) Error() string { 188 return "The server timed out waiting for the request" 189} 190func (e ErrDefault429) Error() string { 191 return "Too many requests have been sent in a given amount of time. Pause" + 192 " requests, wait up to one minute, and try again." 193} 194func (e ErrDefault500) Error() string { 195 return "Internal Server Error" 196} 197func (e ErrDefault503) Error() string { 198 return "The service is currently unable to handle the request due to a temporary" + 199 " overloading or maintenance. This is a temporary condition. Try again later." 200} 201 202// Err400er is the interface resource error types implement to override the error message 203// from a 400 error. 204type Err400er interface { 205 Error400(ErrUnexpectedResponseCode) error 206} 207 208// Err401er is the interface resource error types implement to override the error message 209// from a 401 error. 210type Err401er interface { 211 Error401(ErrUnexpectedResponseCode) error 212} 213 214// Err403er is the interface resource error types implement to override the error message 215// from a 403 error. 216type Err403er interface { 217 Error403(ErrUnexpectedResponseCode) error 218} 219 220// Err404er is the interface resource error types implement to override the error message 221// from a 404 error. 222type Err404er interface { 223 Error404(ErrUnexpectedResponseCode) error 224} 225 226// Err405er is the interface resource error types implement to override the error message 227// from a 405 error. 228type Err405er interface { 229 Error405(ErrUnexpectedResponseCode) error 230} 231 232// Err408er is the interface resource error types implement to override the error message 233// from a 408 error. 234type Err408er interface { 235 Error408(ErrUnexpectedResponseCode) error 236} 237 238// Err409er is the interface resource error types implement to override the error message 239// from a 409 error. 240type Err409er interface { 241 Error409(ErrUnexpectedResponseCode) error 242} 243 244// Err429er is the interface resource error types implement to override the error message 245// from a 429 error. 246type Err429er interface { 247 Error429(ErrUnexpectedResponseCode) error 248} 249 250// Err500er is the interface resource error types implement to override the error message 251// from a 500 error. 252type Err500er interface { 253 Error500(ErrUnexpectedResponseCode) error 254} 255 256// Err503er is the interface resource error types implement to override the error message 257// from a 503 error. 258type Err503er interface { 259 Error503(ErrUnexpectedResponseCode) error 260} 261 262// ErrTimeOut is the error type returned when an operations times out. 263type ErrTimeOut struct { 264 BaseError 265} 266 267func (e ErrTimeOut) Error() string { 268 e.DefaultErrString = "A time out occurred" 269 return e.choseErrString() 270} 271 272// ErrUnableToReauthenticate is the error type returned when reauthentication fails. 273type ErrUnableToReauthenticate struct { 274 BaseError 275 ErrOriginal error 276} 277 278func (e ErrUnableToReauthenticate) Error() string { 279 e.DefaultErrString = fmt.Sprintf("Unable to re-authenticate: %s", e.ErrOriginal) 280 return e.choseErrString() 281} 282 283// ErrErrorAfterReauthentication is the error type returned when reauthentication 284// succeeds, but an error occurs afterword (usually an HTTP error). 285type ErrErrorAfterReauthentication struct { 286 BaseError 287 ErrOriginal error 288} 289 290func (e ErrErrorAfterReauthentication) Error() string { 291 e.DefaultErrString = fmt.Sprintf("Successfully re-authenticated, but got error executing request: %s", e.ErrOriginal) 292 return e.choseErrString() 293} 294 295// ErrServiceNotFound is returned when no service in a service catalog matches 296// the provided EndpointOpts. This is generally returned by provider service 297// factory methods like "NewComputeV2()" and can mean that a service is not 298// enabled for your account. 299type ErrServiceNotFound struct { 300 BaseError 301} 302 303func (e ErrServiceNotFound) Error() string { 304 e.DefaultErrString = "No suitable service could be found in the service catalog." 305 return e.choseErrString() 306} 307 308// ErrEndpointNotFound is returned when no available endpoints match the 309// provided EndpointOpts. This is also generally returned by provider service 310// factory methods, and usually indicates that a region was specified 311// incorrectly. 312type ErrEndpointNotFound struct { 313 BaseError 314} 315 316func (e ErrEndpointNotFound) Error() string { 317 e.DefaultErrString = "No suitable endpoint could be found in the service catalog." 318 return e.choseErrString() 319} 320 321// ErrResourceNotFound is the error when trying to retrieve a resource's 322// ID by name and the resource doesn't exist. 323type ErrResourceNotFound struct { 324 BaseError 325 Name string 326 ResourceType string 327} 328 329func (e ErrResourceNotFound) Error() string { 330 e.DefaultErrString = fmt.Sprintf("Unable to find %s with name %s", e.ResourceType, e.Name) 331 return e.choseErrString() 332} 333 334// ErrMultipleResourcesFound is the error when trying to retrieve a resource's 335// ID by name and multiple resources have the user-provided name. 336type ErrMultipleResourcesFound struct { 337 BaseError 338 Name string 339 Count int 340 ResourceType string 341} 342 343func (e ErrMultipleResourcesFound) Error() string { 344 e.DefaultErrString = fmt.Sprintf("Found %d %ss matching %s", e.Count, e.ResourceType, e.Name) 345 return e.choseErrString() 346} 347 348// ErrUnexpectedType is the error when an unexpected type is encountered 349type ErrUnexpectedType struct { 350 BaseError 351 Expected string 352 Actual string 353} 354 355func (e ErrUnexpectedType) Error() string { 356 e.DefaultErrString = fmt.Sprintf("Expected %s but got %s", e.Expected, e.Actual) 357 return e.choseErrString() 358} 359 360func unacceptedAttributeErr(attribute string) string { 361 return fmt.Sprintf("The base Identity V3 API does not accept authentication by %s", attribute) 362} 363 364func redundantWithTokenErr(attribute string) string { 365 return fmt.Sprintf("%s may not be provided when authenticating with a TokenID", attribute) 366} 367 368func redundantWithUserID(attribute string) string { 369 return fmt.Sprintf("%s may not be provided when authenticating with a UserID", attribute) 370} 371 372// ErrAPIKeyProvided indicates that an APIKey was provided but can't be used. 373type ErrAPIKeyProvided struct{ BaseError } 374 375func (e ErrAPIKeyProvided) Error() string { 376 return unacceptedAttributeErr("APIKey") 377} 378 379// ErrTenantIDProvided indicates that a TenantID was provided but can't be used. 380type ErrTenantIDProvided struct{ BaseError } 381 382func (e ErrTenantIDProvided) Error() string { 383 return unacceptedAttributeErr("TenantID") 384} 385 386// ErrTenantNameProvided indicates that a TenantName was provided but can't be used. 387type ErrTenantNameProvided struct{ BaseError } 388 389func (e ErrTenantNameProvided) Error() string { 390 return unacceptedAttributeErr("TenantName") 391} 392 393// ErrUsernameWithToken indicates that a Username was provided, but token authentication is being used instead. 394type ErrUsernameWithToken struct{ BaseError } 395 396func (e ErrUsernameWithToken) Error() string { 397 return redundantWithTokenErr("Username") 398} 399 400// ErrUserIDWithToken indicates that a UserID was provided, but token authentication is being used instead. 401type ErrUserIDWithToken struct{ BaseError } 402 403func (e ErrUserIDWithToken) Error() string { 404 return redundantWithTokenErr("UserID") 405} 406 407// ErrDomainIDWithToken indicates that a DomainID was provided, but token authentication is being used instead. 408type ErrDomainIDWithToken struct{ BaseError } 409 410func (e ErrDomainIDWithToken) Error() string { 411 return redundantWithTokenErr("DomainID") 412} 413 414// ErrDomainNameWithToken indicates that a DomainName was provided, but token authentication is being used instead.s 415type ErrDomainNameWithToken struct{ BaseError } 416 417func (e ErrDomainNameWithToken) Error() string { 418 return redundantWithTokenErr("DomainName") 419} 420 421// ErrUsernameOrUserID indicates that neither username nor userID are specified, or both are at once. 422type ErrUsernameOrUserID struct{ BaseError } 423 424func (e ErrUsernameOrUserID) Error() string { 425 return "Exactly one of Username and UserID must be provided for password authentication" 426} 427 428// ErrDomainIDWithUserID indicates that a DomainID was provided, but unnecessary because a UserID is being used. 429type ErrDomainIDWithUserID struct{ BaseError } 430 431func (e ErrDomainIDWithUserID) Error() string { 432 return redundantWithUserID("DomainID") 433} 434 435// ErrDomainNameWithUserID indicates that a DomainName was provided, but unnecessary because a UserID is being used. 436type ErrDomainNameWithUserID struct{ BaseError } 437 438func (e ErrDomainNameWithUserID) Error() string { 439 return redundantWithUserID("DomainName") 440} 441 442// ErrDomainIDOrDomainName indicates that a username was provided, but no domain to scope it. 443// It may also indicate that both a DomainID and a DomainName were provided at once. 444type ErrDomainIDOrDomainName struct{ BaseError } 445 446func (e ErrDomainIDOrDomainName) Error() string { 447 return "You must provide exactly one of DomainID or DomainName to authenticate by Username" 448} 449 450// ErrMissingPassword indicates that no password was provided and no token is available. 451type ErrMissingPassword struct{ BaseError } 452 453func (e ErrMissingPassword) Error() string { 454 return "You must provide a password to authenticate" 455} 456 457// ErrScopeDomainIDOrDomainName indicates that a domain ID or Name was required in a Scope, but not present. 458type ErrScopeDomainIDOrDomainName struct{ BaseError } 459 460func (e ErrScopeDomainIDOrDomainName) Error() string { 461 return "You must provide exactly one of DomainID or DomainName in a Scope with ProjectName" 462} 463 464// ErrScopeProjectIDOrProjectName indicates that both a ProjectID and a ProjectName were provided in a Scope. 465type ErrScopeProjectIDOrProjectName struct{ BaseError } 466 467func (e ErrScopeProjectIDOrProjectName) Error() string { 468 return "You must provide at most one of ProjectID or ProjectName in a Scope" 469} 470 471// ErrScopeProjectIDAlone indicates that a ProjectID was provided with other constraints in a Scope. 472type ErrScopeProjectIDAlone struct{ BaseError } 473 474func (e ErrScopeProjectIDAlone) Error() string { 475 return "ProjectID must be supplied alone in a Scope" 476} 477 478// ErrScopeEmpty indicates that no credentials were provided in a Scope. 479type ErrScopeEmpty struct{ BaseError } 480 481func (e ErrScopeEmpty) Error() string { 482 return "You must provide either a Project or Domain in a Scope" 483} 484 485// ErrAppCredMissingSecret indicates that no Application Credential Secret was provided with Application Credential ID or Name 486type ErrAppCredMissingSecret struct{ BaseError } 487 488func (e ErrAppCredMissingSecret) Error() string { 489 return "You must provide an Application Credential Secret" 490} 491