Skip to content

Commit

Permalink
Release 1.2.0
Browse files Browse the repository at this point in the history
  • Loading branch information
cossdk committed Sep 6, 2019
1 parent c3a3c68 commit 1b29d24
Show file tree
Hide file tree
Showing 125 changed files with 7,917 additions and 2,568 deletions.
7 changes: 7 additions & 0 deletions .yardopts
@@ -0,0 +1,7 @@
--plugin go
-e doc-src/plugin/plugin.rb
-m markdown
-o doc/api
--title "IBM COS SDK for Go"
aws/**/*.go
service/**/*.go
7 changes: 7 additions & 0 deletions CHANGELOG.md
@@ -1,5 +1,12 @@
# CHANGELOG

# 1.2.0
## Content
* Immutable Object Storage
* Archive Tier Support
### Defect Fixes
* AWS Patches aligned to version 1.23.4 of the AWS SDK for Go

# 1.1.0
## Content
* Key Protect Support
Expand Down
3 changes: 3 additions & 0 deletions Gemfile
@@ -0,0 +1,3 @@
source 'https://rubygems.org'
gem 'yard', git: 'git://github.com/lsegal/yard'
gem 'yard-go', git: 'git://github.com/lsegal/yard-go'
9 changes: 8 additions & 1 deletion Makefile
Expand Up @@ -51,6 +51,11 @@ cleanup-models:
###################
# Unit/CI Testing #
###################

unit-no-verify:
@echo "go test SDK and vendor packages with no linting"
go test -count=1 -tags ${UNIT_TEST_TAGS} ${SDK_ALL_PKGS}

unit: verify
@echo "go test SDK and vendor packages"
go test -count=1 -tags ${UNIT_TEST_TAGS} ${SDK_ALL_PKGS}
Expand All @@ -67,8 +72,10 @@ ci-test: generate unit-with-race-cover ci-test-generate-validate

ci-test-generate-validate:
@echo "CI test validate no generated code changes"
git update-index --assume-unchanged go.mod go.sum
git add . -A
gitstatus=`git diff --cached --ignore-space-change`; \
git update-index --no-assume-unchanged go.mod go.sum
echo "$$gitstatus"; \
if [ "$$gitstatus" != "" ] && [ "$$gitstatus" != "skipping validation" ]; then echo "$$gitstatus"; exit 1; fi

Expand Down Expand Up @@ -227,4 +234,4 @@ docs:
$(AWS_DOC_GEN_TOOL) `pwd`

api_info:
@go run private/model/cli/api-info/api-info.go
@go run private/model/cli/api-info/api-info.go
11 changes: 10 additions & 1 deletion README.md
Expand Up @@ -26,6 +26,15 @@ You'll need:

