Skip to content

Commit 61bb9c2

Browse files
authored
Merge branch 'master' into master
2 parents 161db66 + 80f0110 commit 61bb9c2

File tree

8 files changed

+568
-69
lines changed

8 files changed

+568
-69
lines changed

bindings/azure/blobstorage/blobstorage.go

Lines changed: 288 additions & 53 deletions
Large diffs are not rendered by default.

bindings/azure/blobstorage/blobstorage_test.go

Lines changed: 80 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,91 @@ package blobstorage
88
import (
99
"testing"
1010

11+
"github.com/Azure/azure-storage-blob-go/azblob"
1112
"github.com/dapr/components-contrib/bindings"
1213
"github.com/dapr/kit/logger"
1314
"github.com/stretchr/testify/assert"
1415
)
1516

1617
func TestParseMetadata(t *testing.T) {
1718
m := bindings.Metadata{}
18-
m.Properties = map[string]string{"storageAccount": "account", "storageAccessKey": "key", "container": "test", "decodeBase64": "true"}
19-
blonStorage := NewAzureBlobStorage(logger.NewLogger("test"))
20-
meta, err := blonStorage.parseMetadata(m)
21-
assert.Nil(t, err)
22-
assert.Equal(t, "test", meta.Container)
23-
assert.Equal(t, "account", meta.StorageAccount)
24-
assert.Equal(t, "key", meta.StorageAccessKey)
25-
assert.Equal(t, "true", meta.DecodeBase64)
19+
blobStorage := NewAzureBlobStorage(logger.NewLogger("test"))
20+
21+
t.Run("parse all metadata", func(t *testing.T) {
22+
m.Properties = map[string]string{
23+
"storageAccount": "account",
24+
"storageAccessKey": "key",
25+
"container": "test",
26+
"getBlobRetryCount": "5",
27+
"decodeBase64": "true",
28+
}
29+
meta, err := blobStorage.parseMetadata(m)
30+
assert.Nil(t, err)
31+
assert.Equal(t, "test", meta.Container)
32+
assert.Equal(t, "account", meta.StorageAccount)
33+
assert.Equal(t, "key", meta.StorageAccessKey)
34+
assert.Equal(t, true, meta.DecodeBase64)
35+
assert.Equal(t, 5, meta.GetBlobRetryCount)
36+
assert.Equal(t, azblob.PublicAccessNone, meta.PublicAccessLevel)
37+
})
38+
39+
t.Run("parse metadata with publicAccessLevel = blob", func(t *testing.T) {
40+
m.Properties = map[string]string{
41+
"publicAccessLevel": "blob",
42+
}
43+
meta, err := blobStorage.parseMetadata(m)
44+
assert.Nil(t, err)
45+
assert.Equal(t, azblob.PublicAccessBlob, meta.PublicAccessLevel)
46+
})
47+
48+
t.Run("parse metadata with publicAccessLevel = container", func(t *testing.T) {
49+
m.Properties = map[string]string{
50+
"publicAccessLevel": "container",
51+
}
52+
meta, err := blobStorage.parseMetadata(m)
53+
assert.Nil(t, err)
54+
assert.Equal(t, azblob.PublicAccessContainer, meta.PublicAccessLevel)
55+
})
56+
57+
t.Run("parse metadata with invalid publicAccessLevel", func(t *testing.T) {
58+
m.Properties = map[string]string{
59+
"publicAccessLevel": "invalid",
60+
}
61+
_, err := blobStorage.parseMetadata(m)
62+
assert.Error(t, err)
63+
})
64+
}
65+
66+
func TestGetOption(t *testing.T) {
67+
blobStorage := NewAzureBlobStorage(logger.NewLogger("test"))
68+
69+
t.Run("return error if blobName is missing", func(t *testing.T) {
70+
r := bindings.InvokeRequest{}
71+
_, err := blobStorage.get(&r)
72+
if assert.Error(t, err) {
73+
assert.Equal(t, ErrMissingBlobName, err)
74+
}
75+
})
76+
}
77+
78+
func TestDeleteOption(t *testing.T) {
79+
blobStorage := NewAzureBlobStorage(logger.NewLogger("test"))
80+
81+
t.Run("return error if blobName is missing", func(t *testing.T) {
82+
r := bindings.InvokeRequest{}
83+
_, err := blobStorage.delete(&r)
84+
if assert.Error(t, err) {
85+
assert.Equal(t, ErrMissingBlobName, err)
86+
}
87+
})
88+
89+
t.Run("return error for invalid deleteSnapshots", func(t *testing.T) {
90+
r := bindings.InvokeRequest{}
91+
r.Metadata = map[string]string{
92+
"blobName": "foo",
93+
"deleteSnapshots": "invalid",
94+
}
95+
_, err := blobStorage.delete(&r)
96+
assert.Error(t, err)
97+
})
2698
}
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
// ------------------------------------------------------------
2+
// Copyright (c) Microsoft Corporation and Dapr Contributors.
3+
// Licensed under the MIT License.
4+
// ------------------------------------------------------------
5+
6+
package cosmosgraphdb
7+
8+
import (
9+
"encoding/json"
10+
"errors"
11+
"fmt"
12+
"time"
13+
14+
"github.com/dapr/components-contrib/bindings"
15+
"github.com/dapr/kit/logger"
16+
gremcos "github.com/supplyon/gremcos"
17+
)
18+
19+
const (
20+
queryOperation bindings.OperationKind = "query"
21+
22+
// keys from request's Data
23+
commandGremlinKey = "gremlin"
24+
25+
// keys from response's Data
26+
respGremlinKey = "gremlin"
27+
respOpKey = "operation"
28+
respStartTimeKey = "start-time"
29+
respEndTimeKey = "end-time"
30+
respDurationKey = "duration"
31+
)
32+
33+
// CosmosGraphDB allows performing state operations on collections
34+
type CosmosGraphDB struct {
35+
metadata *cosmosGraphDBCredentials
36+
client *gremcos.Cosmos
37+
logger logger.Logger
38+
}
39+
40+
type cosmosGraphDBCredentials struct {
41+
URL string `json:"url"`
42+
MasterKey string `json:"masterKey"`
43+
Username string `json:"username"`
44+
}
45+
46+
// NewCosmosGraphDB returns a new CosmosGraphDB instance
47+
func NewCosmosGraphDB(logger logger.Logger) *CosmosGraphDB {
48+
return &CosmosGraphDB{logger: logger}
49+
}
50+
51+
// Init performs CosmosDB connection parsing and connecting
52+
func (c *CosmosGraphDB) Init(metadata bindings.Metadata) error {
53+
c.logger.Debug("Initializing Cosmos Graph DB binding")
54+
55+
m, err := c.parseMetadata(metadata)
56+
if err != nil {
57+
return err
58+
}
59+
c.metadata = m
60+
client, err := gremcos.New(c.metadata.URL,
61+
gremcos.WithAuth(c.metadata.Username, c.metadata.MasterKey),
62+
)
63+
if err != nil {
64+
return errors.New("CosmosGraphDB Error: failed to create the Cosmos Graph DB connector")
65+
}
66+
67+
c.client = client
68+
69+
return nil
70+
}
71+
72+
func (c *CosmosGraphDB) parseMetadata(metadata bindings.Metadata) (*cosmosGraphDBCredentials, error) {
73+
b, err := json.Marshal(metadata.Properties)
74+
if err != nil {
75+
return nil, err
76+
}
77+
78+
var creds cosmosGraphDBCredentials
79+
err = json.Unmarshal(b, &creds)
80+
if err != nil {
81+
return nil, err
82+
}
83+
84+
return &creds, nil
85+
}
86+
87+
func (c *CosmosGraphDB) Operations() []bindings.OperationKind {
88+
return []bindings.OperationKind{queryOperation}
89+
}
90+
91+
func (c *CosmosGraphDB) Invoke(req *bindings.InvokeRequest) (*bindings.InvokeResponse, error) {
92+
var jsonPoint map[string]interface{}
93+
err := json.Unmarshal(req.Data, &jsonPoint)
94+
if err != nil {
95+
return nil, errors.New("CosmosGraphDB Error: Cannot convert request data")
96+
}
97+
98+
gq := fmt.Sprintf("%s", jsonPoint[commandGremlinKey])
99+
100+
if gq == "" {
101+
return nil, errors.New("CosmosGraphDB Error: missing data - gremlin query not set")
102+
}
103+
startTime := time.Now().UTC()
104+
resp := &bindings.InvokeResponse{
105+
Metadata: map[string]string{
106+
respOpKey: string(req.Operation),
107+
respGremlinKey: gq,
108+
respStartTimeKey: startTime.Format(time.RFC3339Nano),
109+
},
110+
}
111+
d, err := c.client.Execute(gq)
112+
if err != nil {
113+
return nil, errors.New("CosmosGraphDB Error:error excuting gremlin")
114+
}
115+
if len(d) > 0 {
116+
resp.Data = d[0].Result.Data
117+
}
118+
endTime := time.Now().UTC()
119+
resp.Metadata[respEndTimeKey] = endTime.Format(time.RFC3339Nano)
120+
resp.Metadata[respDurationKey] = endTime.Sub(startTime).String()
121+
122+
return resp, nil
123+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// ------------------------------------------------------------
2+
// Copyright (c) Microsoft Corporation and Dapr Contributors.
3+
// Licensed under the MIT License.
4+
// ------------------------------------------------------------
5+
6+
package cosmosgraphdb
7+
8+
import (
9+
"testing"
10+
11+
"github.com/dapr/components-contrib/bindings"
12+
"github.com/dapr/kit/logger"
13+
"github.com/stretchr/testify/assert"
14+
)
15+
16+
func TestParseMetadata(t *testing.T) {
17+
m := bindings.Metadata{}
18+
m.Properties = map[string]string{"Url": "a", "masterKey": "a", "username": "a"}
19+
cosmosgraphdb := CosmosGraphDB{logger: logger.NewLogger("test")}
20+
im, err := cosmosgraphdb.parseMetadata(m)
21+
assert.Nil(t, err)
22+
assert.Equal(t, "a", im.URL)
23+
assert.Equal(t, "a", im.MasterKey)
24+
assert.Equal(t, "a", im.Username)
25+
}

bindings/requests.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55

66
package bindings
77

8+
import (
9+
"fmt"
10+
"strconv"
11+
)
12+
813
// InvokeRequest is the object given to a dapr output binding
914
type InvokeRequest struct {
1015
Data []byte `json:"data"`
@@ -22,3 +27,31 @@ const (
2227
DeleteOperation OperationKind = "delete"
2328
ListOperation OperationKind = "list"
2429
)
30+
31+
// GetMetadataAsBool parses metadata as bool
32+
func (r *InvokeRequest) GetMetadataAsBool(key string) (bool, error) {
33+
if val, ok := r.Metadata[key]; ok {
34+
boolVal, err := strconv.ParseBool(val)
35+
if err != nil {
36+
return false, fmt.Errorf("error parsing metadata `%s` with value `%s` as bool: %w", key, val, err)
37+
}
38+
39+
return boolVal, nil
40+
}
41+
42+
return false, nil
43+
}
44+
45+
// GetMetadataAsBool parses metadata as int64
46+
func (r *InvokeRequest) GetMetadataAsInt64(key string, bitSize int) (int64, error) {
47+
if val, ok := r.Metadata[key]; ok {
48+
intVal, err := strconv.ParseInt(val, 10, bitSize)
49+
if err != nil {
50+
return 0, fmt.Errorf("error parsing metadata `%s` with value `%s` as int%d: %w", key, val, bitSize, err)
51+
}
52+
53+
return intVal, nil
54+
}
55+
56+
return 0, nil
57+
}

go.mod

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ require (
1111
github.com/Azure/azure-event-hubs-go/v3 v3.3.10
1212
github.com/Azure/azure-sdk-for-go v48.2.0+incompatible
1313
github.com/Azure/azure-service-bus-go v0.10.10
14-
github.com/Azure/azure-storage-blob-go v0.8.0
14+
github.com/Azure/azure-storage-blob-go v0.10.0
1515
github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd
1616
github.com/Azure/go-amqp v0.13.1
1717
github.com/Azure/go-autorest/autorest v0.11.12
@@ -113,6 +113,7 @@ require (
113113
github.com/sergi/go-diff v1.2.0 // indirect
114114
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271
115115
github.com/stretchr/testify v1.7.0
116+
github.com/supplyon/gremcos v0.1.0
116117
github.com/tidwall/gjson v1.8.0 // indirect
117118
github.com/tidwall/pretty v1.2.0 // indirect
118119
github.com/valyala/fasthttp v1.21.0

0 commit comments

Comments
 (0)