Skip to content

Commit

Permalink
Merge pull request #8 from datadrivers/v0.6.0
Browse files Browse the repository at this point in the history
Support S3 blobstore
  • Loading branch information
Nosmoht authored Mar 29, 2020
2 parents b72dab4 + 379ee3a commit eb3c803
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 18 deletions.
79 changes: 74 additions & 5 deletions blobstore.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ type Blobstore struct {
AvailableSpaceInBytes int `json:"availableSpaceInBytes"`
BlobCount int `json:"blobCount"`
Name string `json:"name"`
Path string `json:"path"`
Path string `json:"path,omitempty"` // only if type File
TotalSizeInBytes int `json:"totalSizeInBytes"`
Type string `json:"type"`

*BlobstoreSoftQuota `json:"softQuota,omitempty"`
*BlobstoreS3BucketConfiguration `json:"bucketConfiguration,omitempty"`
*BlobstoreSoftQuota `json:"softQuota,omitempty"`
}

// BlobstoreSoftQuota data
Expand All @@ -32,6 +33,43 @@ type BlobstoreSoftQuota struct {
Type string `json:"type"`
}

// BlobstoreS3BucketConfiguration data
type BlobstoreS3BucketConfiguration struct {
*BlobstoreS3Bucket `json:"bucket,omitempty"`
*BlobstoreS3Encryption `json:"encryption,omitempty"`
*BlobstoreS3BucketSecurity `json:"bucketSecurity,omitempty"`
*BlobstoreS3AdvancedBucketConnection `json:"advancedBucketConnection,omitempty"`
}

// BlobstoreS3Bucket data
type BlobstoreS3Bucket struct {
Expiration int `json:"expiration"`
Name string `json:"name"`
Prefix string `json:"prefix"`
Region string `json:"region"`
}

// BlobstoreS3Encryption data
type BlobstoreS3Encryption struct {
Key string `json:"encryptionKey"`
Type string `json:"encryptionType"`
}

// BlobstoreS3BucketSecurity data
type BlobstoreS3BucketSecurity struct {
AccessKeyID string `json:"accessKeyId"`
Role string `json:"role"`
SecretAccessKey string `json:"secretAccessKey"`
SessionToken string `json:"sessionToken"`
}

// BlobstoreS3AdvancedBucketConnection data
type BlobstoreS3AdvancedBucketConnection struct {
Endpoint string `json:"endpoint"`
SignerType string `json:"signerType"`
ForcePathStyle bool `json:"forcePathStyle"`
}

