errors.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. // Copyright (c) 2016, 2018, 2020, Oracle and/or its affiliates. All rights reserved.
  2. // This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license.
  3. package common
  4. import (
  5. "encoding/json"
  6. "fmt"
  7. "io/ioutil"
  8. "net/http"
  9. )
  10. // ServiceError models all potential errors generated the service call
  11. type ServiceError interface {
  12. // The http status code of the error
  13. GetHTTPStatusCode() int
  14. // The human-readable error string as sent by the service
  15. GetMessage() string
  16. // A short error code that defines the error, meant for programmatic parsing.
  17. // See https://docs.cloud.oracle.com/Content/API/References/apierrors.htm
  18. GetCode() string
  19. // Unique Oracle-assigned identifier for the request.
  20. // If you need to contact Oracle about a particular request, please provide the request ID.
  21. GetOpcRequestID() string
  22. }
  23. type servicefailure struct {
  24. StatusCode int
  25. Code string `json:"code,omitempty"`
  26. Message string `json:"message,omitempty"`
  27. OpcRequestID string `json:"opc-request-id"`
  28. }
  29. func newServiceFailureFromResponse(response *http.Response) error {
  30. var err error
  31. se := servicefailure{
  32. StatusCode: response.StatusCode,
  33. Code: "BadErrorResponse",
  34. OpcRequestID: response.Header.Get("opc-request-id")}
  35. //If there is an error consume the body, entirely
  36. body, err := ioutil.ReadAll(response.Body)
  37. if err != nil {
  38. se.Message = fmt.Sprintf("The body of the response was not readable, due to :%s", err.Error())
  39. return se
  40. }
  41. err = json.Unmarshal(body, &se)
  42. if err != nil {
  43. Debugf("Error response could not be parsed due to: %s", err.Error())
  44. se.Message = fmt.Sprintf("Failed to parse json from response body due to: %s. With response body %s.", err.Error(), string(body[:]))
  45. return se
  46. }
  47. return se
  48. }
  49. func (se servicefailure) Error() string {
  50. return fmt.Sprintf("Service error:%s. %s. http status code: %d. Opc request id: %s",
  51. se.Code, se.Message, se.StatusCode, se.OpcRequestID)
  52. }
  53. func (se servicefailure) GetHTTPStatusCode() int {
  54. return se.StatusCode
  55. }
  56. func (se servicefailure) GetMessage() string {
  57. return se.Message
  58. }
  59. func (se servicefailure) GetCode() string {
  60. return se.Code
  61. }
  62. func (se servicefailure) GetOpcRequestID() string {
  63. return se.OpcRequestID
  64. }
  65. // IsServiceError returns false if the error is not service side, otherwise true
  66. // additionally it returns an interface representing the ServiceError
  67. func IsServiceError(err error) (failure ServiceError, ok bool) {
  68. failure, ok = err.(servicefailure)
  69. return
  70. }
  71. type deadlineExceededByBackoffError struct{}
  72. func (deadlineExceededByBackoffError) Error() string {
  73. return "now() + computed backoff duration exceeds request deadline"
  74. }
  75. // DeadlineExceededByBackoff is the error returned by Call() when GetNextDuration() returns a time.Duration that would
  76. // force the user to wait past the request deadline before re-issuing a request. This enables us to exit early, since
  77. // we cannot succeed based on the configured retry policy.
  78. var DeadlineExceededByBackoff error = deadlineExceededByBackoffError{}