Merge branch 'master' of https://github.com/dapr/components-contrib into postgres-ttl

This commit is contained in:
ItalyPaleAle 2022-12-01 19:17:41 +00:00
commit b782b520aa
141 changed files with 4598 additions and 978 deletions

View File

@ -16,6 +16,8 @@ for attempt in `seq $MAX_ATTEMPTS`; do
if vault status && if vault status &&
vault kv put secret/dapr/conftestsecret conftestsecret=abcd && vault kv put secret/dapr/conftestsecret conftestsecret=abcd &&
vault kv put secret/dapr/secondsecret secondsecret=efgh && vault kv put secret/dapr/secondsecret secondsecret=efgh &&
vault kv put secret/secretWithNoPrefix noPrefixKey=noProblem &&
vault kv put secret/alternativePrefix/secretUnderAlternativePrefix altPrefixKey=altPrefixValue &&
vault kv put secret/dapr/multiplekeyvaluessecret first=1 second=2 third=3; vault kv put secret/dapr/multiplekeyvaluessecret first=1 second=2 third=3;
then then
echo ✅ secrets set; echo ✅ secrets set;

View File

@ -1,8 +1,9 @@
version: '3.9' version: '3.9'
# Use a YAML reference to define VAULT_TOKEN and DOCKER_IMAGE only once # Use a YAML reference to define VAULT_TOKEN and DOCKER_IMAGE only once
x-common-vaues: x-common-values:
# This should match tests/config/secrestore/hashicorp/vault/hashicorp-vault.yaml # This should match tests/config/secrestore/hashicorp/vault/hashicorp-vault.yaml
# This should match .github/infrastructure/conformance/hashicorp/vault_token_file.txt
vault_token: &VAULT_TOKEN "vault-dev-root-token-id" vault_token: &VAULT_TOKEN "vault-dev-root-token-id"
# Reuse the same docker image to save on resources and because the base vault image # Reuse the same docker image to save on resources and because the base vault image
# has everything we need for seeding the initial key values too. # has everything we need for seeding the initial key values too.

View File

@ -53,6 +53,7 @@ jobs:
- pubsub.mqtt - pubsub.mqtt
- state.mongodb - state.mongodb
- state.redis - state.redis
- state.cockroachdb
- state.postgresql - state.postgresql
- state.cassandra - state.cassandra
- state.memcached - state.memcached

View File