func (c client) BlobstoreCreate(bs Blobstore) error {
ioReader, err := jsonMarshalInterfaceToIOReader(bs)
if err != nil {
Expand All @@ -43,7 +81,7 @@ func (c client) BlobstoreCreate(bs Blobstore) error {
return err
}

if resp.StatusCode != http.StatusNoContent {
if resp.StatusCode != http.StatusNoContent && resp.StatusCode != http.StatusCreated {
return fmt.Errorf("could not create blobstore \"%s\": HTTP: %d, %s", bs.Name, resp.StatusCode, string(body))
}

Expand All @@ -62,12 +100,25 @@ func (c client) BlobstoreRead(id string) (*Blobstore, error) {

var blobstores []Blobstore
if err := json.Unmarshal(body, &blobstores); err != nil {
return nil, fmt.Errorf("could not unmarshal blobstore: %v", err)
return nil, fmt.Errorf("could not unmarshal blobstore \"%s\": %v", id, err)
}

for _, bs := range blobstores {
if bs.Name == id {
return &bs, nil
bsDetailed, err := c.BlobstoreReadDetails(id, bs.Type)
if err != nil {
return nil, err
}

bsDetailed.Name = bs.Name
bsDetailed.Type = bs.Type
bsDetailed.BlobCount = bs.BlobCount
bsDetailed.TotalSizeInBytes = bs.TotalSizeInBytes
bsDetailed.AvailableSpaceInBytes = bs.AvailableSpaceInBytes

bs.Name = bsDetailed.Name

return bsDetailed, nil
}
}

Expand Down Expand Up @@ -103,3 +154,21 @@ func (c client) BlobstoreDelete(id string) error {
}
return nil
}

func (c client) BlobstoreReadDetails(id string, bsType string) (*Blobstore, error) {
body, resp, err := c.Get(fmt.Sprintf("%s/%s/%s", blobstoreAPIEndpoint, strings.ToLower(bsType), id), nil)
if err != nil {
return nil, err
}

if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("could not read blobstore \"%s\" of type \"%s\": HTTP: %d, %s", id, bsType, resp.StatusCode, string(body))
}

blobstore := &Blobstore{}
if err := json.Unmarshal(body, blobstore); err != nil {
return nil, fmt.Errorf("could not unmarshal details of blobstore \"%s\": %v", id, err)
}

return blobstore, nil
}
39 changes: 37 additions & 2 deletions blobstore_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ func TestBlobstoreFile(t *testing.T) {
bsCreated, err := client.BlobstoreRead(bs.Name)
assert.Nil(t, err)
assert.NotNil(t, bsCreated)
// Path not returned by API, not possible to test :-/
// assert.Equal(t, bsPath, bsCreated.Path)
assert.Equal(t, bsPath, bsCreated.Path)
assert.Equal(t, bsType, bsCreated.Type)
assert.Equal(t, 0, bsCreated.BlobCount)
assert.Nil(t, bsCreated.BlobstoreSoftQuota)
Expand Down Expand Up @@ -62,3 +61,39 @@ func TestBlobstoreRead(t *testing.T) {
assert.Equal(t, bsName, bs.Name)
}
}

func TestBlobstoreS3(t *testing.T) {
client := NewClient(getDefaultConfig())

bsName := "test-blobstore-s3"
bsType := BlobstoreTypeS3

bs := Blobstore{
Name: bsName,
Type: bsType,
BlobstoreS3BucketConfiguration: &BlobstoreS3BucketConfiguration{
BlobstoreS3Bucket: &BlobstoreS3Bucket{
Name: getEnv("AWS_BUCKET_NAME", "terraform-provider-nexus-s3-test"),
Region: getEnv("AWS_DEFAULT_REGION", "us-central-1"),
},
BlobstoreS3BucketSecurity: &BlobstoreS3BucketSecurity{
AccessKeyID: getEnv("AWS_ACCESS_KEY_ID", "AWS_ACCESS_KEY_ID must be set"),
SecretAccessKey: getEnv("AWS_SECRET_ACCESS_KEY", "AWS_SECRET_ACCESS_KEY must be set"),
},
},
}

err := client.BlobstoreCreate(bs)
assert.Nil(t, err)

s3BS, err := client.BlobstoreRead(bs.Name)
assert.Nil(t, err)
assert.NotNil(t, s3BS)
assert.Equal(t, BlobstoreTypeS3, s3BS.Type)
assert.NotNil(t, s3BS.BlobstoreS3BucketConfiguration)
assert.NotNil(t, s3BS.BlobstoreS3BucketConfiguration.BlobstoreS3Bucket)
assert.NotNil(t, s3BS.BlobstoreS3BucketConfiguration.BlobstoreS3BucketSecurity)

err = client.BlobstoreDelete(bs.Name)
assert.Nil(t, err)
}
9 changes: 0 additions & 9 deletions client_test.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,11 @@
package client

import (
"os"
"testing"

"github.com/stretchr/testify/assert"
)

func getEnv(key, fallback string) string {
value, exist := os.LookupEnv(key)
if !exist {
return fallback
}
return value
}

func getDefaultConfig() Config {
return Config{
URL: getEnv("NEXUS_URL", "http://127.0.0.1:8081"),
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module github.com/datadrivers/go-nexus-client

go 1.13
go 1.14

require github.com/stretchr/testify v1.4.0
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
1 change: 0 additions & 1 deletion repository_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ func TestRepositoryRead(t *testing.T) {

if repo != nil {
assert.Equal(t, name, repo.Name)
assert.NotNil(t, repo.RepositoryCleanup)
assert.NotNil(t, repo.RepositoryProxy)
}
}
Expand Down
8 changes: 8 additions & 0 deletions tools.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"io"
"os"
)

func jsonMarshalInterfaceToIOReader(data interface{}) (io.Reader, error) {
Expand All @@ -15,3 +16,10 @@ func jsonMarshalInterfaceToIOReader(data interface{}) (io.Reader, error) {

return bytes.NewReader(b), nil
}

func getEnv(key, fallback string) string {
if value, exists := os.LookupEnv(key); exists {
return value
}
return fallback
}

0 comments on commit eb3c803

Please sign in to comment.