Skip to content

Commit b98b8fe

Browse files
authored
Releasing version 2 1 0
Releasing version 2 1 0
1 parent 2323753 commit b98b8fe

38 files changed

+2230
-54
lines changed

CHANGELOG.md

+9
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@ All notable changes to this project will be documented in this file.
44

55
The format is based on [Keep a Changelog](http://keepachangelog.com/)
66

7+
## 2.1.0 - 2018-07-26
8+
### Added
9+
- Support for the OCI Search service
10+
- Support for specifying a backup policy when creating a boot volume in the Block Storage service
11+
12+
### Fixed
13+
- OCI error is missing opc-request-id value [Github Issue 120](https://github.com/oracle/oci-go-sdk/issues/120)
14+
- Include raw http response when service error occurred
15+
716
## 2.0.0 - 2018-07-12
817
### Added
918
- Support for tagging Load Balancers in the Load Balancing service

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
DOC_SERVER_URL=https:\/\/docs.us-phoenix-1.oraclecloud.com
22

3-
GEN_TARGETS = identity core objectstorage loadbalancer database audit dns filestorage email containerengine
3+
GEN_TARGETS = identity core objectstorage loadbalancer database audit dns filestorage email containerengine resourcesearch
44
NON_GEN_TARGETS = common common/auth
55
TARGETS = $(NON_GEN_TARGETS) $(GEN_TARGETS)
66

audit/audit_client.go

+9
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ func (client AuditClient) GetConfiguration(ctx context.Context, request GetConfi
6767
}
6868
ociResponse, err = common.Retry(ctx, request, client.getConfiguration, policy)
6969
if err != nil {
70+
if ociResponse != nil {
71+
response = GetConfigurationResponse{RawResponse: ociResponse.HTTPResponse()}
72+
}
7073
return
7174
}
7275
if convertedResponse, ok := ociResponse.(GetConfigurationResponse); ok {
@@ -106,6 +109,9 @@ func (client AuditClient) ListEvents(ctx context.Context, request ListEventsRequ
106109
}
107110
ociResponse, err = common.Retry(ctx, request, client.listEvents, policy)
108111
if err != nil {
112+
if ociResponse != nil {
113+
response = ListEventsResponse{RawResponse: ociResponse.HTTPResponse()}
114+
}
109115
return
110116
}
111117
if convertedResponse, ok := ociResponse.(ListEventsResponse); ok {
@@ -145,6 +151,9 @@ func (client AuditClient) UpdateConfiguration(ctx context.Context, request Updat
145151
}
146152
ociResponse, err = common.Retry(ctx, request, client.updateConfiguration, policy)
147153
if err != nil {
154+
if ociResponse != nil {
155+
response = UpdateConfigurationResponse{RawResponse: ociResponse.HTTPResponse()}
156+
}
148157
return
149158
}
150159
if convertedResponse, ok := ociResponse.(UpdateConfigurationResponse); ok {

common/errors.go

+23-16
Original file line numberDiff line numberDiff line change
@@ -20,43 +20,46 @@ type ServiceError interface {
2020
// A short error code that defines the error, meant for programmatic parsing.
2121
// See https://docs.us-phoenix-1.oraclecloud.com/Content/API/References/apierrors.htm
2222
GetCode() string
23+
24+
// Unique Oracle-assigned identifier for the request.
25+
// If you need to contact Oracle about a particular request, please provide the request ID.
26+
GetOpcRequestID() string
2327
}
2428

2529
type servicefailure struct {
26-
StatusCode int
27-
Code string `json:"code,omitempty"`
28-
Message string `json:"message,omitempty"`
30+
StatusCode int
31+
Code string `json:"code,omitempty"`
32+
Message string `json:"message,omitempty"`
33+
OpcRequestID string `json:"opc-request-id"`
2934
}
3035

3136
func newServiceFailureFromResponse(response *http.Response) error {
3237
var err error
3338

39+
se := servicefailure{
40+
StatusCode: response.StatusCode,
41+
Code: "BadErrorResponse",
42+
OpcRequestID: response.Header.Get("opc-request-id")}
43+
3444
//If there is an error consume the body, entirely
3545
body, err := ioutil.ReadAll(response.Body)
3646
if err != nil {
37-
return servicefailure{
38-
StatusCode: response.StatusCode,
39-
Code: "BadErrorResponse",
40-
Message: fmt.Sprintf("The body of the response was not readable, due to :%s", err.Error()),
41-
}
47+
se.Message = fmt.Sprintf("The body of the response was not readable, due to :%s", err.Error())
48+
return se
4249
}
4350

44-
se := servicefailure{StatusCode: response.StatusCode}
4551
err = json.Unmarshal(body, &se)
4652
if err != nil {
4753
Debugf("Error response could not be parsed due to: %s", err.Error())
48-
return servicefailure{
49-
StatusCode: response.StatusCode,
50-
Code: "BadErrorResponse",
51-
Message: fmt.Sprintf("Error while parsing failure from response"),
52-
}
54+
se.Message = fmt.Sprintf("Failed to parse json from response body due to: %s. With response body %s.", err.Error(), string(body[:]))
55+
return se
5356
}
5457
return se
5558
}
5659

5760
func (se servicefailure) Error() string {
58-
return fmt.Sprintf("Service error:%s. %s. http status code: %d",
59-
se.Code, se.Message, se.StatusCode)
61+
return fmt.Sprintf("Service error:%s. %s. http status code: %d. Opc request id: %s",
62+
se.Code, se.Message, se.StatusCode, se.OpcRequestID)
6063
}
6164

6265
func (se servicefailure) GetHTTPStatusCode() int {
@@ -72,6 +75,10 @@ func (se servicefailure) GetCode() string {
7275
return se.Code
7376
}
7477

78+
func (se servicefailure) GetOpcRequestID() string {
79+
return se.OpcRequestID
80+
}
81+
7582
// IsServiceError returns false if the error is not service side, otherwise true
7683
// additionally it returns an interface representing the ServiceError
7784
func IsServiceError(err error) (failure ServiceError, ok bool) {

common/errors_test.go

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
2+
3+
package common
4+
5+
import (
6+
"bytes"
7+
"io/ioutil"
8+
"net/http"
9+
"strings"
10+
"testing"
11+
12+
"github.com/stretchr/testify/assert"
13+
)
14+
15+
func TestErrors_ServiceFailureFromResponse(t *testing.T) {
16+
header := http.Header{}
17+
opcID := "111"
18+
header.Set("opc-request-id", opcID)
19+
sampleResponse := `{"key" : "test"}`
20+
21+
httpResponse := http.Response{Header: header}
22+
bodyBuffer := bytes.NewBufferString(sampleResponse)
23+
httpResponse.Body = ioutil.NopCloser(bodyBuffer)
24+
httpResponse.StatusCode = 200
25+
err := newServiceFailureFromResponse(&httpResponse)
26+
assert.Equal(t, err.(ServiceError).GetOpcRequestID(), opcID)
27+
assert.Equal(t, strings.Contains(err.Error(), "Service error:"), true)
28+
29+
failure, ok := IsServiceError(err)
30+
assert.Equal(t, ok, true)
31+
assert.Equal(t, failure.GetHTTPStatusCode(), httpResponse.StatusCode)
32+
}
33+
34+
func TestErrors_FailedToParseJson(t *testing.T) {
35+
// invalid json
36+
sampleResponse := `{"key" : test"}`
37+
38+
httpResponse := http.Response{}
39+
bodyBuffer := bytes.NewBufferString(sampleResponse)
40+
httpResponse.Body = ioutil.NopCloser(bodyBuffer)
41+
err := newServiceFailureFromResponse(&httpResponse)
42+
43+
failure, ok := IsServiceError(err)
44+
assert.Equal(t, ok, true)
45+
assert.Equal(t, failure.GetCode(), "BadErrorResponse")
46+
assert.Equal(t, strings.Contains(failure.GetMessage(), "Failed to parse json from response body due to"), true)
47+
}

common/http.go

+12-2
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,14 @@ func omitNilFieldsInJSON(data interface{}, value reflect.Value) (interface{}, er
180180
}
181181
return jsonMap, nil
182182
case reflect.Slice, reflect.Array:
183-
jsonList := data.([]interface{})
183+
// Special case: a []byte may have been marshalled as a string
184+
if reflect.TypeOf(data).Kind() == reflect.String && value.Type().Elem().Kind() == reflect.Uint8 {
185+
return data, nil
186+
}
187+
jsonList, ok := data.([]interface{})
188+
if !ok {
189+
return nil, fmt.Errorf("can not omit nil fields, data was expected to be a list")
190+
}
184191
newList := make([]interface{}, len(jsonList))
185192
var err error
186193
for i, val := range jsonList {
@@ -191,7 +198,10 @@ func omitNilFieldsInJSON(data interface{}, value reflect.Value) (interface{}, er
191198
}
192199
return newList, nil
193200
case reflect.Map:
194-
jsonMap := data.(map[string]interface{})
201+
jsonMap, ok := data.(map[string]interface{})
202+
if !ok {
203+
return nil, fmt.Errorf("can not omit nil fields, data was expected to be a map")
204+
}
195205
newMap := make(map[string]interface{}, len(jsonMap))
196206
var err error
197207
for key, val := range jsonMap {

common/http_test.go

+29
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,19 @@ type uploadAPIKeyRequestPtr struct {
6161
OpcRetryToken *string `mandatory:"false" contributesTo:"header" name:"opc-retry-token"`
6262
}
6363

64+
type EmbeddedByteSlice struct {
65+
Key *[]byte `mandatory:"false" json:"key"`
66+
Value []byte `mandatory:"true" json:"value"`
67+
}
68+
69+
type KVList struct {
70+
KVs []EmbeddedByteSlice `mandatory:"true" json:"kvs"`
71+
}
72+
73+
type KVRequest struct {
74+
KVList `contributesTo:"body"`
75+
}
76+
6477
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
6578

6679
func TestHttpMarshallerInvalidStruct(t *testing.T) {
@@ -359,6 +372,22 @@ func TestHttpMarshalerUnsupportedTypes(t *testing.T) {
359372
}
360373
}
361374

375+
func TestHttpMarshallerEmbeddedBytes(t *testing.T) {
376+
s := KVRequest{
377+
KVList{
378+
KVs: []EmbeddedByteSlice{
379+
{Value: []byte{1, 2, 3, 4}},
380+
{Key: &[]byte{6, 7, 8, 9}, Value: []byte{1, 2, 3, 4}},
381+
{Value: []byte{}},
382+
},
383+
}}
384+
request := MakeDefaultHTTPRequest(http.MethodPost, "/random")
385+
HTTPRequestMarshaller(s, &request)
386+
b, _ := ioutil.ReadAll(request.Body)
387+
st := string(b)
388+
assert.Equal(t, `{"kvs":[{"value":"AQIDBA=="},{"key":"BgcICQ==","value":"AQIDBA=="},{"value":""}]}`, st)
389+
}
390+
362391
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
363392
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
364393
//Response Unmarshaling

common/version.go

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)