@ -20,18 +20,18 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"net/url"
"strconv" "strconv"
"strings"
"time"
"github.com/Azure/azure-storage-blob-go/azblob" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blockblob"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/container"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/dapr/components-contrib/bindings" "github.com/dapr/components-contrib/bindings"
azauth "github.com/dapr/components-contrib/internal/authentication/azure" storageinternal "github.com/dapr/components-contrib/internal/component/azure/blobstorage"
mdutils "github.com/dapr/components-contrib/metadata"
"github.com/dapr/kit/logger" "github.com/dapr/kit/logger"
"github.com/dapr/kit/ptr"
) )
const ( const (
@ -49,41 +49,23 @@ const (
// Defines the delete snapshots option for the delete operation. // Defines the delete snapshots option for the delete operation.
// See: https://docs.microsoft.com/en-us/rest/api/storageservices/delete-blob#request-headers // See: https://docs.microsoft.com/en-us/rest/api/storageservices/delete-blob#request-headers
metadataKeyDeleteSnapshots = "deleteSnapshots" metadataKeyDeleteSnapshots = "deleteSnapshots"
// HTTP headers to be associated with the blob.
// See: https://docs.microsoft.com/en-us/rest/api/storageservices/put-blob#request-headers-all-blob-types
metadataKeyContentType = "contentType"
metadataKeyContentMD5 = "contentMD5"
metadataKeyContentEncoding = "contentEncoding"
metadataKeyContentLanguage = "contentLanguage"
metadataKeyContentDisposition = "contentDisposition"
metadataKeyCacheControl = "cacheControl"
// Specifies the maximum number of HTTP GET requests that will be made while reading from a RetryReader. A value
// of zero means that no additional HTTP GET requests will be made.
defaultGetBlobRetryCount = 10
// Specifies the maximum number of blobs to return, including all BlobPrefix elements. If the request does not // Specifies the maximum number of blobs to return, including all BlobPrefix elements. If the request does not
// specify maxresults the server will return up to 5,000 items. // specify maxresults the server will return up to 5,000 items.
// See: https://docs.microsoft.com/en-us/rest/api/storageservices/list-blobs#uri-parameters // See: https://docs.microsoft.com/en-us/rest/api/storageservices/list-blobs#uri-parameters
maxResults = 5000 maxResults int32 = 5000
endpointKey = "endpoint"
) )
var ErrMissingBlobName = errors.New("blobName is a required attribute") var ErrMissingBlobName = errors.New("blobName is a required attribute")
// AzureBlobStorage allows saving blobs to an Azure Blob Storage account. // AzureBlobStorage allows saving blobs to an Azure Blob Storage account.
type AzureBlobStorage struct { type AzureBlobStorage struct {
metadata *blobStorageMetadata metadata *storageinternal.BlobStorageMetadata
containerURL azblob.ContainerURL containerClient *container.Client
logger logger.Logger logger logger.Logger
} }
type blobStorageMetadata struct {
AccountName string
Container string
GetBlobRetryCount int
DecodeBase64 bool
PublicAccessLevel azblob.PublicAccessType
}
type createResponse struct { type createResponse struct {
BlobURL string `json:"blobURL"` BlobURL string `json:"blobURL"`
BlobName string `json:"blobName"` BlobName string `json:"blobName"`
@ -111,90 +93,14 @@ func NewAzureBlobStorage(logger logger.Logger) bindings.OutputBinding {
// Init performs metadata parsing. // Init performs metadata parsing.
func (a *AzureBlobStorage) Init(metadata bindings.Metadata) error { func (a *AzureBlobStorage) Init(metadata bindings.Metadata) error {
m, err := a.parseMetadata(metadata) var err error
a.containerClient, a.metadata, err = storageinternal.CreateContainerStorageClient(a.logger, metadata.Properties)
if err != nil { if err != nil {
return err return err
} }
a.metadata = m
credential, env, err := azauth.GetAzureStorageBlobCredentials(a.logger, m.AccountName, metadata.Properties)
if err != nil {
return fmt.Errorf("invalid credentials with error: %s", err.Error())
}
userAgent := "dapr-" + logger.DaprVersion
options := azblob.PipelineOptions{
Telemetry: azblob.TelemetryOptions{Value: userAgent},
}
p := azblob.NewPipeline(credential, options)
var containerURL azblob.ContainerURL
customEndpoint, ok := mdutils.GetMetadataProperty(metadata.Properties, azauth.StorageEndpointKeys...)
if ok && customEndpoint != "" {
URL, parseErr := url.Parse(fmt.Sprintf("%s/%s/%s", customEndpoint, m.AccountName, m.Container))
if parseErr != nil {
return parseErr
}
containerURL = azblob.NewContainerURL(*URL, p)
} else {
URL, _ := url.Parse(fmt.Sprintf("https://%s.blob.%s/%s", m.AccountName, env.StorageEndpointSuffix, m.Container))
containerURL = azblob.NewContainerURL(*URL, p)
}
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
_, err = containerURL.Create(ctx, azblob.Metadata{}, m.PublicAccessLevel)
cancel()
// Don't return error, container might already exist
a.logger.Debugf("error creating container: %w", err)
a.containerURL = containerURL
return nil return nil
} }
func (a *AzureBlobStorage) parseMetadata(metadata bindings.Metadata) (*blobStorageMetadata, error) {
var m blobStorageMetadata
if val, ok := mdutils.GetMetadataProperty(metadata.Properties, azauth.StorageAccountNameKeys...); ok && val != "" {
m.AccountName = val
} else {
return nil, fmt.Errorf("missing or empty %s field from metadata", azauth.StorageAccountNameKeys[0])
}
if val, ok := mdutils.GetMetadataProperty(metadata.Properties, azauth.StorageContainerNameKeys...); ok && val != "" {
m.Container = val
} else {
return nil, fmt.Errorf("missing or empty %s field from metadata", azauth.StorageContainerNameKeys[0])
}
m.GetBlobRetryCount = defaultGetBlobRetryCount
if val, ok := metadata.Properties["getBlobRetryCount"]; ok {
n, err := strconv.Atoi(val)
if err != nil || n == 0 {
return nil, fmt.Errorf("invalid getBlobRetryCount field from metadata")
}
m.GetBlobRetryCount = n
}
m.DecodeBase64 = false
if val, ok := metadata.Properties["decodeBase64"]; ok {
n, err := strconv.ParseBool(val)
if err != nil {
return nil, fmt.Errorf("invalid decodeBase64 field from metadata")
}
m.DecodeBase64 = n
}
m.PublicAccessLevel = azblob.PublicAccessType(strings.ToLower(metadata.Properties["publicAccessLevel"]))
// per the Dapr documentation "none" is a valid value
if m.PublicAccessLevel == "none" {
m.PublicAccessLevel = ""
}
if !a.isValidPublicAccessType(m.PublicAccessLevel) {
return nil, fmt.Errorf("invalid public access level: %s; allowed: %s", m.PublicAccessLevel, azblob.PossiblePublicAccessTypeValues())
}
return &m, nil
}
func (a *AzureBlobStorage) Operations() []bindings.OperationKind { func (a *AzureBlobStorage) Operations() []bindings.OperationKind {
return []bindings.OperationKind{ return []bindings.OperationKind{
bindings.CreateOperation, bindings.CreateOperation,
@ -205,44 +111,21 @@ func (a *AzureBlobStorage) Operations() []bindings.OperationKind {
} }
func (a *AzureBlobStorage) create(ctx context.Context, req *bindings.InvokeRequest) (*bindings.InvokeResponse, error) { func (a *AzureBlobStorage) create(ctx context.Context, req *bindings.InvokeRequest) (*bindings.InvokeResponse, error) {
var blobHTTPHeaders azblob.BlobHTTPHeaders
var blobURL azblob.BlockBlobURL
var blobName string var blobName string
if val, ok := req.Metadata[metadataKeyBlobName]; ok && val != "" { if val, ok := req.Metadata[metadataKeyBlobName]; ok && val != "" {
blobName = val blobName = val
delete(req.Metadata, metadataKeyBlobName) delete(req.Metadata, metadataKeyBlobName)
} else { } else {
blobName = uuid.New().String() id, err := uuid.NewRandom()
} if err != nil {
blobURL = a.getBlobURL(blobName) return nil, err
if val, ok := req.Metadata[metadataKeyContentType]; ok && val != "" {
blobHTTPHeaders.ContentType = val
delete(req.Metadata, metadataKeyContentType)
}
if val, ok := req.Metadata[metadataKeyContentMD5]; ok && val != "" {
sDec, err := b64.StdEncoding.DecodeString(val)
if err != nil || len(sDec) != 16 {
return nil, fmt.Errorf("the MD5 value specified in Content MD5 is invalid, MD5 value must be 128 bits and base64 encoded")
} }
blobHTTPHeaders.ContentMD5 = sDec blobName = id.String()
delete(req.Metadata, metadataKeyContentMD5)
} }
if val, ok := req.Metadata[metadataKeyContentEncoding]; ok && val != "" {
blobHTTPHeaders.ContentEncoding = val blobHTTPHeaders, err := storageinternal.CreateBlobHTTPHeadersFromRequest(req.Metadata, nil, a.logger)
delete(req.Metadata, metadataKeyContentEncoding) if err != nil {
} return nil, err
if val, ok := req.Metadata[metadataKeyContentLanguage]; ok && val != "" {
blobHTTPHeaders.ContentLanguage = val
delete(req.Metadata, metadataKeyContentLanguage)
}
if val, ok := req.Metadata[metadataKeyContentDisposition]; ok && val != "" {
blobHTTPHeaders.ContentDisposition = val
delete(req.Metadata, metadataKeyContentDisposition)
}
if val, ok := req.Metadata[metadataKeyCacheControl]; ok && val != "" {
blobHTTPHeaders.CacheControl = val
delete(req.Metadata, metadataKeyCacheControl)
} }
d, err := strconv.Unquote(string(req.Data)) d, err := strconv.Unquote(string(req.Data))
@ -258,17 +141,21 @@ func (a *AzureBlobStorage) create(ctx context.Context, req *bindings.InvokeReque
req.Data = decoded req.Data = decoded
} }
_, err = azblob.UploadBufferToBlockBlob(ctx, req.Data, blobURL, azblob.UploadToBlockBlobOptions{ uploadOptions := azblob.UploadBufferOptions{
Parallelism: 16, Metadata: storageinternal.SanitizeMetadata(a.logger, req.Metadata),
Metadata: a.sanitizeMetadata(req.Metadata), HTTPHeaders: &blobHTTPHeaders,
BlobHTTPHeaders: blobHTTPHeaders, TransactionalContentMD5: &blobHTTPHeaders.BlobContentMD5,
}) }
blockBlobClient := a.containerClient.NewBlockBlobClient(blobName)
_, err = blockBlobClient.UploadBuffer(ctx, req.Data, &uploadOptions)
if err != nil { if err != nil {
return nil, fmt.Errorf("error uploading az blob: %w", err) return nil, fmt.Errorf("error uploading az blob: %w", err)
} }
resp := createResponse{ resp := createResponse{
BlobURL: blobURL.String(), BlobURL: blockBlobClient.URL(),
} }
b, err := json.Marshal(resp) b, err := json.Marshal(resp)
if err != nil { if err != nil {
@ -286,23 +173,26 @@ func (a *AzureBlobStorage) create(ctx context.Context, req *bindings.InvokeReque
} }
func (a *AzureBlobStorage) get(ctx context.Context, req *bindings.InvokeRequest) (*bindings.InvokeResponse, error) { func (a *AzureBlobStorage) get(ctx context.Context, req *bindings.InvokeRequest) (*bindings.InvokeResponse, error) {
var blobURL azblob.BlockBlobURL var blockBlobClient *blockblob.Client
if val, ok := req.Metadata[metadataKeyBlobName]; ok && val != "" { if val, ok := req.Metadata[metadataKeyBlobName]; ok && val != "" {
blobURL = a.getBlobURL(val) blockBlobClient = a.containerClient.NewBlockBlobClient(val)
} else { } else {
return nil, ErrMissingBlobName return nil, ErrMissingBlobName
} }
resp, err := blobURL.Download(ctx, 0, azblob.CountToEnd, azblob.BlobAccessConditions{}, false) downloadOptions := azblob.DownloadStreamOptions{
AccessConditions: &blob.AccessConditions{},
}
blobDownloadResponse, err := blockBlobClient.DownloadStream(ctx, &downloadOptions)
if err != nil { if err != nil {
return nil, fmt.Errorf("error downloading az blob: %w", err) return nil, fmt.Errorf("error downloading az blob: %w", err)
} }
reader := blobDownloadResponse.Body
bodyStream := resp.Body(azblob.RetryReaderOptions{MaxRetryRequests: a.metadata.GetBlobRetryCount}) defer reader.Close()
blobData, err := io.ReadAll(reader)
data, err := io.ReadAll(bodyStream)
if err != nil { if err != nil {
return nil, fmt.Errorf("error reading az blob body: %w", err) return nil, fmt.Errorf("error reading az blob: %w", err)
} }
var metadata map[string]string var metadata map[string]string
@ -311,45 +201,54 @@ func (a *AzureBlobStorage) get(ctx context.Context, req *bindings.InvokeRequest)
return nil, fmt.Errorf("error parsing metadata: %w", err) return nil, fmt.Errorf("error parsing metadata: %w", err)
} }
getPropertiesOptions := blob.GetPropertiesOptions{
AccessConditions: &blob.AccessConditions{},
}
if fetchMetadata { if fetchMetadata {
props, err := blobURL.GetProperties(ctx, azblob.BlobAccessConditions{}) props, err := blockBlobClient.GetProperties(ctx, &getPropertiesOptions)
if err != nil { if err != nil {
return nil, fmt.Errorf("error reading blob metadata: %w", err) return nil, fmt.Errorf("error reading blob metadata: %w", err)
} }
metadata = props.NewMetadata() metadata = props.Metadata
} }
return &bindings.InvokeResponse{ return &bindings.InvokeResponse{
Data: data, Data: blobData,
Metadata: metadata, Metadata: metadata,
}, nil }, nil
} }
func (a *AzureBlobStorage) delete(ctx context.Context, req *bindings.InvokeRequest) (*bindings.InvokeResponse, error) { func (a *AzureBlobStorage) delete(ctx context.Context, req *bindings.InvokeRequest) (*bindings.InvokeResponse, error) {
var blobURL azblob.BlockBlobURL var blockBlobClient *blockblob.Client
if val, ok := req.Metadata[metadataKeyBlobName]; ok && val != "" { val, ok := req.Metadata[metadataKeyBlobName]
blobURL = a.getBlobURL(val) if !ok || val == "" {
} else {
return nil, ErrMissingBlobName return nil, ErrMissingBlobName
} }
deleteSnapshotsOptions := azblob.DeleteSnapshotsOptionNone var deleteSnapshotsOptions blob.DeleteSnapshotsOptionType
if val, ok := req.Metadata[metadataKeyDeleteSnapshots]; ok && val != "" { if deleteSnapShotOption, ok := req.Metadata[metadataKeyDeleteSnapshots]; ok && val != "" {
deleteSnapshotsOptions = azblob.DeleteSnapshotsOptionType(val) deleteSnapshotsOptions = azblob.DeleteSnapshotsOptionType(deleteSnapShotOption)
if !a.isValidDeleteSnapshotsOptionType(deleteSnapshotsOptions) { if !a.isValidDeleteSnapshotsOptionType(deleteSnapshotsOptions) {
return nil, fmt.Errorf("invalid delete snapshot option type: %s; allowed: %s", return nil, fmt.Errorf("invalid delete snapshot option type: %s; allowed: %s",
deleteSnapshotsOptions, azblob.PossibleDeleteSnapshotsOptionTypeValues()) deleteSnapshotsOptions, azblob.PossibleDeleteSnapshotsOptionTypeValues())
} }
} }
_, err := blobURL.Delete(ctx, deleteSnapshotsOptions, azblob.BlobAccessConditions{}) deleteOptions := blob.DeleteOptions{
DeleteSnapshots: &deleteSnapshotsOptions,
AccessConditions: &blob.AccessConditions{},
}
blockBlobClient = a.containerClient.NewBlockBlobClient(val)
_, err := blockBlobClient.Delete(ctx, &deleteOptions)
return nil, err return nil, err
} }
func (a *AzureBlobStorage) list(ctx context.Context, req *bindings.InvokeRequest) (*bindings.InvokeResponse, error) { func (a *AzureBlobStorage) list(ctx context.Context, req *bindings.InvokeRequest) (*bindings.InvokeResponse, error) {
options := azblob.ListBlobsSegmentOptions{} options := container.ListBlobsFlatOptions{}
hasPayload := false hasPayload := false
var payload listPayload var payload listPayload
@ -360,50 +259,52 @@ func (a *AzureBlobStorage) list(ctx context.Context, req *bindings.InvokeRequest
} }
hasPayload = true hasPayload = true
} }
if hasPayload { if hasPayload {
options.Details.Copy = payload.Include.Copy options.Include.Copy = payload.Include.Copy
options.Details.Metadata = payload.Include.Metadata options.Include.Metadata = payload.Include.Metadata
options.Details.Snapshots = payload.Include.Snapshots options.Include.Snapshots = payload.Include.Snapshots
options.Details.UncommittedBlobs = payload.Include.UncommittedBlobs options.Include.UncommittedBlobs = payload.Include.UncommittedBlobs
options.Details.Deleted = payload.Include.Deleted options.Include.Deleted = payload.Include.Deleted
} }
if hasPayload && payload.MaxResults != int32(0) { if hasPayload && payload.MaxResults > 0 {
options.MaxResults = payload.MaxResults options.MaxResults = &payload.MaxResults
} else { } else {
options.MaxResults = maxResults options.MaxResults = ptr.Of(maxResults) // cannot get address of constant directly
} }
if hasPayload && payload.Prefix != "" { if hasPayload && payload.Prefix != "" {
options.Prefix = payload.Prefix options.Prefix = &payload.Prefix
} }
var initialMarker azblob.Marker var initialMarker string
if hasPayload && payload.Marker != "" { if hasPayload && payload.Marker != "" {
initialMarker = azblob.Marker{Val: &payload.Marker} initialMarker = payload.Marker
} else { } else {
initialMarker = azblob.Marker{} initialMarker = ""
} }
options.Marker = &initialMarker
var blobs []azblob.BlobItem
metadata := map[string]string{} metadata := map[string]string{}
for currentMaker := initialMarker; currentMaker.NotDone(); { blobs := []*container.BlobItem{}
var listBlob *azblob.ListBlobsFlatSegmentResponse pager := a.containerClient.NewListBlobsFlatPager(&options)
listBlob, err := a.containerURL.ListBlobsFlatSegment(ctx, currentMaker, options)
for pager.More() {
resp, err := pager.NextPage(ctx)
if err != nil { if err != nil {
return nil, fmt.Errorf("error listing blobs: %w", err) return nil, fmt.Errorf("error listing blobs: %w", err)
} }
blobs = append(blobs, listBlob.Segment.BlobItems...) blobs = append(blobs, resp.Segment.BlobItems...)
numBlobs := len(blobs) numBlobs := len(blobs)
currentMaker = listBlob.NextMarker
metadata[metadataKeyMarker] = *currentMaker.Val
metadata[metadataKeyNumber] = strconv.FormatInt(int64(numBlobs), 10) metadata[metadataKeyNumber] = strconv.FormatInt(int64(numBlobs), 10)
metadata[metadataKeyMarker] = ""
if resp.Marker != nil {
metadata[metadataKeyMarker] = *resp.Marker
}
if options.MaxResults-maxResults > 0 { if *options.MaxResults-maxResults > 0 {
options.MaxResults -= maxResults *options.MaxResults -= maxResults
} else { } else {
break break
} }
@ -435,23 +336,6 @@ func (a *AzureBlobStorage) Invoke(ctx context.Context, req *bindings.InvokeReque
} }
} }
func (a *AzureBlobStorage) getBlobURL(name string) azblob.BlockBlobURL {
blobURL := a.containerURL.NewBlockBlobURL(name)
return blobURL
}
func (a *AzureBlobStorage) isValidPublicAccessType(accessType azblob.PublicAccessType) bool {
validTypes := azblob.PossiblePublicAccessTypeValues()
for _, item := range validTypes {
if item == accessType {
return true
}
}
return false
}
func (a *AzureBlobStorage) isValidDeleteSnapshotsOptionType(accessType azblob.DeleteSnapshotsOptionType) bool { func (a *AzureBlobStorage) isValidDeleteSnapshotsOptionType(accessType azblob.DeleteSnapshotsOptionType) bool {
validTypes := azblob.PossibleDeleteSnapshotsOptionTypeValues() validTypes := azblob.PossibleDeleteSnapshotsOptionTypeValues()
for _, item := range validTypes { for _, item := range validTypes {
@ -462,41 +346,3 @@ func (a *AzureBlobStorage) isValidDeleteSnapshotsOptionType(accessType azblob.De
return false return false
} }
func (a *AzureBlobStorage) sanitizeMetadata(metadata map[string]string) map[string]string {
for key, val := range metadata {
// Keep only letters and digits
n := 0
newKey := make([]byte, len(key))
for i := 0; i < len(key); i++ {
if (key[i] >= 'A' && key[i] <= 'Z') ||
(key[i] >= 'a' && key[i] <= 'z') ||
(key[i] >= '0' && key[i] <= '9') {
newKey[n] = key[i]
n++
}
}
if n != len(key) {
nks := string(newKey[:n])
a.logger.Warnf("metadata key %s contains disallowed characters, sanitized to %s", key, nks)
delete(metadata, key)
metadata[nks] = val
key = nks
}
// Remove all non-ascii characters
n = 0
newVal := make([]byte, len(val))
for i := 0; i < len(val); i++ {
if val[i] > 127 {
continue
}
newVal[n] = val[i]
n++
}
metadata[key] = string(newVal[:n])
}
return metadata
}

View File

@ -17,83 +17,12 @@ import (
"context" "context"
"testing" "testing"
"github.com/Azure/azure-storage-blob-go/azblob"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/dapr/components-contrib/bindings" "github.com/dapr/components-contrib/bindings"
"github.com/dapr/kit/logger" "github.com/dapr/kit/logger"
) )
func TestParseMetadata(t *testing.T) {
m := bindings.Metadata{}
blobStorage := NewAzureBlobStorage(logger.NewLogger("test")).(*AzureBlobStorage)
t.Run("parse all metadata", func(t *testing.T) {
m.Properties = map[string]string{
"storageAccount": "account",
"storageAccessKey": "key",
"container": "test",
"getBlobRetryCount": "5",
"decodeBase64": "true",
}
meta, err := blobStorage.parseMetadata(m)
assert.Nil(t, err)
assert.Equal(t, "test", meta.Container)
assert.Equal(t, "account", meta.AccountName)
// storageAccessKey is parsed in the azauth package
assert.Equal(t, true, meta.DecodeBase64)
assert.Equal(t, 5, meta.GetBlobRetryCount)
assert.Equal(t, azblob.PublicAccessNone, meta.PublicAccessLevel)
})
t.Run("parse metadata with publicAccessLevel = blob", func(t *testing.T) {
m.Properties = map[string]string{
"storageAccount": "account",
"storageAccessKey": "key",
"container": "test",
"publicAccessLevel": "blob",
}
meta, err := blobStorage.parseMetadata(m)
assert.Nil(t, err)
assert.Equal(t, azblob.PublicAccessBlob, meta.PublicAccessLevel)
})
t.Run("parse metadata with publicAccessLevel = container", func(t *testing.T) {
m.Properties = map[string]string{
"storageAccount": "account",
"storageAccessKey": "key",
"container": "test",
"publicAccessLevel": "container",
}
meta, err := blobStorage.parseMetadata(m)
assert.Nil(t, err)
assert.Equal(t, azblob.PublicAccessContainer, meta.PublicAccessLevel)
})
t.Run("parse metadata with invalid publicAccessLevel", func(t *testing.T) {
m.Properties = map[string]string{
"storageAccount": "account",
"storageAccessKey": "key",
"container": "test",
"publicAccessLevel": "invalid",
}
_, err := blobStorage.parseMetadata(m)
assert.Error(t, err)
})
t.Run("sanitize metadata if necessary", func(t *testing.T) {
m.Properties = map[string]string{
"somecustomfield": "some-custom-value",
"specialfield": "special:valueÜ",
"not-allowed:": "not-allowed",
}
meta := blobStorage.sanitizeMetadata(m.Properties)
assert.Equal(t, meta["somecustomfield"], "some-custom-value")
assert.Equal(t, meta["specialfield"], "special:value")
assert.Equal(t, meta["notallowed"], "not-allowed")
})
}
func TestGetOption(t *testing.T) { func TestGetOption(t *testing.T) {
blobStorage := NewAzureBlobStorage(logger.NewLogger("test")).(*AzureBlobStorage) blobStorage := NewAzureBlobStorage(logger.NewLogger("test")).(*AzureBlobStorage)

View File

@ -28,6 +28,7 @@ import (
"github.com/mitchellh/mapstructure" "github.com/mitchellh/mapstructure"
"github.com/dapr/components-contrib/bindings" "github.com/dapr/components-contrib/bindings"
"github.com/dapr/components-contrib/internal/utils"
"github.com/dapr/kit/logger" "github.com/dapr/kit/logger"
) )
@ -35,10 +36,10 @@ import (
// //
//revive:disable-next-line //revive:disable-next-line
type HTTPSource struct { type HTTPSource struct {
metadata httpMetadata metadata httpMetadata
client *http.Client client *http.Client
errorIfNot2XX bool
logger logger.Logger logger logger.Logger
} }
type httpMetadata struct { type httpMetadata struct {
@ -70,6 +71,13 @@ func (h *HTTPSource) Init(metadata bindings.Metadata) error {
Transport: netTransport, Transport: netTransport,
} }
if val, ok := metadata.Properties["errorIfNot2XX"]; ok {
h.errorIfNot2XX = utils.IsTruthy(val)
} else {
// Default behavior
h.errorIfNot2XX = true
}
return nil return nil
} }
@ -91,6 +99,9 @@ func (h *HTTPSource) Operations() []bindings.OperationKind {
// Invoke performs an HTTP request to the configured HTTP endpoint. // Invoke performs an HTTP request to the configured HTTP endpoint.
func (h *HTTPSource) Invoke(ctx context.Context, req *bindings.InvokeRequest) (*bindings.InvokeResponse, error) { func (h *HTTPSource) Invoke(ctx context.Context, req *bindings.InvokeRequest) (*bindings.InvokeResponse, error) {
u := h.metadata.URL u := h.metadata.URL
errorIfNot2XX := h.errorIfNot2XX // Default to the component config (default is true)
if req.Metadata != nil { if req.Metadata != nil {
if path, ok := req.Metadata["path"]; ok { if path, ok := req.Metadata["path"]; ok {
// Simplicity and no "../../.." type exploits. // Simplicity and no "../../.." type exploits.
@ -99,6 +110,13 @@ func (h *HTTPSource) Invoke(ctx context.Context, req *bindings.InvokeRequest) (*
return nil, fmt.Errorf("invalid path: %s", path) return nil, fmt.Errorf("invalid path: %s", path)
} }
} }
if _, ok := req.Metadata["errorIfNot2XX"]; ok {
errorIfNot2XX = utils.IsTruthy(req.Metadata["errorIfNot2XX"])
}
} else {
// Prevent things below from failing if req.Metadata is nil.
req.Metadata = make(map[string]string)
} }
var body io.Reader var body io.Reader
@ -164,8 +182,8 @@ func (h *HTTPSource) Invoke(ctx context.Context, req *bindings.InvokeRequest) (*
metadata[key] = strings.Join(values, ", ") metadata[key] = strings.Join(values, ", ")
} }
// Create an error for non-200 status codes. // Create an error for non-200 status codes unless suppressed.
if resp.StatusCode/100 != 2 { if errorIfNot2XX && resp.StatusCode/100 != 2 {
err = fmt.Errorf("received status code %d", resp.StatusCode) err = fmt.Errorf("received status code %d", resp.StatusCode)
} }

View File

@ -18,6 +18,7 @@ import (
"io" "io"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"strconv"
"strings" "strings"
"testing" "testing"
@ -45,146 +46,316 @@ func TestOperations(t *testing.T) {
}, opers) }, opers)
} }
func TestInit(t *testing.T) { type TestCase struct {
var path string input string
operation string
metadata map[string]string
path string
err string
statusCode int
}
s := httptest.NewServer( func (tc TestCase) ToInvokeRequest() bindings.InvokeRequest {
http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { requestMetadata := tc.metadata
path = req.URL.Path
input := req.Method
if req.Body != nil {
defer req.Body.Close()
b, _ := io.ReadAll(req.Body)
if len(b) > 0 {
input = string(b)
}
}
inputFromHeader := req.Header.Get("X-Input")
if inputFromHeader != "" {
input = inputFromHeader
}
w.Header().Set("Content-Type", "text/plain")
if input == "internal server error" {
w.WriteHeader(http.StatusInternalServerError)
}
w.Write([]byte(strings.ToUpper(input)))
}),
)
defer s.Close()
if requestMetadata == nil {
requestMetadata = map[string]string{}
}
requestMetadata["X-Status-Code"] = strconv.Itoa(tc.statusCode)
return bindings.InvokeRequest{
Data: []byte(tc.input),
Metadata: requestMetadata,
Operation: bindings.OperationKind(tc.operation),
}
}
type HTTPHandler struct {
Path string
}
func (h *HTTPHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
h.Path = req.URL.Path
input := req.Method
if req.Body != nil {
defer req.Body.Close()
b, _ := io.ReadAll(req.Body)
if len(b) > 0 {
input = string(b)
}
}
inputFromHeader := req.Header.Get("X-Input")
if inputFromHeader != "" {
input = inputFromHeader
}
w.Header().Set("Content-Type", "text/plain")
statusCode := req.Header.Get("X-Status-Code")
if statusCode != "" {
code, _ := strconv.Atoi(statusCode)
w.WriteHeader(code)
}
w.Write([]byte(strings.ToUpper(input)))
}
func NewHTTPHandler() *HTTPHandler {
return &HTTPHandler{
Path: "/",
}
}
func InitBinding(s *httptest.Server, extraProps map[string]string) (bindings.OutputBinding, error) {
m := bindings.Metadata{Base: metadata.Base{ m := bindings.Metadata{Base: metadata.Base{
Properties: map[string]string{ Properties: map[string]string{
"url": s.URL, "url": s.URL,
}, },
}} }}
if extraProps != nil {
for k, v := range extraProps {
m.Properties[k] = v
}
}
hs := bindingHttp.NewHTTP(logger.NewLogger("test")) hs := bindingHttp.NewHTTP(logger.NewLogger("test"))
err := hs.Init(m) err := hs.Init(m)
return hs, err
}
func TestInit(t *testing.T) {
handler := NewHTTPHandler()
s := httptest.NewServer(handler)
defer s.Close()
_, err := InitBinding(s, nil)
require.NoError(t, err)
}
func TestDefaultBehavior(t *testing.T) {
handler := NewHTTPHandler()
s := httptest.NewServer(handler)
defer s.Close()
hs, err := InitBinding(s, nil)
require.NoError(t, err) require.NoError(t, err)
tests := map[string]struct { tests := map[string]TestCase{
input string
operation string
metadata map[string]string
path string
err string
}{
"get": { "get": {
input: "GET", input: "GET",
operation: "get", operation: "get",
metadata: nil, metadata: nil,
path: "/", path: "/",
err: "", err: "",
statusCode: 200,
}, },
"request headers": { "request headers": {
input: "OVERRIDE", input: "OVERRIDE",
operation: "get", operation: "get",
metadata: map[string]string{"X-Input": "override"}, metadata: map[string]string{"X-Input": "override"},
path: "/", path: "/",
err: "", err: "",
statusCode: 200,
}, },
"post": { "post": {
input: "expected", input: "expected",
operation: "post", operation: "post",
metadata: map[string]string{"path": "/test"}, metadata: map[string]string{"path": "/test"},
path: "/test", path: "/test",
err: "", err: "",
statusCode: 201,
}, },
"put": { "put": {
input: "expected", input: "expected",
operation: "put", operation: "put",
metadata: map[string]string{"path": "/test"}, statusCode: 204,
path: "/test", metadata: map[string]string{"path": "/test"},
err: "", path: "/test",
err: "",
}, },
"patch": { "patch": {
input: "expected", input: "expected",
operation: "patch", operation: "patch",
metadata: map[string]string{"path": "/test"}, metadata: map[string]string{"path": "/test"},
path: "/test", path: "/test",
err: "", err: "",
statusCode: 206,
}, },
"delete": { "delete": {
input: "DELETE", input: "DELETE",
operation: "delete", operation: "delete",
metadata: nil, metadata: nil,
path: "/", path: "/",
err: "", err: "",
statusCode: 200,
}, },
"options": { "options": {
input: "OPTIONS", input: "OPTIONS",
operation: "options", operation: "options",
metadata: nil, metadata: nil,
path: "/", path: "/",
err: "", err: "",
statusCode: 200,
}, },
"trace": { "trace": {
input: "TRACE", input: "TRACE",
operation: "trace", operation: "trace",
metadata: nil, metadata: nil,
path: "/", path: "/",
err: "", err: "",
statusCode: 200,
}, },
"backward compatibility": { "backward compatibility": {
input: "expected", input: "expected",
operation: "create", operation: "create",
metadata: map[string]string{"path": "/test"}, metadata: map[string]string{"path": "/test"},
path: "/test", path: "/test",
err: "", err: "",
statusCode: 200,
}, },
"invalid path": { "invalid path": {
input: "expected", input: "expected",
operation: "POST", operation: "POST",
metadata: map[string]string{"path": "/../test"}, metadata: map[string]string{"path": "/../test"},
path: "", path: "",
err: "invalid path: /../test", err: "invalid path: /../test",
statusCode: 400,
}, },
"invalid operation": { "invalid operation": {
input: "notvalid", input: "notvalid",
operation: "notvalid", operation: "notvalid",
metadata: map[string]string{"path": "/test"}, metadata: map[string]string{"path": "/test"},
path: "/test", path: "/test",
err: "invalid operation: notvalid", err: "invalid operation: notvalid",
statusCode: 400,
}, },
"internal server error": { "internal server error": {
input: "internal server error", input: "internal server error",
operation: "post", operation: "post",
metadata: map[string]string{"path": "/"}, metadata: map[string]string{"path": "/"},
path: "/", path: "/",
err: "received status code 500", err: "received status code 500",
statusCode: 500,
},
"internal server error suppressed": {
input: "internal server error", // trigger 500 downstream
operation: "post",
metadata: map[string]string{"path": "/", "errorIfNot2XX": "false"},
path: "/",
err: "",
statusCode: 500,
},
"redirect should not yield an error": {
input: "show me the treasure!",
operation: "post",
metadata: map[string]string{"path": "/", "errorIfNot2XX": "false"},
path: "/",
err: "",
statusCode: 302,
},
"redirect results in an error if not suppressed": {
input: "show me the treasure!",
operation: "post",
metadata: map[string]string{"path": "/"},
path: "/",
err: "received status code 302",
statusCode: 302,
}, },
} }
for name, tc := range tests { for name, tc := range tests {
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
response, err := hs.Invoke(context.TODO(), &bindings.InvokeRequest{ req := tc.ToInvokeRequest()
Data: []byte(tc.input), response, err := hs.Invoke(context.TODO(), &req)
Metadata: tc.metadata,
Operation: bindings.OperationKind(tc.operation),
})
if tc.err == "" { if tc.err == "" {
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, tc.path, path) assert.Equal(t, tc.path, handler.Path)
assert.Equal(t, strings.ToUpper(tc.input), string(response.Data)) if tc.statusCode != 204 {
// 204 will return no content, so we should skip checking
assert.Equal(t, strings.ToUpper(tc.input), string(response.Data))
}
assert.Equal(t, "text/plain", response.Metadata["Content-Type"])
} else {
require.Error(t, err)
assert.Equal(t, tc.err, err.Error())
}
})
}
}
func TestNon2XXErrorsSuppressed(t *testing.T) {
handler := NewHTTPHandler()
s := httptest.NewServer(handler)
defer s.Close()
hs, err := InitBinding(s, map[string]string{"errorIfNot2XX": "false"})
require.NoError(t, err)
tests := map[string]TestCase{
"internal server error": {
input: "internal server error",
operation: "post",
metadata: map[string]string{"path": "/"},
path: "/",
err: "",
statusCode: 500,
},
"internal server error overridden": {
input: "internal server error",
operation: "post",
metadata: map[string]string{"path": "/", "errorIfNot2XX": "true"},
path: "/",
err: "received status code 500",
statusCode: 500,
},
"internal server error suppressed by request and component": {
input: "internal server error", // trigger 500
operation: "post",
metadata: map[string]string{"path": "/", "errorIfNot2XX": "false"},
path: "/",
err: "",
statusCode: 500,
},
"trace": {
input: "TRACE",
operation: "trace",
metadata: nil,
path: "/",
err: "",
statusCode: 200,
},
"backward compatibility": {
input: "expected",
operation: "create",
metadata: map[string]string{"path": "/test"},
path: "/test",
err: "",
statusCode: 200,
},
"invalid path": {
input: "expected",
operation: "POST",
metadata: map[string]string{"path": "/../test"},
path: "",
err: "invalid path: /../test",
statusCode: 400,
},
}
for name, tc := range tests {
t.Run(name, func(t *testing.T) {
req := tc.ToInvokeRequest()
response, err := hs.Invoke(context.TODO(), &req)
if tc.err == "" {
require.NoError(t, err)
assert.Equal(t, tc.path, handler.Path)
if tc.statusCode != 204 {
// 204 will return no content, so we should skip checking
assert.Equal(t, strings.ToUpper(tc.input), string(response.Data))
}
assert.Equal(t, "text/plain", response.Metadata["Content-Type"]) assert.Equal(t, "text/plain", response.Metadata["Content-Type"])
} else { } else {
require.Error(t, err) require.Error(t, err)

3
go.mod
View File

@ -18,6 +18,7 @@ require (
github.com/Azure/azure-sdk-for-go/sdk/data/aztables v1.0.1 github.com/Azure/azure-sdk-for-go/sdk/data/aztables v1.0.1
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.10.1 github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.10.1
github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.1.1 github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.1.1
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.5.1
github.com/Azure/azure-storage-blob-go v0.10.0 github.com/Azure/azure-storage-blob-go v0.10.0
github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd
github.com/Azure/go-amqp v0.17.5 github.com/Azure/go-amqp v0.17.5
@ -133,7 +134,7 @@ require (
github.com/99designs/keyring v1.2.1 // indirect github.com/99designs/keyring v1.2.1 // indirect
github.com/AthenZ/athenz v1.10.39 // indirect github.com/AthenZ/athenz v1.10.39 // indirect
github.com/Azure/azure-pipeline-go v0.2.3 // indirect github.com/Azure/azure-pipeline-go v0.2.3 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.0 // indirect
github.com/Azure/go-autorest v14.2.0+incompatible // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect
github.com/Azure/go-autorest/autorest/azure/cli v0.4.5 // indirect github.com/Azure/go-autorest/autorest/azure/cli v0.4.5 // indirect

6
go.sum
View File

@ -110,14 +110,16 @@ github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos v0.3.2/go.mod h1:Fy3bbChFm4c
github.com/Azure/azure-sdk-for-go/sdk/data/aztables v1.0.1 h1:bFa9IcjvrCber6gGgDAUZ+I2bO8J7s8JxXmu9fhi2ss= github.com/Azure/azure-sdk-for-go/sdk/data/aztables v1.0.1 h1:bFa9IcjvrCber6gGgDAUZ+I2bO8J7s8JxXmu9fhi2ss=
github.com/Azure/azure-sdk-for-go/sdk/data/aztables v1.0.1/go.mod h1:l3wvZkG9oW07GLBW5Cd0WwG5asOfJ8aqE8raUvNzLpk= github.com/Azure/azure-sdk-for-go/sdk/data/aztables v1.0.1/go.mod h1:l3wvZkG9oW07GLBW5Cd0WwG5asOfJ8aqE8raUvNzLpk=
github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8= github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 h1:jp0dGvZ7ZK0mgqnTSClMxa5xuRL7NZgHameVYF6BurY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 h1:XUNQ4mw+zJmaA2KXzP9JlQiecy1SI+Eog7xVkPiqIbg=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w=
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.10.1 h1:AhZnZn4kUKz36bHJ8AK/FH2tH/q3CAkG+Gme+2ibuak= github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.10.1 h1:AhZnZn4kUKz36bHJ8AK/FH2tH/q3CAkG+Gme+2ibuak=
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.10.1/go.mod h1:S78i9yTr4o/nXlH76bKjGUye9Z2wSxO5Tz7GoDr4vfI= github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.10.1/go.mod h1:S78i9yTr4o/nXlH76bKjGUye9Z2wSxO5Tz7GoDr4vfI=
github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.0 h1:Lg6BW0VPmCwcMlvOviL3ruHFO+H9tZNqscK0AeuFjGM= github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.0 h1:Lg6BW0VPmCwcMlvOviL3ruHFO+H9tZNqscK0AeuFjGM=
github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.0/go.mod h1:9V2j0jn9jDEkCkv8w/bKTNppX/d0FVA1ud77xCIP4KA= github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.0/go.mod h1:9V2j0jn9jDEkCkv8w/bKTNppX/d0FVA1ud77xCIP4KA=
github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.1.1 h1:Zm7A6yKHT3evC/0lquPWJ9hrkRGVIeZOmIvHPv6xV9Q= github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.1.1 h1:Zm7A6yKHT3evC/0lquPWJ9hrkRGVIeZOmIvHPv6xV9Q=
github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.1.1/go.mod h1:LH9XQnMr2ZYxQdVdCrzLO9mxeDyrDFa6wbSI3x5zCZk= github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.1.1/go.mod h1:LH9XQnMr2ZYxQdVdCrzLO9mxeDyrDFa6wbSI3x5zCZk=
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.5.1 h1:BMTdr+ib5ljLa9MxTJK8x/Ds0MbBb4MfuW5BL0zMJnI=
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.5.1/go.mod h1:c6WvOhtmjNUWbLfOG1qxM/q0SPvQNSVJvolm+C52dIU=
github.com/Azure/azure-storage-blob-go v0.6.0/go.mod h1:oGfmITT1V6x//CswqY2gtAHND+xIP64/qL7a5QJix0Y= github.com/Azure/azure-storage-blob-go v0.6.0/go.mod h1:oGfmITT1V6x//CswqY2gtAHND+xIP64/qL7a5QJix0Y=
github.com/Azure/azure-storage-blob-go v0.10.0 h1:evCwGreYo3XLeBV4vSxLbLiYb6e0SzsJiXQVRGsRXxs= github.com/Azure/azure-storage-blob-go v0.10.0 h1:evCwGreYo3XLeBV4vSxLbLiYb6e0SzsJiXQVRGsRXxs=
github.com/Azure/azure-storage-blob-go v0.10.0/go.mod h1:ep1edmW+kNQx4UfWM9heESNmQdijykocJ0YOxmMX8SE= github.com/Azure/azure-storage-blob-go v0.10.0/go.mod h1:ep1edmW+kNQx4UfWM9heESNmQdijykocJ0YOxmMX8SE=

View File

@ -0,0 +1,111 @@
/*
Copyright 2021 The Dapr Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package blobstorage
import (
"context"
"fmt"
"net/url"
"time"
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/container"
azauth "github.com/dapr/components-contrib/internal/authentication/azure"
mdutils "github.com/dapr/components-contrib/metadata"
"github.com/dapr/kit/logger"
)
const (
// Specifies the maximum number of HTTP requests that will be made to retry blob operations. A value
// of zero means that no additional HTTP requests will be made.
defaultBlobRetryCount = 3
)
func CreateContainerStorageClient(log logger.Logger, meta map[string]string) (*container.Client, *BlobStorageMetadata, error) {
m, err := parseMetadata(meta)
if err != nil {
return nil, nil, err
}
userAgent := "dapr-" + logger.DaprVersion
options := container.ClientOptions{
ClientOptions: azcore.ClientOptions{
Retry: policy.RetryOptions{
MaxRetries: m.RetryCount,
},
Telemetry: policy.TelemetryOptions{
ApplicationID: userAgent,
},
},
}
settings, err := azauth.NewEnvironmentSettings("storage", meta)
if err != nil {
return nil, nil, err
}
var customEndpoint string
if val, ok := mdutils.GetMetadataProperty(meta, azauth.StorageEndpointKeys...); ok && val != "" {
customEndpoint = val
}
var URL *url.URL
if customEndpoint != "" {
var parseErr error
URL, parseErr = url.Parse(fmt.Sprintf("%s/%s/%s", customEndpoint, m.AccountName, m.ContainerName))
if parseErr != nil {
return nil, nil, parseErr
}
} else {
env := settings.AzureEnvironment
URL, _ = url.Parse(fmt.Sprintf("https://%s.blob.%s/%s", m.AccountName, env.StorageEndpointSuffix, m.ContainerName))
}
var clientErr error
var client *container.Client
// Try using shared key credentials first
if m.AccountKey != "" {
credential, newSharedKeyErr := azblob.NewSharedKeyCredential(m.AccountName, m.AccountKey)
if err != nil {
return nil, nil, fmt.Errorf("invalid shared key credentials with error: %w", newSharedKeyErr)
}
client, clientErr = container.NewClientWithSharedKeyCredential(URL.String(), credential, &options)
if clientErr != nil {
return nil, nil, fmt.Errorf("cannot init Blobstorage container client: %w", err)
}
} else {
// fallback to AAD
credential, tokenErr := settings.GetTokenCredential()
if err != nil {
return nil, nil, fmt.Errorf("invalid token credentials with error: %w", tokenErr)
}
client, clientErr = container.NewClient(URL.String(), credential, &options)
}
if clientErr != nil {
return nil, nil, fmt.Errorf("cannot init Blobstorage client: %w", clientErr)
}
createContainerOptions := container.CreateOptions{
Access: &m.PublicAccessLevel,
Metadata: map[string]string{},
}
timeoutCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
_, err = client.Create(timeoutCtx, &createContainerOptions)
cancel()
// Don't return error, container might already exist
log.Debugf("error creating container: %v", err)
return client, m, nil
}

View File

@ -0,0 +1,64 @@
/*
Copyright 2021 The Dapr Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package blobstorage
import (
"testing"
"github.com/stretchr/testify/assert"
azauth "github.com/dapr/components-contrib/internal/authentication/azure"
"github.com/dapr/kit/logger"
)
type scenario struct {
metadata map[string]string
expectedFailureSubString string
}
func TestClientInitFailures(t *testing.T) {
log := logger.NewLogger("test")
scenarios := map[string]scenario{
"missing accountName": {
metadata: createTestMetadata(false, true, true),
expectedFailureSubString: "missing or empty accountName field from metadata",
},
"missing container": {
metadata: createTestMetadata(true, true, false),
expectedFailureSubString: "missing or empty containerName field from metadata",
},
}
for name, s := range scenarios {
t.Run(name, func(t *testing.T) {
_, _, err := CreateContainerStorageClient(log, s.metadata)
assert.Contains(t, err.Error(), s.expectedFailureSubString)
})
}
}
func createTestMetadata(accountName bool, accountKey bool, container bool) map[string]string {
m := map[string]string{}
if accountName {
m[azauth.StorageAccountNameKeys[0]] = "account"
}
if accountKey {
m[azauth.StorageAccountKeyKeys[0]] = "key"
}
if container {
m[azauth.StorageContainerNameKeys[0]] = "test"
}
return m
}

View File

@ -0,0 +1,88 @@
/*
Copyright 2021 The Dapr Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package blobstorage
import (
"fmt"
"strconv"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob"
azauth "github.com/dapr/components-contrib/internal/authentication/azure"
mdutils "github.com/dapr/components-contrib/metadata"
)
type BlobStorageMetadata struct {
AccountName string
AccountKey string
ContainerName string
RetryCount int32 `json:"retryCount,string"`
DecodeBase64 bool `json:"decodeBase64,string"`
PublicAccessLevel azblob.PublicAccessType
}
func parseMetadata(meta map[string]string) (*BlobStorageMetadata, error) {
m := BlobStorageMetadata{
RetryCount: defaultBlobRetryCount,
}
mdutils.DecodeMetadata(meta, &m)
if val, ok := mdutils.GetMetadataProperty(meta, azauth.StorageAccountNameKeys...); ok && val != "" {
m.AccountName = val
} else {
return nil, fmt.Errorf("missing or empty %s field from metadata", azauth.StorageAccountNameKeys[0])
}
if val, ok := mdutils.GetMetadataProperty(meta, azauth.StorageContainerNameKeys...); ok && val != "" {
m.ContainerName = val
} else {
return nil, fmt.Errorf("missing or empty %s field from metadata", azauth.StorageContainerNameKeys[0])
}
if val, ok := mdutils.GetMetadataProperty(meta, azauth.StorageAccountKeyKeys...); ok && val != "" {
m.AccountKey = val
}
// per the Dapr documentation "none" is a valid value
if m.PublicAccessLevel == "none" {
m.PublicAccessLevel = ""
}
if m.PublicAccessLevel != "" && !isValidPublicAccessType(m.PublicAccessLevel) {
return nil, fmt.Errorf("invalid public access level: %s; allowed: %s",
m.PublicAccessLevel, azblob.PossiblePublicAccessTypeValues())
}
// we need this key for backwards compatibility
if val, ok := meta["getBlobRetryCount"]; ok && val != "" {
// convert val from string to int32
parseInt, err := strconv.ParseInt(val, 10, 32)
if err != nil {
return nil, err
}
m.RetryCount = int32(parseInt)
}
return &m, nil
}
func isValidPublicAccessType(accessType azblob.PublicAccessType) bool {
validTypes := azblob.PossiblePublicAccessTypeValues()
for _, item := range validTypes {
if item == accessType {
return true
}
}
return false
}

View File

@ -0,0 +1,79 @@
/*
Copyright 2021 The Dapr Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package blobstorage
import (
"testing"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob"
"github.com/stretchr/testify/assert"
)
func TestParseMetadata(t *testing.T) {
var m map[string]string
t.Run("parse all metadata", func(t *testing.T) {
m = map[string]string{
"storageAccount": "account",
"storageAccessKey": "key",
"container": "test",
"getBlobRetryCount": "5",
"decodeBase64": "true",
}
meta, err := parseMetadata(m)
assert.Nil(t, err)
assert.Equal(t, "test", meta.ContainerName)
assert.Equal(t, "account", meta.AccountName)
// storageAccessKey is parsed in the azauth package
assert.Equal(t, true, meta.DecodeBase64)
assert.Equal(t, int32(5), meta.RetryCount)
assert.Equal(t, "", string(meta.PublicAccessLevel))
})
t.Run("parse metadata with publicAccessLevel = blob", func(t *testing.T) {
m = map[string]string{
"storageAccount": "account",
"storageAccessKey": "key",
"container": "test",
"publicAccessLevel": "blob",
}
meta, err := parseMetadata(m)
assert.Nil(t, err)
assert.Equal(t, azblob.PublicAccessTypeBlob, meta.PublicAccessLevel)
})
t.Run("parse metadata with publicAccessLevel = container", func(t *testing.T) {
m = map[string]string{
"storageAccount": "account",
"storageAccessKey": "key",
"container": "test",
"publicAccessLevel": "container",
}
meta, err := parseMetadata(m)
assert.Nil(t, err)
assert.Equal(t, azblob.PublicAccessTypeContainer, meta.PublicAccessLevel)
})
t.Run("parse metadata with invalid publicAccessLevel", func(t *testing.T) {
m = map[string]string{
"storageAccount": "account",
"storageAccessKey": "key",
"container": "test",
"publicAccessLevel": "invalid",
}
_, err := parseMetadata(m)
assert.Error(t, err)
})
}

View File

@ -0,0 +1,118 @@
/*
Copyright 2021 The Dapr Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package blobstorage
import (
b64 "encoding/base64"
"fmt"
"strings"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob"
"github.com/dapr/kit/logger"
)
const (
contentTypeKey = "contenttype"
contentMD5Key = "contentmd5"
contentEncodingKey = "contentencoding"
contentLanguageKey = "contentlanguage"
contentDispositionKey = "contentdisposition"
cacheControlKey = "cachecontrol"
)
func CreateBlobHTTPHeadersFromRequest(meta map[string]string, contentType *string, log logger.Logger) (blob.HTTPHeaders, error) {
// build map to support arbitrary case
caseMap := make(map[string]string)
for k := range meta {
caseMap[strings.ToLower(k)] = k
}
blobHTTPHeaders := blob.HTTPHeaders{}
if val, ok := meta[caseMap[contentTypeKey]]; ok && val != "" {
blobHTTPHeaders.BlobContentType = &val
delete(meta, caseMap[contentTypeKey])
}
if contentType != nil {
if blobHTTPHeaders.BlobContentType != nil {
log.Warnf("ContentType received from request Metadata %s, as well as ContentType property %s, choosing value from contentType property", blobHTTPHeaders.BlobContentType, *contentType)
}
blobHTTPHeaders.BlobContentType = contentType
}
if val, ok := meta[caseMap[contentMD5Key]]; ok && val != "" {
sDec, err := b64.StdEncoding.DecodeString(val)
if err != nil || len(sDec) != 16 {
return blob.HTTPHeaders{}, fmt.Errorf("the MD5 value specified in Content MD5 is invalid, MD5 value must be 128 bits and base64 encoded")
}
blobHTTPHeaders.BlobContentMD5 = sDec
delete(meta, caseMap[contentMD5Key])
}
if val, ok := meta[caseMap[contentEncodingKey]]; ok && val != "" {
blobHTTPHeaders.BlobContentEncoding = &val
delete(meta, caseMap[contentEncodingKey])
}
if val, ok := meta[caseMap[contentLanguageKey]]; ok && val != "" {
blobHTTPHeaders.BlobContentLanguage = &val
delete(meta, caseMap[contentLanguageKey])
}
if val, ok := meta[caseMap[contentDispositionKey]]; ok && val != "" {
blobHTTPHeaders.BlobContentDisposition = &val
delete(meta, caseMap[contentDispositionKey])
}
if val, ok := meta[caseMap[cacheControlKey]]; ok && val != "" {
blobHTTPHeaders.BlobCacheControl = &val
delete(meta, caseMap[cacheControlKey])
}
return blobHTTPHeaders, nil
}
func SanitizeMetadata(log logger.Logger, metadata map[string]string) map[string]string {
for key, val := range metadata {
// Keep only letters and digits
n := 0
newKey := make([]byte, len(key))
for i := 0; i < len(key); i++ {
if (key[i] >= 'A' && key[i] <= 'Z') ||
(key[i] >= 'a' && key[i] <= 'z') ||
(key[i] >= '0' && key[i] <= '9') {
newKey[n] = key[i]
n++
}
}
if n != len(key) {
nks := string(newKey[:n])
log.Warnf("metadata key %s contains disallowed characters, sanitized to %s", key, nks)
delete(metadata, key)
metadata[nks] = val
key = nks
}
// Remove all non-ascii characters
n = 0
newVal := make([]byte, len(val))
for i := 0; i < len(val); i++ {
if val[i] > 127 {
continue
}
newVal[n] = val[i]
n++
}
metadata[key] = string(newVal[:n])
}
return metadata
}

View File

@ -0,0 +1,68 @@
/*
Copyright 2021 The Dapr Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package blobstorage
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/dapr/kit/logger"
)
func TestBlobHTTPHeaderGeneration(t *testing.T) {
log := logger.NewLogger("test")
t.Run("Content type is set from request, forward compatibility", func(t *testing.T) {
contentType := "application/json"
requestMetadata := map[string]string{}
blobHeaders, err := CreateBlobHTTPHeadersFromRequest(requestMetadata, &contentType, log)
assert.Nil(t, err)
assert.Equal(t, "application/json", *blobHeaders.BlobContentType)
})
t.Run("Content type and metadata provided (conflict), content type chosen", func(t *testing.T) {
contentType := "application/json"
requestMetadata := map[string]string{
contentTypeKey: "text/plain",
}
blobHeaders, err := CreateBlobHTTPHeadersFromRequest(requestMetadata, &contentType, log)
assert.Nil(t, err)
assert.Equal(t, "application/json", *blobHeaders.BlobContentType)
})
t.Run("ContentType not provided, metadata provided set backward compatibility", func(t *testing.T) {
requestMetadata := map[string]string{
contentTypeKey: "text/plain",
}
blobHeaders, err := CreateBlobHTTPHeadersFromRequest(requestMetadata, nil, log)
assert.Nil(t, err)
assert.Equal(t, "text/plain", *blobHeaders.BlobContentType)
})
}
func TestSanitizeRequestMetadata(t *testing.T) {
log := logger.NewLogger("test")
t.Run("sanitize metadata if necessary", func(t *testing.T) {
m := map[string]string{
"somecustomfield": "some-custom-value",
"specialfield": "special:valueÜ",
"not-allowed:": "not-allowed",
}
meta := SanitizeMetadata(log, m)
assert.Equal(t, meta["somecustomfield"], "some-custom-value")
assert.Equal(t, meta["specialfield"], "special:value")
assert.Equal(t, meta["notallowed"], "not-allowed")
})
}

View File

@ -162,6 +162,7 @@ func (js *jetstreamPubSub) Subscribe(ctx context.Context, req pubsub.SubscribeRe
if js.meta.hearbeat != 0 { if js.meta.hearbeat != 0 {
consumerConfig.Heartbeat = js.meta.hearbeat consumerConfig.Heartbeat = js.meta.hearbeat
} }
consumerConfig.FilterSubject = req.Topic
natsHandler := func(m *nats.Msg) { natsHandler := func(m *nats.Msg) {
jsm, err := m.Metadata() jsm, err := m.Metadata()

View File

@ -22,6 +22,7 @@ import (
"fmt" "fmt"
"net/url" "net/url"
"regexp" "regexp"
"strconv"
"strings" "strings"
"sync" "sync"
"time" "time"
@ -276,8 +277,9 @@ func (m *mqttPubSub) onMessage(ctx context.Context) func(client mqtt.Client, mqt
}() }()
msg := pubsub.NewMessage{ msg := pubsub.NewMessage{
Topic: mqttMsg.Topic(), Topic: mqttMsg.Topic(),
Data: mqttMsg.Payload(), Data: mqttMsg.Payload(),
Metadata: map[string]string{"retained": strconv.FormatBool(mqttMsg.Retained())},
} }
topicHandler := m.handlerForTopic(msg.Topic) topicHandler := m.handlerForTopic(msg.Topic)

View File

@ -4,4 +4,4 @@ Secret Stores provide a common way to interact with different secret stores, clo
## Implementing a new Secret Store ## Implementing a new Secret Store
A compliant secret store needs to implement the `SecretStore` inteface included in the [`secret_store.go`](secret_store.go) file. A compliant secret store needs to implement the `SecretStore` interface included in the [`secret_store.go`](secret_store.go) file.

View File

@ -508,5 +508,9 @@ func readCertificateFolder(certPool *x509.CertPool, path string) error {
// Features returns the features available in this secret store. // Features returns the features available in this secret store.
func (v *vaultSecretStore) Features() []secretstores.Feature { func (v *vaultSecretStore) Features() []secretstores.Feature {
if v.vaultValueType == valueTypeText {
return []secretstores.Feature{}
}
return []secretstores.Feature{secretstores.FeatureMultipleKeyValuesPerSecret} return []secretstores.Feature{secretstores.FeatureMultipleKeyValuesPerSecret}
} }

View File

@ -28,49 +28,53 @@ import (
const ( const (
// base64 encoded certificate. // base64 encoded certificate.
certificate = "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURVakNDQWpvQ0NRRFlZdzdMeXN4VXRUQU5CZ2txaGtpRzl3MEJBUXNGQURCck1Rc3dDUVlEVlFRR0V3SkQKUVRFWk1CY0dBMVVFQ0F3UVFuSnBkR2x6YUNCRGIyeDFiV0pwWVRFU01CQUdBMVVFQnd3SlZtRnVZMjkxZG1WeQpNUk13RVFZRFZRUUtEQXB0YVhOb2NtRmpiM0p3TVJnd0ZnWURWUVFEREE5MllYVnNkSEJ5YjJwbFkzUXVhVzh3CkhoY05NVGt4TVRBeE1UQTBPREV5V2hjTk1qQXhNRE14TVRBME9ERXlXakJyTVFzd0NRWURWUVFHRXdKRFFURVoKTUJjR0ExVUVDQXdRUW5KcGRHbHphQ0JEYjJ4MWJXSnBZVEVTTUJBR0ExVUVCd3dKVm1GdVkyOTFkbVZ5TVJNdwpFUVlEVlFRS0RBcHRhWE5vY21GamIzSndNUmd3RmdZRFZRUUREQTkyWVhWc2RIQnliMnBsWTNRdWFXOHdnZ0VpCk1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRQ3JtaitTTmtGUHEvK2FXUFV1MlpFamtSK3AKTm1PeEVNSnZZcGhHNkJvRFAySE9ZbGRzdk9FWkRkbTBpWFlmeFIwZm5rUmtTMWEzSlZiYmhINWJnTElKb0dxcwo5aWpzN2hyQ0Rrdk9uRWxpUEZuc05pQ2NWNDNxNkZYaFMvNFpoNGpOMnlyUkU2UmZiS1BEeUw0a282NkFhSld1CnVkTldKVWpzSFZBSWowZHlnTXFKYm0rT29iSzk5ckUxcDg5Z3RNUStJdzFkWnUvUFF4SjlYOStMeXdxZUxPckQKOWhpNWkxajNFUUp2RXQxSVUzclEwc2E0NU5zZkt4YzEwZjdhTjJuSDQzSnhnMVRiZXNPOWYrcWlyeDBHYmVSYQpyVmNaazNVaFc2cHZmam9XbDBEc0NwNTJwZDBQN05rUmhmak44b2RMN0h3bFVIc1NqemlSYytsTG5YREJBZ01CCkFBRXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBSVdKdmRPZ01PUnQxWk53SENkNTNieTlkMlBkcW5tWHFZZ20KNDZHK2Fvb1dSeTJKMEMwS3ZOVGZGbEJFOUlydzNXUTVNMnpqY25qSUp5bzNLRUM5TDdPMnQ1WC9LTGVDck5ZVgpIc1d4cU5BTVBGY2VBa09HT0I1TThGVllkdjJTaVV2UDJjMEZQSzc2WFVzcVNkdnRsWGFkTk5ENzE3T0NTNm0yCnBIVjh1NWJNd1VmR2NCVFpEV2o4bjIzRVdHaXdnYkJkdDc3Z3h3YWc5NTROZkM2Ny9nSUc5ZlRrTTQ4aVJCUzEKc0NGYVBjMkFIT3hiMSs0ajVCMVY2Z29iZDZYWkFvbHdNaTNHUUtkbEM1NXZNeTNwK09WbDNNbEc3RWNTVUpMdApwZ2ZKaWw3L3dTWWhpUnhJU3hrYkk5cWhvNEwzZm5PZVB3clFVd2FzU1ZiL1lxbHZ2WHM9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K" certificate = "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURVakNDQWpvQ0NRRFlZdzdMeXN4VXRUQU5CZ2txaGtpRzl3MEJBUXNGQURCck1Rc3dDUVlEVlFRR0V3SkQKUVRFWk1CY0dBMVVFQ0F3UVFuSnBkR2x6YUNCRGIyeDFiV0pwWVRFU01CQUdBMVVFQnd3SlZtRnVZMjkxZG1WeQpNUk13RVFZRFZRUUtEQXB0YVhOb2NtRmpiM0p3TVJnd0ZnWURWUVFEREE5MllYVnNkSEJ5YjJwbFkzUXVhVzh3CkhoY05NVGt4TVRBeE1UQTBPREV5V2hjTk1qQXhNRE14TVRBME9ERXlXakJyTVFzd0NRWURWUVFHRXdKRFFURVoKTUJjR0ExVUVDQXdRUW5KcGRHbHphQ0JEYjJ4MWJXSnBZVEVTTUJBR0ExVUVCd3dKVm1GdVkyOTFkbVZ5TVJNdwpFUVlEVlFRS0RBcHRhWE5vY21GamIzSndNUmd3RmdZRFZRUUREQTkyWVhWc2RIQnliMnBsWTNRdWFXOHdnZ0VpCk1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRQ3JtaitTTmtGUHEvK2FXUFV1MlpFamtSK3AKTm1PeEVNSnZZcGhHNkJvRFAySE9ZbGRzdk9FWkRkbTBpWFlmeFIwZm5rUmtTMWEzSlZiYmhINWJnTElKb0dxcwo5aWpzN2hyQ0Rrdk9uRWxpUEZuc05pQ2NWNDNxNkZYaFMvNFpoNGpOMnlyUkU2UmZiS1BEeUw0a282NkFhSld1CnVkTldKVWpzSFZBSWowZHlnTXFKYm0rT29iSzk5ckUxcDg5Z3RNUStJdzFkWnUvUFF4SjlYOStMeXdxZUxPckQKOWhpNWkxajNFUUp2RXQxSVUzclEwc2E0NU5zZkt4YzEwZjdhTjJuSDQzSnhnMVRiZXNPOWYrcWlyeDBHYmVSYQpyVmNaazNVaFc2cHZmam9XbDBEc0NwNTJwZDBQN05rUmhmak44b2RMN0h3bFVIc1NqemlSYytsTG5YREJBZ01CCkFBRXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBSVdKdmRPZ01PUnQxWk53SENkNTNieTlkMlBkcW5tWHFZZ20KNDZHK2Fvb1dSeTJKMEMwS3ZOVGZGbEJFOUlydzNXUTVNMnpqY25qSUp5bzNLRUM5TDdPMnQ1WC9LTGVDck5ZVgpIc1d4cU5BTVBGY2VBa09HT0I1TThGVllkdjJTaVV2UDJjMEZQSzc2WFVzcVNkdnRsWGFkTk5ENzE3T0NTNm0yCnBIVjh1NWJNd1VmR2NCVFpEV2o4bjIzRVdHaXdnYkJkdDc3Z3h3YWc5NTROZkM2Ny9nSUc5ZlRrTTQ4aVJCUzEKc0NGYVBjMkFIT3hiMSs0ajVCMVY2Z29iZDZYWkFvbHdNaTNHUUtkbEM1NXZNeTNwK09WbDNNbEc3RWNTVUpMdApwZ2ZKaWw3L3dTWWhpUnhJU3hrYkk5cWhvNEwzZm5PZVB3clFVd2FzU1ZiL1lxbHZ2WHM9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K"
expectedTok = "myRootToken" expectedTok = "myRootToken"
expectedTokMountPath = "./vault.txt" expectedTokenMountFileContents = "Hey! TokenMountFile contents here!"
) )
func createTempFileWithContent(t *testing.T, contents string) (fileName string, cleanUpFunc func()) {
dir := os.TempDir()
f, err := os.CreateTemp(dir, "vault-token")
assert.NoError(t, err)
fileName = f.Name()
cleanUpFunc = func() {
os.Remove(fileName)
}
_, err = f.WriteString(contents)
assert.NoError(t, err)
return fileName, cleanUpFunc
}
func createTokenMountPathFile(t *testing.T) (fileName string, cleanUpFunc func()) {
return createTempFileWithContent(t, expectedTokenMountFileContents)
}
func TestReadVaultToken(t *testing.T) { func TestReadVaultToken(t *testing.T) {
tokenString := "This-IS-TheRootToken"
tmpFileName, cleanUpFunc := createTempFileWithContent(t, tokenString)
defer cleanUpFunc()
t.Run("read correct token", func(t *testing.T) { t.Run("read correct token", func(t *testing.T) {
dir := os.TempDir()
f, err := os.CreateTemp(dir, "vault-token")
assert.NoError(t, err)
fileName := f.Name()
defer os.Remove(fileName)
tokenString := "thisisnottheroottoken"
_, err = f.WriteString(tokenString)
assert.NoError(t, err)
v := vaultSecretStore{ v := vaultSecretStore{
vaultTokenMountPath: f.Name(), vaultTokenMountPath: tmpFileName,
} }
err = v.initVaultToken() err := v.initVaultToken()
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, tokenString, v.vaultToken) assert.Equal(t, tokenString, v.vaultToken)
}) })
t.Run("read incorrect token", func(t *testing.T) { t.Run("read incorrect token", func(t *testing.T) {
dir := os.TempDir()
f, err := os.CreateTemp(dir, "vault-token")
assert.NoError(t, err)
fileName := f.Name()
defer os.Remove(fileName)
tokenString := "thisisnottheroottoken"
_, err = f.WriteString(tokenString)
assert.NoError(t, err)
v := vaultSecretStore{ v := vaultSecretStore{
vaultTokenMountPath: f.Name(), vaultTokenMountPath: tmpFileName,
} }
err = v.initVaultToken()
err := v.initVaultToken()
assert.Nil(t, err) assert.Nil(t, err)
assert.NotEqual(t, "thisistheroottoken", v.vaultToken) assert.NotEqual(t, "ThisIs-NOT-TheRootToken", v.vaultToken)
}) })
t.Run("read token from vaultToken", func(t *testing.T) { t.Run("read token from vaultToken", func(t *testing.T) {
@ -126,6 +130,9 @@ func TestVaultEnginePath(t *testing.T) {
} }
func TestVaultTokenPrefix(t *testing.T) { func TestVaultTokenPrefix(t *testing.T) {
expectedTokMountPath, cleanUpFunc := createTokenMountPathFile(t)
defer cleanUpFunc()
t.Run("default value of vaultKVUsePrefix is true to emulate previous behaviour", func(t *testing.T) { t.Run("default value of vaultKVUsePrefix is true to emulate previous behaviour", func(t *testing.T) {
properties := map[string]string{ properties := map[string]string{
componentVaultToken: expectedTok, componentVaultToken: expectedTok,
@ -140,11 +147,9 @@ func TestVaultTokenPrefix(t *testing.T) {
logger: nil, logger: nil,
} }
// This call will throw an error on Windows systems because of the of if err := target.Init(m); err != nil {
// the call x509.SystemCertPool() because system root pool is not t.Fatal(err)
// available on Windows so ignore the error for when the tests are run }
// on the Windows platform during CI
_ = target.Init(m)
assert.Equal(t, defaultVaultKVPrefix, target.vaultKVPrefix) assert.Equal(t, defaultVaultKVPrefix, target.vaultKVPrefix)
}) })
@ -165,11 +170,9 @@ func TestVaultTokenPrefix(t *testing.T) {
logger: nil, logger: nil,
} }
// This call will throw an error on Windows systems because of the of if err := target.Init(m); err != nil {
// the call x509.SystemCertPool() because system root pool is not t.Fatal(err)
// available on Windows so ignore the error for when the tests are run }
// on the Windows platform during CI
_ = target.Init(m)
assert.Equal(t, "", target.vaultKVPrefix) assert.Equal(t, "", target.vaultKVPrefix)
}) })
@ -190,10 +193,6 @@ func TestVaultTokenPrefix(t *testing.T) {
logger: nil, logger: nil,
} }
// This call will throw an error on Windows systems because of the of
// the call x509.SystemCertPool() because system root pool is not
// available on Windows so ignore the error for when the tests are run
// on the Windows platform during CI
err := target.Init(m) err := target.Init(m)
assert.NotNil(t, err) assert.NotNil(t, err)
@ -201,6 +200,9 @@ func TestVaultTokenPrefix(t *testing.T) {
} }
func TestVaultTokenMountPathOrVaultTokenRequired(t *testing.T) { func TestVaultTokenMountPathOrVaultTokenRequired(t *testing.T) {
expectedTokMountPath, cleanUpFunc := createTokenMountPathFile(t)
defer cleanUpFunc()
t.Run("without vaultTokenMount or vaultToken", func(t *testing.T) { t.Run("without vaultTokenMount or vaultToken", func(t *testing.T) {
properties := map[string]string{} properties := map[string]string{}
@ -235,13 +237,11 @@ func TestVaultTokenMountPathOrVaultTokenRequired(t *testing.T) {
logger: nil, logger: nil,
} }
// This call will throw an error on Windows systems because of the of if err := target.Init(m); err != nil {
// the call x509.SystemCertPool() because system root pool is not t.Fatal(err)
// available on Windows so ignore the error for when the tests are run }
// on the Windows platform during CI
_ = target.Init(m)
assert.Equal(t, "", target.vaultToken) assert.Equal(t, expectedTokenMountFileContents, target.vaultToken)
assert.Equal(t, expectedTokMountPath, target.vaultTokenMountPath) assert.Equal(t, expectedTokMountPath, target.vaultTokenMountPath)
}) })
@ -259,11 +259,9 @@ func TestVaultTokenMountPathOrVaultTokenRequired(t *testing.T) {
logger: nil, logger: nil,
} }
// This call will throw an error on Windows systems because of the of if err := target.Init(m); err != nil {
// the call x509.SystemCertPool() because system root pool is not t.Fatal(err)
// available on Windows so ignore the error for when the tests are run }
// on the Windows platform during CI
_ = target.Init(m)
assert.Equal(t, "", target.vaultTokenMountPath) assert.Equal(t, "", target.vaultTokenMountPath)
assert.Equal(t, expectedTok, target.vaultToken) assert.Equal(t, expectedTok, target.vaultToken)
@ -294,9 +292,12 @@ func TestVaultTokenMountPathOrVaultTokenRequired(t *testing.T) {
} }
func TestDefaultVaultAddress(t *testing.T) { func TestDefaultVaultAddress(t *testing.T) {
expectedTokMountPath, cleanUpFunc := createTokenMountPathFile(t)
defer cleanUpFunc()
t.Run("with blank vaultAddr", func(t *testing.T) { t.Run("with blank vaultAddr", func(t *testing.T) {
properties := map[string]string{ properties := map[string]string{
"vaultTokenMountPath": "./vault.txt", "vaultTokenMountPath": expectedTokMountPath,
} }
m := secretstores.Metadata{ m := secretstores.Metadata{
@ -308,11 +309,9 @@ func TestDefaultVaultAddress(t *testing.T) {
logger: nil, logger: nil,
} }
// This call will throw an error on Windows systems because of the of if err := target.Init(m); err != nil {
// the call x509.SystemCertPool() because system root pool is not t.Fatal(err)
// available on Windows so ignore the error for when the tests are run }
// on the Windows platform during CI
_ = target.Init(m)
assert.Equal(t, defaultVaultAddress, target.vaultAddress, "default was not set") assert.Equal(t, defaultVaultAddress, target.vaultAddress, "default was not set")
}) })
@ -409,10 +408,49 @@ func getCertificate() []byte {
} }
func TestGetFeatures(t *testing.T) { func TestGetFeatures(t *testing.T) {
s := NewHashiCorpVaultSecretStore(logger.NewLogger("test")) initVaultWithVaultValueType := func(vaultValueType string) secretstores.SecretStore {
// Yes, we are skipping initialization as feature retrieval doesn't depend on it. properties := map[string]string{
t.Run("Vault supports MULTIPLE_KEY_VALUES_PER_SECRET", func(t *testing.T) { "vaultToken": expectedTok,
"skipVerify": "true",
"vaultValueType": vaultValueType,
}
m := secretstores.Metadata{
Base: metadata.Base{Properties: properties},
}
target := &vaultSecretStore{
client: nil,
logger: nil,
}
// This call will throw an error on Windows systems because of the of
// the call x509.SystemCertPool() because system root pool is not
// available on Windows so ignore the error for when the tests are run
// on the Windows platform during CI
_ = target.Init(m)
return target
}
t.Run("Vault supports MULTIPLE_KEY_VALUES_PER_SECRET by default", func(t *testing.T) {
// Yes, we are skipping initialization as feature retrieval doesn't depend on it for the default value
s := NewHashiCorpVaultSecretStore(logger.NewLogger("test"))
f := s.Features() f := s.Features()
assert.True(t, secretstores.FeatureMultipleKeyValuesPerSecret.IsPresent(f)) assert.True(t, secretstores.FeatureMultipleKeyValuesPerSecret.IsPresent(f))
}) })
t.Run("Vault supports MULTIPLE_KEY_VALUES_PER_SECRET if configured with vaultValueType=map", func(t *testing.T) {
// Yes, we are skipping initialization as feature retrieval doesn't depend on it for the default value
s := initVaultWithVaultValueType("text")
f := s.Features()
assert.False(t, secretstores.FeatureMultipleKeyValuesPerSecret.IsPresent(f))
})
t.Run("Vault does not support MULTIPLE_KEY_VALUES_PER_SECRET if configured with vaultValueType=text", func(t *testing.T) {
// Yes, we are skipping initialization as feature retrieval doesn't depend on it for the default value
s := initVaultWithVaultValueType("text")
f := s.Features()
assert.False(t, secretstores.FeatureMultipleKeyValuesPerSecret.IsPresent(f))
})
} }

View File

@ -37,18 +37,19 @@ package blobstorage
import ( import (
"context" "context"
b64 "encoding/base64"
"fmt" "fmt"
"io" "io"
"net"
"net/url"
"reflect" "reflect"
"strings" "strings"
"github.com/Azure/azure-storage-blob-go/azblob" "github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/bloberror"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/container"
jsoniter "github.com/json-iterator/go" jsoniter "github.com/json-iterator/go"
azauth "github.com/dapr/components-contrib/internal/authentication/azure" storageinternal "github.com/dapr/components-contrib/internal/component/azure/blobstorage"
mdutils "github.com/dapr/components-contrib/metadata" mdutils "github.com/dapr/components-contrib/metadata"
"github.com/dapr/components-contrib/state" "github.com/dapr/components-contrib/state"
"github.com/dapr/kit/logger" "github.com/dapr/kit/logger"
@ -56,72 +57,26 @@ import (
) )
const ( const (
keyDelimiter = "||" keyDelimiter = "||"
contentType = "ContentType"
contentMD5 = "ContentMD5"
contentEncoding = "ContentEncoding"
contentLanguage = "ContentLanguage"
contentDisposition = "ContentDisposition"
cacheControl = "CacheControl"
) )
// StateStore Type. // StateStore Type.
type StateStore struct { type StateStore struct {
state.DefaultBulkStore state.DefaultBulkStore
containerURL azblob.ContainerURL containerClient *container.Client
json jsoniter.API json jsoniter.API
features []state.Feature features []state.Feature
logger logger.Logger logger logger.Logger
} }
type blobStorageMetadata struct {
AccountName string
ContainerName string
}
// Init the connection to blob storage, optionally creates a blob container if it doesn't exist. // Init the connection to blob storage, optionally creates a blob container if it doesn't exist.
func (r *StateStore) Init(metadata state.Metadata) error { func (r *StateStore) Init(metadata state.Metadata) error {
meta, err := getBlobStorageMetadata(metadata.Properties) var err error
r.containerClient, _, err = storageinternal.CreateContainerStorageClient(r.logger, metadata.Properties)
if err != nil { if err != nil {
return err return err
} }
credential, env, err := azauth.GetAzureStorageBlobCredentials(r.logger, meta.AccountName, metadata.Properties)
if err != nil {
return fmt.Errorf("invalid credentials with error: %s", err.Error())
}
userAgent := "dapr-" + logger.DaprVersion
options := azblob.PipelineOptions{
Telemetry: azblob.TelemetryOptions{Value: userAgent},
}
p := azblob.NewPipeline(credential, options)
var URL *url.URL
customEndpoint, ok := mdutils.GetMetadataProperty(metadata.Properties, azauth.StorageEndpointKeys...)
if ok && customEndpoint != "" {
URL, err = url.Parse(fmt.Sprintf("%s/%s/%s", customEndpoint, meta.AccountName, meta.ContainerName))
} else {
URL, err = url.Parse(fmt.Sprintf("https://%s.blob.%s/%s", meta.AccountName, env.StorageEndpointSuffix, meta.ContainerName))
}
if err != nil {
return err
}
containerURL := azblob.NewContainerURL(*URL, p)
_, err = net.LookupHost(URL.Hostname())
if err != nil {
return err
}
ctx := context.Background()
_, err = containerURL.Create(ctx, azblob.Metadata{}, azblob.PublicAccessNone)
r.logger.Debugf("error creating container: %s", err)
r.containerURL = containerURL
r.logger.Debugf("using container '%s'", meta.ContainerName)
return nil return nil
} }
@ -132,34 +87,29 @@ func (r *StateStore) Features() []state.Feature {
// Delete the state. // Delete the state.
func (r *StateStore) Delete(req *state.DeleteRequest) error { func (r *StateStore) Delete(req *state.DeleteRequest) error {
r.logger.Debugf("delete %s", req.Key)
return r.deleteFile(context.Background(), req) return r.deleteFile(context.Background(), req)
} }
// Get the state. // Get the state.
func (r *StateStore) Get(req *state.GetRequest) (*state.GetResponse, error) { func (r *StateStore) Get(req *state.GetRequest) (*state.GetResponse, error) {
r.logger.Debugf("get %s", req.Key)
return r.readFile(context.Background(), req) return r.readFile(context.Background(), req)
} }
// Set the state. // Set the state.
func (r *StateStore) Set(req *state.SetRequest) error { func (r *StateStore) Set(req *state.SetRequest) error {
r.logger.Debugf("saving %s", req.Key)
return r.writeFile(context.Background(), req) return r.writeFile(context.Background(), req)
} }
func (r *StateStore) Ping() error { func (r *StateStore) Ping() error {
accessConditions := azblob.BlobAccessConditions{} if _, err := r.containerClient.GetProperties(context.Background(), nil); err != nil {
return fmt.Errorf("blob storage: error connecting to Blob storage at %s: %s", r.containerClient.URL(), err)
if _, err := r.containerURL.GetProperties(context.Background(), accessConditions.LeaseAccessConditions); err != nil {
return fmt.Errorf("blob storage: error connecting to Blob storage at %s: %s", r.containerURL.URL().Host, err)
} }
return nil return nil
} }
func (r *StateStore) GetComponentMetadata() map[string]string { func (r *StateStore) GetComponentMetadata() map[string]string {
metadataStruct := blobStorageMetadata{} metadataStruct := storageinternal.BlobStorageMetadata{}
metadataInfo := map[string]string{} metadataInfo := map[string]string{}
mdutils.GetMetadataInfoFromStructType(reflect.TypeOf(metadataStruct), &metadataInfo) mdutils.GetMetadataInfoFromStructType(reflect.TypeOf(metadataStruct), &metadataInfo)
return metadataInfo return metadataInfo
@ -177,32 +127,10 @@ func NewAzureBlobStorageStore(logger logger.Logger) state.Store {
return s return s
} }
func getBlobStorageMetadata(meta map[string]string) (*blobStorageMetadata, error) {
m := blobStorageMetadata{}
err := mdutils.DecodeMetadata(meta, &m)
if val, ok := mdutils.GetMetadataProperty(meta, azauth.StorageAccountNameKeys...); ok && val != "" {
m.AccountName = val
} else {
return nil, fmt.Errorf("missing or empty %s field from metadata", azauth.StorageAccountNameKeys[0])
}
if val, ok := mdutils.GetMetadataProperty(meta, azauth.StorageContainerNameKeys...); ok && val != "" {
m.ContainerName = val
} else {
return nil, fmt.Errorf("missing or empty %s field from metadata", azauth.StorageContainerNameKeys[0])
}
return &m, err
}
func (r *StateStore) readFile(ctx context.Context, req *state.GetRequest) (*state.GetResponse, error) { func (r *StateStore) readFile(ctx context.Context, req *state.GetRequest) (*state.GetResponse, error) {
blobURL := r.containerURL.NewBlockBlobURL(getFileName(req.Key)) blockBlobClient := r.containerClient.NewBlockBlobClient(getFileName(req.Key))
blobDownloadResponse, err := blockBlobClient.DownloadStream(ctx, nil)
resp, err := blobURL.Download(ctx, 0, azblob.CountToEnd, azblob.BlobAccessConditions{}, false)
if err != nil { if err != nil {
r.logger.Debugf("download file %s, err %s", req.Key, err)
if isNotFoundError(err) { if isNotFoundError(err) {
return &state.GetResponse{}, nil return &state.GetResponse{}, nil
} }
@ -210,110 +138,79 @@ func (r *StateStore) readFile(ctx context.Context, req *state.GetRequest) (*stat
return &state.GetResponse{}, err return &state.GetResponse{}, err
} }
bodyStream := resp.Body(azblob.RetryReaderOptions{}) reader := blobDownloadResponse.Body
data, err := io.ReadAll(bodyStream) defer reader.Close()
blobData, err := io.ReadAll(reader)
if err != nil { if err != nil {
r.logger.Debugf("read file %s, err %s", req.Key, err) return &state.GetResponse{}, fmt.Errorf("error reading az blob: %w", err)
return &state.GetResponse{}, err
} }
contentType := resp.ContentType() contentType := blobDownloadResponse.ContentType
return &state.GetResponse{ return &state.GetResponse{
Data: data, Data: blobData,
ETag: ptr.Of(string(resp.ETag())), ETag: ptr.Of(string(*blobDownloadResponse.ETag)),
ContentType: &contentType, ContentType: contentType,
}, nil }, nil
} }
func (r *StateStore) writeFile(ctx context.Context, req *state.SetRequest) error { func (r *StateStore) writeFile(ctx context.Context, req *state.SetRequest) error {
accessConditions := azblob.BlobAccessConditions{} modifiedAccessConditions := blob.ModifiedAccessConditions{}
if req.ETag != nil && *req.ETag != "" { if req.ETag != nil && *req.ETag != "" {
accessConditions.IfMatch = azblob.ETag(*req.ETag) modifiedAccessConditions.IfMatch = ptr.Of(azcore.ETag(*req.ETag))
} }
if req.Options.Concurrency == state.FirstWrite && (req.ETag == nil || *req.ETag == "") { if req.Options.Concurrency == state.FirstWrite && (req.ETag == nil || *req.ETag == "") {
accessConditions.IfNoneMatch = azblob.ETag("*") modifiedAccessConditions.IfNoneMatch = ptr.Of(azcore.ETagAny)
} }
blobURL := r.containerURL.NewBlockBlobURL(getFileName(req.Key)) accessConditions := blob.AccessConditions{
ModifiedAccessConditions: &modifiedAccessConditions,
}
blobHTTPHeaders, err := r.createBlobHTTPHeadersFromRequest(req) blobHTTPHeaders, err := storageinternal.CreateBlobHTTPHeadersFromRequest(req.Metadata, req.ContentType, r.logger)
if err != nil { if err != nil {
return err return err
} }
_, err = azblob.UploadBufferToBlockBlob(ctx, r.marshal(req), blobURL, azblob.UploadToBlockBlobOptions{
Metadata: req.Metadata,
AccessConditions: accessConditions,
BlobHTTPHeaders: blobHTTPHeaders,
})
if err != nil {
r.logger.Debugf("write file %s, err %s", req.Key, err)
uploadOptions := azblob.UploadBufferOptions{
AccessConditions: &accessConditions,
Metadata: storageinternal.SanitizeMetadata(r.logger, req.Metadata),
HTTPHeaders: &blobHTTPHeaders,
}
blockBlobClient := r.containerClient.NewBlockBlobClient(getFileName(req.Key))
_, err = blockBlobClient.UploadBuffer(ctx, r.marshal(req), &uploadOptions)
if err != nil {
// Check if the error is due to ETag conflict // Check if the error is due to ETag conflict
if req.ETag != nil && isETagConflictError(err) { if req.ETag != nil && isETagConflictError(err) {
return state.NewETagError(state.ETagMismatch, err) return state.NewETagError(state.ETagMismatch, err)
} }
return err return fmt.Errorf("error uploading az blob: %w", err)
} }
return nil return nil
} }
func (r *StateStore) createBlobHTTPHeadersFromRequest(req *state.SetRequest) (azblob.BlobHTTPHeaders, error) {
var blobHTTPHeaders azblob.BlobHTTPHeaders
if val, ok := req.Metadata[contentType]; ok && val != "" {
blobHTTPHeaders.ContentType = val
delete(req.Metadata, contentType)
}
if req.ContentType != nil {
if blobHTTPHeaders.ContentType != "" {
r.logger.Warnf("ContentType received from request Metadata %s, as well as ContentType property %s, choosing value from contentType property", blobHTTPHeaders.ContentType, *req.ContentType)
}
blobHTTPHeaders.ContentType = *req.ContentType
}
if val, ok := req.Metadata[contentMD5]; ok && val != "" {
sDec, err := b64.StdEncoding.DecodeString(val)
if err != nil || len(sDec) != 16 {
return azblob.BlobHTTPHeaders{}, fmt.Errorf("the MD5 value specified in Content MD5 is invalid, MD5 value must be 128 bits and base64 encoded")
}
blobHTTPHeaders.ContentMD5 = sDec
delete(req.Metadata, contentMD5)
}
if val, ok := req.Metadata[contentEncoding]; ok && val != "" {
blobHTTPHeaders.ContentEncoding = val
delete(req.Metadata, contentEncoding)
}
if val, ok := req.Metadata[contentLanguage]; ok && val != "" {
blobHTTPHeaders.ContentLanguage = val
delete(req.Metadata, contentLanguage)
}
if val, ok := req.Metadata[contentDisposition]; ok && val != "" {
blobHTTPHeaders.ContentDisposition = val
delete(req.Metadata, contentDisposition)
}
if val, ok := req.Metadata[cacheControl]; ok && val != "" {
blobHTTPHeaders.CacheControl = val
delete(req.Metadata, cacheControl)
}
return blobHTTPHeaders, nil
}
func (r *StateStore) deleteFile(ctx context.Context, req *state.DeleteRequest) error { func (r *StateStore) deleteFile(ctx context.Context, req *state.DeleteRequest) error {
blobURL := r.containerURL.NewBlockBlobURL(getFileName(req.Key)) blockBlobClient := r.containerClient.NewBlockBlobClient(getFileName(req.Key))
accessConditions := azblob.BlobAccessConditions{}
modifiedAccessConditions := blob.ModifiedAccessConditions{}
if req.ETag != nil && *req.ETag != "" { if req.ETag != nil && *req.ETag != "" {
accessConditions.IfMatch = azblob.ETag(*req.ETag) modifiedAccessConditions.IfMatch = ptr.Of(azcore.ETag(*req.ETag))
} }
_, err := blobURL.Delete(ctx, azblob.DeleteSnapshotsOptionNone, accessConditions) deleteOptions := blob.DeleteOptions{
if err != nil { DeleteSnapshots: nil,
r.logger.Debugf("delete file %s, err %s", req.Key, err) AccessConditions: &blob.AccessConditions{
ModifiedAccessConditions: &modifiedAccessConditions,
},
}
_, err := blockBlobClient.Delete(ctx, &deleteOptions)
if err != nil {
if req.ETag != nil && isETagConflictError(err) { if req.ETag != nil && isETagConflictError(err) {
return state.NewETagError(state.ETagMismatch, err) return state.NewETagError(state.ETagMismatch, err)
} else if isNotFoundError(err) { } else if isNotFoundError(err) {
@ -349,13 +246,9 @@ func (r *StateStore) marshal(req *state.SetRequest) []byte {
} }
func isNotFoundError(err error) bool { func isNotFoundError(err error) bool {
azureError, ok := err.(azblob.StorageError) return bloberror.HasCode(err, bloberror.BlobNotFound)
return ok && azureError.ServiceCode() == azblob.ServiceCodeBlobNotFound
} }
func isETagConflictError(err error) bool { func isETagConflictError(err error) bool {
azureError, ok := err.(azblob.StorageError) return bloberror.HasCode(err, bloberror.ConditionNotMet)
return ok && azureError.ServiceCode() == azblob.ServiceCodeConditionNotMet
} }

View File

@ -34,8 +34,7 @@ func TestInit(t *testing.T) {
} }
err := s.Init(m) err := s.Init(m)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, "acc.blob.core.windows.net", s.containerURL.URL().Host) assert.Equal(t, "https://acc.blob.core.windows.net/dapr", s.containerClient.URL())
assert.Equal(t, "/dapr", s.containerURL.URL().Path)
}) })
t.Run("Init with missing metadata", func(t *testing.T) { t.Run("Init with missing metadata", func(t *testing.T) {
@ -53,31 +52,12 @@ func TestInit(t *testing.T) {
"accountKey": "e+Dnvl8EOxYxV94nurVaRQ==", "accountKey": "e+Dnvl8EOxYxV94nurVaRQ==",
"containerName": "dapr", "containerName": "dapr",
} }
err := s.Init(m) s.Init(m)
err := s.Ping()
assert.NotNil(t, err) assert.NotNil(t, err)
}) })
} }
func TestGetBlobStorageMetaData(t *testing.T) {
t.Run("Nothing at all passed", func(t *testing.T) {
m := make(map[string]string)
_, err := getBlobStorageMetadata(m)
assert.NotNil(t, err)
})
t.Run("All parameters passed and parsed", func(t *testing.T) {
m := make(map[string]string)
m["accountName"] = "acc"
m["containerName"] = "dapr"
meta, err := getBlobStorageMetadata(m)
assert.Nil(t, err)
assert.Equal(t, "acc", meta.AccountName)
assert.Equal(t, "dapr", meta.ContainerName)
})
}
func TestFileName(t *testing.T) { func TestFileName(t *testing.T) {
t.Run("Valid composite key", func(t *testing.T) { t.Run("Valid composite key", func(t *testing.T) {
key := getFileName("app_id||key") key := getFileName("app_id||key")
@ -89,41 +69,3 @@ func TestFileName(t *testing.T) {
assert.Equal(t, "key", key) assert.Equal(t, "key", key)
}) })
} }
func TestBlobHTTPHeaderGeneration(t *testing.T) {
s := NewAzureBlobStorageStore(logger.NewLogger("logger")).(*StateStore)
t.Run("Content type is set from request, forward compatibility", func(t *testing.T) {
contentType := "application/json"
req := &state.SetRequest{
ContentType: &contentType,
}
blobHeaders, err := s.createBlobHTTPHeadersFromRequest(req)
assert.Nil(t, err)
assert.Equal(t, "application/json", blobHeaders.ContentType)
})
t.Run("Content type and metadata provided (conflict), content type chosen", func(t *testing.T) {
contentType := "application/json"
req := &state.SetRequest{
ContentType: &contentType,
Metadata: map[string]string{
contentType: "text/plain",
},
}
blobHeaders, err := s.createBlobHTTPHeadersFromRequest(req)
assert.Nil(t, err)
assert.Equal(t, "application/json", blobHeaders.ContentType)
})
t.Run("ContentType not provided, metadata provided set backward compatibility", func(t *testing.T) {
req := &state.SetRequest{
Metadata: map[string]string{
contentType: "text/plain",
},
}
blobHeaders, err := s.createBlobHTTPHeadersFromRequest(req)
assert.Nil(t, err)
assert.Equal(t, "text/plain", blobHeaders.ContentType)
})
}

View File

@ -15,11 +15,13 @@ package cockroachdb
import ( import (
"database/sql" "database/sql"
"database/sql/driver"
"encoding/base64" "encoding/base64"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"strconv" "strconv"
"time"
"github.com/dapr/components-contrib/metadata" "github.com/dapr/components-contrib/metadata"
"github.com/dapr/components-contrib/state" "github.com/dapr/components-contrib/state"
@ -27,15 +29,17 @@ import (
"github.com/dapr/components-contrib/state/utils" "github.com/dapr/components-contrib/state/utils"
"github.com/dapr/kit/logger" "github.com/dapr/kit/logger"
"github.com/dapr/kit/ptr" "github.com/dapr/kit/ptr"
"github.com/dapr/kit/retry"
// Blank import for the underlying PostgreSQL driver. // Blank import for the underlying PostgreSQL driver.
_ "github.com/jackc/pgx/v5/stdlib" _ "github.com/jackc/pgx/v5/stdlib"
) )
const ( const (
connectionStringKey = "connectionString" connectionStringKey = "connectionString"
errMissingConnectionString = "missing connection string" errMissingConnectionString = "missing connection string"
tableName = "state" tableName = "state"
defaultMaxConnectionAttempts = 5 // A bad driver connection error can occur inside the sql code so this essentially allows for more retries since the sql code does not allow that to be changed
) )
// cockroachDBAccess implements dbaccess. // cockroachDBAccess implements dbaccess.
@ -47,8 +51,9 @@ type cockroachDBAccess struct {
} }
type cockroachDBMetadata struct { type cockroachDBMetadata struct {
ConnectionString string ConnectionString string
TableName string TableName string
MaxConnectionAttempts *int
} }
// newCockroachDBAccess creates a new instance of cockroachDBAccess. // newCockroachDBAccess creates a new instance of cockroachDBAccess.
@ -109,6 +114,12 @@ func (p *cockroachDBAccess) Init(metadata state.Metadata) error {
return err return err
} }
// Ensure that a connection to the database is actually established
err = p.Ping()
if err != nil {
return err
}
return nil return nil
} }
@ -188,6 +199,7 @@ func (p *cockroachDBAccess) BulkSet(req []state.SetRequest) error {
// Get returns data from the database. If data does not exist for the key an empty state.GetResponse will be returned. // Get returns data from the database. If data does not exist for the key an empty state.GetResponse will be returned.
func (p *cockroachDBAccess) Get(req *state.GetRequest) (*state.GetResponse, error) { func (p *cockroachDBAccess) Get(req *state.GetRequest) (*state.GetResponse, error) {
p.logger.Debug("Getting state value from CockroachDB") p.logger.Debug("Getting state value from CockroachDB")
if req.Key == "" { if req.Key == "" {
return nil, fmt.Errorf("missing key in get operation") return nil, fmt.Errorf("missing key in get operation")
} }
@ -236,6 +248,7 @@ func (p *cockroachDBAccess) Get(req *state.GetRequest) (*state.GetResponse, erro
// Delete removes an item from the state store. // Delete removes an item from the state store.
func (p *cockroachDBAccess) Delete(req *state.DeleteRequest) error { func (p *cockroachDBAccess) Delete(req *state.DeleteRequest) error {
p.logger.Debug("Deleting state value from CockroachDB") p.logger.Debug("Deleting state value from CockroachDB")
if req.Key == "" { if req.Key == "" {
return fmt.Errorf("missing key in delete operation") return fmt.Errorf("missing key in delete operation")
} }
@ -386,7 +399,27 @@ func (p *cockroachDBAccess) Query(req *state.QueryRequest) (*state.QueryResponse
// Ping implements database ping. // Ping implements database ping.
func (p *cockroachDBAccess) Ping() error { func (p *cockroachDBAccess) Ping() error {
return p.db.Ping() retryCount := defaultMaxConnectionAttempts
if p.metadata.MaxConnectionAttempts != nil && *p.metadata.MaxConnectionAttempts >= 0 {
retryCount = *p.metadata.MaxConnectionAttempts
}
config := retry.DefaultConfig()
config.Policy = retry.PolicyExponential
config.MaxInterval = 100 * time.Millisecond
config.MaxRetries = int64(retryCount)
backoff := config.NewBackOff()
return retry.NotifyRecover(func() error {
err := p.db.Ping()
if errors.Is(err, driver.ErrBadConn) {
return fmt.Errorf("error when attempting to establish connection with cockroachDB: %v", err)
}
return nil
}, backoff, func(err error, _ time.Duration) {
p.logger.Debugf("Could not establish connection with cockroachDB. Retrying...: %v", err)
}, func() {
p.logger.Debug("Successfully established connection with cockroachDB after it previously failed")
})
} }
// Close implements io.Close. // Close implements io.Close.

View File

@ -7,7 +7,7 @@ require (
github.com/apache/dubbo-go-hessian2 v1.11.3 github.com/apache/dubbo-go-hessian2 v1.11.3
github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650
github.com/dapr/components-contrib/tests/certification v0.0.0-20211026011813-36b75e9ae272 github.com/dapr/components-contrib/tests/certification v0.0.0-20211026011813-36b75e9ae272
github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4
github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721
github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f
github.com/stretchr/testify v1.8.1 github.com/stretchr/testify v1.8.1
@ -103,6 +103,7 @@ require (
github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/openzipkin/zipkin-go v0.4.1 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect
github.com/pelletier/go-toml v1.9.4 // indirect github.com/pelletier/go-toml v1.9.4 // indirect
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.13.0 // indirect github.com/prometheus/client_golang v1.13.0 // indirect

View File

@ -696,6 +696,7 @@ github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhEC
github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=

View File

@ -5,7 +5,7 @@ go 1.19
require ( require (
github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650
github.com/dapr/components-contrib/tests/certification v0.0.0-20211026011813-36b75e9ae272 github.com/dapr/components-contrib/tests/certification v0.0.0-20211026011813-36b75e9ae272
github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4
github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721
github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f
github.com/nacos-group/nacos-sdk-go/v2 v2.1.2 github.com/nacos-group/nacos-sdk-go/v2 v2.1.2
@ -78,6 +78,7 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/openzipkin/zipkin-go v0.4.1 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.13.0 // indirect github.com/prometheus/client_golang v1.13.0 // indirect

View File

@ -397,6 +397,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=

View File

@ -33,12 +33,16 @@ import (
dapr_testing "github.com/dapr/dapr/pkg/testing" dapr_testing "github.com/dapr/dapr/pkg/testing"
daprsdk "github.com/dapr/go-sdk/client" daprsdk "github.com/dapr/go-sdk/client"
"github.com/dapr/kit/logger" "github.com/dapr/kit/logger"
"github.com/dapr/kit/ptr"
"github.com/dapr/components-contrib/tests/certification/embedded" "github.com/dapr/components-contrib/tests/certification/embedded"
"github.com/dapr/components-contrib/tests/certification/flow" "github.com/dapr/components-contrib/tests/certification/flow"
"github.com/dapr/components-contrib/tests/certification/flow/sidecar" "github.com/dapr/components-contrib/tests/certification/flow/sidecar"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/bloberror"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/container"
) )
const ( const (
@ -104,10 +108,12 @@ func listBlobRequest(ctx flow.Context, client daprsdk.Client, prefix string, mar
} }
// deleteBlobRequest is used to make a common binding request for the delete operation. // deleteBlobRequest is used to make a common binding request for the delete operation.
func deleteBlobRequest(ctx flow.Context, client daprsdk.Client, name string, deleteSnapshotsOption string) (out *daprsdk.BindingEvent, err error) { func deleteBlobRequest(ctx flow.Context, client daprsdk.Client, name string, deleteSnapshotsOption *string) (out *daprsdk.BindingEvent, err error) {
invokeDeleteMetadata := map[string]string{ invokeDeleteMetadata := map[string]string{
"blobName": name, "blobName": name,
"deleteSnapshots": deleteSnapshotsOption, }
if deleteSnapshotsOption != nil {
invokeDeleteMetadata["deleteSnapshots"] = *deleteSnapshotsOption
} }
invokeGetRequest := &daprsdk.InvokeBindingRequest{ invokeGetRequest := &daprsdk.InvokeBindingRequest{
@ -185,19 +191,19 @@ func TestBlobStorage(t *testing.T) {
assert.Equal(t, newString, input2) assert.Equal(t, newString, input2)
// cleanup. // cleanup.
out, invokeDeleteErr := deleteBlobRequest(ctx, client, blobName, "") out, invokeDeleteErr := deleteBlobRequest(ctx, client, blobName, nil)
assert.NoError(t, invokeDeleteErr) assert.NoError(t, invokeDeleteErr)
assert.Empty(t, out.Data) assert.Empty(t, out.Data)
// confirm the deletion. // confirm the deletion.
_, invokeSecondGetErr := getBlobRequest(ctx, client, blobName, false) _, invokeSecondGetErr := getBlobRequest(ctx, client, blobName, false)
assert.Error(t, invokeSecondGetErr) assert.Error(t, invokeSecondGetErr)
assert.Contains(t, invokeSecondGetErr.Error(), "ServiceCode=BlobNotFound") assert.Contains(t, invokeSecondGetErr.Error(), bloberror.BlobNotFound)
// deleting the key again should fail. // deleting the key again should fail.
_, invokeDeleteErr2 := deleteBlobRequest(ctx, client, blobName, "") _, invokeDeleteErr2 := deleteBlobRequest(ctx, client, blobName, nil)
assert.Error(t, invokeDeleteErr2) assert.Error(t, invokeDeleteErr2)
assert.Contains(t, invokeDeleteErr2.Error(), "ServiceCode=BlobNotFound") assert.Contains(t, invokeDeleteErr2.Error(), bloberror.BlobNotFound)
return nil return nil
} }
@ -230,7 +236,7 @@ func TestBlobStorage(t *testing.T) {
_, invokeCreateErr := client.InvokeBinding(ctx, invokeCreateRequest) _, invokeCreateErr := client.InvokeBinding(ctx, invokeCreateRequest)
assert.Error(t, invokeCreateErr) assert.Error(t, invokeCreateErr)
assert.Contains(t, invokeCreateErr.Error(), "ServiceCode=Md5Mismatch") assert.Contains(t, invokeCreateErr.Error(), bloberror.MD5Mismatch)
return nil return nil
} }
@ -272,14 +278,14 @@ func TestBlobStorage(t *testing.T) {
assert.Equal(t, responseData, dataBytes) assert.Equal(t, responseData, dataBytes)
assert.Empty(t, out.Metadata) assert.Empty(t, out.Metadata)
out, invokeDeleteErr := deleteBlobRequest(ctx, client, blobName, "") out, invokeDeleteErr := deleteBlobRequest(ctx, client, blobName, nil)
assert.NoError(t, invokeDeleteErr) assert.NoError(t, invokeDeleteErr)
assert.Empty(t, out.Data) assert.Empty(t, out.Data)
// confirm the deletion. // confirm the deletion.
_, invokeSecondGetErr := getBlobRequest(ctx, client, blobName, false) _, invokeSecondGetErr := getBlobRequest(ctx, client, blobName, false)
assert.Error(t, invokeSecondGetErr) assert.Error(t, invokeSecondGetErr)
assert.Contains(t, invokeSecondGetErr.Error(), "ServiceCode=BlobNotFound") assert.Contains(t, invokeSecondGetErr.Error(), bloberror.BlobNotFound)
return nil return nil
} }
@ -327,7 +333,7 @@ func TestBlobStorage(t *testing.T) {
} }
// cleanup. // cleanup.
_, invokeDeleteErr := deleteBlobRequest(ctx, client, blobName, "") _, invokeDeleteErr := deleteBlobRequest(ctx, client, blobName, nil)
assert.NoError(t, invokeDeleteErr) assert.NoError(t, invokeDeleteErr)
return nil return nil
@ -384,9 +390,9 @@ func TestBlobStorage(t *testing.T) {
out, invokeGetErr := client.InvokeBinding(ctx, invokeGetRequest) out, invokeGetErr := client.InvokeBinding(ctx, invokeGetRequest)
assert.NoError(t, invokeGetErr) assert.NoError(t, invokeGetErr)
assert.Equal(t, string(out.Data), input) assert.Equal(t, input, string(out.Data))
assert.Contains(t, out.Metadata, "custom") assert.Contains(t, out.Metadata, "Custom")
assert.Equal(t, out.Metadata["custom"], "hello-world") assert.Equal(t, "hello-world", out.Metadata["Custom"])
out, invokeErr := listBlobRequest(ctx, client, "", "", -1, true, false, false, false, false) out, invokeErr := listBlobRequest(ctx, client, "", "", -1, true, false, false, false, false)
assert.NoError(t, invokeErr) assert.NoError(t, invokeErr)
@ -412,14 +418,14 @@ func TestBlobStorage(t *testing.T) {
} }
assert.True(t, found) assert.True(t, found)
out, invokeDeleteErr := deleteBlobRequest(ctx, client, "filename.txt", "") out, invokeDeleteErr := deleteBlobRequest(ctx, client, "filename.txt", nil)
assert.NoError(t, invokeDeleteErr) assert.NoError(t, invokeDeleteErr)
assert.Empty(t, out.Data) assert.Empty(t, out.Data)
// confirm the deletion. // confirm the deletion.
_, invokeSecondGetErr := getBlobRequest(ctx, client, "filename.txt", false) _, invokeSecondGetErr := getBlobRequest(ctx, client, "filename.txt", false)
assert.Error(t, invokeSecondGetErr) assert.Error(t, invokeSecondGetErr)
assert.Contains(t, invokeSecondGetErr.Error(), "ServiceCode=BlobNotFound") assert.Contains(t, invokeSecondGetErr.Error(), bloberror.BlobNotFound)
return nil return nil
} }
@ -505,8 +511,8 @@ func TestBlobStorage(t *testing.T) {
unmarshalErr := json.Unmarshal(out.Data, &output) unmarshalErr := json.Unmarshal(out.Data, &output)
assert.NoError(t, unmarshalErr) assert.NoError(t, unmarshalErr)
assert.Equal(t, len(output), 1) assert.Equal(t, 1, len(output))
assert.Equal(t, output[0]["Name"], "prefixA/filename.txt") assert.Contains(t, output[0]["Name"], "prefixA")
nextMarker := out.Metadata["marker"] nextMarker := out.Metadata["marker"]
@ -518,27 +524,27 @@ func TestBlobStorage(t *testing.T) {
err2 := json.Unmarshal(out2.Data, &output2) err2 := json.Unmarshal(out2.Data, &output2)
assert.NoError(t, err2) assert.NoError(t, err2)
assert.Equal(t, len(output2), 1) assert.Equal(t, 1, len(output2))
assert.Equal(t, output2[0]["Name"], "prefixAfilename.txt") assert.Contains(t, output2[0]["Name"], "prefixA")
// cleanup. // cleanup.
_, invokeDeleteErr1 := deleteBlobRequest(ctx, client, "prefixA/filename.txt", "") _, invokeDeleteErr1 := deleteBlobRequest(ctx, client, "prefixA/filename.txt", nil)
assert.NoError(t, invokeDeleteErr1) assert.NoError(t, invokeDeleteErr1)
_, invokeDeleteErr2 := deleteBlobRequest(ctx, client, "prefixAfilename.txt", "") _, invokeDeleteErr2 := deleteBlobRequest(ctx, client, "prefixAfilename.txt", nil)
assert.NoError(t, invokeDeleteErr2) assert.NoError(t, invokeDeleteErr2)
_, invokeDeleteErr3 := deleteBlobRequest(ctx, client, "prefixB/filename.txt", "") _, invokeDeleteErr3 := deleteBlobRequest(ctx, client, "prefixB/filename.txt", nil)
assert.NoError(t, invokeDeleteErr3) assert.NoError(t, invokeDeleteErr3)
// list deleted items with prefix. // list deleted items with prefix.
out3, listErr3 := listBlobRequest(ctx, client, "prefixA", "", -1, false, false, false, false, true) out3, listErr3 := listBlobRequest(ctx, client, "prefixA/", "", -1, false, false, false, false, true)
assert.NoError(t, listErr3) assert.NoError(t, listErr3)
// this will only return the deleted items if soft delete policy is enabled for the blob service. // this will only return the deleted items if soft delete policy is enabled for the blob service.
assert.Equal(t, out3.Metadata["number"], "2") assert.Equal(t, "1", out3.Metadata["number"])
var output3 []map[string]interface{} var output3 []map[string]interface{}
err3 := json.Unmarshal(out3.Data, &output3) err3 := json.Unmarshal(out3.Data, &output3)
assert.NoError(t, err3) assert.NoError(t, err3)
assert.Equal(t, len(output3), 2) assert.Equal(t, len(output3), 1)
return nil return nil
} }
@ -553,17 +559,15 @@ func TestBlobStorage(t *testing.T) {
defer client.Close() defer client.Close()
cred, _ := azblob.NewSharedKeyCredential(os.Getenv("AzureBlobStorageAccount"), os.Getenv("AzureBlobStorageAccessKey")) cred, _ := azblob.NewSharedKeyCredential(os.Getenv("AzureBlobStorageAccount"), os.Getenv("AzureBlobStorageAccessKey"))
service, _ := azblob.NewServiceClientWithSharedKey(fmt.Sprintf("https://%s.blob.core.windows.net/", os.Getenv("AzureBlobStorageAccount")), cred, nil) containerClient, _ := container.NewClientWithSharedKeyCredential(fmt.Sprintf("https://%s.blob.core.windows.net/%s", os.Getenv("AzureBlobStorageAccount"), os.Getenv("AzureBlobStorageContainer")), cred, nil)
containerClient, _ := service.NewContainerClient(os.Getenv("AzureBlobStorageContainer"))
blobClient, _ := containerClient.NewBlockBlobClient("snapshotthis.txt") blobClient := containerClient.NewBlockBlobClient("snapshotthis.txt")
uploadResp, uploadErr := blobClient.UploadBuffer( _, uploadErr := blobClient.UploadBuffer(
ctx, []byte("some example content"), ctx, []byte("some example content"),
azblob.UploadOption{}) //nolint:exhaustivestruct &azblob.UploadBufferOptions{}) //nolint:exhaustivestruct
assert.NoError(t, uploadErr) assert.NoError(t, uploadErr)
uploadResp.Body.Close()
_, createSnapshotErr := blobClient.CreateSnapshot( _, createSnapshotErr := blobClient.CreateSnapshot(
ctx, &azblob.BlobCreateSnapshotOptions{}) //nolint:exhaustivestruct ctx, &blob.CreateSnapshotOptions{}) //nolint:exhaustivestruct
assert.NoError(t, createSnapshotErr) assert.NoError(t, createSnapshotErr)
// list the contents of the container including snapshots for the specific blob only. // list the contents of the container including snapshots for the specific blob only.
@ -572,27 +576,27 @@ func TestBlobStorage(t *testing.T) {
assert.Equal(t, out.Metadata["number"], "2") assert.Equal(t, out.Metadata["number"], "2")
// delete snapshots. // delete snapshots.
_, invokeDeleteErr := deleteBlobRequest(ctx, client, "snapshotthis.txt", "only") _, invokeDeleteErr := deleteBlobRequest(ctx, client, "snapshotthis.txt", ptr.Of(string(blob.DeleteSnapshotsOptionTypeOnly)))
assert.NoError(t, invokeDeleteErr) assert.NoError(t, invokeDeleteErr)
// verify snapshot is deleted. // verify snapshot is deleted.
out2, listErr2 := listBlobRequest(ctx, client, "snapshotthis.txt", "", -1, false, true, false, false, false) out2, listErr2 := listBlobRequest(ctx, client, "snapshotthis.txt", "", -1, false, true, false, false, false)
assert.NoError(t, listErr2) assert.NoError(t, listErr2)
assert.Equal(t, out2.Metadata["number"], "1") assert.Equal(t, "1", out2.Metadata["number"])
// create another snapshot. // create another snapshot.
_, createSnapshotErr2 := blobClient.CreateSnapshot( _, createSnapshotErr2 := blobClient.CreateSnapshot(
ctx, &azblob.BlobCreateSnapshotOptions{}) //nolint:exhaustivestruct ctx, &blob.CreateSnapshotOptions{}) //nolint:exhaustivestruct
assert.NoError(t, createSnapshotErr2) assert.NoError(t, createSnapshotErr2)
// delete base blob and snapshots all at once. // delete base blob and snapshots all at once.
_, invokeDeleteErr2 := deleteBlobRequest(ctx, client, "snapshotthis.txt", "include") _, invokeDeleteErr2 := deleteBlobRequest(ctx, client, "snapshotthis.txt", ptr.Of(string(blob.DeleteSnapshotsOptionTypeInclude)))
assert.NoError(t, invokeDeleteErr2) assert.NoError(t, invokeDeleteErr2)
// verify base blob and snapshots are deleted. // verify base blob and snapshots are deleted.
out3, listErr3 := listBlobRequest(ctx, client, "snapshotthis.txt", "", -1, false, true, false, false, false) out3, listErr3 := listBlobRequest(ctx, client, "snapshotthis.txt", "", -1, false, true, false, false, false)
assert.NoError(t, listErr3) assert.NoError(t, listErr3)
assert.Equal(t, out3.Metadata["number"], "0") assert.Equal(t, "0", out3.Metadata["number"])
return nil return nil
} }

View File

@ -3,10 +3,10 @@ module github.com/dapr/components-contrib/tests/certification/bindings/azure/blo
go 1.19 go 1.19
require ( require (
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.4.1 github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.5.1
github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650
github.com/dapr/components-contrib/tests/certification v0.0.0-20211130185200-4918900c09e1 github.com/dapr/components-contrib/tests/certification v0.0.0-20211130185200-4918900c09e1
github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4
github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721
github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f
github.com/stretchr/testify v1.8.1 github.com/stretchr/testify v1.8.1
@ -19,7 +19,7 @@ require (
github.com/Azure/azure-pipeline-go v0.2.3 // indirect github.com/Azure/azure-pipeline-go v0.2.3 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 // indirect
github.com/Azure/azure-storage-blob-go v0.10.0 // indirect github.com/Azure/azure-storage-blob-go v0.10.0 // indirect
github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd // indirect github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd // indirect
github.com/Azure/go-autorest v14.2.0+incompatible // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect
@ -96,6 +96,7 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/openzipkin/zipkin-go v0.4.1 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 // indirect github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect

View File

@ -45,10 +45,10 @@ github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 h1:pqrAR74b6EoR4kcxF7L7Wg2B8
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 h1:QkAcEIAKbNL4KoFr4SathZPhDhF4mVwpBMFlYjyAqy8= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 h1:QkAcEIAKbNL4KoFr4SathZPhDhF4mVwpBMFlYjyAqy8=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0/go.mod h1:bhXu1AjYL+wutSL/kpSq6s7733q2Rb0yuot9Zgfqa/0= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0/go.mod h1:bhXu1AjYL+wutSL/kpSq6s7733q2Rb0yuot9Zgfqa/0=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 h1:jp0dGvZ7ZK0mgqnTSClMxa5xuRL7NZgHameVYF6BurY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 h1:XUNQ4mw+zJmaA2KXzP9JlQiecy1SI+Eog7xVkPiqIbg=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w=
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.4.1 h1:QSdcrd/UFJv6Bp/CfoVf2SrENpFn9P6Yh8yb+xNhYMM= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.5.1 h1:BMTdr+ib5ljLa9MxTJK8x/Ds0MbBb4MfuW5BL0zMJnI=
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.4.1/go.mod h1:eZ4g6GUvXiGulfIbbhh1Xr4XwUYaYaWMqzGD/284wCA= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.5.1/go.mod h1:c6WvOhtmjNUWbLfOG1qxM/q0SPvQNSVJvolm+C52dIU=
github.com/Azure/azure-storage-blob-go v0.10.0 h1:evCwGreYo3XLeBV4vSxLbLiYb6e0SzsJiXQVRGsRXxs= github.com/Azure/azure-storage-blob-go v0.10.0 h1:evCwGreYo3XLeBV4vSxLbLiYb6e0SzsJiXQVRGsRXxs=
github.com/Azure/azure-storage-blob-go v0.10.0/go.mod h1:ep1edmW+kNQx4UfWM9heESNmQdijykocJ0YOxmMX8SE= github.com/Azure/azure-storage-blob-go v0.10.0/go.mod h1:ep1edmW+kNQx4UfWM9heESNmQdijykocJ0YOxmMX8SE=
github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd h1:b3wyxBl3vvr15tUAziPBPK354y+LSdfPCpex5oBttHo= github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd h1:b3wyxBl3vvr15tUAziPBPK354y+LSdfPCpex5oBttHo=
@ -454,6 +454,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 h1:Qj1ukM4GlMWXNdMBuXcXfz/Kw9s1qm0CLY32QxuSImI= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 h1:Qj1ukM4GlMWXNdMBuXcXfz/Kw9s1qm0CLY32QxuSImI=
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=

View File

@ -6,7 +6,7 @@ require (
github.com/a8m/documentdb v1.3.1-0.20220405205223-5b41ba0aaeb1 github.com/a8m/documentdb v1.3.1-0.20220405205223-5b41ba0aaeb1
github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650
github.com/dapr/components-contrib/tests/certification v0.0.0-20211130185200-4918900c09e1 github.com/dapr/components-contrib/tests/certification v0.0.0-20211130185200-4918900c09e1
github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4
github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721
github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f
github.com/google/uuid v1.3.0 github.com/google/uuid v1.3.0
@ -22,7 +22,7 @@ require (
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos v0.3.2 // indirect github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos v0.3.2 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 // indirect
github.com/Azure/azure-storage-blob-go v0.10.0 // indirect github.com/Azure/azure-storage-blob-go v0.10.0 // indirect
github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd // indirect github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd // indirect
github.com/Azure/go-autorest v14.2.0+incompatible // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect
@ -98,6 +98,7 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/openzipkin/zipkin-go v0.4.1 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 // indirect github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect

View File

@ -49,8 +49,8 @@ github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 h1:QkAcEIAKbNL4KoFr4Sath
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0/go.mod h1:bhXu1AjYL+wutSL/kpSq6s7733q2Rb0yuot9Zgfqa/0= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0/go.mod h1:bhXu1AjYL+wutSL/kpSq6s7733q2Rb0yuot9Zgfqa/0=
github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos v0.3.2 h1:yJegJqjhrMJ3Oe5s43jOTGL2AsE7pJyx+7Yqls/65tw= github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos v0.3.2 h1:yJegJqjhrMJ3Oe5s43jOTGL2AsE7pJyx+7Yqls/65tw=
github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos v0.3.2/go.mod h1:Fy3bbChFm4cZn6oIxYYqKB2FG3rBDxk3NZDLDJCHl+Q= github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos v0.3.2/go.mod h1:Fy3bbChFm4cZn6oIxYYqKB2FG3rBDxk3NZDLDJCHl+Q=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 h1:jp0dGvZ7ZK0mgqnTSClMxa5xuRL7NZgHameVYF6BurY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 h1:XUNQ4mw+zJmaA2KXzP9JlQiecy1SI+Eog7xVkPiqIbg=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w=
github.com/Azure/azure-storage-blob-go v0.10.0 h1:evCwGreYo3XLeBV4vSxLbLiYb6e0SzsJiXQVRGsRXxs= github.com/Azure/azure-storage-blob-go v0.10.0 h1:evCwGreYo3XLeBV4vSxLbLiYb6e0SzsJiXQVRGsRXxs=
github.com/Azure/azure-storage-blob-go v0.10.0/go.mod h1:ep1edmW+kNQx4UfWM9heESNmQdijykocJ0YOxmMX8SE= github.com/Azure/azure-storage-blob-go v0.10.0/go.mod h1:ep1edmW+kNQx4UfWM9heESNmQdijykocJ0YOxmMX8SE=
github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd h1:b3wyxBl3vvr15tUAziPBPK354y+LSdfPCpex5oBttHo= github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd h1:b3wyxBl3vvr15tUAziPBPK354y+LSdfPCpex5oBttHo=
@ -459,6 +459,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 h1:Qj1ukM4GlMWXNdMBuXcXfz/Kw9s1qm0CLY32QxuSImI= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 h1:Qj1ukM4GlMWXNdMBuXcXfz/Kw9s1qm0CLY32QxuSImI=
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=

View File

@ -5,7 +5,7 @@ go 1.19
require ( require (
github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650
github.com/dapr/components-contrib/tests/certification v0.0.0-20211026011813-36b75e9ae272 github.com/dapr/components-contrib/tests/certification v0.0.0-20211026011813-36b75e9ae272
github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4
github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721
github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f
github.com/google/uuid v1.3.0 github.com/google/uuid v1.3.0
@ -22,7 +22,7 @@ require (
github.com/Azure/azure-sdk-for-go v67.0.0+incompatible // indirect github.com/Azure/azure-sdk-for-go v67.0.0+incompatible // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 // indirect
github.com/Azure/azure-storage-blob-go v0.10.0 // indirect github.com/Azure/azure-storage-blob-go v0.10.0 // indirect
github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd // indirect github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd // indirect
github.com/Azure/go-amqp v0.17.5 // indirect github.com/Azure/go-amqp v0.17.5 // indirect
@ -104,6 +104,7 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/openzipkin/zipkin-go v0.4.1 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 // indirect github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect

View File

@ -51,8 +51,8 @@ github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 h1:pqrAR74b6EoR4kcxF7L7Wg2B8
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 h1:QkAcEIAKbNL4KoFr4SathZPhDhF4mVwpBMFlYjyAqy8= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 h1:QkAcEIAKbNL4KoFr4SathZPhDhF4mVwpBMFlYjyAqy8=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0/go.mod h1:bhXu1AjYL+wutSL/kpSq6s7733q2Rb0yuot9Zgfqa/0= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0/go.mod h1:bhXu1AjYL+wutSL/kpSq6s7733q2Rb0yuot9Zgfqa/0=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 h1:jp0dGvZ7ZK0mgqnTSClMxa5xuRL7NZgHameVYF6BurY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 h1:XUNQ4mw+zJmaA2KXzP9JlQiecy1SI+Eog7xVkPiqIbg=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w=
github.com/Azure/azure-storage-blob-go v0.6.0/go.mod h1:oGfmITT1V6x//CswqY2gtAHND+xIP64/qL7a5QJix0Y= github.com/Azure/azure-storage-blob-go v0.6.0/go.mod h1:oGfmITT1V6x//CswqY2gtAHND+xIP64/qL7a5QJix0Y=
github.com/Azure/azure-storage-blob-go v0.10.0 h1:evCwGreYo3XLeBV4vSxLbLiYb6e0SzsJiXQVRGsRXxs= github.com/Azure/azure-storage-blob-go v0.10.0 h1:evCwGreYo3XLeBV4vSxLbLiYb6e0SzsJiXQVRGsRXxs=
github.com/Azure/azure-storage-blob-go v0.10.0/go.mod h1:ep1edmW+kNQx4UfWM9heESNmQdijykocJ0YOxmMX8SE= github.com/Azure/azure-storage-blob-go v0.10.0/go.mod h1:ep1edmW+kNQx4UfWM9heESNmQdijykocJ0YOxmMX8SE=
@ -479,6 +479,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 h1:Qj1ukM4GlMWXNdMBuXcXfz/Kw9s1qm0CLY32QxuSImI= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 h1:Qj1ukM4GlMWXNdMBuXcXfz/Kw9s1qm0CLY32QxuSImI=
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=

View File

@ -5,7 +5,7 @@ go 1.19
require ( require (
github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650
github.com/dapr/components-contrib/tests/certification v0.0.0-20211026011813-36b75e9ae272 github.com/dapr/components-contrib/tests/certification v0.0.0-20211026011813-36b75e9ae272
github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4
github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721
github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f
github.com/stretchr/testify v1.8.1 github.com/stretchr/testify v1.8.1
@ -19,7 +19,7 @@ require (
github.com/Azure/azure-pipeline-go v0.2.3 // indirect github.com/Azure/azure-pipeline-go v0.2.3 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.1.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.1.1 // indirect
github.com/Azure/azure-storage-blob-go v0.10.0 // indirect github.com/Azure/azure-storage-blob-go v0.10.0 // indirect
github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd // indirect github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd // indirect
@ -100,6 +100,7 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/openzipkin/zipkin-go v0.4.1 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 // indirect github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect

View File

@ -45,8 +45,8 @@ github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 h1:pqrAR74b6EoR4kcxF7L7Wg2B8
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 h1:QkAcEIAKbNL4KoFr4SathZPhDhF4mVwpBMFlYjyAqy8= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 h1:QkAcEIAKbNL4KoFr4SathZPhDhF4mVwpBMFlYjyAqy8=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0/go.mod h1:bhXu1AjYL+wutSL/kpSq6s7733q2Rb0yuot9Zgfqa/0= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0/go.mod h1:bhXu1AjYL+wutSL/kpSq6s7733q2Rb0yuot9Zgfqa/0=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 h1:jp0dGvZ7ZK0mgqnTSClMxa5xuRL7NZgHameVYF6BurY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 h1:XUNQ4mw+zJmaA2KXzP9JlQiecy1SI+Eog7xVkPiqIbg=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w=
github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.1.1 h1:Zm7A6yKHT3evC/0lquPWJ9hrkRGVIeZOmIvHPv6xV9Q= github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.1.1 h1:Zm7A6yKHT3evC/0lquPWJ9hrkRGVIeZOmIvHPv6xV9Q=
github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.1.1/go.mod h1:LH9XQnMr2ZYxQdVdCrzLO9mxeDyrDFa6wbSI3x5zCZk= github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.1.1/go.mod h1:LH9XQnMr2ZYxQdVdCrzLO9mxeDyrDFa6wbSI3x5zCZk=
github.com/Azure/azure-storage-blob-go v0.10.0 h1:evCwGreYo3XLeBV4vSxLbLiYb6e0SzsJiXQVRGsRXxs= github.com/Azure/azure-storage-blob-go v0.10.0 h1:evCwGreYo3XLeBV4vSxLbLiYb6e0SzsJiXQVRGsRXxs=
@ -462,6 +462,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 h1:Qj1ukM4GlMWXNdMBuXcXfz/Kw9s1qm0CLY32QxuSImI= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 h1:Qj1ukM4GlMWXNdMBuXcXfz/Kw9s1qm0CLY32QxuSImI=
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=

View File

@ -5,7 +5,7 @@ go 1.19
require ( require (
github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650
github.com/dapr/components-contrib/tests/certification v0.0.0-20211026011813-36b75e9ae272 github.com/dapr/components-contrib/tests/certification v0.0.0-20211026011813-36b75e9ae272
github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4
github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721
github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f
github.com/stretchr/testify v1.8.1 github.com/stretchr/testify v1.8.1
@ -19,7 +19,7 @@ require (
github.com/Azure/azure-pipeline-go v0.2.3 // indirect github.com/Azure/azure-pipeline-go v0.2.3 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 // indirect
github.com/Azure/azure-storage-blob-go v0.10.0 // indirect github.com/Azure/azure-storage-blob-go v0.10.0 // indirect
github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd // indirect github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd // indirect
github.com/Azure/go-autorest v14.2.0+incompatible // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect
@ -97,6 +97,7 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/openzipkin/zipkin-go v0.4.1 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 // indirect github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect

View File

@ -45,8 +45,8 @@ github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 h1:pqrAR74b6EoR4kcxF7L7Wg2B8
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 h1:QkAcEIAKbNL4KoFr4SathZPhDhF4mVwpBMFlYjyAqy8= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 h1:QkAcEIAKbNL4KoFr4SathZPhDhF4mVwpBMFlYjyAqy8=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0/go.mod h1:bhXu1AjYL+wutSL/kpSq6s7733q2Rb0yuot9Zgfqa/0= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0/go.mod h1:bhXu1AjYL+wutSL/kpSq6s7733q2Rb0yuot9Zgfqa/0=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 h1:jp0dGvZ7ZK0mgqnTSClMxa5xuRL7NZgHameVYF6BurY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 h1:XUNQ4mw+zJmaA2KXzP9JlQiecy1SI+Eog7xVkPiqIbg=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w=
github.com/Azure/azure-storage-blob-go v0.10.0 h1:evCwGreYo3XLeBV4vSxLbLiYb6e0SzsJiXQVRGsRXxs= github.com/Azure/azure-storage-blob-go v0.10.0 h1:evCwGreYo3XLeBV4vSxLbLiYb6e0SzsJiXQVRGsRXxs=
github.com/Azure/azure-storage-blob-go v0.10.0/go.mod h1:ep1edmW+kNQx4UfWM9heESNmQdijykocJ0YOxmMX8SE= github.com/Azure/azure-storage-blob-go v0.10.0/go.mod h1:ep1edmW+kNQx4UfWM9heESNmQdijykocJ0YOxmMX8SE=
github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd h1:b3wyxBl3vvr15tUAziPBPK354y+LSdfPCpex5oBttHo= github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd h1:b3wyxBl3vvr15tUAziPBPK354y+LSdfPCpex5oBttHo=
@ -454,6 +454,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 h1:Qj1ukM4GlMWXNdMBuXcXfz/Kw9s1qm0CLY32QxuSImI= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 h1:Qj1ukM4GlMWXNdMBuXcXfz/Kw9s1qm0CLY32QxuSImI=
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=

View File

@ -7,7 +7,7 @@ require (
github.com/cenkalti/backoff/v4 v4.1.3 github.com/cenkalti/backoff/v4 v4.1.3
github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650
github.com/dapr/components-contrib/tests/certification v0.0.0-20220519061249-c2cb1dad5bb0 github.com/dapr/components-contrib/tests/certification v0.0.0-20220519061249-c2cb1dad5bb0
github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4
github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721
github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f
github.com/google/uuid v1.3.0 github.com/google/uuid v1.3.0
@ -87,6 +87,7 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/openzipkin/zipkin-go v0.4.1 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect
github.com/pierrec/lz4/v4 v4.1.17 // indirect github.com/pierrec/lz4/v4 v4.1.17 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect

View File

@ -409,6 +409,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc= github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc=
github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=

View File

@ -5,7 +5,7 @@ go 1.19
require ( require (
github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650
github.com/dapr/components-contrib/tests/certification v0.0.0-00010101000000-000000000000 github.com/dapr/components-contrib/tests/certification v0.0.0-00010101000000-000000000000
github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4
github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721
github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f
github.com/stretchr/testify v1.8.1 github.com/stretchr/testify v1.8.1
@ -75,6 +75,7 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/openzipkin/zipkin-go v0.4.1 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.13.0 // indirect github.com/prometheus/client_golang v1.13.0 // indirect

View File

@ -381,6 +381,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=

View File

@ -5,7 +5,7 @@ go 1.19
require ( require (
github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650
github.com/dapr/components-contrib/tests/certification v0.0.0-20220526162429-d03aeba3e0d6 github.com/dapr/components-contrib/tests/certification v0.0.0-20220526162429-d03aeba3e0d6
github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4
github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721
github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f
github.com/lib/pq v1.10.7 github.com/lib/pq v1.10.7
@ -79,6 +79,7 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/openzipkin/zipkin-go v0.4.1 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.13.0 // indirect github.com/prometheus/client_golang v1.13.0 // indirect

View File

@ -389,6 +389,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=

View File

@ -5,7 +5,7 @@ go 1.19
require ( require (
github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650
github.com/dapr/components-contrib/tests/certification v0.0.0-20211130185200-4918900c09e1 github.com/dapr/components-contrib/tests/certification v0.0.0-20211130185200-4918900c09e1
github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4
github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721
github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f
github.com/rabbitmq/amqp091-go v1.5.0 github.com/rabbitmq/amqp091-go v1.5.0
@ -77,6 +77,7 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/openzipkin/zipkin-go v0.4.1 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.13.0 // indirect github.com/prometheus/client_golang v1.13.0 // indirect

View File

@ -381,6 +381,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=

View File

@ -5,7 +5,7 @@ go 1.19
require ( require (
github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650
github.com/dapr/components-contrib/tests/certification v0.0.0-20220908221803-2b5650c2faa4 github.com/dapr/components-contrib/tests/certification v0.0.0-20220908221803-2b5650c2faa4
github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4
github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721
github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f
github.com/go-redis/redis/v8 v8.11.5 github.com/go-redis/redis/v8 v8.11.5
@ -76,6 +76,7 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/openzipkin/zipkin-go v0.4.1 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.13.0 // indirect github.com/prometheus/client_golang v1.13.0 // indirect

View File

@ -385,6 +385,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=

View File

@ -22,13 +22,13 @@ import (
global_config "github.com/dapr/dapr/pkg/config" global_config "github.com/dapr/dapr/pkg/config"
env "github.com/dapr/dapr/pkg/config/env" env "github.com/dapr/dapr/pkg/config/env"
"github.com/dapr/dapr/pkg/cors" "github.com/dapr/dapr/pkg/cors"
"github.com/dapr/dapr/pkg/grpc"
"github.com/dapr/dapr/pkg/modes" "github.com/dapr/dapr/pkg/modes"
"github.com/dapr/dapr/pkg/operator/client" "github.com/dapr/dapr/pkg/operator/client"
"github.com/dapr/dapr/pkg/resiliency" "github.com/dapr/dapr/pkg/resiliency"
"github.com/dapr/dapr/pkg/runtime" "github.com/dapr/dapr/pkg/runtime"
"github.com/dapr/dapr/pkg/runtime/security" "github.com/dapr/dapr/pkg/runtime/security"
"github.com/dapr/kit/logger" "github.com/dapr/kit/logger"
"github.com/phayes/freeport"
) )
const ( const (
@ -138,7 +138,7 @@ func NewRuntime(appID string, opts ...Option) (*runtime.DaprRuntime, *runtime.Co
} }
if runtimeConfig.InternalGRPCPort == 0 { if runtimeConfig.InternalGRPCPort == 0 {
if runtimeConfig.InternalGRPCPort, err = grpc.GetFreePort(); err != nil { if runtimeConfig.InternalGRPCPort, err = freeport.GetFreePort(); err != nil {
return nil, nil, err return nil, nil, err
} }
} }

View File

@ -4,7 +4,7 @@ go 1.19
require ( require (
github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650
github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4
github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721
github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f
github.com/google/go-cmp v0.5.9 github.com/google/go-cmp v0.5.9
@ -134,6 +134,7 @@ require (
require ( require (
github.com/cenkalti/backoff/v4 v4.1.3 github.com/cenkalti/backoff/v4 v4.1.3
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5
github.com/tylertreat/comcast v1.0.1 github.com/tylertreat/comcast v1.0.1
) )

View File

@ -381,6 +381,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=

View File

@ -5,7 +5,7 @@ go 1.19
require ( require (
github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650
github.com/dapr/components-contrib/tests/certification v1.4.0-rc2 github.com/dapr/components-contrib/tests/certification v1.4.0-rc2
github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4
github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721
github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f
github.com/google/uuid v1.3.0 github.com/google/uuid v1.3.0
@ -22,7 +22,7 @@ require (
github.com/Azure/azure-sdk-for-go v67.0.0+incompatible // indirect github.com/Azure/azure-sdk-for-go v67.0.0+incompatible // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 // indirect
github.com/Azure/azure-storage-blob-go v0.10.0 // indirect github.com/Azure/azure-storage-blob-go v0.10.0 // indirect
github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd // indirect github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd // indirect
github.com/Azure/go-amqp v0.17.5 // indirect github.com/Azure/go-amqp v0.17.5 // indirect
@ -104,6 +104,7 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/openzipkin/zipkin-go v0.4.1 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 // indirect github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect

View File

@ -51,8 +51,8 @@ github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 h1:pqrAR74b6EoR4kcxF7L7Wg2B8
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 h1:QkAcEIAKbNL4KoFr4SathZPhDhF4mVwpBMFlYjyAqy8= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 h1:QkAcEIAKbNL4KoFr4SathZPhDhF4mVwpBMFlYjyAqy8=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0/go.mod h1:bhXu1AjYL+wutSL/kpSq6s7733q2Rb0yuot9Zgfqa/0= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0/go.mod h1:bhXu1AjYL+wutSL/kpSq6s7733q2Rb0yuot9Zgfqa/0=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 h1:jp0dGvZ7ZK0mgqnTSClMxa5xuRL7NZgHameVYF6BurY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 h1:XUNQ4mw+zJmaA2KXzP9JlQiecy1SI+Eog7xVkPiqIbg=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w=
github.com/Azure/azure-storage-blob-go v0.6.0/go.mod h1:oGfmITT1V6x//CswqY2gtAHND+xIP64/qL7a5QJix0Y= github.com/Azure/azure-storage-blob-go v0.6.0/go.mod h1:oGfmITT1V6x//CswqY2gtAHND+xIP64/qL7a5QJix0Y=
github.com/Azure/azure-storage-blob-go v0.10.0 h1:evCwGreYo3XLeBV4vSxLbLiYb6e0SzsJiXQVRGsRXxs= github.com/Azure/azure-storage-blob-go v0.10.0 h1:evCwGreYo3XLeBV4vSxLbLiYb6e0SzsJiXQVRGsRXxs=
github.com/Azure/azure-storage-blob-go v0.10.0/go.mod h1:ep1edmW+kNQx4UfWM9heESNmQdijykocJ0YOxmMX8SE= github.com/Azure/azure-storage-blob-go v0.10.0/go.mod h1:ep1edmW+kNQx4UfWM9heESNmQdijykocJ0YOxmMX8SE=
@ -479,6 +479,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 h1:Qj1ukM4GlMWXNdMBuXcXfz/Kw9s1qm0CLY32QxuSImI= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 h1:Qj1ukM4GlMWXNdMBuXcXfz/Kw9s1qm0CLY32QxuSImI=
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=

View File

@ -5,7 +5,7 @@ go 1.19
require ( require (
github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650
github.com/dapr/components-contrib/tests/certification v0.0.0-20211026011813-36b75e9ae272 github.com/dapr/components-contrib/tests/certification v0.0.0-20211026011813-36b75e9ae272
github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4
github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721
github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f
github.com/google/uuid v1.3.0 github.com/google/uuid v1.3.0
@ -20,7 +20,7 @@ require (
github.com/Azure/azure-pipeline-go v0.2.3 // indirect github.com/Azure/azure-pipeline-go v0.2.3 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.1.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.1.1 // indirect
github.com/Azure/azure-storage-blob-go v0.10.0 // indirect github.com/Azure/azure-storage-blob-go v0.10.0 // indirect
github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd // indirect github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd // indirect
@ -100,6 +100,7 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/openzipkin/zipkin-go v0.4.1 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 // indirect github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect

View File

@ -45,8 +45,8 @@ github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 h1:pqrAR74b6EoR4kcxF7L7Wg2B8
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 h1:QkAcEIAKbNL4KoFr4SathZPhDhF4mVwpBMFlYjyAqy8= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 h1:QkAcEIAKbNL4KoFr4SathZPhDhF4mVwpBMFlYjyAqy8=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0/go.mod h1:bhXu1AjYL+wutSL/kpSq6s7733q2Rb0yuot9Zgfqa/0= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0/go.mod h1:bhXu1AjYL+wutSL/kpSq6s7733q2Rb0yuot9Zgfqa/0=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 h1:jp0dGvZ7ZK0mgqnTSClMxa5xuRL7NZgHameVYF6BurY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 h1:XUNQ4mw+zJmaA2KXzP9JlQiecy1SI+Eog7xVkPiqIbg=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w=
github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.1.1 h1:Zm7A6yKHT3evC/0lquPWJ9hrkRGVIeZOmIvHPv6xV9Q= github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.1.1 h1:Zm7A6yKHT3evC/0lquPWJ9hrkRGVIeZOmIvHPv6xV9Q=
github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.1.1/go.mod h1:LH9XQnMr2ZYxQdVdCrzLO9mxeDyrDFa6wbSI3x5zCZk= github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.1.1/go.mod h1:LH9XQnMr2ZYxQdVdCrzLO9mxeDyrDFa6wbSI3x5zCZk=
github.com/Azure/azure-storage-blob-go v0.10.0 h1:evCwGreYo3XLeBV4vSxLbLiYb6e0SzsJiXQVRGsRXxs= github.com/Azure/azure-storage-blob-go v0.10.0 h1:evCwGreYo3XLeBV4vSxLbLiYb6e0SzsJiXQVRGsRXxs=
@ -462,6 +462,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 h1:Qj1ukM4GlMWXNdMBuXcXfz/Kw9s1qm0CLY32QxuSImI= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 h1:Qj1ukM4GlMWXNdMBuXcXfz/Kw9s1qm0CLY32QxuSImI=
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=

View File

@ -7,7 +7,7 @@ require (
github.com/cenkalti/backoff/v4 v4.1.3 github.com/cenkalti/backoff/v4 v4.1.3
github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650
github.com/dapr/components-contrib/tests/certification v0.0.0-20220519061249-c2cb1dad5bb0 github.com/dapr/components-contrib/tests/certification v0.0.0-20220519061249-c2cb1dad5bb0
github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4
github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721
github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f
github.com/google/uuid v1.3.0 github.com/google/uuid v1.3.0
@ -87,6 +87,7 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/openzipkin/zipkin-go v0.4.1 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect
github.com/pierrec/lz4/v4 v4.1.17 // indirect github.com/pierrec/lz4/v4 v4.1.17 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect

View File

@ -409,6 +409,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc= github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc=
github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=

View File

@ -6,7 +6,7 @@ require (
github.com/cenkalti/backoff/v4 v4.1.3 github.com/cenkalti/backoff/v4 v4.1.3
github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650
github.com/dapr/components-contrib/tests/certification v1.4.0-rc2 github.com/dapr/components-contrib/tests/certification v1.4.0-rc2
github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4
github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721
github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f
github.com/eclipse/paho.mqtt.golang v1.4.2 github.com/eclipse/paho.mqtt.golang v1.4.2
@ -79,6 +79,7 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/openzipkin/zipkin-go v0.4.1 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.13.0 // indirect github.com/prometheus/client_golang v1.13.0 // indirect

View File

@ -388,6 +388,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=

View File

@ -6,7 +6,7 @@ require (
github.com/cenkalti/backoff/v4 v4.1.3 github.com/cenkalti/backoff/v4 v4.1.3
github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650
github.com/dapr/components-contrib/tests/certification v0.0.0-20211130185200-4918900c09e1 github.com/dapr/components-contrib/tests/certification v0.0.0-20211130185200-4918900c09e1
github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4
github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721
github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f
github.com/rabbitmq/amqp091-go v1.5.0 github.com/rabbitmq/amqp091-go v1.5.0
@ -77,6 +77,7 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/openzipkin/zipkin-go v0.4.1 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.13.0 // indirect github.com/prometheus/client_golang v1.13.0 // indirect

View File

@ -381,6 +381,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=

View File

@ -5,7 +5,7 @@ go 1.19
require ( require (
github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650
github.com/dapr/components-contrib/tests/certification v0.0.0-20211130185200-4918900c09e1 github.com/dapr/components-contrib/tests/certification v0.0.0-20211130185200-4918900c09e1
github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4
github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721
github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f
github.com/stretchr/testify v1.8.1 github.com/stretchr/testify v1.8.1
@ -18,7 +18,7 @@ require (
github.com/Azure/azure-pipeline-go v0.2.3 // indirect github.com/Azure/azure-pipeline-go v0.2.3 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.10.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.10.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.0 // indirect
github.com/Azure/azure-storage-blob-go v0.10.0 // indirect github.com/Azure/azure-storage-blob-go v0.10.0 // indirect
@ -97,6 +97,7 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/openzipkin/zipkin-go v0.4.1 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 // indirect github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect

View File

@ -45,8 +45,8 @@ github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 h1:pqrAR74b6EoR4kcxF7L7Wg2B8
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 h1:QkAcEIAKbNL4KoFr4SathZPhDhF4mVwpBMFlYjyAqy8= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 h1:QkAcEIAKbNL4KoFr4SathZPhDhF4mVwpBMFlYjyAqy8=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0/go.mod h1:bhXu1AjYL+wutSL/kpSq6s7733q2Rb0yuot9Zgfqa/0= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0/go.mod h1:bhXu1AjYL+wutSL/kpSq6s7733q2Rb0yuot9Zgfqa/0=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 h1:jp0dGvZ7ZK0mgqnTSClMxa5xuRL7NZgHameVYF6BurY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 h1:XUNQ4mw+zJmaA2KXzP9JlQiecy1SI+Eog7xVkPiqIbg=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w=
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.10.1 h1:AhZnZn4kUKz36bHJ8AK/FH2tH/q3CAkG+Gme+2ibuak= github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.10.1 h1:AhZnZn4kUKz36bHJ8AK/FH2tH/q3CAkG+Gme+2ibuak=
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.10.1/go.mod h1:S78i9yTr4o/nXlH76bKjGUye9Z2wSxO5Tz7GoDr4vfI= github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.10.1/go.mod h1:S78i9yTr4o/nXlH76bKjGUye9Z2wSxO5Tz7GoDr4vfI=
github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.0 h1:Lg6BW0VPmCwcMlvOviL3ruHFO+H9tZNqscK0AeuFjGM= github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.0 h1:Lg6BW0VPmCwcMlvOviL3ruHFO+H9tZNqscK0AeuFjGM=
@ -456,6 +456,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 h1:Qj1ukM4GlMWXNdMBuXcXfz/Kw9s1qm0CLY32QxuSImI= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 h1:Qj1ukM4GlMWXNdMBuXcXfz/Kw9s1qm0CLY32QxuSImI=
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=

View File

@ -16,17 +16,118 @@ This secret store [supports the following features][features]:
## Test network instability ## Test network instability
1. Vault component does not expose a time out configuration option. For this test, let's assume a 1 minute timeout. 1. Vault component does not expose a time out configuration option. For this test, let's assume a 1 minute timeout.
2. Retrieve a key to show the connection is fine. 2. Retrieve a key to show the connection is fine.
3. Interrupt the network (Vault port, 8200) for longer than the established timeout value. 3. Interrupt the network on Vault's port (8200) for longer than the established timeout value.
4. Wait a few seconds (less than the timeout value). 4. Wait a few seconds (less than the timeout value).
5. Try to read the key from step 2 and assert it is still there. 5. Try to read the key from step 2 and assert it is still there.
## Test support for multiple keys under the same secret ## Test support for multiple keys under the same secret
1. Test retrieval of secrets with multiple keys under it 1. Test retrieval of secrets with multiple keys under it.
## Tests for metadata fields
### Tests for `vaultKVPrefix`, `vaultKVUsePrefix` and `vaultValueTypeText`
1. Verify `vaultKVPrefix` is used
* set field to to non default value
* run dapr application with component
* component should successfully initialize
* component should advertise `multipleKeyValuesPerSecret` feature
* retrieval of key under registered under new prefix should succeed
* keys under default and empty prefixes should be missing
1. Verify `vaultKVUsePrefix` is used
* set field to `false` (non default value)
* run dapr application with component
* component should successfully initialize
* component should advertise `multipleKeyValuesPerSecret` feature
* retrieval of key registered without (empty) prefix should succeed
* keys under default and non-default prefix from step above should be missing
1. Verify `vaultValueTypeText` is used
* set field to to non default value `text`
* run dapr application with component
* component should successfully initialize
* component should **not** advertise `multipleKeyValuesPerSecret` feature
* retrieval of key under registered under new prefix should succeed
* keys under default and empty prefixes should be missing
### Tests for `vaultToken` and `vaultTokenMountPath`
1. Verify `vaultToken` is used (happy case)
* The baseline fo this test is all the previous test are using a known-to-work value that matches what our docker-compose environment sets up.
1. Verify failure when we use a `vaultToken` value that does not match what our environment sets up
1. Verify `vaultTokenMountPath` is used (happy case)
1. Verify failure when `vaultTokenMountPath` points to a broken path
1. Verify failure when both `vaultToken` and `vaultTokenMountPath` are missing
1. Verify failure when both `vaultToken` and `vaultTokenMountPath` are present
### Tests for vaultAddr
1. Verify `vaultAddr` is used (happy case)
* The baseline fo this test is all the previous test are using this flag with a known-to-work value that matches what our docker-compose environment sets up and is **not the default**.
1. Verify initialization and operation success when `vaultAddr` is missing `skipVerify` is `true`
* Start a vault instance using a self-signed HTTPS certificate.
* Component configuration lacks `vaultAddr` and defaults to address `https://127.0.0.1:8200`
* Due to `skipVerify` the component accepts the self-signed certificate
1. Verify initialization success but operation failure when `vaultAddr` is missing `skipVerify` is `false`
* Start a vault instance using a self-signed HTTPS certificate.
* Component configuration lacks `vaultAddr` and defaults to address `https://127.0.0.1:8200`
* Since `skipVerify` is disable the component requires a valid TLS certificate and refuses to connect to our vault instance, failing requests.
1. Verify `vaultAddr` is used when it points to a non-std port
* Start a vault instance in dev-mode (HTTP) but listening on a non-std port
* Modify component configuration to use this non-std port
* Ensure component initialization success and successful retrieval of secrets
1. Verify successful initialization but secret retrieval failure when `vaultAddr` points to an address not served by a Vault
* Start a vault instance in dev-mode (HTTP) listening on std port
* Modify component configuration to use a distinct (non-std) port
* Ensure component initialization success but secret retrieval failure
### Tests for enginePath
1. Verify that setting `enginePath` to an explicit default value works
1. Verify that setting `enginePath` to a custom value (`TestEnginePathCustomSecretsPath`) works
* Start a vault instance in dev-mode
* In the companion shell script that seeds the vault instance with secrets,
1. Create a new **path** named `customSecretsPath` that uses the KV engine version 2 (`-version=2 kv` or `kv-v2`)
* We cannot use version 1 as the vault component lacks support for non-versioned engines.
2. Seeds this path with a secret specific for this test (to avoid the risk of false-positive tests)
* Verify that the custom path has secrets under it using BulkList (this is a sanity check)
* Verify that the custom path-specific secret is found
### Tests for CA and other certificate-related parameters
TODO: Should we add code to enforce that only one of these is provided?
1. Verify happy-case behavior when `caPem` is set to valid CA certificate and `tlsServerName` matches the server name and `skipVerify` is false.
1. Verify happy-case behavior when `caPath` is set to valid CA certificate and `tlsServerName` matches the server name and `skipVerify` is false.
1. Verify happy-case behavior when `caCert` is set to valid CA certificate and `tlsServerName` matches the server name and `skipVerify` is false.
1. Verify successful initialization but secret retrieval failure when `caPem` is set to a valid server certificate (baseline) but `tlsServerName` does not match the server name and `skipVerify` is false.
1. Verify successful initialization but secret retrieval failure when `caPem` is set to an invalid server certificate (flag under test) despite `tlsServerName` matching the server name and `skipVerify` is false.
1. Same as the one above but `skipVerify` is true and we should observe happy-case behavior.
1. skipVerify
* We also tested before with the vault-generated self-signed cert while testing for `vaultAddr`
#### Versioning
1. Verify success on retrieval of a past version of a secret
* Start a vault instance in dev-mode (HTTP)
* Seed vault instance with multiple versions of a single secret
* Use standard component configuration
* Ensure component initialization success
* Ensure successful retrieval of latest version of the secret
* Ensure successful retrieval of an specific version of the secret
## Out of scope ## Out of scope
1. Verifying how vault component handles engines that do not support versioning, like KV version 1
* Vault component only handles engines with version support (Bug?)
1. Tests verifying writing and updating a secret since secret stores do not expose this functionality. 1. Tests verifying writing and updating a secret since secret stores do not expose this functionality.
@ -34,8 +135,24 @@ This secret store [supports the following features][features]:
Under the current directory run: Under the current directory run:
```shell
GOLANG_PROTOBUF_REGISTRATION_CONFLICT=warn go test -v .
``` ```
go test -v vault_test.go
To run an specific test run (replacing `TestVersioning` with the name of the test method):
```shell
GOLANG_PROTOBUF_REGISTRATION_CONFLICT=warn go test -run TestVersioning -v .
```
### Docker-compose
You might need to verify if docker-compose is doing what you think it is doing: seeding the right secrets or even booting up properly.
Head to the directory hosting the `docker-compose-hashicorp-vault.yml` file and run:
```shell
docker-compose -f docker-compose-hashicorp-vault.yml up --remove-orphans
``` ```
# References: # References:
@ -44,7 +161,10 @@ go test -v vault_test.go
* [List of secret store components and their features][features] * [List of secret store components and their features][features]
* [PR with Conformance tests for Hashicorp Vault][conformance] * [PR with Conformance tests for Hashicorp Vault][conformance]
* [HashiCorp Vault API reference](https://www.vaultproject.io/api-docs) * [HashiCorp Vault API reference](https://www.vaultproject.io/api-docs)
* [Vault Official Docker image documentation][vault-docker]
[HashiCorp Vault Secret Store]: https://docs.dapr.io/reference/components-reference/supported-secret-stores/hashicorp-vault/ [HashiCorp Vault Secret Store]: https://docs.dapr.io/reference/components-reference/supported-secret-stores/hashicorp-vault/
[features]: https://docs.dapr.io/reference/components-reference/supported-secret-stores/ [features]: https://docs.dapr.io/reference/components-reference/supported-secret-stores/
[conformance]: https://github.com/dapr/components-contrib/pull/2031 [conformance]: https://github.com/dapr/components-contrib/pull/2031
[vault-docker]: https://hub.docker.com/_/vault/

View File

@ -0,0 +1,109 @@
/*
Copyright 2021 The Dapr Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package vault_test
import (
"bufio"
"bytes"
"io"
"os"
"strings"
"github.com/dapr/components-contrib/tests/certification/flow"
"github.com/dapr/kit/logger"
"github.com/stretchr/testify/assert"
)
//
// Helper functions for asserting error messages during component initialization
//
// These can be exported to their own module.
// Do notice that they have side effects: using more than one in a single
// flow will cause only the latest to work. Perhaps this functionality
// (dapr.runtime log capture) could be baked into flows themselves?
//
// Also: this is not thread-safe nor concurrent safe: only one test
// can be run at a time to ensure deterministic capture of dapr.runtime output.
type InitErrorChecker func(ctx flow.Context, errorLine string) error
func CaptureLogsAndCheckInitErrors(checker InitErrorChecker) flow.Runnable {
// Setup log capture
logCaptor := &bytes.Buffer{}
runtimeLogger := logger.NewLogger("dapr.runtime")
runtimeLogger.SetOutput(io.MultiWriter(os.Stdout, logCaptor))
// Stop log capture, reset buffer just for good mesure
cleanup := func() {
logCaptor.Reset()
runtimeLogger.SetOutput(os.Stdout)
}
grepInitErrorFromLogs := func() (string, error) {
errorMarker := []byte("INIT_COMPONENT_FAILURE")
scanner := bufio.NewScanner(logCaptor)
for scanner.Scan() {
if err := scanner.Err(); err != nil {
return "", err
}
if bytes.Contains(scanner.Bytes(), errorMarker) {
return scanner.Text(), nil
}
}
return "", scanner.Err()
}
// Wraps our InitErrorChecker with cleanup and error-grepping logic so we only care about the
// log error
return func(ctx flow.Context) error {
defer cleanup()
errorLine, err := grepInitErrorFromLogs()
if err != nil {
return err
}
ctx.Logf("captured errorLine: %s", errorLine)
return checker(ctx, errorLine)
}
}
func AssertNoInitializationErrorsForComponent(componentName string) flow.Runnable {
checker := func(ctx flow.Context, errorLine string) error {
componentFailedToInitialize := strings.Contains(errorLine, componentName)
assert.False(ctx.T, componentFailedToInitialize,
"Found component name mentioned in an component initialization error message: %s", errorLine)
return nil
}
return CaptureLogsAndCheckInitErrors(checker)
}
func AssertInitializationFailedWithErrorsForComponent(componentName string, additionalSubStringsToMatch ...string) flow.Runnable {
checker := func(ctx flow.Context, errorLine string) error {
assert.NotEmpty(ctx.T, errorLine, "Expected a component initialization error message but none found")
assert.Contains(ctx.T, errorLine, componentName,
"Expected to find component '%s' mentioned in error message but found none: %s", componentName, errorLine)
for _, subString := range additionalSubStringsToMatch {
assert.Contains(ctx.T, errorLine, subString,
"Expected to find '%s' mentioned in error message but found none: %s", componentName, errorLine)
}
return nil
}
return CaptureLogsAndCheckInitErrors(checker)
}

View File

@ -0,0 +1,53 @@
TARGETS = certificates/key.pem certificates/cert.pem caPem/hashicorp-vault.yml certificates/incorrect-ca-key.pem certificates/incorrect-ca-cert.pem
all: $(TARGETS)
# Create cert and key lasting 10 years, no password, no prompt for
# subject details. Also set subjectAltName so we avoid the
# "x509: certificate relies on legacy Common Name field" errors
certificates/key.pem certificates/cert.pem:
set -e; \
mkdir -v -p certificates; \
openssl req -x509 -newkey rsa:4096 \
-keyout certificates/key.pem \
-out certificates/cert.pem \
-sha256 -days 3650 \
-nodes \
-addext "subjectAltName = DNS:hashicorp_vault,DNS:localhost,IP:127.0.0.1" \
-subj "/C=CA/ST=BC/L=Vancouver/O=Dapr Testing/OU=Org/CN=www.dapr.io"; \
chmod -v 644 certificates/key.pem certificates/cert.pem
# We use this for negative tests that ensure we reject connecting to
# a server using a distinct Certificate Authority -- despite the server certificate
# having all the right identifiers
certificates/incorrect-ca-key.pem certificates/incorrect-ca-cert.pem:
set -e; \
mkdir -v -p certificates; \
openssl req -x509 -newkey rsa:4096 \
-keyout certificates/incorrect-ca-key.pem \
-out certificates/incorrect-ca-cert.pem \
-sha256 -days 3650 \
-nodes \
-addext "subjectAltName = DNS:hashicorp_vault,DNS:localhost,IP:127.0.0.1" \
-subj "/C=CA/ST=BC/L=Vancouver/O=Dapr Testing/OU=Org/CN=www.dapr.io" ; \
chmod -v 644 certificates/incorrect-ca-key.pem certificates/incorrect-ca-cert.pem
caPem/hashicorp-vault.yml: caPem/hashicorp-vault.yml.template certificates/cert.pem
set -e; \
echo "#\n# THIS FILE IS AUTO-GENERATED - DO NOT EDIT\n#\n\n" > $@.tmp; \
cat caPem/hashicorp-vault.yml.template >> $@.tmp;\
sed 's/^/ /' certificates/cert.pem >> $@.tmp; \
mv -f $@.tmp $@
# %: .tmp.%
# mv $< $@
clean:
rm -f -v $(TARGETS)
rmdir certificates
.PHONY: clean
.PHONY: all

View File

@ -0,0 +1,27 @@
# Certificate-related tests
These tests are particularly tricky to setup- so a little README in case you decide to change
this in the future and things break.
# vault, `-dev-tls` and its default port
To make our testing easier we start vault with `-dev-tls`. We do this:
* to keep the development behavior on,
* to force vault to start with a default TLS listener with its own self-signed TLS cert. We will
use this listener for our negative tests (for `skipValidation` and `tlsServerName`).
To keep the rest of the test setup consistent and similar to other tests, we move this listener to a non-default port.
# Using and generating our very own certificate and key
Besides `-dev-tls`, we also instruct vault to use a configuration that defines another listener using `-config /vault/config/vault_server.hcl`. This listener, defined in the `config/vault_server.hcl` is configured use a certificate-key pair we generated ourselves. It also binds this listener to the default vault port - to make the keep some sort of consistency in the test setup.
We use this certificate we generated to assist with the validation of `caPem`, `caCert`, `caPath`, `skipValidate` and `tlsServerName` flags. All of these refer to the same certificate. Testing `caPem` is a bit special in that it needs the certificate inlined in the component YAML file.
A Makefile is included here in order to document and to ease re-generation of the certificate and keys. It will also re-generate the `caPem`-dependent component YAML, so one does not have to remember updating it whenever the certificate is updated or regenerated.
As a matter of fact, our code does not ship with any of these certificates. Instead, this Makefile is invoked at the begging on `TestCaFamilyOfFields` test.
# Misc. references
For how to configure the vault docker image we are using check https://hub.docker.com/_/vault/

View File

@ -0,0 +1,46 @@
version: '3.9'
# Use a YAML reference to define VAULT_TOKEN and DOCKER_IMAGE only once
x-common-values:
# This should match tests/config/secrestore/hashicorp/vault/hashicorp-vault.yaml
# This should match .github/infrastructure/conformance/hashicorp/vault_token_file.txt
vault_token: &VAULT_TOKEN "vault-dev-root-token-id"
# Reuse the same docker image to save on resources and because the base vault image
# has everything we need for seeding the initial key values too.
vault_docker_image: &VAULT_DOCKER_IMAGE vault:1.12.1
services:
hashicorp_vault:
image: *VAULT_DOCKER_IMAGE
ports:
- '8200:8200'
cap_add:
- IPC_LOCK
environment:
# Move vault's dev-mode self-signed TLS listener to another port so we can use the default one for
# our own listener with our own self-signed certificate.
VAULT_DEV_LISTEN_ADDRESS: "0.0.0.0:7200"
VAULT_DEV_ROOT_TOKEN_ID: *VAULT_TOKEN
volumes:
- ../vaultConfig:/vault/config/:ro
- ../certificates:/certificates:ro
# Force vault to use TLS/HTTPS in dev mode
entrypoint: vault server -dev-tls -config /vault/config/vault_server.hcl
# We define a aux. service to seed the expected conformance secrets to vault
seed_conformance_secrets:
image: *VAULT_DOCKER_IMAGE
depends_on:
- hashicorp_vault
environment:
VAULT_TOKEN : *VAULT_TOKEN
# We are using HTTPS
VAULT_ADDR: https://hashicorp_vault:8200/
# Force the server to use our own certificate
VAULT_SKIP_VERIFY: 'false'
VAULT_CACERT: /certificates/cert.pem
volumes:
- ../../../../../../../../.github/infrastructure/conformance/hashicorp:/setup:ro
- ../certificates:/certificates:ro
entrypoint: /setup/setup-hashicorp-vault-secrets.sh

View File

@ -0,0 +1,20 @@
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: my-hashicorp-vault-TestCaFamilyOfFields-badCaCert
namespace: default
spec:
type: secretstores.hashicorp.vault
version: v1
metadata:
- name: vaultAddr
value: "https://127.0.0.1:8200"
# Enforce TLS verification because this test is all about this
- name: skipVerify
value: false
- name: vaultToken # Matches docker compose VAULT_DEV_ROOT_TOKEN_ID env. var.
value: "vault-dev-root-token-id"
- name: tlsServerName
value: hashicorp_vault
- name: caCert
value: components/caFamily/certificates/incorrect-ca-cert.pem # <<<<< We should fail authentication

View File

@ -0,0 +1,46 @@
version: '3.9'
# Use a YAML reference to define VAULT_TOKEN and DOCKER_IMAGE only once
x-common-values:
# This should match tests/config/secrestore/hashicorp/vault/hashicorp-vault.yaml
# This should match .github/infrastructure/conformance/hashicorp/vault_token_file.txt
vault_token: &VAULT_TOKEN "vault-dev-root-token-id"
# Reuse the same docker image to save on resources and because the base vault image
# has everything we need for seeding the initial key values too.
vault_docker_image: &VAULT_DOCKER_IMAGE vault:1.12.1
services:
hashicorp_vault:
image: *VAULT_DOCKER_IMAGE
ports:
- '8200:8200'
cap_add:
- IPC_LOCK
environment:
# Move vault's dev-mode self-signed TLS listener to another port so we can use the default one for
# our own listener with our own self-signed certificate.
VAULT_DEV_LISTEN_ADDRESS: "0.0.0.0:7200"
VAULT_DEV_ROOT_TOKEN_ID: *VAULT_TOKEN
volumes:
- ../vaultConfig:/vault/config/:ro
- ../certificates:/certificates:ro
# Force vault to use TLS/HTTPS in dev mode
entrypoint: vault server -dev-tls -config /vault/config/vault_server.hcl
# We define a aux. service to seed the expected conformance secrets to vault
seed_conformance_secrets:
image: *VAULT_DOCKER_IMAGE
depends_on:
- hashicorp_vault
environment:
VAULT_TOKEN : *VAULT_TOKEN
# We are using HTTPS
VAULT_ADDR: https://hashicorp_vault:8200/
# Force the server to use our own certificate
VAULT_SKIP_VERIFY: 'false'
VAULT_CACERT: /certificates/cert.pem
volumes:
- ../../../../../../../../.github/infrastructure/conformance/hashicorp:/setup:ro
- ../certificates:/certificates:ro
entrypoint: /setup/setup-hashicorp-vault-secrets.sh

View File

@ -0,0 +1,20 @@
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: my-hashicorp-vault-TestCaFamilyOfFields-badCaCertAndSkipVerify
namespace: default
spec:
type: secretstores.hashicorp.vault
version: v1
metadata:
- name: vaultAddr
value: "https://127.0.0.1:8200"
# Enforce TLS verification because this test is all about this
- name: skipVerify
value: true # <<< flag under test
- name: vaultToken # Matches docker compose VAULT_DEV_ROOT_TOKEN_ID env. var.
value: "vault-dev-root-token-id"
- name: tlsServerName
value: hashicorp_vault
- name: caCert
value: components/caFamily/certificates/incorrect-ca-cert.pem # <<<<< We would fail authentication if it wasn't for skipVerify

View File

@ -0,0 +1,46 @@
version: '3.9'
# Use a YAML reference to define VAULT_TOKEN and DOCKER_IMAGE only once
x-common-values:
# This should match tests/config/secrestore/hashicorp/vault/hashicorp-vault.yaml
# This should match .github/infrastructure/conformance/hashicorp/vault_token_file.txt
vault_token: &VAULT_TOKEN "vault-dev-root-token-id"
# Reuse the same docker image to save on resources and because the base vault image
# has everything we need for seeding the initial key values too.
vault_docker_image: &VAULT_DOCKER_IMAGE vault:1.12.1
services:
hashicorp_vault:
image: *VAULT_DOCKER_IMAGE
ports:
- '8200:8200'
cap_add:
- IPC_LOCK
environment:
# Move vault's dev-mode self-signed TLS listener to another port so we can use the default one for
# our own listener with our own self-signed certificate.
VAULT_DEV_LISTEN_ADDRESS: "0.0.0.0:7200"
VAULT_DEV_ROOT_TOKEN_ID: *VAULT_TOKEN
volumes:
- ../vaultConfig:/vault/config/:ro
- ../certificates:/certificates:ro
# Force vault to use TLS/HTTPS in dev mode
entrypoint: vault server -dev-tls -config /vault/config/vault_server.hcl
# We define a aux. service to seed the expected conformance secrets to vault
seed_conformance_secrets:
image: *VAULT_DOCKER_IMAGE
depends_on:
- hashicorp_vault
environment:
VAULT_TOKEN : *VAULT_TOKEN
# We are using HTTPS
VAULT_ADDR: https://hashicorp_vault:8200/
# Force the server to use our own certificate
VAULT_SKIP_VERIFY: 'false'
VAULT_CACERT: /certificates/cert.pem
volumes:
- ../../../../../../../../.github/infrastructure/conformance/hashicorp:/setup:ro
- ../certificates:/certificates:ro
entrypoint: /setup/setup-hashicorp-vault-secrets.sh

View File

@ -0,0 +1,20 @@
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: my-hashicorp-vault-TestCaFamilyOfFields-badTlsServerName
namespace: default
spec:
type: secretstores.hashicorp.vault
version: v1
metadata:
- name: vaultAddr
value: "https://127.0.0.1:8200"
# Enforce TLS verification because this test is all about this
- name: skipVerify
value: false
- name: vaultToken # Matches docker compose VAULT_DEV_ROOT_TOKEN_ID env. var.
value: "vault-dev-root-token-id"
- name: tlsServerName
value: badTlsServerName # <<<<< Ooops, this won't match our cert.
- name: caCert
value: components/caFamily/certificates/cert.pem

View File

@ -0,0 +1,46 @@
version: '3.9'
# Use a YAML reference to define VAULT_TOKEN and DOCKER_IMAGE only once
x-common-values:
# This should match tests/config/secrestore/hashicorp/vault/hashicorp-vault.yaml
# This should match .github/infrastructure/conformance/hashicorp/vault_token_file.txt
vault_token: &VAULT_TOKEN "vault-dev-root-token-id"
# Reuse the same docker image to save on resources and because the base vault image
# has everything we need for seeding the initial key values too.
vault_docker_image: &VAULT_DOCKER_IMAGE vault:1.12.1
services:
hashicorp_vault:
image: *VAULT_DOCKER_IMAGE
ports:
- '8200:8200'
cap_add:
- IPC_LOCK
environment:
# Move vault's dev-mode self-signed TLS listener to another port so we can use the default one for
# our own listener with our own self-signed certificate.
VAULT_DEV_LISTEN_ADDRESS: "0.0.0.0:7200"
VAULT_DEV_ROOT_TOKEN_ID: *VAULT_TOKEN
volumes:
- ../vaultConfig:/vault/config/:ro
- ../certificates:/certificates:ro
# Force vault to use TLS/HTTPS in dev mode
entrypoint: vault server -dev-tls -config /vault/config/vault_server.hcl
# We define a aux. service to seed the expected conformance secrets to vault
seed_conformance_secrets:
image: *VAULT_DOCKER_IMAGE
depends_on:
- hashicorp_vault
environment:
VAULT_TOKEN : *VAULT_TOKEN
# We are using HTTPS
VAULT_ADDR: https://hashicorp_vault:8200/
# Force the server to use our own certificate
VAULT_SKIP_VERIFY: 'false'
VAULT_CACERT: /certificates/cert.pem
volumes:
- ../../../../../../../../.github/infrastructure/conformance/hashicorp:/setup:ro
- ../certificates:/certificates:ro
entrypoint: /setup/setup-hashicorp-vault-secrets.sh

View File

@ -0,0 +1,20 @@
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: my-hashicorp-vault-TestCaFamilyOfFields-caCert
namespace: default
spec:
type: secretstores.hashicorp.vault
version: v1
metadata:
- name: vaultAddr
value: "https://127.0.0.1:8200"
# Enforce TLS verification because this test is all about this
- name: skipVerify
value: false
- name: vaultToken # Matches docker compose VAULT_DEV_ROOT_TOKEN_ID env. var.
value: "vault-dev-root-token-id"
- name: tlsServerName
value: hashicorp_vault
- name: caCert
value: components/caFamily/certificates/cert.pem

View File

@ -0,0 +1,46 @@
version: '3.9'
# Use a YAML reference to define VAULT_TOKEN and DOCKER_IMAGE only once
x-common-values:
# This should match tests/config/secrestore/hashicorp/vault/hashicorp-vault.yaml
# This should match .github/infrastructure/conformance/hashicorp/vault_token_file.txt
vault_token: &VAULT_TOKEN "vault-dev-root-token-id"
# Reuse the same docker image to save on resources and because the base vault image
# has everything we need for seeding the initial key values too.
vault_docker_image: &VAULT_DOCKER_IMAGE vault:1.12.1
services:
hashicorp_vault:
image: *VAULT_DOCKER_IMAGE
ports:
- '8200:8200'
cap_add:
- IPC_LOCK
environment:
# Move vault's dev-mode self-signed TLS listener to another port so we can use the default one for
# our own listener with our own self-signed certificate.
VAULT_DEV_LISTEN_ADDRESS: "0.0.0.0:7200"
VAULT_DEV_ROOT_TOKEN_ID: *VAULT_TOKEN
volumes:
- ../vaultConfig:/vault/config/:ro
- ../certificates:/certificates:ro
# Force vault to use TLS/HTTPS in dev mode
entrypoint: vault server -dev-tls -config /vault/config/vault_server.hcl
# We define a aux. service to seed the expected conformance secrets to vault
seed_conformance_secrets:
image: *VAULT_DOCKER_IMAGE
depends_on:
- hashicorp_vault
environment:
VAULT_TOKEN : *VAULT_TOKEN
# We are using HTTPS
VAULT_ADDR: https://hashicorp_vault:8200/
# Force the server to use our own certificate
VAULT_SKIP_VERIFY: 'false'
VAULT_CACERT: /certificates/cert.pem
volumes:
- ../../../../../../../../.github/infrastructure/conformance/hashicorp:/setup:ro
- ../certificates:/certificates:ro
entrypoint: /setup/setup-hashicorp-vault-secrets.sh

View File

@ -0,0 +1,20 @@
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: my-hashicorp-vault-TestCaFamilyOfFields-caPath
namespace: default
spec:
type: secretstores.hashicorp.vault
version: v1
metadata:
- name: vaultAddr
value: "https://127.0.0.1:8200"
# Enforce TLS verification because this test is all about this
- name: skipVerify
value: false
- name: vaultToken # Matches docker compose VAULT_DEV_ROOT_TOKEN_ID env. var.
value: "vault-dev-root-token-id"
- name: tlsServerName
value: hashicorp_vault
- name: caPath
value: components/caFamily/certificates/

View File

@ -0,0 +1,46 @@
version: '3.9'
# Use a YAML reference to define VAULT_TOKEN and DOCKER_IMAGE only once
x-common-values:
# This should match tests/config/secrestore/hashicorp/vault/hashicorp-vault.yaml
# This should match .github/infrastructure/conformance/hashicorp/vault_token_file.txt
vault_token: &VAULT_TOKEN "vault-dev-root-token-id"
# Reuse the same docker image to save on resources and because the base vault image
# has everything we need for seeding the initial key values too.
vault_docker_image: &VAULT_DOCKER_IMAGE vault:1.12.1
services:
hashicorp_vault:
image: *VAULT_DOCKER_IMAGE
ports:
- '8200:8200'
cap_add:
- IPC_LOCK
environment:
# Move vault's dev-mode self-signed TLS listener to another port so we can use the default one for
# our own listener with our own self-signed certificate.
VAULT_DEV_LISTEN_ADDRESS: "0.0.0.0:7200"
VAULT_DEV_ROOT_TOKEN_ID: *VAULT_TOKEN
volumes:
- ../vaultConfig:/vault/config/:ro
- ../certificates:/certificates:ro
# Force vault to use TLS/HTTPS in dev mode
entrypoint: vault server -dev-tls -config /vault/config/vault_server.hcl
# We define a aux. service to seed the expected conformance secrets to vault
seed_conformance_secrets:
image: *VAULT_DOCKER_IMAGE
depends_on:
- hashicorp_vault
environment:
VAULT_TOKEN : *VAULT_TOKEN
# We are using HTTPS
VAULT_ADDR: https://hashicorp_vault:8200/
# Force the server to use our own certificate
VAULT_SKIP_VERIFY: 'false'
VAULT_CACERT: /certificates/cert.pem
volumes:
- ../../../../../../../../.github/infrastructure/conformance/hashicorp:/setup:ro
- ../certificates:/certificates:ro
entrypoint: /setup/setup-hashicorp-vault-secrets.sh

View File

@ -0,0 +1,20 @@
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: my-hashicorp-vault-TestCaFamilyOfFields-caPem
namespace: default
spec:
type: secretstores.hashicorp.vault
version: v1
metadata:
- name: vaultAddr
value: "https://127.0.0.1:8200"
# Enforce TLS verification because this test is all about this
- name: skipVerify
value: false
- name: vaultToken # Matches docker compose VAULT_DEV_ROOT_TOKEN_ID env. var.
value: "vault-dev-root-token-id"
- name: tlsServerName
value: hashicorp_vault
- name: caPem
value: |-

View File

@ -0,0 +1,6 @@
listener "tcp" {
address = "0.0.0.0:8200"
tls_disable = "false"
tls_cert_file = "/certificates/cert.pem"
tls_key_file = "/certificates/key.pem"
}

View File

@ -0,0 +1,35 @@
version: '3.9'
# Use a YAML reference to define VAULT_TOKEN and DOCKER_IMAGE only once
x-common-values:
# This should match tests/config/secrestore/hashicorp/vault/hashicorp-vault.yaml
# This should match .github/infrastructure/conformance/hashicorp/vault_token_file.txt
vault_token: &VAULT_TOKEN "vault-dev-root-token-id"
# Reuse the same docker image to save on resources and because the base vault image
# has everything we need for seeding the initial key values too.
vault_docker_image: &VAULT_DOCKER_IMAGE vault:1.12.1
services:
hashicorp_vault:
image: *VAULT_DOCKER_IMAGE
ports:
- '8200:8200'
cap_add:
- IPC_LOCK
environment:
VAULT_DEV_LISTEN_ADDRESS: "0.0.0.0:8200"
VAULT_DEV_ROOT_TOKEN_ID: *VAULT_TOKEN
# We define a aux. service to seed the expected conformance secrets to vault
seed_conformance_secrets:
image: *VAULT_DOCKER_IMAGE
depends_on:
- hashicorp_vault
environment:
VAULT_TOKEN : *VAULT_TOKEN
VAULT_ADDR: http://hashicorp_vault:8200/
volumes:
- .:/setup:ro
entrypoint: /setup/setup-hashicorp-vault-secrets.sh # <<< Use our custom secret seeder for the enginePath/customSecretsPath

View File

@ -0,0 +1,15 @@
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: my-hashicorp-vault-TestEnginePath-customSecretsPath
namespace: default
spec:
type: secretstores.hashicorp.vault
version: v1
metadata:
- name: vaultAddr
value: "http://127.0.0.1:8200"
- name: vaultToken # Matches docker compose VAULT_DEV_ROOT_TOKEN_ID env. var.
value: "vault-dev-root-token-id"
- name: enginePath
value: customSecretsPath

View File

@ -0,0 +1,31 @@
#!/bin/sh
# Notice that while hashicorp supports multiple keys in a secret,
# our confirmance tests needs to go for the common demominator
# which is a secret store that only has name/value semantic.
# Hence we setup secret containing a single key with the their
# same name.
set -eu
MAX_ATTEMPTS=30
for attempt in `seq $MAX_ATTEMPTS`; do
# Test connectivity to vault server and create secrets to match
# conformance tests / contents from tests/conformance/secrets.json
if vault status &&
vault secrets enable -path=customSecretsPath kv-v2 && # Enable this path with kv/version2 engine
vault kv put customSecretsPath/dapr/secretUnderCustomPath the=trick was=the path=parameter &&
vault kv get customSecretsPath/dapr/secretUnderCustomPath ;
then
echo ✅ secrets set;
sleep 1;
exit 0;
else
echo "⏰ vault not available, waiting... - attempt $attempt of $MAX_ATTEMPTS";
sleep 1;
fi
done;
echo ❌ Failed to set secrets;
exit 1

View File

@ -0,0 +1,15 @@
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: my-hashicorp-vault-TestEnginePath-secret
namespace: default
spec:
type: secretstores.hashicorp.vault
version: v1
metadata:
- name: vaultAddr
value: "http://127.0.0.1:8200"
- name: vaultToken # Matches docker compose VAULT_DEV_ROOT_TOKEN_ID env. var.
value: "vault-dev-root-token-id"
- name: enginePath
value: secret

View File

@ -0,0 +1,38 @@
version: '3.9'
# Use a YAML reference to define VAULT_TOKEN and DOCKER_IMAGE only once
x-common-values:
# This should match tests/config/secrestore/hashicorp/vault/hashicorp-vault.yaml
# This should match .github/infrastructure/conformance/hashicorp/vault_token_file.txt
vault_token: &VAULT_TOKEN "vault-dev-root-token-id"
# Reuse the same docker image to save on resources and because the base vault image
# has everything we need for seeding the initial key values too.
vault_docker_image: &VAULT_DOCKER_IMAGE vault:1.12.1
services:
hashicorp_vault:
image: *VAULT_DOCKER_IMAGE
ports:
- '8200:8200'
cap_add:
- IPC_LOCK
environment:
VAULT_DEV_LISTEN_ADDRESS: "0.0.0.0:8200"
VAULT_DEV_ROOT_TOKEN_ID: *VAULT_TOKEN
# Force vault to use TLS/HTTPS in dev mode
entrypoint: vault server -dev-tls=true
# We define a aux. service to seed the expected conformance secrets to vault
seed_conformance_secrets:
image: *VAULT_DOCKER_IMAGE
depends_on:
- hashicorp_vault
environment:
VAULT_TOKEN : *VAULT_TOKEN
# We are using HTTPS
VAULT_ADDR: https://hashicorp_vault:8200/
VAULT_SKIP_VERIFY: 'true'
volumes:
- ../../../../../../../../.github/infrastructure/conformance/hashicorp:/setup:ro
entrypoint: /setup/setup-hashicorp-vault-secrets.sh

View File

@ -0,0 +1,19 @@
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: my-hashicorp-vault-TestVaultAddr-missing
namespace: default
spec:
type: secretstores.hashicorp.vault
version: v1
metadata:
# Yes, we commented out vaultAddr.
# Default value should kick in: https://127.0.0.1:8200. Notice: HTTPS (TLS)
# - name: vaultAddr
# value: "http://127.0.0.1:8200"
# Do not perform TLS verification since e are starting vault in development
# mode with a self-signed certificate
- name: skipVerify
value: true
- name: vaultToken # Matches docker compose VAULT_DEV_ROOT_TOKEN_ID env. var.
value: "vault-dev-root-token-id"

View File

@ -0,0 +1,38 @@
version: '3.9'
# Use a YAML reference to define VAULT_TOKEN and DOCKER_IMAGE only once
x-common-values:
# This should match tests/config/secrestore/hashicorp/vault/hashicorp-vault.yaml
# This should match .github/infrastructure/conformance/hashicorp/vault_token_file.txt
vault_token: &VAULT_TOKEN "vault-dev-root-token-id"
# Reuse the same docker image to save on resources and because the base vault image
# has everything we need for seeding the initial key values too.
vault_docker_image: &VAULT_DOCKER_IMAGE vault:1.12.1
services:
hashicorp_vault:
image: *VAULT_DOCKER_IMAGE
ports:
- '8200:8200'
cap_add:
- IPC_LOCK
environment:
VAULT_DEV_LISTEN_ADDRESS: "0.0.0.0:8200"
VAULT_DEV_ROOT_TOKEN_ID: *VAULT_TOKEN
# Force vault to use TLS/HTTPS in dev mode
entrypoint: vault server -dev-tls=true
# We define a aux. service to seed the expected conformance secrets to vault
seed_conformance_secrets:
image: *VAULT_DOCKER_IMAGE
depends_on:
- hashicorp_vault
environment:
VAULT_TOKEN : *VAULT_TOKEN
# We are using HTTPS
VAULT_ADDR: https://hashicorp_vault:8200/
VAULT_SKIP_VERIFY: 'true'
volumes:
- ../../../../../../../../.github/infrastructure/conformance/hashicorp:/setup:ro
entrypoint: /setup/setup-hashicorp-vault-secrets.sh

View File

@ -0,0 +1,19 @@
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: my-hashicorp-vault-TestVaultAddr-missingSkipVerifyFalse
namespace: default
spec:
type: secretstores.hashicorp.vault
version: v1
metadata:
# Yes, we commented out vaultAddr.
# Default value should kick in: https://127.0.0.1:8200. Notice: HTTPS (TLS)
# - name: vaultAddr
# value: "http://127.0.0.1:8200"
# Do not perform TLS verification since e are starting vault in development
# mode with a self-signed certificate
- name: skipVerify
value: false
- name: vaultToken # Matches docker compose VAULT_DEV_ROOT_TOKEN_ID env. var.
value: "vault-dev-root-token-id"

View File

@ -0,0 +1,36 @@
version: '3.9'
# Use a YAML reference to define VAULT_TOKEN and DOCKER_IMAGE only once
x-common-values:
# This should match tests/config/secrestore/hashicorp/vault/hashicorp-vault.yaml
# This should match .github/infrastructure/conformance/hashicorp/vault_token_file.txt
vault_token: &VAULT_TOKEN "vault-dev-root-token-id"
# Reuse the same docker image to save on resources and because the base vault image
# has everything we need for seeding the initial key values too.
vault_docker_image: &VAULT_DOCKER_IMAGE vault:1.12.1
services:
hashicorp_vault:
image: *VAULT_DOCKER_IMAGE
ports:
- '11200:11200'
cap_add:
- IPC_LOCK
environment:
VAULT_DEV_LISTEN_ADDRESS: "0.0.0.0:11200"
VAULT_DEV_ROOT_TOKEN_ID: *VAULT_TOKEN
# We define a aux. service to seed the expected conformance secrets to vault
seed_conformance_secrets:
image: *VAULT_DOCKER_IMAGE
depends_on:
- hashicorp_vault
environment:
VAULT_TOKEN : *VAULT_TOKEN
# We are using HTTPS
VAULT_ADDR: http://hashicorp_vault:11200/
VAULT_SKIP_VERIFY: 'true'
volumes:
- ../../../../../../../../.github/infrastructure/conformance/hashicorp:/setup:ro
entrypoint: /setup/setup-hashicorp-vault-secrets.sh

View File

@ -0,0 +1,14 @@
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: my-hashicorp-vault-TestVaultAddr-nonStdPort
namespace: default
spec:
type: secretstores.hashicorp.vault
version: v1
metadata:
# Use non-standard port
- name: vaultAddr
value: "http://127.0.0.1:11200"
- name: vaultToken # Matches docker compose VAULT_DEV_ROOT_TOKEN_ID env. var.
value: "vault-dev-root-token-id"

View File

@ -0,0 +1,13 @@
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: my-hashicorp-vault-TestVaultAddr-wrongAddress
namespace: default
spec:
type: secretstores.hashicorp.vault
version: v1
metadata:
- name: vaultAddr
value: "http://127.0.0.1:28234" # yeah.. let's hope no one starts a Vault here
- name: vaultToken # Matches docker compose VAULT_DEV_ROOT_TOKEN_ID env. var.
value: "vault-dev-root-token-id"

View File

@ -0,0 +1,15 @@
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: my-hashicorp-vault
namespace: default
spec:
type: secretstores.hashicorp.vault
version: v1
metadata:
- name: vaultAddr
value: "http://127.0.0.1:8200"
- name: vaultToken # Matches docker compose VAULT_DEV_ROOT_TOKEN_ID env. var.
value: "vault-dev-root-token-id"
- name: vaultKVPrefix
value: alternativePrefix

View File

@ -0,0 +1,15 @@
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: my-hashicorp-vault
namespace: default
spec:
type: secretstores.hashicorp.vault
version: v1
metadata:
- name: vaultAddr
value: "http://127.0.0.1:8200"
- name: vaultToken # Matches docker compose VAULT_DEV_ROOT_TOKEN_ID env. var.
value: "vault-dev-root-token-id"
- name: vaultKVUsePrefix
value: false

View File

@ -0,0 +1,14 @@
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: my-hashicorp-vault-TestTokenAndTokenMountPath-badVaultToken
namespace: default
spec:
type: secretstores.hashicorp.vault
version: v1
ignoreErrors: true # This component will fail to load but we don't want Dapr to FATAL because of it.
metadata:
- name: vaultAddr
value: "http://127.0.0.1:8200"
- name: vaultToken
value: "this-is-not-the-correct-vault-token-to-talk-to-our-server"

View File

@ -0,0 +1,16 @@
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: my-hashicorp-vault-TestTokenAndTokenMountPath-both
namespace: default
spec:
type: secretstores.hashicorp.vault
version: v1
ignoreErrors: true # This component will fail to load but we don't want Dapr to FATAL because of it.
metadata:
- name: vaultAddr
value: "http://127.0.0.1:8200"
- name: vaultToken
value: "vault-dev-root-token-id"
- name: vaultTokenMountPath
value: /tmp/vaultToken.txt

View File

@ -0,0 +1,13 @@
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: my-hashicorp-vault-TestTokenAndTokenMountPath-neither
namespace: default
spec:
type: secretstores.hashicorp.vault
version: v1
ignoreErrors: true # This component will fail to load but we don't want Dapr to FATAL because of it.
metadata:
- name: vaultAddr
value: "http://127.0.0.1:8200"
# no vaultToken or vaultTokenMountPath

View File

@ -0,0 +1,15 @@
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: my-hashicorp-vault-TestTokenAndTokenMountPath-tokenMountPathHappyCase
namespace: default
spec:
type: secretstores.hashicorp.vault
version: v1
ignoreErrors: true # This component will fail to load but we don't want Dapr to FATAL because of it.
metadata:
- name: vaultAddr
value: "http://127.0.0.1:8200"
- name: vaultTokenMountPath
# This is a long path but this file is in current directory ;)
value: components/vaultTokenAndTokenMountPath/tokenMountPathHappyCase/vault_token_file.txt

View File

@ -0,0 +1,14 @@
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: my-hashicorp-vault-TestTokenAndTokenMountPath-tokenMountPathPointsToBrokenPath
namespace: default
spec:
type: secretstores.hashicorp.vault
version: v1
ignoreErrors: true # This component will fail to load but we don't want Dapr to FATAL because of it.
metadata:
- name: vaultAddr
value: "http://127.0.0.1:8200"
- name: vaultTokenMountPath
value: /this/path/does/not/exist/vaultToken.txt

View File

@ -0,0 +1,15 @@
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: my-hashicorp-vault
namespace: default
spec:
type: secretstores.hashicorp.vault
version: v1
metadata:
- name: vaultAddr
value: "http://127.0.0.1:8200"
- name: vaultToken # Matches docker compose VAULT_DEV_ROOT_TOKEN_ID env. var.
value: "vault-dev-root-token-id"
- name: vaultValueType
value: text # Turns Vault into a secret store with name/value semantics.

Some files were not shown because too many files have changed in this diff Show More