Skip to content

Commit 071f9ec

Browse files
authored
add azure blob storage binding (#4)
1 parent 925f8a4 commit 071f9ec

File tree

5 files changed

+118
-0
lines changed

5 files changed

+118
-0
lines changed

bindings/Readme.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ List of bindings and their status:
1818
| MQTT | V | V | Experimental |
1919
| Redis | | V | Experimental |
2020
| AWS DynamoDB | | V | Experimental |
21+
| Azure Blob Storage | | V | Experimental |
2122

2223
## Implementing a new binding
2324

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package blobstorage
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"fmt"
7+
"net/url"
8+
9+
"github.com/google/uuid"
10+
11+
log "github.com/Sirupsen/logrus"
12+
13+
"github.com/Azure/azure-storage-blob-go/azblob"
14+
"github.com/actionscore/components-contrib/bindings"
15+
)
16+
17+
const (
18+
blobName = "blobName"
19+
)
20+
21+
// AzureBlobStorage allows saving blobs to an Azure Blob Storage account
22+
type AzureBlobStorage struct {
23+
metadata *blobStorageMetadata
24+
containerURL azblob.ContainerURL
25+
}
26+
27+
type blobStorageMetadata struct {
28+
StorageAccount string `json:"storageAccount"`
29+
StorageAccessKey string `json:"storageAccessKey"`
30+
Container string `json:"container"`
31+
}
32+
33+
// NewAzureBlobStorage returns a new CosmosDB instance
34+
func NewAzureBlobStorage() *AzureBlobStorage {
35+
return &AzureBlobStorage{}
36+
}
37+
38+
// Init performs metadata parsing
39+
func (a *AzureBlobStorage) Init(metadata bindings.Metadata) error {
40+
m, err := a.parseMetadata(metadata)
41+
if err != nil {
42+
return err
43+
}
44+
a.metadata = m
45+
credential, err := azblob.NewSharedKeyCredential(m.StorageAccount, m.StorageAccessKey)
46+
if err != nil {
47+
return fmt.Errorf("Invalid credentials with error: %s", err.Error())
48+
}
49+
p := azblob.NewPipeline(credential, azblob.PipelineOptions{})
50+
51+
containerName := a.metadata.Container
52+
URL, _ := url.Parse(
53+
fmt.Sprintf("https://%s.blob.core.windows.net/%s", m.StorageAccount, containerName))
54+
containerURL := azblob.NewContainerURL(*URL, p)
55+
56+
ctx := context.Background()
57+
_, err = containerURL.Create(ctx, azblob.Metadata{}, azblob.PublicAccessNone)
58+
// Don't return error, container might already exist
59+
log.Debugf("error creating container: %s", err)
60+
a.containerURL = containerURL
61+
return nil
62+
}
63+
64+
func (a *AzureBlobStorage) parseMetadata(metadata bindings.Metadata) (*blobStorageMetadata, error) {
65+
connInfo := metadata.Properties
66+
b, err := json.Marshal(connInfo)
67+
if err != nil {
68+
return nil, err
69+
}
70+
71+
var m blobStorageMetadata
72+
err = json.Unmarshal(b, &m)
73+
if err != nil {
74+
return nil, err
75+
}
76+
return &m, nil
77+
}
78+
79+
func (a *AzureBlobStorage) Write(req *bindings.WriteRequest) error {
80+
name := ""
81+
if val, ok := req.Metadata[blobName]; ok && val != "" {
82+
name = val
83+
} else {
84+
name = uuid.New().String()
85+
}
86+
blobURL := a.containerURL.NewBlockBlobURL(name)
87+
_, err := azblob.UploadBufferToBlockBlob(context.Background(), req.Data, blobURL, azblob.UploadToBlockBlobOptions{
88+
Parallelism: 16,
89+
})
90+
return err
91+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package blobstorage
2+
3+
import (
4+
"testing"
5+
6+
"github.com/actionscore/components-contrib/bindings"
7+
"github.com/stretchr/testify/assert"
8+
)
9+
10+
func TestParseMetadata(t *testing.T) {
11+
m := bindings.Metadata{}
12+
m.Properties = map[string]string{"storageAccount": "account", "storageAccessKey": "key", "container": "test"}
13+
blonStorage := NewAzureBlobStorage()
14+
meta, err := blonStorage.parseMetadata(m)
15+
assert.Nil(t, err)
16+
assert.Equal(t, "test", meta.Container)
17+
assert.Equal(t, "account", meta.StorageAccount)
18+
assert.Equal(t, "key", meta.StorageAccessKey)
19+
}

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ require (
77
contrib.go.opencensus.io/exporter/ocagent v0.6.0 // indirect
88
github.com/Azure/azure-event-hubs-go v1.3.1
99
github.com/Azure/azure-sdk-for-go v29.0.0+incompatible
10+
github.com/Azure/azure-storage-blob-go v0.8.0
1011
github.com/Azure/go-autorest v12.0.0+incompatible
1112
github.com/DataDog/zstd v1.4.1 // indirect
1213
github.com/Shopify/sarama v1.23.1

go.sum

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,14 @@ github.com/Azure/azure-amqp-common-go v1.1.4/go.mod h1:FhZtXirFANw40UXI2ntweO+VO
2323
github.com/Azure/azure-event-hubs-go v1.3.1 h1:vKw7tLOFJ8kVMkhNvOXZWz+3purRQ/WTe60+bavZ5qc=
2424
github.com/Azure/azure-event-hubs-go v1.3.1/go.mod h1:me2m3+0WC7G7JRBTWI5SQ81s2TYyOqgV3JIpYg86jZA=
2525
github.com/Azure/azure-pipeline-go v0.1.8/go.mod h1:XA1kFWRVhSK+KNFiOhfv83Fv8L9achrP7OxIzeTn1Yg=
26+
github.com/Azure/azure-pipeline-go v0.2.1 h1:OLBdZJ3yvOn2MezlWvbrBMTEUQC72zAftRZOMdj5HYo=
27+
github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4=
2628
github.com/Azure/azure-sdk-for-go v21.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
2729
github.com/Azure/azure-sdk-for-go v29.0.0+incompatible h1:CYPU39ULbGjQBo3gXIqiWouK0C4F+Pt2Zx5CqGvqknE=
2830
github.com/Azure/azure-sdk-for-go v29.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
2931
github.com/Azure/azure-storage-blob-go v0.0.0-20181023070848-cf01652132cc/go.mod h1:oGfmITT1V6x//CswqY2gtAHND+xIP64/qL7a5QJix0Y=
32+
github.com/Azure/azure-storage-blob-go v0.8.0 h1:53qhf0Oxa0nOjgbDeeYPUeyiNmafAFEY95rZLK0Tj6o=
33+
github.com/Azure/azure-storage-blob-go v0.8.0/go.mod h1:lPI3aLPpuLTeUwh1sViKXFxwl2B6teiRqI0deQUvsw0=
3034
github.com/Azure/go-autorest v11.0.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
3135
github.com/Azure/go-autorest v11.1.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
3236
github.com/Azure/go-autorest v11.1.2+incompatible h1:viZ3tV5l4gE2Sw0xrasFHytCGtzYCrT+um/rrSQ1BfA=
@@ -166,6 +170,8 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
166170
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
167171
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
168172
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
173+
github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149 h1:HfxbT6/JcvIljmERptWhwa8XzP7H3T+Z2N26gTsaDaA=
174+
github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
169175
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
170176
github.com/mediocregopher/radix.v2 v0.0.0-20181115013041-b67df6e626f9 h1:ViNuGS149jgnttqhc6XQNPwdupEMBXqCx9wtlW7P3sA=
171177
github.com/mediocregopher/radix.v2 v0.0.0-20181115013041-b67df6e626f9/go.mod h1:fLRUbhbSd5Px2yKUaGYYPltlyxi1guJz1vCmo1RQL50=

0 commit comments

Comments
 (0)