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 &&
vault kv put secret/dapr/conftestsecret conftestsecret=abcd &&
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;
then
echo ✅ secrets set;

View File

@ -1,8 +1,9 @@
version: '3.9'
# 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 .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.

View File

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

View File

@ -20,18 +20,18 @@ import (
"errors"
"fmt"
"io"
"net/url"
"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/dapr/components-contrib/bindings"
azauth "github.com/dapr/components-contrib/internal/authentication/azure"
mdutils "github.com/dapr/components-contrib/metadata"
storageinternal "github.com/dapr/components-contrib/internal/component/azure/blobstorage"
"github.com/dapr/kit/logger"
"github.com/dapr/kit/ptr"
)
const (
@ -49,41 +49,23 @@ const (
// Defines the delete snapshots option for the delete operation.
// See: https://docs.microsoft.com/en-us/rest/api/storageservices/delete-blob#request-headers
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
// 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
maxResults = 5000
maxResults int32 = 5000
endpointKey = "endpoint"
)
var ErrMissingBlobName = errors.New("blobName is a required attribute")
// AzureBlobStorage allows saving blobs to an Azure Blob Storage account.
type AzureBlobStorage struct {
metadata *blobStorageMetadata
containerURL azblob.ContainerURL
metadata *storageinternal.BlobStorageMetadata
containerClient *container.Client
logger logger.Logger
}
type blobStorageMetadata struct {
AccountName string
Container string
GetBlobRetryCount int
DecodeBase64 bool
PublicAccessLevel azblob.PublicAccessType
}
type createResponse struct {
BlobURL string `json:"blobURL"`
BlobName string `json:"blobName"`
@ -111,90 +93,14 @@ func NewAzureBlobStorage(logger logger.Logger) bindings.OutputBinding {
// Init performs metadata parsing.
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 {
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
}
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 {
return []bindings.OperationKind{
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) {
var blobHTTPHeaders azblob.BlobHTTPHeaders
var blobURL azblob.BlockBlobURL
var blobName string
if val, ok := req.Metadata[metadataKeyBlobName]; ok && val != "" {
blobName = val
delete(req.Metadata, metadataKeyBlobName)
} else {
blobName = uuid.New().String()
}
blobURL = a.getBlobURL(blobName)
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")
id, err := uuid.NewRandom()
if err != nil {
return nil, err
}
blobHTTPHeaders.ContentMD5 = sDec
delete(req.Metadata, metadataKeyContentMD5)
blobName = id.String()
}
if val, ok := req.Metadata[metadataKeyContentEncoding]; ok && val != "" {
blobHTTPHeaders.ContentEncoding = val
delete(req.Metadata, metadataKeyContentEncoding)
}
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)
blobHTTPHeaders, err := storageinternal.CreateBlobHTTPHeadersFromRequest(req.Metadata, nil, a.logger)
if err != nil {
return nil, err
}
d, err := strconv.Unquote(string(req.Data))
@ -258,17 +141,21 @@ func (a *AzureBlobStorage) create(ctx context.Context, req *bindings.InvokeReque
req.Data = decoded
}
_, err = azblob.UploadBufferToBlockBlob(ctx, req.Data, blobURL, azblob.UploadToBlockBlobOptions{
Parallelism: 16,
Metadata: a.sanitizeMetadata(req.Metadata),
BlobHTTPHeaders: blobHTTPHeaders,
})
uploadOptions := azblob.UploadBufferOptions{
Metadata: storageinternal.SanitizeMetadata(a.logger, req.Metadata),
HTTPHeaders: &blobHTTPHeaders,
TransactionalContentMD5: &blobHTTPHeaders.BlobContentMD5,
}
blockBlobClient := a.containerClient.NewBlockBlobClient(blobName)
_, err = blockBlobClient.UploadBuffer(ctx, req.Data, &uploadOptions)
if err != nil {
return nil, fmt.Errorf("error uploading az blob: %w", err)
}
resp := createResponse{
BlobURL: blobURL.String(),
BlobURL: blockBlobClient.URL(),
}
b, err := json.Marshal(resp)
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) {
var blobURL azblob.BlockBlobURL
var blockBlobClient *blockblob.Client
if val, ok := req.Metadata[metadataKeyBlobName]; ok && val != "" {
blobURL = a.getBlobURL(val)
blockBlobClient = a.containerClient.NewBlockBlobClient(val)
} else {
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 {
return nil, fmt.Errorf("error downloading az blob: %w", err)
}
bodyStream := resp.Body(azblob.RetryReaderOptions{MaxRetryRequests: a.metadata.GetBlobRetryCount})
data, err := io.ReadAll(bodyStream)
reader := blobDownloadResponse.Body
defer reader.Close()
blobData, err := io.ReadAll(reader)
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
@ -311,45 +201,54 @@ func (a *AzureBlobStorage) get(ctx context.Context, req *bindings.InvokeRequest)
return nil, fmt.Errorf("error parsing metadata: %w", err)
}
getPropertiesOptions := blob.GetPropertiesOptions{
AccessConditions: &blob.AccessConditions{},
}
if fetchMetadata {
props, err := blobURL.GetProperties(ctx, azblob.BlobAccessConditions{})
props, err := blockBlobClient.GetProperties(ctx, &getPropertiesOptions)
if err != nil {
return nil, fmt.Errorf("error reading blob metadata: %w", err)
}
metadata = props.NewMetadata()
metadata = props.Metadata
}
return &bindings.InvokeResponse{
Data: data,
Data: blobData,
Metadata: metadata,
}, nil
}
func (a *AzureBlobStorage) delete(ctx context.Context, req *bindings.InvokeRequest) (*bindings.InvokeResponse, error) {
var blobURL azblob.BlockBlobURL
if val, ok := req.Metadata[metadataKeyBlobName]; ok && val != "" {
blobURL = a.getBlobURL(val)
} else {
var blockBlobClient *blockblob.Client
val, ok := req.Metadata[metadataKeyBlobName]
if !ok || val == "" {
return nil, ErrMissingBlobName
}
deleteSnapshotsOptions := azblob.DeleteSnapshotsOptionNone
if val, ok := req.Metadata[metadataKeyDeleteSnapshots]; ok && val != "" {
deleteSnapshotsOptions = azblob.DeleteSnapshotsOptionType(val)
var deleteSnapshotsOptions blob.DeleteSnapshotsOptionType
if deleteSnapShotOption, ok := req.Metadata[metadataKeyDeleteSnapshots]; ok && val != "" {
deleteSnapshotsOptions = azblob.DeleteSnapshotsOptionType(deleteSnapShotOption)
if !a.isValidDeleteSnapshotsOptionType(deleteSnapshotsOptions) {
return nil, fmt.Errorf("invalid delete snapshot option type: %s; allowed: %s",
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
}
func (a *AzureBlobStorage) list(ctx context.Context, req *bindings.InvokeRequest) (*bindings.InvokeResponse, error) {
options := azblob.ListBlobsSegmentOptions{}
options := container.ListBlobsFlatOptions{}
hasPayload := false
var payload listPayload
@ -360,50 +259,52 @@ func (a *AzureBlobStorage) list(ctx context.Context, req *bindings.InvokeRequest
}
hasPayload = true
}
if hasPayload {
options.Details.Copy = payload.Include.Copy
options.Details.Metadata = payload.Include.Metadata
options.Details.Snapshots = payload.Include.Snapshots
options.Details.UncommittedBlobs = payload.Include.UncommittedBlobs
options.Details.Deleted = payload.Include.Deleted
options.Include.Copy = payload.Include.Copy
options.Include.Metadata = payload.Include.Metadata
options.Include.Snapshots = payload.Include.Snapshots
options.Include.UncommittedBlobs = payload.Include.UncommittedBlobs
options.Include.Deleted = payload.Include.Deleted
}
if hasPayload && payload.MaxResults != int32(0) {
options.MaxResults = payload.MaxResults
if hasPayload && payload.MaxResults > 0 {
options.MaxResults = &payload.MaxResults
} else {
options.MaxResults = maxResults
options.MaxResults = ptr.Of(maxResults) // cannot get address of constant directly
}
if hasPayload && payload.Prefix != "" {
options.Prefix = payload.Prefix
options.Prefix = &payload.Prefix
}
var initialMarker azblob.Marker
var initialMarker string
if hasPayload && payload.Marker != "" {
initialMarker = azblob.Marker{Val: &payload.Marker}
initialMarker = payload.Marker
} else {
initialMarker = azblob.Marker{}
initialMarker = ""
}
options.Marker = &initialMarker
var blobs []azblob.BlobItem
metadata := map[string]string{}
for currentMaker := initialMarker; currentMaker.NotDone(); {
var listBlob *azblob.ListBlobsFlatSegmentResponse
listBlob, err := a.containerURL.ListBlobsFlatSegment(ctx, currentMaker, options)
blobs := []*container.BlobItem{}
pager := a.containerClient.NewListBlobsFlatPager(&options)
for pager.More() {
resp, err := pager.NextPage(ctx)
if err != nil {
return nil, fmt.Errorf("error listing blobs: %w", err)
}
blobs = append(blobs, listBlob.Segment.BlobItems...)
blobs = append(blobs, resp.Segment.BlobItems...)
numBlobs := len(blobs)
currentMaker = listBlob.NextMarker
metadata[metadataKeyMarker] = *currentMaker.Val
metadata[metadataKeyNumber] = strconv.FormatInt(int64(numBlobs), 10)
metadata[metadataKeyMarker] = ""
if resp.Marker != nil {
metadata[metadataKeyMarker] = *resp.Marker
}
if options.MaxResults-maxResults > 0 {
options.MaxResults -= maxResults
if *options.MaxResults-maxResults > 0 {
*options.MaxResults -= maxResults
} else {
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 {
validTypes := azblob.PossibleDeleteSnapshotsOptionTypeValues()
for _, item := range validTypes {
@ -462,41 +346,3 @@ func (a *AzureBlobStorage) isValidDeleteSnapshotsOptionType(accessType azblob.De
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"
"testing"
"github.com/Azure/azure-storage-blob-go/azblob"
"github.com/stretchr/testify/assert"
"github.com/dapr/components-contrib/bindings"
"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) {
blobStorage := NewAzureBlobStorage(logger.NewLogger("test")).(*AzureBlobStorage)

View File

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

View File

@ -18,6 +18,7 @@ import (
"io"
"net/http"
"net/http/httptest"
"strconv"
"strings"
"testing"
@ -45,146 +46,316 @@ func TestOperations(t *testing.T) {
}, opers)
}
func TestInit(t *testing.T) {
var path string
type TestCase struct {
input string
operation string
metadata map[string]string
path string
err string
statusCode int
}
s := httptest.NewServer(
http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
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()
func (tc TestCase) ToInvokeRequest() bindings.InvokeRequest {
requestMetadata := tc.metadata
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{
Properties: map[string]string{
"url": s.URL,
},
}}
if extraProps != nil {
for k, v := range extraProps {
m.Properties[k] = v
}
}
hs := bindingHttp.NewHTTP(logger.NewLogger("test"))
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)
tests := map[string]struct {
input string
operation string
metadata map[string]string
path string
err string
}{
tests := map[string]TestCase{
"get": {
input: "GET",
operation: "get",
metadata: nil,
path: "/",
err: "",
input: "GET",
operation: "get",
metadata: nil,
path: "/",
err: "",
statusCode: 200,
},
"request headers": {
input: "OVERRIDE",
operation: "get",
metadata: map[string]string{"X-Input": "override"},
path: "/",
err: "",
input: "OVERRIDE",
operation: "get",
metadata: map[string]string{"X-Input": "override"},
path: "/",
err: "",
statusCode: 200,
},
"post": {
input: "expected",
operation: "post",
metadata: map[string]string{"path": "/test"},
path: "/test",
err: "",
input: "expected",
operation: "post",
metadata: map[string]string{"path": "/test"},
path: "/test",
err: "",
statusCode: 201,
},
"put": {
input: "expected",
operation: "put",
metadata: map[string]string{"path": "/test"},
path: "/test",
err: "",
input: "expected",
operation: "put",
statusCode: 204,
metadata: map[string]string{"path": "/test"},
path: "/test",
err: "",
},
"patch": {
input: "expected",
operation: "patch",
metadata: map[string]string{"path": "/test"},
path: "/test",
err: "",
input: "expected",
operation: "patch",
metadata: map[string]string{"path": "/test"},
path: "/test",
err: "",
statusCode: 206,
},
"delete": {
input: "DELETE",
operation: "delete",
metadata: nil,
path: "/",
err: "",
input: "DELETE",
operation: "delete",
metadata: nil,
path: "/",
err: "",
statusCode: 200,
},
"options": {
input: "OPTIONS",
operation: "options",
metadata: nil,
path: "/",
err: "",
input: "OPTIONS",
operation: "options",
metadata: nil,
path: "/",
err: "",
statusCode: 200,
},
"trace": {
input: "TRACE",
operation: "trace",
metadata: nil,
path: "/",
err: "",
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: "",
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",
input: "expected",
operation: "POST",
metadata: map[string]string{"path": "/../test"},
path: "",
err: "invalid path: /../test",
statusCode: 400,
},
"invalid operation": {
input: "notvalid",
operation: "notvalid",
metadata: map[string]string{"path": "/test"},
path: "/test",
err: "invalid operation: notvalid",
input: "notvalid",
operation: "notvalid",
metadata: map[string]string{"path": "/test"},
path: "/test",
err: "invalid operation: notvalid",
statusCode: 400,
},
"internal server error": {
input: "internal server error",
operation: "post",
metadata: map[string]string{"path": "/"},
path: "/",
err: "received status code 500",
input: "internal server error",
operation: "post",
metadata: map[string]string{"path": "/"},
path: "/",
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 {
t.Run(name, func(t *testing.T) {
response, err := hs.Invoke(context.TODO(), &bindings.InvokeRequest{
Data: []byte(tc.input),
Metadata: tc.metadata,
Operation: bindings.OperationKind(tc.operation),
})
req := tc.ToInvokeRequest()
response, err := hs.Invoke(context.TODO(), &req)
if tc.err == "" {
require.NoError(t, err)
assert.Equal(t, tc.path, path)
assert.Equal(t, strings.ToUpper(tc.input), string(response.Data))
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"])
} 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"])
} else {
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/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/storage/azblob v0.5.1
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/go-amqp v0.17.5
@ -133,7 +134,7 @@ require (
github.com/99designs/keyring v1.2.1 // indirect
github.com/AthenZ/athenz v1.10.39 // 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/go-autorest v14.2.0+incompatible // 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/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 v1.0.0 h1:jp0dGvZ7ZK0mgqnTSClMxa5xuRL7NZgHameVYF6BurY=
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 h1:XUNQ4mw+zJmaA2KXzP9JlQiecy1SI+Eog7xVkPiqIbg=
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/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/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/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.10.0 h1:evCwGreYo3XLeBV4vSxLbLiYb6e0SzsJiXQVRGsRXxs=
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 {
consumerConfig.Heartbeat = js.meta.hearbeat
}
consumerConfig.FilterSubject = req.Topic
natsHandler := func(m *nats.Msg) {
jsm, err := m.Metadata()

View File

@ -22,6 +22,7 @@ import (
"fmt"
"net/url"
"regexp"
"strconv"
"strings"
"sync"
"time"
@ -276,8 +277,9 @@ func (m *mqttPubSub) onMessage(ctx context.Context) func(client mqtt.Client, mqt
}()
msg := pubsub.NewMessage{
Topic: mqttMsg.Topic(),
Data: mqttMsg.Payload(),
Topic: mqttMsg.Topic(),
Data: mqttMsg.Payload(),
Metadata: map[string]string{"retained": strconv.FormatBool(mqttMsg.Retained())},
}
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
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.
func (v *vaultSecretStore) Features() []secretstores.Feature {
if v.vaultValueType == valueTypeText {
return []secretstores.Feature{}
}
return []secretstores.Feature{secretstores.FeatureMultipleKeyValuesPerSecret}
}

View File

@ -28,49 +28,53 @@ import (
const (
// base64 encoded certificate.
certificate = "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURVakNDQWpvQ0NRRFlZdzdMeXN4VXRUQU5CZ2txaGtpRzl3MEJBUXNGQURCck1Rc3dDUVlEVlFRR0V3SkQKUVRFWk1CY0dBMVVFQ0F3UVFuSnBkR2x6YUNCRGIyeDFiV0pwWVRFU01CQUdBMVVFQnd3SlZtRnVZMjkxZG1WeQpNUk13RVFZRFZRUUtEQXB0YVhOb2NtRmpiM0p3TVJnd0ZnWURWUVFEREE5MllYVnNkSEJ5YjJwbFkzUXVhVzh3CkhoY05NVGt4TVRBeE1UQTBPREV5V2hjTk1qQXhNRE14TVRBME9ERXlXakJyTVFzd0NRWURWUVFHRXdKRFFURVoKTUJjR0ExVUVDQXdRUW5KcGRHbHphQ0JEYjJ4MWJXSnBZVEVTTUJBR0ExVUVCd3dKVm1GdVkyOTFkbVZ5TVJNdwpFUVlEVlFRS0RBcHRhWE5vY21GamIzSndNUmd3RmdZRFZRUUREQTkyWVhWc2RIQnliMnBsWTNRdWFXOHdnZ0VpCk1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRQ3JtaitTTmtGUHEvK2FXUFV1MlpFamtSK3AKTm1PeEVNSnZZcGhHNkJvRFAySE9ZbGRzdk9FWkRkbTBpWFlmeFIwZm5rUmtTMWEzSlZiYmhINWJnTElKb0dxcwo5aWpzN2hyQ0Rrdk9uRWxpUEZuc05pQ2NWNDNxNkZYaFMvNFpoNGpOMnlyUkU2UmZiS1BEeUw0a282NkFhSld1CnVkTldKVWpzSFZBSWowZHlnTXFKYm0rT29iSzk5ckUxcDg5Z3RNUStJdzFkWnUvUFF4SjlYOStMeXdxZUxPckQKOWhpNWkxajNFUUp2RXQxSVUzclEwc2E0NU5zZkt4YzEwZjdhTjJuSDQzSnhnMVRiZXNPOWYrcWlyeDBHYmVSYQpyVmNaazNVaFc2cHZmam9XbDBEc0NwNTJwZDBQN05rUmhmak44b2RMN0h3bFVIc1NqemlSYytsTG5YREJBZ01CCkFBRXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBSVdKdmRPZ01PUnQxWk53SENkNTNieTlkMlBkcW5tWHFZZ20KNDZHK2Fvb1dSeTJKMEMwS3ZOVGZGbEJFOUlydzNXUTVNMnpqY25qSUp5bzNLRUM5TDdPMnQ1WC9LTGVDck5ZVgpIc1d4cU5BTVBGY2VBa09HT0I1TThGVllkdjJTaVV2UDJjMEZQSzc2WFVzcVNkdnRsWGFkTk5ENzE3T0NTNm0yCnBIVjh1NWJNd1VmR2NCVFpEV2o4bjIzRVdHaXdnYkJkdDc3Z3h3YWc5NTROZkM2Ny9nSUc5ZlRrTTQ4aVJCUzEKc0NGYVBjMkFIT3hiMSs0ajVCMVY2Z29iZDZYWkFvbHdNaTNHUUtkbEM1NXZNeTNwK09WbDNNbEc3RWNTVUpMdApwZ2ZKaWw3L3dTWWhpUnhJU3hrYkk5cWhvNEwzZm5PZVB3clFVd2FzU1ZiL1lxbHZ2WHM9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K"
expectedTok = "myRootToken"
expectedTokMountPath = "./vault.txt"
certificate = "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURVakNDQWpvQ0NRRFlZdzdMeXN4VXRUQU5CZ2txaGtpRzl3MEJBUXNGQURCck1Rc3dDUVlEVlFRR0V3SkQKUVRFWk1CY0dBMVVFQ0F3UVFuSnBkR2x6YUNCRGIyeDFiV0pwWVRFU01CQUdBMVVFQnd3SlZtRnVZMjkxZG1WeQpNUk13RVFZRFZRUUtEQXB0YVhOb2NtRmpiM0p3TVJnd0ZnWURWUVFEREE5MllYVnNkSEJ5YjJwbFkzUXVhVzh3CkhoY05NVGt4TVRBeE1UQTBPREV5V2hjTk1qQXhNRE14TVRBME9ERXlXakJyTVFzd0NRWURWUVFHRXdKRFFURVoKTUJjR0ExVUVDQXdRUW5KcGRHbHphQ0JEYjJ4MWJXSnBZVEVTTUJBR0ExVUVCd3dKVm1GdVkyOTFkbVZ5TVJNdwpFUVlEVlFRS0RBcHRhWE5vY21GamIzSndNUmd3RmdZRFZRUUREQTkyWVhWc2RIQnliMnBsWTNRdWFXOHdnZ0VpCk1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRQ3JtaitTTmtGUHEvK2FXUFV1MlpFamtSK3AKTm1PeEVNSnZZcGhHNkJvRFAySE9ZbGRzdk9FWkRkbTBpWFlmeFIwZm5rUmtTMWEzSlZiYmhINWJnTElKb0dxcwo5aWpzN2hyQ0Rrdk9uRWxpUEZuc05pQ2NWNDNxNkZYaFMvNFpoNGpOMnlyUkU2UmZiS1BEeUw0a282NkFhSld1CnVkTldKVWpzSFZBSWowZHlnTXFKYm0rT29iSzk5ckUxcDg5Z3RNUStJdzFkWnUvUFF4SjlYOStMeXdxZUxPckQKOWhpNWkxajNFUUp2RXQxSVUzclEwc2E0NU5zZkt4YzEwZjdhTjJuSDQzSnhnMVRiZXNPOWYrcWlyeDBHYmVSYQpyVmNaazNVaFc2cHZmam9XbDBEc0NwNTJwZDBQN05rUmhmak44b2RMN0h3bFVIc1NqemlSYytsTG5YREJBZ01CCkFBRXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBSVdKdmRPZ01PUnQxWk53SENkNTNieTlkMlBkcW5tWHFZZ20KNDZHK2Fvb1dSeTJKMEMwS3ZOVGZGbEJFOUlydzNXUTVNMnpqY25qSUp5bzNLRUM5TDdPMnQ1WC9LTGVDck5ZVgpIc1d4cU5BTVBGY2VBa09HT0I1TThGVllkdjJTaVV2UDJjMEZQSzc2WFVzcVNkdnRsWGFkTk5ENzE3T0NTNm0yCnBIVjh1NWJNd1VmR2NCVFpEV2o4bjIzRVdHaXdnYkJkdDc3Z3h3YWc5NTROZkM2Ny9nSUc5ZlRrTTQ4aVJCUzEKc0NGYVBjMkFIT3hiMSs0ajVCMVY2Z29iZDZYWkFvbHdNaTNHUUtkbEM1NXZNeTNwK09WbDNNbEc3RWNTVUpMdApwZ2ZKaWw3L3dTWWhpUnhJU3hrYkk5cWhvNEwzZm5PZVB3clFVd2FzU1ZiL1lxbHZ2WHM9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K"
expectedTok = "myRootToken"
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) {
tokenString := "This-IS-TheRootToken"
tmpFileName, cleanUpFunc := createTempFileWithContent(t, tokenString)
defer cleanUpFunc()
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{
vaultTokenMountPath: f.Name(),
vaultTokenMountPath: tmpFileName,
}
err = v.initVaultToken()
err := v.initVaultToken()
assert.Nil(t, err)
assert.Equal(t, tokenString, v.vaultToken)
})
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{
vaultTokenMountPath: f.Name(),
vaultTokenMountPath: tmpFileName,
}
err = v.initVaultToken()
err := v.initVaultToken()
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) {
@ -126,6 +130,9 @@ func TestVaultEnginePath(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) {
properties := map[string]string{
componentVaultToken: expectedTok,
@ -140,11 +147,9 @@ func TestVaultTokenPrefix(t *testing.T) {
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)
if err := target.Init(m); err != nil {
t.Fatal(err)
}
assert.Equal(t, defaultVaultKVPrefix, target.vaultKVPrefix)
})
@ -165,11 +170,9 @@ func TestVaultTokenPrefix(t *testing.T) {
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)
if err := target.Init(m); err != nil {
t.Fatal(err)
}
assert.Equal(t, "", target.vaultKVPrefix)
})
@ -190,10 +193,6 @@ func TestVaultTokenPrefix(t *testing.T) {
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)
assert.NotNil(t, err)
@ -201,6 +200,9 @@ func TestVaultTokenPrefix(t *testing.T) {
}
func TestVaultTokenMountPathOrVaultTokenRequired(t *testing.T) {
expectedTokMountPath, cleanUpFunc := createTokenMountPathFile(t)
defer cleanUpFunc()
t.Run("without vaultTokenMount or vaultToken", func(t *testing.T) {
properties := map[string]string{}
@ -235,13 +237,11 @@ func TestVaultTokenMountPathOrVaultTokenRequired(t *testing.T) {
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)
if err := target.Init(m); err != nil {
t.Fatal(err)
}
assert.Equal(t, "", target.vaultToken)
assert.Equal(t, expectedTokenMountFileContents, target.vaultToken)
assert.Equal(t, expectedTokMountPath, target.vaultTokenMountPath)
})
@ -259,11 +259,9 @@ func TestVaultTokenMountPathOrVaultTokenRequired(t *testing.T) {
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)
if err := target.Init(m); err != nil {
t.Fatal(err)
}
assert.Equal(t, "", target.vaultTokenMountPath)
assert.Equal(t, expectedTok, target.vaultToken)
@ -294,9 +292,12 @@ func TestVaultTokenMountPathOrVaultTokenRequired(t *testing.T) {
}
func TestDefaultVaultAddress(t *testing.T) {
expectedTokMountPath, cleanUpFunc := createTokenMountPathFile(t)
defer cleanUpFunc()
t.Run("with blank vaultAddr", func(t *testing.T) {
properties := map[string]string{
"vaultTokenMountPath": "./vault.txt",
"vaultTokenMountPath": expectedTokMountPath,
}
m := secretstores.Metadata{
@ -308,11 +309,9 @@ func TestDefaultVaultAddress(t *testing.T) {
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)
if err := target.Init(m); err != nil {
t.Fatal(err)
}
assert.Equal(t, defaultVaultAddress, target.vaultAddress, "default was not set")
})
@ -409,10 +408,49 @@ func getCertificate() []byte {
}
func TestGetFeatures(t *testing.T) {
s := NewHashiCorpVaultSecretStore(logger.NewLogger("test"))
// Yes, we are skipping initialization as feature retrieval doesn't depend on it.
t.Run("Vault supports MULTIPLE_KEY_VALUES_PER_SECRET", func(t *testing.T) {
initVaultWithVaultValueType := func(vaultValueType string) secretstores.SecretStore {
properties := map[string]string{
"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()
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 (
"context"
b64 "encoding/base64"
"fmt"
"io"
"net"
"net/url"
"reflect"
"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"
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/components-contrib/state"
"github.com/dapr/kit/logger"
@ -56,72 +57,26 @@ import (
)
const (
keyDelimiter = "||"
contentType = "ContentType"
contentMD5 = "ContentMD5"
contentEncoding = "ContentEncoding"
contentLanguage = "ContentLanguage"
contentDisposition = "ContentDisposition"
cacheControl = "CacheControl"
keyDelimiter = "||"
)
// StateStore Type.
type StateStore struct {
state.DefaultBulkStore
containerURL azblob.ContainerURL
json jsoniter.API
containerClient *container.Client
json jsoniter.API
features []state.Feature
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.
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 {
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
}
@ -132,34 +87,29 @@ func (r *StateStore) Features() []state.Feature {
// Delete the state.
func (r *StateStore) Delete(req *state.DeleteRequest) error {
r.logger.Debugf("delete %s", req.Key)
return r.deleteFile(context.Background(), req)
}
// Get the state.
func (r *StateStore) Get(req *state.GetRequest) (*state.GetResponse, error) {
r.logger.Debugf("get %s", req.Key)
return r.readFile(context.Background(), req)
}
// Set the state.
func (r *StateStore) Set(req *state.SetRequest) error {
r.logger.Debugf("saving %s", req.Key)
return r.writeFile(context.Background(), req)
}
func (r *StateStore) Ping() error {
accessConditions := azblob.BlobAccessConditions{}
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)
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)
}
return nil
}
func (r *StateStore) GetComponentMetadata() map[string]string {
metadataStruct := blobStorageMetadata{}
metadataStruct := storageinternal.BlobStorageMetadata{}
metadataInfo := map[string]string{}
mdutils.GetMetadataInfoFromStructType(reflect.TypeOf(metadataStruct), &metadataInfo)
return metadataInfo
@ -177,32 +127,10 @@ func NewAzureBlobStorageStore(logger logger.Logger) state.Store {
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) {
blobURL := r.containerURL.NewBlockBlobURL(getFileName(req.Key))
resp, err := blobURL.Download(ctx, 0, azblob.CountToEnd, azblob.BlobAccessConditions{}, false)
blockBlobClient := r.containerClient.NewBlockBlobClient(getFileName(req.Key))
blobDownloadResponse, err := blockBlobClient.DownloadStream(ctx, nil)
if err != nil {
r.logger.Debugf("download file %s, err %s", req.Key, err)
if isNotFoundError(err) {
return &state.GetResponse{}, nil
}
@ -210,110 +138,79 @@ func (r *StateStore) readFile(ctx context.Context, req *state.GetRequest) (*stat
return &state.GetResponse{}, err
}
bodyStream := resp.Body(azblob.RetryReaderOptions{})
data, err := io.ReadAll(bodyStream)
reader := blobDownloadResponse.Body
defer reader.Close()
blobData, err := io.ReadAll(reader)
if err != nil {
r.logger.Debugf("read file %s, err %s", req.Key, err)
return &state.GetResponse{}, err
return &state.GetResponse{}, fmt.Errorf("error reading az blob: %w", err)
}
contentType := resp.ContentType()
contentType := blobDownloadResponse.ContentType
return &state.GetResponse{
Data: data,
ETag: ptr.Of(string(resp.ETag())),
ContentType: &contentType,
Data: blobData,
ETag: ptr.Of(string(*blobDownloadResponse.ETag)),
ContentType: contentType,
}, nil
}
func (r *StateStore) writeFile(ctx context.Context, req *state.SetRequest) error {
accessConditions := azblob.BlobAccessConditions{}
modifiedAccessConditions := blob.ModifiedAccessConditions{}
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 == "") {
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 {
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
if req.ETag != nil && isETagConflictError(err) {
return state.NewETagError(state.ETagMismatch, err)
}
return err
return fmt.Errorf("error uploading az blob: %w", err)
}
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 {
blobURL := r.containerURL.NewBlockBlobURL(getFileName(req.Key))
accessConditions := azblob.BlobAccessConditions{}
blockBlobClient := r.containerClient.NewBlockBlobClient(getFileName(req.Key))
modifiedAccessConditions := blob.ModifiedAccessConditions{}
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)
if err != nil {
r.logger.Debugf("delete file %s, err %s", req.Key, err)
deleteOptions := blob.DeleteOptions{
DeleteSnapshots: nil,
AccessConditions: &blob.AccessConditions{
ModifiedAccessConditions: &modifiedAccessConditions,
},
}
_, err := blockBlobClient.Delete(ctx, &deleteOptions)
if err != nil {
if req.ETag != nil && isETagConflictError(err) {
return state.NewETagError(state.ETagMismatch, err)
} else if isNotFoundError(err) {
@ -349,13 +246,9 @@ func (r *StateStore) marshal(req *state.SetRequest) []byte {
}
func isNotFoundError(err error) bool {
azureError, ok := err.(azblob.StorageError)
return ok && azureError.ServiceCode() == azblob.ServiceCodeBlobNotFound
return bloberror.HasCode(err, bloberror.BlobNotFound)
}
func isETagConflictError(err error) bool {
azureError, ok := err.(azblob.StorageError)
return ok && azureError.ServiceCode() == azblob.ServiceCodeConditionNotMet
return bloberror.HasCode(err, bloberror.ConditionNotMet)
}

View File

@ -34,8 +34,7 @@ func TestInit(t *testing.T) {
}
err := s.Init(m)
assert.Nil(t, err)
assert.Equal(t, "acc.blob.core.windows.net", s.containerURL.URL().Host)
assert.Equal(t, "/dapr", s.containerURL.URL().Path)
assert.Equal(t, "https://acc.blob.core.windows.net/dapr", s.containerClient.URL())
})
t.Run("Init with missing metadata", func(t *testing.T) {
@ -53,31 +52,12 @@ func TestInit(t *testing.T) {
"accountKey": "e+Dnvl8EOxYxV94nurVaRQ==",
"containerName": "dapr",
}
err := s.Init(m)
s.Init(m)
err := s.Ping()
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) {
t.Run("Valid composite key", func(t *testing.T) {
key := getFileName("app_id||key")
@ -89,41 +69,3 @@ func TestFileName(t *testing.T) {
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 (
"database/sql"
"database/sql/driver"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"strconv"
"time"
"github.com/dapr/components-contrib/metadata"
"github.com/dapr/components-contrib/state"
@ -27,15 +29,17 @@ import (
"github.com/dapr/components-contrib/state/utils"
"github.com/dapr/kit/logger"
"github.com/dapr/kit/ptr"
"github.com/dapr/kit/retry"
// Blank import for the underlying PostgreSQL driver.
_ "github.com/jackc/pgx/v5/stdlib"
)
const (
connectionStringKey = "connectionString"
errMissingConnectionString = "missing connection string"
tableName = "state"
connectionStringKey = "connectionString"
errMissingConnectionString = "missing connection string"
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.
@ -47,8 +51,9 @@ type cockroachDBAccess struct {
}
type cockroachDBMetadata struct {
ConnectionString string
TableName string
ConnectionString string
TableName string
MaxConnectionAttempts *int
}
// newCockroachDBAccess creates a new instance of cockroachDBAccess.
@ -109,6 +114,12 @@ func (p *cockroachDBAccess) Init(metadata state.Metadata) error {
return err
}
// Ensure that a connection to the database is actually established
err = p.Ping()
if err != nil {
return err
}
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.
func (p *cockroachDBAccess) Get(req *state.GetRequest) (*state.GetResponse, error) {
p.logger.Debug("Getting state value from CockroachDB")
if req.Key == "" {
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.
func (p *cockroachDBAccess) Delete(req *state.DeleteRequest) error {
p.logger.Debug("Deleting state value from CockroachDB")
if req.Key == "" {
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.
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.

View File

@ -7,7 +7,7 @@ require (
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/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/kit v0.0.3-0.20221102045011-c213121f0b4f
github.com/stretchr/testify v1.8.1
@ -103,6 +103,7 @@ require (
github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/openzipkin/zipkin-go v0.4.1 // 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/pmezard/go-difflib v1.0.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/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/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
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 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=

View File

@ -5,7 +5,7 @@ go 1.19
require (
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/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/kit v0.0.3-0.20221102045011-c213121f0b4f
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/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // 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/pmezard/go-difflib v1.0.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/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/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
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.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=

View File

@ -33,12 +33,16 @@ import (
dapr_testing "github.com/dapr/dapr/pkg/testing"
daprsdk "github.com/dapr/go-sdk/client"
"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/flow"
"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/blob"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/bloberror"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/container"
)
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.
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{
"blobName": name,
"deleteSnapshots": deleteSnapshotsOption,
"blobName": name,
}
if deleteSnapshotsOption != nil {
invokeDeleteMetadata["deleteSnapshots"] = *deleteSnapshotsOption
}
invokeGetRequest := &daprsdk.InvokeBindingRequest{
@ -185,19 +191,19 @@ func TestBlobStorage(t *testing.T) {
assert.Equal(t, newString, input2)
// cleanup.
out, invokeDeleteErr := deleteBlobRequest(ctx, client, blobName, "")
out, invokeDeleteErr := deleteBlobRequest(ctx, client, blobName, nil)
assert.NoError(t, invokeDeleteErr)
assert.Empty(t, out.Data)
// confirm the deletion.
_, invokeSecondGetErr := getBlobRequest(ctx, client, blobName, false)
assert.Error(t, invokeSecondGetErr)
assert.Contains(t, invokeSecondGetErr.Error(), "ServiceCode=BlobNotFound")
assert.Contains(t, invokeSecondGetErr.Error(), bloberror.BlobNotFound)
// deleting the key again should fail.
_, invokeDeleteErr2 := deleteBlobRequest(ctx, client, blobName, "")
_, invokeDeleteErr2 := deleteBlobRequest(ctx, client, blobName, nil)
assert.Error(t, invokeDeleteErr2)
assert.Contains(t, invokeDeleteErr2.Error(), "ServiceCode=BlobNotFound")
assert.Contains(t, invokeDeleteErr2.Error(), bloberror.BlobNotFound)
return nil
}
@ -230,7 +236,7 @@ func TestBlobStorage(t *testing.T) {
_, invokeCreateErr := client.InvokeBinding(ctx, invokeCreateRequest)
assert.Error(t, invokeCreateErr)
assert.Contains(t, invokeCreateErr.Error(), "ServiceCode=Md5Mismatch")
assert.Contains(t, invokeCreateErr.Error(), bloberror.MD5Mismatch)
return nil
}
@ -272,14 +278,14 @@ func TestBlobStorage(t *testing.T) {
assert.Equal(t, responseData, dataBytes)
assert.Empty(t, out.Metadata)
out, invokeDeleteErr := deleteBlobRequest(ctx, client, blobName, "")
out, invokeDeleteErr := deleteBlobRequest(ctx, client, blobName, nil)
assert.NoError(t, invokeDeleteErr)
assert.Empty(t, out.Data)
// confirm the deletion.
_, invokeSecondGetErr := getBlobRequest(ctx, client, blobName, false)
assert.Error(t, invokeSecondGetErr)
assert.Contains(t, invokeSecondGetErr.Error(), "ServiceCode=BlobNotFound")
assert.Contains(t, invokeSecondGetErr.Error(), bloberror.BlobNotFound)
return nil
}
@ -327,7 +333,7 @@ func TestBlobStorage(t *testing.T) {
}
// cleanup.
_, invokeDeleteErr := deleteBlobRequest(ctx, client, blobName, "")
_, invokeDeleteErr := deleteBlobRequest(ctx, client, blobName, nil)
assert.NoError(t, invokeDeleteErr)
return nil
@ -384,9 +390,9 @@ func TestBlobStorage(t *testing.T) {
out, invokeGetErr := client.InvokeBinding(ctx, invokeGetRequest)
assert.NoError(t, invokeGetErr)
assert.Equal(t, string(out.Data), input)
assert.Contains(t, out.Metadata, "custom")
assert.Equal(t, out.Metadata["custom"], "hello-world")
assert.Equal(t, input, string(out.Data))
assert.Contains(t, out.Metadata, "Custom")
assert.Equal(t, "hello-world", out.Metadata["Custom"])
out, invokeErr := listBlobRequest(ctx, client, "", "", -1, true, false, false, false, false)
assert.NoError(t, invokeErr)
@ -412,14 +418,14 @@ func TestBlobStorage(t *testing.T) {
}
assert.True(t, found)
out, invokeDeleteErr := deleteBlobRequest(ctx, client, "filename.txt", "")
out, invokeDeleteErr := deleteBlobRequest(ctx, client, "filename.txt", nil)
assert.NoError(t, invokeDeleteErr)
assert.Empty(t, out.Data)
// confirm the deletion.
_, invokeSecondGetErr := getBlobRequest(ctx, client, "filename.txt", false)
assert.Error(t, invokeSecondGetErr)
assert.Contains(t, invokeSecondGetErr.Error(), "ServiceCode=BlobNotFound")
assert.Contains(t, invokeSecondGetErr.Error(), bloberror.BlobNotFound)
return nil
}
@ -505,8 +511,8 @@ func TestBlobStorage(t *testing.T) {
unmarshalErr := json.Unmarshal(out.Data, &output)
assert.NoError(t, unmarshalErr)
assert.Equal(t, len(output), 1)
assert.Equal(t, output[0]["Name"], "prefixA/filename.txt")
assert.Equal(t, 1, len(output))
assert.Contains(t, output[0]["Name"], "prefixA")
nextMarker := out.Metadata["marker"]
@ -518,27 +524,27 @@ func TestBlobStorage(t *testing.T) {
err2 := json.Unmarshal(out2.Data, &output2)
assert.NoError(t, err2)
assert.Equal(t, len(output2), 1)
assert.Equal(t, output2[0]["Name"], "prefixAfilename.txt")
assert.Equal(t, 1, len(output2))
assert.Contains(t, output2[0]["Name"], "prefixA")
// cleanup.
_, invokeDeleteErr1 := deleteBlobRequest(ctx, client, "prefixA/filename.txt", "")
_, invokeDeleteErr1 := deleteBlobRequest(ctx, client, "prefixA/filename.txt", nil)
assert.NoError(t, invokeDeleteErr1)
_, invokeDeleteErr2 := deleteBlobRequest(ctx, client, "prefixAfilename.txt", "")
_, invokeDeleteErr2 := deleteBlobRequest(ctx, client, "prefixAfilename.txt", nil)
assert.NoError(t, invokeDeleteErr2)
_, invokeDeleteErr3 := deleteBlobRequest(ctx, client, "prefixB/filename.txt", "")
_, invokeDeleteErr3 := deleteBlobRequest(ctx, client, "prefixB/filename.txt", nil)
assert.NoError(t, invokeDeleteErr3)
// 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)
// 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{}
err3 := json.Unmarshal(out3.Data, &output3)
assert.NoError(t, err3)
assert.Equal(t, len(output3), 2)
assert.Equal(t, len(output3), 1)
return nil
}
@ -553,17 +559,15 @@ func TestBlobStorage(t *testing.T) {
defer client.Close()
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, _ := service.NewContainerClient(os.Getenv("AzureBlobStorageContainer"))
containerClient, _ := container.NewClientWithSharedKeyCredential(fmt.Sprintf("https://%s.blob.core.windows.net/%s", os.Getenv("AzureBlobStorageAccount"), os.Getenv("AzureBlobStorageContainer")), cred, nil)
blobClient, _ := containerClient.NewBlockBlobClient("snapshotthis.txt")
uploadResp, uploadErr := blobClient.UploadBuffer(
blobClient := containerClient.NewBlockBlobClient("snapshotthis.txt")
_, uploadErr := blobClient.UploadBuffer(
ctx, []byte("some example content"),
azblob.UploadOption{}) //nolint:exhaustivestruct
&azblob.UploadBufferOptions{}) //nolint:exhaustivestruct
assert.NoError(t, uploadErr)
uploadResp.Body.Close()
_, createSnapshotErr := blobClient.CreateSnapshot(
ctx, &azblob.BlobCreateSnapshotOptions{}) //nolint:exhaustivestruct
ctx, &blob.CreateSnapshotOptions{}) //nolint:exhaustivestruct
assert.NoError(t, createSnapshotErr)
// 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")
// delete snapshots.
_, invokeDeleteErr := deleteBlobRequest(ctx, client, "snapshotthis.txt", "only")
_, invokeDeleteErr := deleteBlobRequest(ctx, client, "snapshotthis.txt", ptr.Of(string(blob.DeleteSnapshotsOptionTypeOnly)))
assert.NoError(t, invokeDeleteErr)
// verify snapshot is deleted.
out2, listErr2 := listBlobRequest(ctx, client, "snapshotthis.txt", "", -1, false, true, false, false, false)
assert.NoError(t, listErr2)
assert.Equal(t, out2.Metadata["number"], "1")
assert.Equal(t, "1", out2.Metadata["number"])
// create another snapshot.
_, createSnapshotErr2 := blobClient.CreateSnapshot(
ctx, &azblob.BlobCreateSnapshotOptions{}) //nolint:exhaustivestruct
ctx, &blob.CreateSnapshotOptions{}) //nolint:exhaustivestruct
assert.NoError(t, createSnapshotErr2)
// 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)
// verify base blob and snapshots are deleted.
out3, listErr3 := listBlobRequest(ctx, client, "snapshotthis.txt", "", -1, false, true, false, false, false)
assert.NoError(t, listErr3)
assert.Equal(t, out3.Metadata["number"], "0")
assert.Equal(t, "0", out3.Metadata["number"])
return nil
}

View File

@ -3,10 +3,10 @@ module github.com/dapr/components-contrib/tests/certification/bindings/azure/blo
go 1.19
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/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/kit v0.0.3-0.20221102045011-c213121f0b4f
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-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/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-queue-go v0.0.0-20191125232315-636801874cdd // 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/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // 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/errors v0.9.1 // 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/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/internal v1.0.0 h1:jp0dGvZ7ZK0mgqnTSClMxa5xuRL7NZgHameVYF6BurY=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/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.4.1/go.mod h1:eZ4g6GUvXiGulfIbbhh1Xr4XwUYaYaWMqzGD/284wCA=
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.1/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w=
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.10.0 h1:evCwGreYo3XLeBV4vSxLbLiYb6e0SzsJiXQVRGsRXxs=
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=
@ -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/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/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/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ=
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/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650
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/kit v0.0.3-0.20221102045011-c213121f0b4f
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/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/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-queue-go v0.0.0-20191125232315-636801874cdd // 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/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // 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/errors v0.9.1 // 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/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/internal v1.0.0 h1:jp0dGvZ7ZK0mgqnTSClMxa5xuRL7NZgHameVYF6BurY=
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 h1:XUNQ4mw+zJmaA2KXzP9JlQiecy1SI+Eog7xVkPiqIbg=
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/go.mod h1:ep1edmW+kNQx4UfWM9heESNmQdijykocJ0YOxmMX8SE=
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/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/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/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=

View File

@ -5,7 +5,7 @@ go 1.19
require (
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/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/kit v0.0.3-0.20221102045011-c213121f0b4f
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/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/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-queue-go v0.0.0-20191125232315-636801874cdd // 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/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // 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/errors v0.9.1 // 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/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/internal v1.0.0 h1:jp0dGvZ7ZK0mgqnTSClMxa5xuRL7NZgHameVYF6BurY=
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 h1:XUNQ4mw+zJmaA2KXzP9JlQiecy1SI+Eog7xVkPiqIbg=
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.10.0 h1:evCwGreYo3XLeBV4vSxLbLiYb6e0SzsJiXQVRGsRXxs=
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/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/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/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=

View File

@ -5,7 +5,7 @@ go 1.19
require (
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/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/kit v0.0.3-0.20221102045011-c213121f0b4f
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-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/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-storage-blob-go v0.10.0 // 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/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // 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/errors v0.9.1 // 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/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/internal v1.0.0 h1:jp0dGvZ7ZK0mgqnTSClMxa5xuRL7NZgHameVYF6BurY=
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 h1:XUNQ4mw+zJmaA2KXzP9JlQiecy1SI+Eog7xVkPiqIbg=
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/go.mod h1:LH9XQnMr2ZYxQdVdCrzLO9mxeDyrDFa6wbSI3x5zCZk=
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/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/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/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=

View File

@ -5,7 +5,7 @@ go 1.19
require (
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/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/kit v0.0.3-0.20221102045011-c213121f0b4f
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-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/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-queue-go v0.0.0-20191125232315-636801874cdd // 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/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // 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/errors v0.9.1 // 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/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/internal v1.0.0 h1:jp0dGvZ7ZK0mgqnTSClMxa5xuRL7NZgHameVYF6BurY=
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 h1:XUNQ4mw+zJmaA2KXzP9JlQiecy1SI+Eog7xVkPiqIbg=
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/go.mod h1:ep1edmW+kNQx4UfWM9heESNmQdijykocJ0YOxmMX8SE=
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/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/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/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ=
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/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650
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/kit v0.0.3-0.20221102045011-c213121f0b4f
github.com/google/uuid v1.3.0
@ -87,6 +87,7 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // 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/pkg/errors v0.9.1 // 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/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/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/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=

View File

@ -5,7 +5,7 @@ go 1.19
require (
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/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/kit v0.0.3-0.20221102045011-c213121f0b4f
github.com/stretchr/testify v1.8.1
@ -75,6 +75,7 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // 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/pmezard/go-difflib v1.0.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/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/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
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.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=

View File

@ -5,7 +5,7 @@ go 1.19
require (
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/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/kit v0.0.3-0.20221102045011-c213121f0b4f
github.com/lib/pq v1.10.7
@ -79,6 +79,7 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // 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/pmezard/go-difflib v1.0.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/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/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
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.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=

View File

@ -5,7 +5,7 @@ go 1.19
require (
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/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/kit v0.0.3-0.20221102045011-c213121f0b4f
github.com/rabbitmq/amqp091-go v1.5.0
@ -77,6 +77,7 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // 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/pmezard/go-difflib v1.0.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/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/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
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.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=

View File

@ -5,7 +5,7 @@ go 1.19
require (
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/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/kit v0.0.3-0.20221102045011-c213121f0b4f
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/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // 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/pmezard/go-difflib v1.0.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/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/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
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.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=

View File

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

View File

@ -4,7 +4,7 @@ go 1.19
require (
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/kit v0.0.3-0.20221102045011-c213121f0b4f
github.com/google/go-cmp v0.5.9
@ -134,6 +134,7 @@ require (
require (
github.com/cenkalti/backoff/v4 v4.1.3
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5
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/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/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
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.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=

View File

@ -5,7 +5,7 @@ go 1.19
require (
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/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/kit v0.0.3-0.20221102045011-c213121f0b4f
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/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/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-queue-go v0.0.0-20191125232315-636801874cdd // 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/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // 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/errors v0.9.1 // 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/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/internal v1.0.0 h1:jp0dGvZ7ZK0mgqnTSClMxa5xuRL7NZgHameVYF6BurY=
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 h1:XUNQ4mw+zJmaA2KXzP9JlQiecy1SI+Eog7xVkPiqIbg=
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.10.0 h1:evCwGreYo3XLeBV4vSxLbLiYb6e0SzsJiXQVRGsRXxs=
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/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/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/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=

View File

@ -5,7 +5,7 @@ go 1.19
require (
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/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/kit v0.0.3-0.20221102045011-c213121f0b4f
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-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/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-storage-blob-go v0.10.0 // 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/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // 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/errors v0.9.1 // 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/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/internal v1.0.0 h1:jp0dGvZ7ZK0mgqnTSClMxa5xuRL7NZgHameVYF6BurY=
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 h1:XUNQ4mw+zJmaA2KXzP9JlQiecy1SI+Eog7xVkPiqIbg=
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/go.mod h1:LH9XQnMr2ZYxQdVdCrzLO9mxeDyrDFa6wbSI3x5zCZk=
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/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/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/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ=
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/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650
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/kit v0.0.3-0.20221102045011-c213121f0b4f
github.com/google/uuid v1.3.0
@ -87,6 +87,7 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // 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/pkg/errors v0.9.1 // 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/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/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/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
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/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650
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/kit v0.0.3-0.20221102045011-c213121f0b4f
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/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // 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/pmezard/go-difflib v1.0.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/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/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
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.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=

View File

@ -6,7 +6,7 @@ require (
github.com/cenkalti/backoff/v4 v4.1.3
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/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/kit v0.0.3-0.20221102045011-c213121f0b4f
github.com/rabbitmq/amqp091-go v1.5.0
@ -77,6 +77,7 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // 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/pmezard/go-difflib v1.0.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/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/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
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.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=

View File

@ -5,7 +5,7 @@ go 1.19
require (
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/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/kit v0.0.3-0.20221102045011-c213121f0b4f
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-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/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/internal v0.7.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/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // 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/errors v0.9.1 // 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/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/internal v1.0.0 h1:jp0dGvZ7ZK0mgqnTSClMxa5xuRL7NZgHameVYF6BurY=
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 h1:XUNQ4mw+zJmaA2KXzP9JlQiecy1SI+Eog7xVkPiqIbg=
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/go.mod h1:S78i9yTr4o/nXlH76bKjGUye9Z2wSxO5Tz7GoDr4vfI=
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/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/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/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ=
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
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.
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).
5. Try to read the key from step 2 and assert it is still there.
## 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
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.
@ -34,8 +135,24 @@ This secret store [supports the following features][features]:
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:
@ -44,7 +161,10 @@ go test -v vault_test.go
* [List of secret store components and their features][features]
* [PR with Conformance tests for Hashicorp Vault][conformance]
* [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/
[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