These values can be found in the IBM Cloud Console by [generating a 'service credential'](https://cloud.ibm.com/docs/services/cloud-object-storage/iam?topic=cloud-object-storage-service-credentials#service-credentials).

## Archive Tier Support
You can automatically archive objects after a specified length of time or after a specified date. Once archived, a temporary copy of an object can be restored for access as needed. Restore time may take up to 15 hours.

An archive policy is set at the bucket level by calling the ``PutBucketLifecycleConfiguration`` method on a client instance. A newly added or modified archive policy applies to new objects uploaded and does not affect existing objects. For more detail, see the [documentation](https://cloud.ibm.com/docs/services/cloud-object-storage?topic=cloud-object-storage-go).

## Immutable Object Storage
Users can configure buckets with an Immutable Object Storage policy to prevent objects from being modified or deleted for a defined period of time. The retention period can be specified on a per-object basis, or objects can inherit a default retention period set on the bucket. It is also possible to set open-ended and permanent retention periods. Immutable Object Storage meets the rules set forth by the SEC governing record retention, and IBM Cloud administrators are unable to bypass these restrictions. For more detail, see the [IBM Cloud documentation](https://cloud.ibm.com/docs/services/cloud-object-storage?topic=cloud-object-storage-go).

Note: Immutable Object Storage does not support Aspera transfers via the SDK to upload objects or directories at this stage.

## Getting the SDK

Expand Down Expand Up @@ -59,7 +68,7 @@ import (
const (
apiKey = "<API_KEY>"
serviceInstanceID = "<RESOURCE_INSTANCE_ID>"
authEndpoint = "https://iam.bluemix.net/oidc/token"
authEndpoint = "https://iam.cloud.ibm.com/identity/token"
serviceEndpoint = "https://s3-api.us-geo.objectstorage.softlayer.net"
)

Expand Down
43 changes: 41 additions & 2 deletions aws/awserr/error.go
Expand Up @@ -42,6 +42,26 @@ type Error interface {
OrigErr() error
}

// BatchError is a batch of errors which also wraps lower level errors with
// code, message, and original errors. Calling Error() will include all errors
// that occurred in the batch.
//
// Deprecated: Replaced with BatchedErrors. Only defined for backwards
// compatibility.
type BatchError interface {
// Satisfy the generic error interface.
error

// Returns the short phrase depicting the classification of the error.
Code() string

// Returns the error details message.
Message() string

// Returns the original error if one was set. Nil is returned if not set.
OrigErrs() []error
}

// BatchedErrors is a batch of errors which also wraps lower level errors with
// code, message, and original errors. Calling Error() will include all errors
// that occurred in the batch.
Expand Down Expand Up @@ -118,8 +138,27 @@ type RequestFailure interface {
RequestID() string
}

// NewRequestFailure returns a new request error wrapper for the given Error
// provided.
// NewRequestFailure returns a wrapped error with additional information for
// request status code, and service requestID.
//
// Should be used to wrap all request which involve service requests. Even if
// the request failed without a service response, but had an HTTP status code
// that may be meaningful.
func NewRequestFailure(err Error, statusCode int, reqID string) RequestFailure {
return newRequestError(err, statusCode, reqID)
}

// UnmarshalError provides the interface for the SDK failing to unmarshal data.
type UnmarshalError interface {
awsError
Bytes() []byte
}

// NewUnmarshalError returns an initialized UnmarshalError error wrapper adding
// the bytes that fail to unmarshal to the error.
func NewUnmarshalError(err error, msg string, bytes []byte) UnmarshalError {
return &unmarshalError{
awsError: New("UnmarshalError", msg, err),
bytes: bytes,
}
}
31 changes: 29 additions & 2 deletions aws/awserr/types.go
@@ -1,6 +1,9 @@
package awserr

import "fmt"
import (
"encoding/hex"
"fmt"
)

// SprintError returns a string of the formatted error code.
//
Expand Down Expand Up @@ -119,6 +122,7 @@ type requestError struct {
awsError
statusCode int
requestID string
bytes []byte
}

// newRequestError returns a wrapped error with additional information for
Expand Down Expand Up @@ -170,6 +174,29 @@ func (r requestError) OrigErrs() []error {
return []error{r.OrigErr()}
}

type unmarshalError struct {
awsError
bytes []byte
}

// Error returns the string representation of the error.
// Satisfies the error interface.
func (e unmarshalError) Error() string {
extra := hex.Dump(e.bytes)
return SprintError(e.Code(), e.Message(), extra, e.OrigErr())
}

// String returns the string representation of the error.
// Alias for Error to satisfy the stringer interface.
func (e unmarshalError) String() string {
return e.Error()
}

// Bytes returns the bytes that failed to unmarshal.
func (e unmarshalError) Bytes() []byte {
return e.bytes
}

// An error list that satisfies the golang interface
type errorList []error

Expand All @@ -181,7 +208,7 @@ func (e errorList) Error() string {
// How do we want to handle the array size being zero
if size := len(e); size > 0 {
for i := 0; i < size; i++ {
msg += fmt.Sprintf("%s", e[i].Error())
msg += e[i].Error()
// We check the next index to see if it is within the slice.
// If it is, then we append a newline. We do this, because unit tests
// could be broken with the additional '\n'
Expand Down
11 changes: 5 additions & 6 deletions aws/awsutil/path_value.go
Expand Up @@ -185,13 +185,12 @@ func ValuesAtPath(i interface{}, path string) ([]interface{}, error) {
// SetValueAtPath sets a value at the case insensitive lexical path inside
// of a structure.
func SetValueAtPath(i interface{}, path string, v interface{}) {
if rvals := rValuesAtPath(i, path, true, false, v == nil); rvals != nil {
for _, rval := range rvals {
if rval.Kind() == reflect.Ptr && rval.IsNil() {
continue
}
setValue(rval, v)
rvals := rValuesAtPath(i, path, true, false, v == nil)
for _, rval := range rvals {
if rval.Kind() == reflect.Ptr && rval.IsNil() {
continue
}
setValue(rval, v)
}
}

Expand Down
31 changes: 9 additions & 22 deletions aws/client/default_retryer.go
Expand Up @@ -14,12 +14,12 @@ import (
// struct and override the specific methods. For example, to override only
// the MaxRetries method:
//
// type retryer struct {
// client.DefaultRetryer
// }
// type retryer struct {
// client.DefaultRetryer
// }
//
// // This implementation always has 100 max retries
// func (d retryer) MaxRetries() int { return 100 }
// // This implementation always has 100 max retries
// func (d retryer) MaxRetries() int { return 100 }
type DefaultRetryer struct {
NumMaxRetries int
}
Expand All @@ -34,8 +34,8 @@ func (d DefaultRetryer) MaxRetries() int {
func (d DefaultRetryer) RetryRules(r *request.Request) time.Duration {
// Set the upper limit of delay in retrying at ~five minutes
minTime := 30
throttle := d.shouldThrottle(r)
if throttle {
isThrottle := r.IsErrorThrottle()
if isThrottle {
if delay, ok := getRetryDelay(r); ok {
return delay
}
Expand All @@ -44,7 +44,7 @@ func (d DefaultRetryer) RetryRules(r *request.Request) time.Duration {
}

retryCount := r.RetryCount
if throttle && retryCount > 8 {
if isThrottle && retryCount > 8 {
retryCount = 8
} else if retryCount > 13 {
retryCount = 13
Expand All @@ -65,21 +65,8 @@ func (d DefaultRetryer) ShouldRetry(r *request.Request) bool {
if r.HTTPResponse.StatusCode >= 500 && r.HTTPResponse.StatusCode != 501 {
return true
}
return r.IsErrorRetryable() || d.shouldThrottle(r)
}

// ShouldThrottle returns true if the request should be throttled.
func (d DefaultRetryer) shouldThrottle(r *request.Request) bool {
switch r.HTTPResponse.StatusCode {
case 429:
case 502:
case 503:
case 504:
default:
return r.IsErrorThrottle()
}

return true
return r.IsErrorRetryable() || r.IsErrorThrottle()
}

// This will look in the Retry-After header, RFC 7231, for how long
Expand Down
2 changes: 1 addition & 1 deletion aws/client/default_retryer_test.go
Expand Up @@ -60,7 +60,7 @@ func TestRetryThrottleStatusCodes(t *testing.T) {

d := DefaultRetryer{NumMaxRetries: 10}
for i, c := range cases {
throttle := d.shouldThrottle(&c.r)
throttle := c.r.IsErrorThrottle()
retry := d.ShouldRetry(&c.r)

if e, a := c.expectThrottle, throttle; e != a {
Expand Down
12 changes: 8 additions & 4 deletions aws/client/logger.go
Expand Up @@ -67,10 +67,14 @@ func logRequest(r *request.Request) {
if !bodySeekable {
r.SetReaderBody(aws.ReadSeekCloser(r.HTTPRequest.Body))
}
// Reset the request body because dumpRequest will re-wrap the r.HTTPRequest's
// Body as a NoOpCloser and will not be reset after read by the HTTP
// client reader.
r.ResetBody()
// Reset the request body because dumpRequest will re-wrap the
// r.HTTPRequest's Body as a NoOpCloser and will not be reset after
// read by the HTTP client reader.
if err := r.Error; err != nil {
r.Config.Logger.Log(fmt.Sprintf(logReqErrMsg,
r.ClientInfo.ServiceName, r.Operation.Name, err))
return
}
}

r.Config.Logger.Log(fmt.Sprintf(logReqMsg,
Expand Down
4 changes: 2 additions & 2 deletions aws/config.go
Expand Up @@ -20,7 +20,7 @@ type RequestRetryer interface{}
// A Config provides service configuration for service clients. By default,
// all clients will use the defaults.DefaultConfig structure.
//
// // Create Session with MaxRetry configuration to be shared by multiple
// // Create Session with MaxRetries configuration to be shared by multiple
// // service clients.
// sess := session.Must(session.NewSession(&aws.Config{
// MaxRetries: aws.Int(3),
Expand Down Expand Up @@ -251,7 +251,7 @@ type Config struct {
// NewConfig returns a new Config pointer that can be chained with builder
// methods to set multiple configuration values inline without using pointers.
//
// // Create Session with MaxRetry configuration to be shared by multiple
// // Create Session with MaxRetries configuration to be shared by multiple
// // service clients.
// sess := session.Must(session.NewSession(aws.NewConfig().
// WithMaxRetries(3),
Expand Down
2 changes: 1 addition & 1 deletion aws/convert_types_test.go
Expand Up @@ -562,7 +562,7 @@ func TestTimeValueSlice(t *testing.T) {
}
for i := range out2 {
if in[i] == nil {
if !(*(out2[i])).IsZero() {
if !(out2[i]).IsZero() {
t.Errorf("Unexpected value at idx %d", idx)
}
} else {
Expand Down

0 comments on commit 1b29d24

Please sign in to comment.