diff --git a/bindings/alicloud/dingtalk/webhook/metadata.yaml b/bindings/alicloud/dingtalk/webhook/metadata.yaml new file mode 100644 index 0000000000..7cc7dc9f80 --- /dev/null +++ b/bindings/alicloud/dingtalk/webhook/metadata.yaml @@ -0,0 +1,31 @@ +# yaml-language-server: $schema=../../../component-metadata-schema.json +schemaVersion: v1 +type: bindings +name: alicloud.dingtalk.webhook +version: v1 +status: alpha +title: "AliCloud DingTalk Webhook" +urls: + - title: Reference + url: https://docs.dapr.io/reference/components-reference/supported-bindings/alicloud-dingtalk/ +binding: + output: true + input: true + operations: + - name: create + description: "Send a message to DingTalk webhook" + - name: read + description: "Receive messages from DingTalk webhook" +metadata: + - name: id + required: true + description: "The webhook ID" + example: "your-webhook-id" + - name: url + required: true + description: "The webhook URL" + example: '"https://oapi.dingtalk.com/robot/send?access_token=your-token"' + - name: secret + required: false + description: "The webhook secret for signature verification" + example: "your-webhook-secret" diff --git a/bindings/alicloud/oss/metadata.yaml b/bindings/alicloud/oss/metadata.yaml new file mode 100644 index 0000000000..b86983069d --- /dev/null +++ b/bindings/alicloud/oss/metadata.yaml @@ -0,0 +1,48 @@ +# yaml-language-server: $schema=../../../component-metadata-schema.json +schemaVersion: v1 +type: bindings +name: alicloud.oss +version: v1 +status: alpha +title: "AliCloud Object Storage Service (OSS)" +urls: + - title: Reference + url: https://docs.dapr.io/reference/components-reference/supported-bindings/oss/ +binding: + output: true + input: false + operations: + - name: create + description: "Upload file to OSS" +authenticationProfiles: + - title: "AliCloud Access Key Authentication" + description: | + Authenticate using AliCloud access key credentials. + metadata: + - name: accessKeyID + required: false + description: "The AliCloud access key ID" + example: '"your-access-key-id"' + sensitive: true + - name: accessKeySecret + required: false + sensitive: true + description: "The AliCloud access key secret" + example: '"your-access-key-secret"' + - name: accessKey + required: false + description: "The AliCloud access key" + example: "access-key" +metadata: + - name: endpoint + required: true + description: "The OSS endpoint" + example: "https://oss-cn-hangzhou.aliyuncs.com" + - name: bucket + required: true + description: "The OSS bucket name" + example: "your-bucket-name" + - name: objectKey + required: true + description: "The object key in the bucket" + example: "path/to/file.txt" diff --git a/bindings/alicloud/sls/metadata.yaml b/bindings/alicloud/sls/metadata.yaml new file mode 100644 index 0000000000..069ca26e9c --- /dev/null +++ b/bindings/alicloud/sls/metadata.yaml @@ -0,0 +1,52 @@ +# yaml-language-server: $schema=../../../component-metadata-schema.json +schemaVersion: v1 +type: bindings +name: alicloud.sls +version: v1 +status: alpha +title: "AliCloud Simple Log Storage (SLS)" +urls: + - title: Reference + url: https://docs.dapr.io/reference/components-reference/supported-bindings/alicloudsls/ +binding: + output: true + input: false + operations: + - name: create + description: "Send logs to SLS" +authenticationProfiles: + - title: "Access Key Authentication" + description: | + Authenticate using AliCloud access key credentials. + metadata: + - name: accessKeyID + required: false + sensitive: true + description: "The AliCloud access key ID" + example: "your-access-key-id" + - name: accessKeySecret + required: false + sensitive: true + description: "The AliCloud access key secret" + example: "your-access-key-secret" +metadata: + - name: endpoint + required: true + description: "The SLS endpoint" + example: "https://your-project.cn-hangzhou.log.aliyuncs.com" + - name: project + required: true + description: "The SLS project name" + example: '"your-project-name"' + - name: logstore + required: true + description: "The SLS logstore name" + example: "your-logstore-name" + - name: topic + required: true + description: "The SLS topic name" + example: "your-topic-name" + - name: source + required: true + description: "The SLS source name" + example: "your-source-name" diff --git a/bindings/alicloud/sls/sls.go b/bindings/alicloud/sls/sls.go index 42d7b4a55c..9cc983736f 100644 --- a/bindings/alicloud/sls/sls.go +++ b/bindings/alicloud/sls/sls.go @@ -60,6 +60,7 @@ func NewAliCloudSlsLogstorage(logger logger.Logger) bindings.OutputBinding { func (s *AliCloudSlsLogstorage) Invoke(ctx context.Context, req *bindings.InvokeRequest) (*bindings.InvokeResponse, error) { // verify the metadata property + // TODO: move these to the struct with proper tags if logProject := req.Metadata["project"]; logProject == "" { return nil, errors.New("SLS binding error: project property not supplied") } diff --git a/bindings/alicloud/tablestore/metadata.yaml b/bindings/alicloud/tablestore/metadata.yaml new file mode 100644 index 0000000000..481791183d --- /dev/null +++ b/bindings/alicloud/tablestore/metadata.yaml @@ -0,0 +1,48 @@ + +# yaml-language-server: $schema=../../../component-metadata-schema.json +schemaVersion: v1 +type: bindings +name: alicloud.tablestore +version: v1 +status: stable +title: "AliCloud Table Store" +urls: + - title: Reference + url: https://docs.dapr.io/reference/components-reference/supported-bindings/alicloudtablestore/ +binding: + output: true + input: false + operations: + - name: create + description: "Write data to Table Store" +authenticationProfiles: + - title: "Access Key Authentication" + description: | + Authenticate using AliCloud access key credentials. + metadata: + - name: accessKeyID + required: true + description: "The AliCloud access key ID" + example: "access-key-id" + - name: accessKeySecret + required: true + sensitive: true + description: "The AliCloud access key secret" + example: "access-key-secret" + - name: accessKey + required: true + description: "The AliCloud access key" + example: "access-key" +metadata: + - name: endpoint + required: true + description: "The Table Store endpoint" + example: '"https://your-instance.cn-hangzhou.ots.aliyuncs.com"' + - name: instanceName + required: true + description: "The Table Store instance name" + example: "instance-name" + - name: tableName + required: true + description: "The table name to write to" + example: "table-name" diff --git a/bindings/alicloud/tablestore/tablestore.go b/bindings/alicloud/tablestore/tablestore.go index c153f2c1e0..e8762e8487 100644 --- a/bindings/alicloud/tablestore/tablestore.go +++ b/bindings/alicloud/tablestore/tablestore.go @@ -137,7 +137,7 @@ func (s *AliCloudTableStore) get(req *bindings.InvokeRequest, resp *bindings.Inv pkNames := strings.Split(req.Metadata[primaryKeys], ",") pks := make([]*tablestore.PrimaryKeyColumn, len(pkNames)) - data := make(map[string]interface{}) + data := make(map[string]any) err := json.Unmarshal(req.Data, &data) if err != nil { return err @@ -313,7 +313,7 @@ func (s *AliCloudTableStore) unmarshal(pks []*tablestore.PrimaryKeyColumn, colum return nil, nil } - data := make(map[string]interface{}) + data := make(map[string]any) for _, pk := range pks { data[pk.ColumnName] = pk.Value diff --git a/bindings/apns/apns.go b/bindings/apns/apns.go index b0a08d4532..abb8a99b68 100644 --- a/bindings/apns/apns.go +++ b/bindings/apns/apns.go @@ -33,6 +33,7 @@ import ( kitmd "github.com/dapr/kit/metadata" ) +// TODO: these should be configured in the metadata.yaml file and be part of the metadata struct with proper json tags. const ( collapseIDKey = "apns-collapse-id" developmentKey = "development" @@ -67,6 +68,7 @@ type APNS struct { authorizationBuilder *authorizationBuilder } +// TODO: use proper tags type APNSmetadata struct { Development bool `mapstructure:"development"` KeyID string `mapstructure:"key-id"` diff --git a/bindings/apns/metadata.yaml b/bindings/apns/metadata.yaml new file mode 100644 index 0000000000..312ff65d03 --- /dev/null +++ b/bindings/apns/metadata.yaml @@ -0,0 +1,40 @@ +# yaml-language-server: $schema=../../component-metadata-schema.json +schemaVersion: v1 +type: bindings +name: apns +version: v1 +status: alpha +title: "Apple Push Notification Service (APNS)" +urls: + - title: Reference + url: https://docs.dapr.io/reference/components-reference/supported-bindings/apns/ +binding: + output: true + input: false + operations: + - name: create + description: "Send push notification via APNS" +authenticationProfiles: + - title: "APNS Key Authentication" + description: | + Authenticate using APNS key credentials. + metadata: + - name: key-id + required: true + description: "The APNS key ID" + example: "ABC123DEF4" + - name: team-id + required: true + description: "The APNS team ID" + example: "DEF123GHI4" + - name: private-key + required: true + sensitive: true + description: "The APNS private key (P8 file content)" +metadata: + - name: development + type: boolean + required: false + description: "The APNS environment is development or not" + example: true + default: false diff --git a/bindings/aws/dynamodb/dynamodb.go b/bindings/aws/dynamodb/dynamodb.go index 2096f22433..3f20abdcdd 100644 --- a/bindings/aws/dynamodb/dynamodb.go +++ b/bindings/aws/dynamodb/dynamodb.go @@ -36,6 +36,7 @@ type DynamoDB struct { logger logger.Logger } +// TODO: the metadata fields need updating to use the builtin aws auth provider fully and reflect in metadata.yaml type dynamoDBMetadata struct { Region string `json:"region" mapstructure:"region"` Endpoint string `json:"endpoint" mapstructure:"endpoint"` diff --git a/bindings/aws/dynamodb/metadata.yaml b/bindings/aws/dynamodb/metadata.yaml new file mode 100644 index 0000000000..488936bfa7 --- /dev/null +++ b/bindings/aws/dynamodb/metadata.yaml @@ -0,0 +1,48 @@ +# yaml-language-server: $schema=../../../component-metadata-schema.json +schemaVersion: v1 +type: bindings +name: aws.dynamodb +version: v1 +status: stable +title: "AWS DynamoDB" +urls: + - title: Reference + url: https://docs.dapr.io/reference/components-reference/supported-bindings/dynamodb/ +binding: + output: true + input: false + operations: + - name: create + description: "Write item to DynamoDB table" +authenticationProfiles: + - title: "AWS Access Key Authentication" + description: | + Authenticate using AWS access key credentials. + metadata: + - name: accessKey + required: true + description: "The AWS access key" + example: "AKIAIOSFODNN7EXAMPLE" + - name: secretKey + required: true + sensitive: true + description: "The AWS secret key" + example: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" + - name: sessionToken + required: false + sensitive: true + description: "The AWS session token" + example: "TOKEN" + - name: region + required: true + description: "The AWS region" + example: "us-east-1" +metadata: + - name: table + required: true + description: "The DynamoDB table name" + example: "my-table" + - name: endpoint + required: false + description: "The DynamoDB endpoint URL" + example: "http://localhost:8000" diff --git a/bindings/aws/kinesis/kinesis.go b/bindings/aws/kinesis/kinesis.go index 0b84b44dcd..cce67bd3da 100644 --- a/bindings/aws/kinesis/kinesis.go +++ b/bindings/aws/kinesis/kinesis.go @@ -55,6 +55,7 @@ type AWSKinesis struct { wg sync.WaitGroup } +// TODO: we need to clean up the metadata fields here and update this binding to use the builtin aws auth provider and reflect in metadata.yaml type kinesisMetadata struct { StreamName string `json:"streamName" mapstructure:"streamName"` ConsumerName string `json:"consumerName" mapstructure:"consumerName"` @@ -73,7 +74,7 @@ const ( // SharedThroughput - shared throughput using checkpoint and monitoring. SharedThroughput = "shared" - partitionKeyName = "partitionKey" + partitionKeyName = "partitionKey" // TODO: mv to metadata field instead ) // recordProcessorFactory. diff --git a/bindings/aws/kinesis/metadata.yaml b/bindings/aws/kinesis/metadata.yaml new file mode 100644 index 0000000000..b9563973cf --- /dev/null +++ b/bindings/aws/kinesis/metadata.yaml @@ -0,0 +1,66 @@ +# yaml-language-server: $schema=../../../component-metadata-schema.json +schemaVersion: v1 +type: bindings +name: aws.kinesis +version: v1 +status: alpha +title: "AWS Kinesis" +urls: + - title: Reference + url: https://docs.dapr.io/reference/components-reference/supported-bindings/kinesis/ +binding: + output: true + input: true + operations: + - name: create + description: "Send record to Kinesis stream" + - name: read + description: "Receive records from Kinesis stream" +authenticationProfiles: + - title: "AWS Access Key Authentication" + description: | + Authenticate using AWS access key credentials. + metadata: + - name: accessKey + required: true + description: "The AWS access key" + example: "AKIAIOSFODNN7EXAMPLE" + - name: secretKey + required: true + sensitive: true + description: "The AWS secret key" + example: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" + - name: sessionToken + required: false + sensitive: true + description: "The AWS session token" + example: "TOKEN" + - name: region + required: true + description: "The AWS region" + example: "us-east-1" +metadata: + - name: streamName + required: true + description: "The Kinesis stream name" + example: "my-stream" + - name: consumerName + required: false + description: "The consumer name for input binding" + example: "my-consumer" + - name: mode + required: false + description: "The consumer mode" + example: "shared" + default: "shared" + allowedValues: + - "shared" + - "extended" + - name: partitionKey + required: false + description: "The partition key for the Kinesis stream" + example: "partition-key" + - name: endpoint + required: false + description: "The Kinesis endpoint URL" + example: "http://localhost:4566" diff --git a/bindings/aws/ses/metadata.yaml b/bindings/aws/ses/metadata.yaml new file mode 100644 index 0000000000..fb2f48b074 --- /dev/null +++ b/bindings/aws/ses/metadata.yaml @@ -0,0 +1,60 @@ +# yaml-language-server: $schema=../../../component-metadata-schema.json +schemaVersion: v1 +type: bindings +name: aws.ses +version: v1 +status: stable +title: "AWS Simple Email Service (SES)" +urls: + - title: Reference + url: https://docs.dapr.io/reference/components-reference/supported-bindings/ses/ +binding: + output: true + input: false + operations: + - name: create + description: "Send email via AWS SES" +authenticationProfiles: + - title: "AWS Access Key Authentication" + description: | + Authenticate using AWS access key credentials. + metadata: + - name: accessKey + required: true + description: "The AWS access key" + example: "AKIAIOSFODNN7EXAMPLE" + - name: secretKey + required: true + sensitive: true + description: "The AWS secret key" + example: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" + - name: sessionToken + required: false + sensitive: true + description: "The AWS session token" + example: "TOKEN" + - name: region + required: true + description: "The AWS region" + example: "us-east-1" +metadata: + - name: emailFrom + required: true + description: "The sender email address" + example: "sender@example.com" + - name: emailTo + required: true + description: "The recipient email address" + example: "recipient@example.com" + - name: subject + required: true + description: "The email subject" + example: "Hello from Dapr" + - name: emailCc + required: false + description: "The email CC address" + example: "cc@example.com" + - name: emailBcc + required: false + description: "The email BCC address" + example: "bcc@example.com" diff --git a/bindings/aws/ses/ses.go b/bindings/aws/ses/ses.go index b8d2ff3faa..2fb9300f6e 100644 --- a/bindings/aws/ses/ses.go +++ b/bindings/aws/ses/ses.go @@ -43,6 +43,7 @@ type AWSSES struct { logger logger.Logger } +// TODO: the metadata fields need updating to use the builtin aws auth provider fully and reflect in metadata.yaml type sesMetadata struct { Region string `json:"region"` AccessKey string `json:"accessKey"` diff --git a/bindings/aws/sqs/metadata.yaml b/bindings/aws/sqs/metadata.yaml new file mode 100644 index 0000000000..3bb0d13cf7 --- /dev/null +++ b/bindings/aws/sqs/metadata.yaml @@ -0,0 +1,50 @@ +# yaml-language-server: $schema=../../../component-metadata-schema.json +schemaVersion: v1 +type: bindings +name: aws.sqs +version: v1 +status: alpha +title: "AWS SQS" +urls: + - title: Reference + url: https://docs.dapr.io/reference/components-reference/supported-bindings/sqs/ +binding: + output: true + input: true + operations: + - name: create + description: "Send message to SQS queue" + - name: read + description: "Receive messages from SQS queue" +authenticationProfiles: + - title: "AWS Access Key Authentication" + description: | + Authenticate using AWS access key credentials. + metadata: + - name: accessKey + required: true + description: "The AWS access key" + example: "AKIAIOSFODNN7EXAMPLE" + - name: secretKey + required: true + sensitive: true + description: "The AWS secret key" + example: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" + - name: sessionToken + required: false + sensitive: true + description: "The AWS session token" + example: '"TOKEN"' + - name: region + required: true + description: "The AWS region" + example: "us-east-1" +metadata: + - name: queueName + required: true + description: "The SQS queue name" + example: "my-queue" + - name: endpoint + required: false + description: "The SQS endpoint URL" + example: "http://localhost:4566" diff --git a/bindings/aws/sqs/sqs.go b/bindings/aws/sqs/sqs.go index b09fde61f6..7d979f009e 100644 --- a/bindings/aws/sqs/sqs.go +++ b/bindings/aws/sqs/sqs.go @@ -41,6 +41,7 @@ type AWSSQS struct { closed atomic.Bool } +// TODO: the metadata fields need updating to use the builtin aws auth provider fully and reflect in metadata.yaml type sqsMetadata struct { QueueName string `json:"queueName"` Region string `json:"region"` diff --git a/bindings/azure/cosmosdbgremlinapi/cosmosdbgremlinapi.go b/bindings/azure/cosmosdb/gremlinapi/cosmosdbgremlinapi.go similarity index 100% rename from bindings/azure/cosmosdbgremlinapi/cosmosdbgremlinapi.go rename to bindings/azure/cosmosdb/gremlinapi/cosmosdbgremlinapi.go diff --git a/bindings/azure/cosmosdbgremlinapi/cosmosdbgremlinapi_test.go b/bindings/azure/cosmosdb/gremlinapi/cosmosdbgremlinapi_test.go similarity index 100% rename from bindings/azure/cosmosdbgremlinapi/cosmosdbgremlinapi_test.go rename to bindings/azure/cosmosdb/gremlinapi/cosmosdbgremlinapi_test.go diff --git a/bindings/azure/cosmosdbgremlinapi/metadata.yaml b/bindings/azure/cosmosdb/gremlinapi/metadata.yaml similarity index 86% rename from bindings/azure/cosmosdbgremlinapi/metadata.yaml rename to bindings/azure/cosmosdb/gremlinapi/metadata.yaml index 609bd1aea9..765a8391da 100644 --- a/bindings/azure/cosmosdbgremlinapi/metadata.yaml +++ b/bindings/azure/cosmosdb/gremlinapi/metadata.yaml @@ -24,17 +24,17 @@ authenticationProfiles: sensitive: true description: | The key to authenticate to the Cosmos DB account. - example: '"my-secret-key"' + example: "my-secret-key" - name: username required: true sensitive: false description: | The username of the Cosmos DB database. - example: '"/dbs//colls/"' + example: "/dbs//colls/" metadata: - name: url type: string required: true description: | The Cosmos DB URL for Gremlin APIs - example: '"wss://******.gremlin.cosmos.azure.com:443/"' \ No newline at end of file + example: "wss://******.gremlin.cosmos.azure.com:443/" diff --git a/bindings/cloudflare/queues/metadata.yaml b/bindings/cloudflare/queues/metadata.yaml new file mode 100644 index 0000000000..fb7a4c7bce --- /dev/null +++ b/bindings/cloudflare/queues/metadata.yaml @@ -0,0 +1,68 @@ +# yaml-language-server: $schema=../../../component-metadata-schema.json +schemaVersion: v1 +type: bindings +name: cloudflare.queues +version: v1 +status: alpha +title: "Cloudflare Queues" +urls: + - title: Reference + url: https://docs.dapr.io/reference/components-reference/supported-bindings/cloudflare-queues/ +binding: + output: true + input: false + operations: + - name: create + description: "Send message to Cloudflare Queue" + - name: read + description: "Receive messages from Cloudflare Queue" +authenticationProfiles: + - title: "API Token Authentication" + description: | + Authenticate using Cloudflare API token and account ID. Dapr will create/manage the worker. + metadata: + - name: cfAPIToken + required: true + sensitive: true + description: "The Cloudflare API token" + example: "api-token" + - name: cfAccountID + required: true + description: "The Cloudflare account ID" + example: "account-id" + - name: key + required: true + sensitive: true + description: "The Ed25519 private key in PKCS#8 PEM format for JWT signing" + example: "-----BEGIN PRIVATE KEY-----\nXXX..." + - name: workerName + required: true + description: "The worker name for JWT token audience" + example: "worker" + - title: "Connect to Pre-deployed Worker" + description: | + Connect to a worker that has been pre-deployed and is ready to use. No API tokens needed. + metadata: + - name: workerUrl + required: true + description: "The Cloudflare worker URL" + example: "https://your-worker.your-subdomain.workers.dev" + - name: key + required: true + sensitive: true + description: "The Ed25519 private key in PKCS#8 PEM format for JWT signing" + example: "-----BEGIN PRIVATE KEY-----\nXXX..." + - name: workerName + required: true + description: "The worker name for JWT token audience" + example: "my-worker" +metadata: + - name: queueName + required: true + description: "The Cloudflare queue name" + example: "my-queue" + - name: timeoutInSeconds + required: false + description: "Timeout for network requests in seconds" + example: '20' + default: '20' diff --git a/bindings/commercetools/commercetools.go b/bindings/commercetools/commercetools.go index d48acba52b..fe36540f5a 100644 --- a/bindings/commercetools/commercetools.go +++ b/bindings/commercetools/commercetools.go @@ -40,12 +40,12 @@ type Data struct { } type commercetoolsMetadata struct { - Region string - Provider string - ProjectKey string - ClientID string - ClientSecret string - Scopes string + Region string `json:"region"` + Provider string `json:"provider"` + ProjectKey string `json:"projectKey"` + ClientID string `json:"clientID"` + ClientSecret string `json:"clientSecret"` + Scopes string `json:"scopes"` } func NewCommercetools(logger logger.Logger) bindings.OutputBinding { diff --git a/bindings/commercetools/metadata.yaml b/bindings/commercetools/metadata.yaml new file mode 100644 index 0000000000..e86bfdeffa --- /dev/null +++ b/bindings/commercetools/metadata.yaml @@ -0,0 +1,50 @@ +# yaml-language-server: $schema=../../component-metadata-schema.json +schemaVersion: v1 +type: bindings +name: commercetools +version: v1 +status: alpha +title: "Commercetools" +urls: + - title: Reference + url: https://docs.dapr.io/reference/components-reference/supported-bindings/commercetools/ +binding: + output: true + input: false + operations: + - name: create + description: "Create resource in Commercetools" +authenticationProfiles: + - title: "OAuth Client Authentication" + description: | + Authenticate using OAuth client credentials. + metadata: + - name: clientID + required: true + description: "The Commercetools client ID" + example: "client-id" + - name: clientSecret + required: true + sensitive: true + description: "The Commercetools client secret" + example: "client-secret" +metadata: + - name: projectKey + required: true + description: "The Commercetools project key" + example: "my-project" + - name: region + required: true + description: "The Commercetools region" + example: "gcp-europe-west1" + default: "gcp-europe-west1" + - name: provider + required: true + description: "The Commercetools provider" + example: "gcp" + default: "gcp" + - name: scopes + required: true + description: "The OAuth scopes" + example: "manage_project:my-project" + diff --git a/bindings/dubbo/metadata.yaml b/bindings/dubbo/metadata.yaml new file mode 100644 index 0000000000..198d3bb8cf --- /dev/null +++ b/bindings/dubbo/metadata.yaml @@ -0,0 +1,41 @@ +# yaml-language-server: $schema=../../component-metadata-schema.json +schemaVersion: v1 +type: bindings +name: dubbo +version: v1 +status: alpha +title: "Apache Dubbo" +urls: + - title: Reference + url: https://docs.dapr.io/reference/components-reference/supported-bindings/ +binding: + output: true + input: false + operations: + - name: create + description: "Invoke Dubbo service" +metadata: + - name: interfaceName + required: true + description: "The Dubbo interface name" + example: "com.example.UserService" + - name: methodName + required: true + description: "The method name to invoke" + example: "getUser" + - name: version + required: false + description: "The service version" + example: "1.0.0" + - name: group + required: false + description: "The service group" + example: "mygroup" + - name: providerHostname + required: false + description: "The provider hostname" + example: "localhost" + - name: providerPort + required: false + description: "The provider port" + example: '8080' diff --git a/bindings/gcp/pubsub/metadata.yaml b/bindings/gcp/pubsub/metadata.yaml new file mode 100644 index 0000000000..cb8e847682 --- /dev/null +++ b/bindings/gcp/pubsub/metadata.yaml @@ -0,0 +1,29 @@ +# yaml-language-server: $schema=../../../component-metadata-schema.json +schemaVersion: v1 +type: bindings +name: gcp.pubsub +version: v1 +status: alpha +title: "Google Cloud Pub/Sub" +urls: + - title: Reference + url: https://docs.dapr.io/reference/components-reference/supported-bindings/pubsub/ +binding: + output: true + input: true + operations: + - name: create + description: "Publish message to Pub/Sub topic" + - name: read + description: "Receive messages from Pub/Sub subscription" +builtinAuthenticationProfiles: + - name: "gcp" +metadata: + - name: topic + required: true + description: "The Pub/Sub topic name" + example: "my-topic" + - name: subscription + required: false + description: "The Pub/Sub subscription name" + example: "my-subscription" diff --git a/bindings/gcp/pubsub/pubsub.go b/bindings/gcp/pubsub/pubsub.go index dfc8a69787..bf89d91aef 100644 --- a/bindings/gcp/pubsub/pubsub.go +++ b/bindings/gcp/pubsub/pubsub.go @@ -28,6 +28,7 @@ import ( "github.com/dapr/components-contrib/bindings" contribMetadata "github.com/dapr/components-contrib/metadata" "github.com/dapr/kit/logger" + kitmd "github.com/dapr/kit/metadata" ) const ( @@ -46,10 +47,27 @@ type GCPPubSub struct { wg sync.WaitGroup } +// These JSON tags directly match the builtin auth provider metadata fields for GCP. type pubSubMetadata struct { - Topic string `json:"topic"` - Subscription string `json:"subscription"` - Type string `json:"type"` + Topic string `json:"topic" mapstructure:"topic"` + Subscription string `json:"subscription" mapstructure:"subscription"` + + // Note: the mdignore is to ignore these fields on the metadata analyzer, + // as these fields are parsed and used by the builtin auth provider, + // so they are still captured in the metadata.yaml file and in parsing. + Type string `json:"type" mapstructure:"type" mdignore:"true"` + ProjectID string `json:"projectID" mapstructure:"project_id" mapstructurealiases:"projectID" mdignore:"true"` + PrivateKeyID string `json:"privateKeyID" mapstructure:"private_key_id" mapstructurealiases:"privateKeyID" mdignore:"true"` + PrivateKey string `json:"privateKey" mapstructure:"private_key" mapstructurealiases:"privateKey" mdignore:"true"` + ClientEmail string `json:"clientEmail" mapstructure:"client_email" mapstructurealiases:"clientEmail" mdignore:"true"` + ClientID string `json:"clientID" mapstructure:"client_id" mapstructurealiases:"clientID" mdignore:"true"` + AuthURI string `json:"authURI" mapstructure:"auth_uri" mapstructurealiases:"authURI" mdignore:"true"` + TokenURI string `json:"tokenURI" mapstructure:"token_uri" mapstructurealiases:"tokenURI" mdignore:"true"` + AuthProviderX509CertURL string `json:"authProviderX509CertURL" mapstructure:"auth_provider_x509_cert_url" mapstructurealiases:"authProviderX509CertURL" mdignore:"true"` + ClientX509CertURL string `json:"clientX509CertURL" mapstructure:"client_x509_cert_url" mapstructurealiases:"clientX509CertURL" mdignore:"true"` +} + +type GCPAuthJSON struct { ProjectID string `json:"project_id"` PrivateKeyID string `json:"private_key_id"` PrivateKey string `json:"private_key"` @@ -59,6 +77,7 @@ type pubSubMetadata struct { TokenURI string `json:"token_uri"` AuthProviderCertURL string `json:"auth_provider_x509_cert_url"` ClientCertURL string `json:"client_x509_cert_url"` + Type string `json:"type"` } // NewGCPPubSub returns a new GCPPubSub instance. @@ -71,20 +90,39 @@ func NewGCPPubSub(logger logger.Logger) bindings.InputOutputBinding { // Init parses metadata and creates a new Pub Sub client. func (g *GCPPubSub) Init(ctx context.Context, metadata bindings.Metadata) error { - b, err := g.parseMetadata(metadata) + var ( + pubsubMeta pubSubMetadata + pubsubClient *pubsub.Client + ) + err := kitmd.DecodeMetadata(metadata.Properties, &pubsubMeta) if err != nil { return err } - var pubsubMeta pubSubMetadata - err = json.Unmarshal(b, &pubsubMeta) - if err != nil { - return err - } - clientOptions := option.WithCredentialsJSON(b) - pubsubClient, err := pubsub.NewClient(ctx, pubsubMeta.ProjectID, clientOptions) - if err != nil { - return fmt.Errorf("error creating pubsub client: %s", err) + if pubsubMeta.PrivateKeyID != "" { + authJSON := &GCPAuthJSON{ + ProjectID: pubsubMeta.ProjectID, + PrivateKeyID: pubsubMeta.PrivateKeyID, + PrivateKey: pubsubMeta.PrivateKey, + ClientEmail: pubsubMeta.ClientEmail, + ClientID: pubsubMeta.ClientID, + AuthURI: pubsubMeta.AuthURI, + TokenURI: pubsubMeta.TokenURI, + AuthProviderCertURL: pubsubMeta.AuthProviderX509CertURL, + ClientCertURL: pubsubMeta.ClientX509CertURL, + Type: pubsubMeta.Type, + } + gcpCompatibleJSON, _ := json.Marshal(authJSON) + clientOptions := option.WithCredentialsJSON(gcpCompatibleJSON) + pubsubClient, err = pubsub.NewClient(ctx, pubsubMeta.ProjectID, clientOptions) + if err != nil { + return fmt.Errorf("error creating pubsub client: %s", err) + } + } else { + pubsubClient, err = pubsub.NewClient(ctx, pubsubMeta.ProjectID) + if err != nil { + return fmt.Errorf("error creating pubsub client: %s", err) + } } g.client = pubsubClient @@ -93,10 +131,6 @@ func (g *GCPPubSub) Init(ctx context.Context, metadata bindings.Metadata) error return nil } -func (g *GCPPubSub) parseMetadata(metadata bindings.Metadata) ([]byte, error) { - return json.Marshal(metadata.Properties) -} - func (g *GCPPubSub) Read(ctx context.Context, handler bindings.Handler) error { if g.closed.Load() { return errors.New("binding is closed") diff --git a/bindings/gcp/pubsub/pubsub_test.go b/bindings/gcp/pubsub/pubsub_test.go index cd4d3f8171..8da98de3e1 100644 --- a/bindings/gcp/pubsub/pubsub_test.go +++ b/bindings/gcp/pubsub/pubsub_test.go @@ -14,14 +14,13 @@ limitations under the License. package pubsub import ( - "encoding/json" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/dapr/components-contrib/bindings" - "github.com/dapr/kit/logger" + kitmd "github.com/dapr/kit/metadata" ) func TestInit(t *testing.T) { @@ -30,19 +29,15 @@ func TestInit(t *testing.T) { "auth_provider_x509_cert_url": "https://auth", "auth_uri": "https://auth", "client_x509_cert_url": "https://cert", "client_email": "test@test.com", "client_id": "id", "private_key": "****", "private_key_id": "key_id", "project_id": "project1", "token_uri": "https://token", "type": "serviceaccount", "topic": "t1", "subscription": "s1", } - ps := GCPPubSub{logger: logger.NewLogger("test")} - b, err := ps.parseMetadata(m) - require.NoError(t, err) - var pubsubMeta pubSubMetadata - err = json.Unmarshal(b, &pubsubMeta) + err := kitmd.DecodeMetadata(m.Properties, &pubsubMeta) require.NoError(t, err) assert.Equal(t, "s1", pubsubMeta.Subscription) assert.Equal(t, "t1", pubsubMeta.Topic) - assert.Equal(t, "https://auth", pubsubMeta.AuthProviderCertURL) + assert.Equal(t, "https://auth", pubsubMeta.AuthProviderX509CertURL) assert.Equal(t, "https://auth", pubsubMeta.AuthURI) - assert.Equal(t, "https://cert", pubsubMeta.ClientCertURL) + assert.Equal(t, "https://cert", pubsubMeta.ClientX509CertURL) assert.Equal(t, "test@test.com", pubsubMeta.ClientEmail) assert.Equal(t, "id", pubsubMeta.ClientID) assert.Equal(t, "****", pubsubMeta.PrivateKey) @@ -51,3 +46,43 @@ func TestInit(t *testing.T) { assert.Equal(t, "https://token", pubsubMeta.TokenURI) assert.Equal(t, "serviceaccount", pubsubMeta.Type) } + +func TestInit_MetadataCaseInsensitive(t *testing.T) { + t.Run("snake_case metadata", func(t *testing.T) { + m := bindings.Metadata{} + m.Properties = map[string]string{ + "project_id": "snake-project", + "private_key_id": "snake-key", + "client_email": "snake@test.com", + "topic": "snake-topic", + } + + var pubsubMeta pubSubMetadata + err := kitmd.DecodeMetadata(m.Properties, &pubsubMeta) + require.NoError(t, err) + + assert.Equal(t, "snake-project", pubsubMeta.ProjectID) + assert.Equal(t, "snake-key", pubsubMeta.PrivateKeyID) + assert.Equal(t, "snake@test.com", pubsubMeta.ClientEmail) + assert.Equal(t, "snake-topic", pubsubMeta.Topic) + }) + + t.Run("camelCase metadata", func(t *testing.T) { + m := bindings.Metadata{} + m.Properties = map[string]string{ + "projectID": "camel-project", + "privateKeyID": "camel-key", + "clientEmail": "camel@test.com", + "topic": "camel-topic", + } + + var pubsubMeta pubSubMetadata + err := kitmd.DecodeMetadata(m.Properties, &pubsubMeta) + require.NoError(t, err) + + assert.Equal(t, "camel-project", pubsubMeta.ProjectID) + assert.Equal(t, "camel-key", pubsubMeta.PrivateKeyID) + assert.Equal(t, "camel@test.com", pubsubMeta.ClientEmail) + assert.Equal(t, "camel-topic", pubsubMeta.Topic) + }) +} diff --git a/bindings/graphql/metadata.yaml b/bindings/graphql/metadata.yaml new file mode 100644 index 0000000000..e7c0fb075b --- /dev/null +++ b/bindings/graphql/metadata.yaml @@ -0,0 +1,21 @@ +# yaml-language-server: $schema=../../component-metadata-schema.json +schemaVersion: v1 +type: bindings +name: graphql +version: v1 +status: alpha +title: "GraphQL" +urls: + - title: Reference + url: https://docs.dapr.io/reference/components-reference/supported-bindings/graphql/ +binding: + output: true + input: false + operations: + - name: create + description: "Execute GraphQL query or mutation" +metadata: + - name: endpoint + required: true + description: "The GraphQL endpoint URL" + example: "https://api.example.com/graphql" diff --git a/bindings/huawei/obs/metadata.yaml b/bindings/huawei/obs/metadata.yaml new file mode 100644 index 0000000000..09d7e5c629 --- /dev/null +++ b/bindings/huawei/obs/metadata.yaml @@ -0,0 +1,43 @@ +# yaml-language-server: $schema=../../../component-metadata-schema.json +schemaVersion: v1 +type: bindings +name: huawei.obs +version: v1 +status: alpha +title: "Huawei Object Storage Service (OBS)" +urls: + - title: Reference + url: https://docs.dapr.io/reference/components-reference/supported-bindings/huawei-obs +binding: + output: true + input: false + operations: + - name: create + description: "Upload file to OBS" +authenticationProfiles: + - title: "Access Key Authentication" + description: | + Authenticate using Huawei Cloud access key credentials. + metadata: + - name: accessKey + required: true + description: "The Huawei Cloud access key ID" + example: "access-key-id" + - name: secretKey + required: true + sensitive: true + description: "The Huawei Cloud secret access key" + example: "secret-access-key" + - name: region + required: true + description: "The Huawei Cloud region" + example: "cn-north-4" +metadata: + - name: endpoint + required: true + description: "The OBS endpoint" + example: "https://obs.cn-north-4.myhuaweicloud.com" + - name: bucket + required: true + description: "The OBS bucket name" + example: "bucket-name" diff --git a/bindings/influx/metadata.yaml b/bindings/influx/metadata.yaml new file mode 100644 index 0000000000..a33810eaed --- /dev/null +++ b/bindings/influx/metadata.yaml @@ -0,0 +1,43 @@ +# yaml-language-server: $schema=../../component-metadata-schema.json +schemaVersion: v1 +type: bindings +name: influx +version: v1 +status: alpha +title: "InfluxDB" +urls: + - title: Reference + url: https://docs.dapr.io/reference/components-reference/supported-bindings/influxdb/ +binding: + output: true + input: false + operations: + - name: create + description: "Write data points to InfluxDB" +authenticationProfiles: + - title: "Token Authentication" + description: | + Authenticate using InfluxDB token. + metadata: + - name: token + required: true + sensitive: true + description: "The InfluxDB authentication token" + example: "your-influxdb-token" +metadata: + - name: url + required: true + description: "The InfluxDB server URL" + example: "http://localhost:8086" + - name: org + required: true + description: "The InfluxDB organization name" + example: "your-org" + - name: bucket + required: true + description: "The InfluxDB bucket name" + example: "your-bucket" + - name: measurement + required: true + description: "The measurement name" + example: "cpu_usage" diff --git a/bindings/kitex/metadata.yaml b/bindings/kitex/metadata.yaml new file mode 100644 index 0000000000..64d161d661 --- /dev/null +++ b/bindings/kitex/metadata.yaml @@ -0,0 +1,33 @@ +# yaml-language-server: $schema=../../component-metadata-schema.json +schemaVersion: v1 +type: bindings +name: kitex +version: v1 +status: alpha +title: "Kitex" +urls: + - title: Reference + url: https://docs.dapr.io/reference/components-reference/supported-bindings/kitex/ +binding: + output: true + input: false + operations: + - name: create + description: "Invoke Kitex service" +metadata: + - name: serviceName + required: true + description: "The Kitex service name" + example: "my-service" + - name: methodName + required: true + description: "The method name to invoke" + example: "getUser" + - name: destService + required: true + description: "The destination service name" + example: "my-service" + - name: hostPorts + required: true + description: "The service address" + example: "localhost:8080" diff --git a/bindings/kubemq/metadata.yaml b/bindings/kubemq/metadata.yaml new file mode 100644 index 0000000000..b47dc28557 --- /dev/null +++ b/bindings/kubemq/metadata.yaml @@ -0,0 +1,56 @@ +# yaml-language-server: $schema=../../component-metadata-schema.json +schemaVersion: v1 +type: bindings +name: kubemq +version: v1 +status: beta +title: "KubeMQ" +urls: + - title: Reference + url: https://docs.dapr.io/reference/components-reference/supported-bindings/kubemq/ +binding: + output: true + input: true + operations: + - name: create + description: "Send message to KubeMQ" + - name: read + description: "Receive messages from KubeMQ" +authenticationProfiles: + - title: "Token Authentication" + description: "Connect to KubeMQ using an authentication token." + metadata: + - name: authToken + type: string + required: true + description: The authentication token for KubeMQ. + example: "auth-token" +metadata: + - name: address + type: string + required: true + description: The KubeMQ server address in format host:port. + example: "localhost:50000" + - name: channel + type: string + required: true + description: The KubeMQ channel name. + example: "my-channel" + - name: pollMaxItems + type: int + required: false + description: The maximum number of items to poll. + example: 10 + default: 1 + - name: pollTimeoutSeconds + type: int + required: false + description: The timeout in seconds for polling. + example: 3600 + default: 3600 + - name: autoAcknowledged + type: bool + required: false + description: Whether to automatically acknowledge messages. + example: true + default: false diff --git a/bindings/kubernetes/kubernetes.go b/bindings/kubernetes/kubernetes.go index f41bc88cba..07a2d9b966 100644 --- a/bindings/kubernetes/kubernetes.go +++ b/bindings/kubernetes/kubernetes.go @@ -52,9 +52,12 @@ type EventResponse struct { } type kubernetesMetadata struct { - Namespace string `mapstructure:"namespace"` - KubeconfigPath string `mapstructure:"kubeconfigPath"` - ResyncPeriod time.Duration `mapstructure:"resyncPeriod" mapstructurealiases:"resyncPeriodInSec"` + Namespace string `mapstructure:"namespace"` + KubeconfigPath string `mapstructure:"kubeconfigPath"` + // Note: we add mdignore to this so the metadata parser doesn't throw an error if resyncPeriodInSec on the metadata.yaml file. + // It has the ResyncPeriodInSec as a field, but we don't need users to see both resyncPeriod and resyncPeriodInSec, + // so the mdignore is just to make CI happy since we support both representations. + ResyncPeriod time.Duration `mapstructure:"resyncPeriod" mapstructurealiases:"resyncPeriodInSec" mdignore:"true"` } // NewKubernetes returns a new Kubernetes event input binding. @@ -121,7 +124,7 @@ func (k *kubernetesInput) Read(ctx context.Context, handler bindings.Handler) er &corev1.Event{}, k.metadata.ResyncPeriod, cache.ResourceEventHandlerFuncs{ - AddFunc: func(obj interface{}) { + AddFunc: func(obj any) { if obj != nil { resultChan <- EventResponse{ Event: "add", @@ -132,7 +135,7 @@ func (k *kubernetesInput) Read(ctx context.Context, handler bindings.Handler) er k.logger.Warnf("Nil Object in Add handle %v", obj) } }, - DeleteFunc: func(obj interface{}) { + DeleteFunc: func(obj any) { if obj != nil { resultChan <- EventResponse{ Event: "delete", @@ -143,7 +146,7 @@ func (k *kubernetesInput) Read(ctx context.Context, handler bindings.Handler) er k.logger.Warnf("Nil Object in Delete handle %v", obj) } }, - UpdateFunc: func(oldObj, newObj interface{}) { + UpdateFunc: func(oldObj, newObj any) { if oldObj != nil && newObj != nil { resultChan <- EventResponse{ Event: "update", diff --git a/bindings/kubernetes/metadata.yaml b/bindings/kubernetes/metadata.yaml new file mode 100644 index 0000000000..237e4b3a4c --- /dev/null +++ b/bindings/kubernetes/metadata.yaml @@ -0,0 +1,33 @@ +# yaml-language-server: $schema=../../component-metadata-schema.json +schemaVersion: v1 +type: bindings +name: kubernetes +version: v1 +status: alpha +title: "Kubernetes Events" +urls: + - title: Reference + url: https://docs.dapr.io/reference/components-reference/supported-bindings/kubernetes-binding/ +binding: + output: false + input: true + operations: + - name: read + description: "Read Kubernetes events" +metadata: + - name: namespace + required: false + description: "The Kubernetes namespace" + example: "default" + default: "default" + - name: kubeconfigPath + required: false + description: "The path to the kubeconfig file" + example: "~/.kube/config" + default: "~/.kube/config" + - name: resyncPeriodInSec + required: false + type: duration + description: "The resync period in seconds" + example: '30s' + default: '10s' diff --git a/bindings/localstorage/metadata.yaml b/bindings/localstorage/metadata.yaml new file mode 100644 index 0000000000..58107c88d9 --- /dev/null +++ b/bindings/localstorage/metadata.yaml @@ -0,0 +1,25 @@ +# yaml-language-server: $schema=../../component-metadata-schema.json +schemaVersion: v1 +type: bindings +name: localstorage +version: v1 +status: stable +title: "Local Storage" +urls: + - title: Reference + url: https://docs.dapr.io/reference/components-reference/supported-bindings/localstorage/ +binding: + output: true + input: false + operations: + - name: create + description: "Write file to local storage" +metadata: + - name: rootPath + required: true + description: "The root directory path" + example: "/tmp/dapr" + - name: fileName + required: true + description: "The file name to write" + example: "data.txt" diff --git a/bindings/mqtt3/metadata.go b/bindings/mqtt3/metadata.go index b9fd05abe2..5bc38066f1 100644 --- a/bindings/mqtt3/metadata.go +++ b/bindings/mqtt3/metadata.go @@ -25,16 +25,14 @@ import ( const ( // Keys. - mqttURL = "url" - mqttTopic = "topic" - mqttQOS = "qos" // This key is deprecated - mqttRetain = "retain" - mqttClientID = "consumerID" - mqttCleanSession = "cleanSession" - mqttCACert = "caCert" - mqttClientCert = "clientCert" - mqttClientKey = "clientKey" - mqttBackOffMaxRetries = "backOffMaxRetries" + mqttURL = "url" + mqttTopic = "topic" + mqttQOS = "qos" // This key is deprecated + mqttRetain = "retain" + mqttCleanSession = "cleanSession" + mqttCACert = "caCert" + mqttClientCert = "clientCert" + mqttClientKey = "clientKey" // Defaults. defaultQOS = 1 diff --git a/bindings/mqtt3/metadata.yaml b/bindings/mqtt3/metadata.yaml new file mode 100644 index 0000000000..6fe6404bca --- /dev/null +++ b/bindings/mqtt3/metadata.yaml @@ -0,0 +1,64 @@ +# yaml-language-server: $schema=../../component-metadata-schema.json +schemaVersion: v1 +type: bindings +name: mqtt3 +version: v1 +status: beta +title: "MQTT v3" +urls: + - title: Reference + url: https://docs.dapr.io/reference/components-reference/supported-bindings/mqtt3/ +binding: + output: true + input: true + operations: + - name: create + description: "Publish message to MQTT topic" + - name: read + description: "Subscribe to MQTT topic" +authenticationProfiles: + - title: "TLS Authentication" + description: | + Authenticate using TLS certificates. + metadata: + - name: caCert + required: true + description: "CA certificate for TLS" + example: "-----BEGIN CERTIFICATE-----\n..." + - name: clientCert + required: true + description: "Client certificate for TLS" + example: "-----BEGIN CERTIFICATE-----\n..." + - name: clientKey + required: true + sensitive: true + description: "Client private key for TLS" + example: "-----BEGIN PRIVATE KEY-----\n..." +metadata: + - name: url + required: true + description: "The MQTT broker URL" + example: "tcp://localhost:1883" + - name: topic + required: true + description: "The MQTT topic" + example: "my-topic" + - name: consumerID + required: false + description: "The MQTT client ID" + example: "my-client" + - name: retain + required: false + description: "Whether to retain messages" + example: false + default: false + - name: cleanSession + required: false + description: "Whether to use clean session" + example: true + default: true + - name: backOffMaxRetries + required: false + description: "Maximum retries for backoff" + example: '3' + default: '3' diff --git a/bindings/postmark/metadata.yaml b/bindings/postmark/metadata.yaml new file mode 100644 index 0000000000..a634279f5f --- /dev/null +++ b/bindings/postmark/metadata.yaml @@ -0,0 +1,45 @@ +# yaml-language-server: $schema=../../component-metadata-schema.json +schemaVersion: v1 +type: bindings +name: postmark +version: v1 +status: alpha +title: "Postmark" +urls: + - title: Reference + url: https://docs.dapr.io/reference/components-reference/supported-bindings/postmark/ +binding: + output: true + input: false + operations: + - name: create + description: "Send an email using Postmark" +metadata: + - name: serverToken + required: true + description: "The Postmark server token" + example: "your-server-token" + - name: accountToken + required: true + description: "The Postmark account token" + example: "your-account-token" + - name: emailFrom + required: false + description: "The sender email address" + example: "sender@example.com" + - name: emailTo + required: false + description: "The recipient email address" + example: "recipient@example.com" + - name: subject + required: false + description: "The email subject" + example: "Hello from Dapr" + - name: emailCc + required: false + description: "The CC email address" + example: "cc@example.com" + - name: emailBcc + required: false + description: "The BCC email address" + example: "bcc@example.com" diff --git a/bindings/rethinkdb/statechange/metadata.yaml b/bindings/rethinkdb/statechange/metadata.yaml new file mode 100644 index 0000000000..63b3b0a2ce --- /dev/null +++ b/bindings/rethinkdb/statechange/metadata.yaml @@ -0,0 +1,158 @@ +# yaml-language-server: $schema=../../../component-metadata-schema.json +schemaVersion: v1 +type: bindings +name: rethinkdb.statechange +version: v1 +status: beta +title: "RethinkDB State Change" +urls: + - title: Reference + url: https://docs.dapr.io/reference/components-reference/supported-bindings/rethinkdb/ +binding: + output: false + input: true + operations: + - name: read + description: "Listen for state changes in RethinkDB" +authenticationProfiles: + - title: "Basic Authentication" + description: "Authenticate using username and password." + metadata: + - name: address + type: string + required: false + description: The RethinkDB server address. + example: "localhost:28015" + - name: addresses + type: string + required: false + description: Comma-separated list of RethinkDB server addresses. + example: "localhost:28015,localhost:28016" + - name: database + type: string + required: true + description: The RethinkDB database name. + example: "dapr" + default: "" + - name: username + type: string + required: false + description: The username for authentication. If not provided, the admin user is used for v1 handshake protocol. + example: "admin" + - name: password + type: string + required: false + description: The password for authentication. This is only used for v1 handshake protocol. + example: "password" + - title: "TLS Authentication" + description: "Authenticate using client certificate and key." + metadata: + - name: enableTLS + type: bool + required: false + description: Whether to enable TLS encryption. + example: false + default: false + - name: clientCert + type: string + required: true + description: The client certificate for TLS authentication. + example: "-----BEGIN CERTIFICATE-----\nXXX..." + - name: clientKey + type: string + required: true + description: The client key for TLS authentication. + example: "-----BEGIN PRIVATE KEY-----\nXXX..." + sensitive: true +metadata: + - name: table + type: string + required: false + description: The table name to store state data. + example: "daprstate" + default: "daprstate" + - name: archive + type: bool + required: false + description: Whether to archive changes to a separate table. + example: false + default: false + - name: timeout + type: string + required: false + description: Connection timeout duration. + example: "10s" + - name: useJSONNumber + type: bool + required: false + description: Whether to use json.Number instead of float64. + example: false + default: false + - name: numRetries + type: number + required: false + description: Number of times to retry queries on connection errors. + example: 3 + - name: hostDecayDuration + type: string + required: false + description: Host decay duration for weighted host selection. + example: "5m" + default: "5m" + - name: useOpentracing + type: bool + required: false + description: Whether to enable opentracing for queries. + example: false + default: false + - name: writeTimeout + type: string + required: false + description: Write timeout duration." + example: "10s" + - name: readTimeout + type: string + required: false + description: Read timeout duration." + example: "10s" + - name: handshakeVersion + type: number + required: false + description: Handshake version for RethinkDB." + example: 1 + - name: keepAlivePeriod + type: string + required: false + description: Keep alive period duration." + example: "30s" + - name: maxIdle + type: number + required: false + description: Maximum number of idle connections." + example: 5 + - name: authKey + type: string + required: false + description: The authentication key for RethinkDB. This field is now deprecated." + example: "auth-key" + sensitive: true + - name: initialCap + type: number + required: false + description: Initial connection pool capacity." + example: 5 + - name: maxOpen + type: number + required: false + description: Maximum number of open connections." + example: 10 + - name: discoverHosts + type: bool + required: false + description: Whether to discover hosts." + example: false + - name: nodeRefreshInterval + type: string + required: false + description: Node refresh interval duration." + example: "5m" diff --git a/bindings/rethinkdb/statechange/statechange.go b/bindings/rethinkdb/statechange/statechange.go index 8f53c9cc52..74e7bbba29 100644 --- a/bindings/rethinkdb/statechange/statechange.go +++ b/bindings/rethinkdb/statechange/statechange.go @@ -15,6 +15,7 @@ package statechange import ( "context" + "crypto/tls" "encoding/json" "errors" "fmt" @@ -22,6 +23,7 @@ import ( "strings" "sync" "sync/atomic" + "time" r "github.com/dancannon/gorethink" @@ -44,8 +46,37 @@ type Binding struct { // StateConfig is the binding config. type StateConfig struct { - r.ConnectOpts `mapstructure:",squash"` - Table string `mapstructure:"table"` + ConnectOptsWrapper `mapstructure:",squash"` + Table string `mapstructure:"table"` +} + +// ConnectOptsWrapper wraps r.ConnectOpts but excludes TLSConfig +// This is needed because the metadata decoder does not support nested structs with tags as inputs in the metadata.yaml file +type ConnectOptsWrapper struct { + Address string `gorethink:"address,omitempty"` + Addresses []string `gorethink:"addresses,omitempty"` + Database string `gorethink:"database,omitempty"` + Username string `gorethink:"username,omitempty"` + Password string `gorethink:"password,omitempty"` + AuthKey string `gorethink:"authkey,omitempty"` + Timeout time.Duration `gorethink:"timeout,omitempty"` + WriteTimeout time.Duration `gorethink:"write_timeout,omitempty"` + ReadTimeout time.Duration `gorethink:"read_timeout,omitempty"` + KeepAlivePeriod time.Duration `gorethink:"keep_alive_timeout,omitempty"` + HandshakeVersion int `gorethink:"handshake_version,omitempty"` + MaxIdle int `gorethink:"max_idle,omitempty"` + InitialCap int `gorethink:"initial_cap,omitempty"` + MaxOpen int `gorethink:"max_open,omitempty"` + DiscoverHosts bool `gorethink:"discover_hosts,omitempty"` + NodeRefreshInterval time.Duration `gorethink:"node_refresh_interval,omitempty"` + UseJSONNumber bool `gorethink:"use_json_number,omitempty"` + NumRetries int `gorethink:"num_retries,omitempty"` + HostDecayDuration time.Duration `gorethink:"host_decay_duration,omitempty"` + UseOpentracing bool `gorethink:"use_opentracing,omitempty"` + // TLS fields must be brought in as separate fields as they will not be processed by the metadata decoder properly without this + EnableTLS bool `gorethink:"enable_tls,omitempty"` + ClientCert string `gorethink:"client_cert,omitempty"` + ClientKey string `gorethink:"client_key,omitempty"` } // NewRethinkDBStateChangeBinding returns a new RethinkDB actor event input binding. @@ -64,7 +95,40 @@ func (b *Binding) Init(ctx context.Context, metadata bindings.Metadata) error { } b.config = cfg - ses, err := r.Connect(b.config.ConnectOpts) + // Convert wrapper to r.ConnectOpts + connectOpts := r.ConnectOpts{ + Address: cfg.Address, + Addresses: cfg.Addresses, + Database: cfg.Database, + Username: cfg.Username, + Password: cfg.Password, + AuthKey: cfg.AuthKey, + Timeout: cfg.Timeout, + WriteTimeout: cfg.WriteTimeout, + ReadTimeout: cfg.ReadTimeout, + KeepAlivePeriod: cfg.KeepAlivePeriod, + HandshakeVersion: r.HandshakeVersion(cfg.HandshakeVersion), + MaxIdle: cfg.MaxIdle, + InitialCap: cfg.InitialCap, + MaxOpen: cfg.MaxOpen, + DiscoverHosts: cfg.DiscoverHosts, + NodeRefreshInterval: cfg.NodeRefreshInterval, + UseJSONNumber: cfg.UseJSONNumber, + NumRetries: cfg.NumRetries, + HostDecayDuration: cfg.HostDecayDuration, + UseOpentracing: cfg.UseOpentracing, + } + + // Configure TLS if enabled + if cfg.EnableTLS { + tlsConfig, tlsErr := createTLSConfig(cfg.ClientCert, cfg.ClientKey) + if tlsErr != nil { + return fmt.Errorf("error creating TLS config: %w", tlsErr) + } + connectOpts.TLSConfig = tlsConfig + } + + ses, err := r.Connect(connectOpts) if err != nil { return fmt.Errorf("error connecting to the database: %w", err) } @@ -73,6 +137,23 @@ func (b *Binding) Init(ctx context.Context, metadata bindings.Metadata) error { return nil } +// createTLSConfig creates a tls.Config from client certificate and key +func createTLSConfig(clientCert, clientKey string) (*tls.Config, error) { + if clientCert == "" || clientKey == "" { + return nil, errors.New("both client certificate and key are required for TLS") + } + + cert, err := tls.X509KeyPair([]byte(clientCert), []byte(clientKey)) + if err != nil { + return nil, fmt.Errorf("error parsing client certificate and key: %w", err) + } + + return &tls.Config{ + Certificates: []tls.Certificate{cert}, + MinVersion: tls.VersionTLS12, + }, nil +} + // Read triggers the RethinkDB scheduler. func (b *Binding) Read(ctx context.Context, handler bindings.Handler) error { if b.closed.Load() { @@ -107,7 +188,7 @@ func (b *Binding) Read(ctx context.Context, handler bindings.Handler) error { go func() { defer b.wg.Done() for readCtx.Err() == nil { - var change interface{} + var change any ok := cursor.Next(&change) if !ok { b.logger.Errorf("error detecting change: %v", cursor.Err()) @@ -149,7 +230,7 @@ func (b *Binding) Close() error { return b.session.Close() } -func metadataToConfig(cfg map[string]string, logger logger.Logger) (StateConfig, error) { +func metadataToConfig(cfg map[string]string, _ logger.Logger) (StateConfig, error) { c := StateConfig{} // prepare metadata keys for decoding diff --git a/bindings/rocketmq/metadata.yaml b/bindings/rocketmq/metadata.yaml new file mode 100644 index 0000000000..3d87c0dcad --- /dev/null +++ b/bindings/rocketmq/metadata.yaml @@ -0,0 +1,77 @@ +# yaml-language-server: $schema=../../component-metadata-schema.json +schemaVersion: v1 +type: bindings +name: rocketmq +version: v1 +status: alpha +title: "Apache RocketMQ" +urls: + - title: Reference + url: https://docs.dapr.io/reference/components-reference/supported-bindings/ +binding: + output: true + input: true + operations: + - name: create + description: "Send message to RocketMQ topic" + - name: read + description: "Receive messages from RocketMQ topic" +authenticationProfiles: + - title: "Access Key Authentication" + description: | + Authenticate with RocketMQ using access key and secret. + metadata: + - name: accessKey + required: true + description: "The access key for authentication" + example: "access-key" + - name: secretKey + required: true + sensitive: true + description: "The secret key for authentication" + example: "secret-key" +metadata: + - name: accessProto + required: false + description: "SDK protocol" + example: "tcp" + allowedValues: + - "tcp" + - "tcp-cgo" + - "http" + - name: nameServer + required: false + description: "The RocketMQ name server address" + example: "localhost:9876" + - name: endpoint + required: false + description: "The RocketMQ endpoint (for http proto)" + example: "http://localhost:8080" + - name: consumerGroup + required: false + description: "Consumer group for RocketMQ subscribers" + example: "my-consumer-group" + - name: consumerBatchSize + required: false + description: "Consumer batch size" + example: '10' + - name: consumerThreadNums + required: false + description: "Consumer thread numbers (for tcp-cgo proto)" + example: '4' + - name: instanceId + required: false + description: "RocketMQ namespace" + example: "my-instance" + - name: nameServerDomain + required: false + description: "RocketMQ name server domain" + example: "rocketmq.example.com" + - name: retries + required: false + description: "Retry times to connect to RocketMQ broker" + example: '3' + - name: topics + required: true + description: "Topics to subscribe (comma-separated for multiple topics)" + example: "topic1,topic2,topic3" diff --git a/bindings/rocketmq/settings.go b/bindings/rocketmq/settings.go index de3f7932eb..a2588da2ae 100644 --- a/bindings/rocketmq/settings.go +++ b/bindings/rocketmq/settings.go @@ -62,7 +62,7 @@ type Settings struct { Topics TopicsDelimited `mapstructure:"topics"` } -func (s *Settings) Decode(in interface{}) error { +func (s *Settings) Decode(in any) error { if err := metadata.DecodeMetadata(in, s); err != nil { return fmt.Errorf("decode error: %w", err) } diff --git a/bindings/sftp/metadata.yaml b/bindings/sftp/metadata.yaml new file mode 100644 index 0000000000..69922efa4e --- /dev/null +++ b/bindings/sftp/metadata.yaml @@ -0,0 +1,79 @@ +# yaml-language-server: $schema=../../component-metadata-schema.json +schemaVersion: v1 +type: bindings +name: sftp +version: v1 +status: alpha +title: "Secure File Transfer Protocol (SFTP)" +urls: + - title: Reference + url: https://docs.dapr.io/reference/components-reference/supported-bindings/sftp/ +binding: + output: true + input: false + operations: + - name: create + description: "Upload file via SFTP" + - name: get + description: "Download file from SFTP" + - name: delete + description: "Delete file from SFTP" + - name: list + description: "List files in SFTP directory" +authenticationProfiles: + - title: "Password Authentication" + description: | + Authenticate using username and password. + metadata: + - name: username + required: true + description: "The SFTP username" + example: "sftpuser" + - name: password + required: true + sensitive: true + description: "The SFTP password" + example: "password" + - title: "Private Key Authentication" + description: | + Authenticate using username and private key. + metadata: + - name: username + required: true + description: "The SFTP username" + example: "sftpuser" + - name: privateKey + required: true + sensitive: true + description: "The private key for authentication" + example: "-----BEGIN OPENSSH PRIVATE KEY-----\n..." + - name: privateKeyPassphrase + required: false + sensitive: true + description: "The passphrase for the private key" + example: "your-passphrase" +metadata: + - name: address + required: true + description: "The SFTP server address (host:port)" + example: "sftp.example.com:22" + - name: rootPath + required: true + description: "The root directory path on the SFTP server" + example: "/home/sftpuser" + - name: fileName + required: false + description: "The file name (can be overridden in request metadata)" + example: "data.txt" + - name: hostPublicKey + required: false + description: "The host public key for verification" + - name: knownHostsFile + required: false + description: "Path to the known_hosts file" + example: "/path/to/known_hosts" + - name: insecureIgnoreHostKey + required: false + description: "Skip host key verification (insecure)" + example: false + default: false diff --git a/bindings/smtp/metadata.yaml b/bindings/smtp/metadata.yaml new file mode 100644 index 0000000000..a7520d9f7a --- /dev/null +++ b/bindings/smtp/metadata.yaml @@ -0,0 +1,70 @@ +# yaml-language-server: $schema=../../component-metadata-schema.json +schemaVersion: v1 +type: bindings +name: smtp +version: v1 +status: alpha +title: "SMTP" +urls: + - title: Reference + url: https://docs.dapr.io/reference/components-reference/supported-bindings/smtp/ +binding: + output: true + input: false + operations: + - name: create + description: "Send email via SMTP" +authenticationProfiles: + - title: "User/Password Authentication" + description: | + Authenticate with SMTP server using username and password. + metadata: + - name: user + required: true + description: "The SMTP username" + example: "user@gmail.com" + - name: password + required: true + sensitive: true + description: "The SMTP password" + example: "password" +metadata: + - name: host + required: true + description: "The SMTP server host" + example: "smtp.gmail.com" + - name: port + required: false + description: "The SMTP server port" + example: '587' + default: '587' + - name: emailFrom + required: true + description: "The sender email address" + example: "sender@example.com" + - name: emailTo + required: true + description: "The recipient email address" + example: "recipient@example.com" + - name: emailCC + required: false + description: "The email CC address" + example: "cc@example.com" + - name: emailBCC + required: false + description: "The email BCC address" + example: "bcc@example.com" + - name: priority + required: false + description: "The email priority" + example: '3' + default: '3' + - name: subject + required: true + description: "The email subject" + example: "Hello from Dapr" + - name: skipTLSVerify + required: false + description: "Skip TLS verification" + example: false + default: false diff --git a/bindings/twilio/sendgrid/metadata.yaml b/bindings/twilio/sendgrid/metadata.yaml new file mode 100644 index 0000000000..f645420b1b --- /dev/null +++ b/bindings/twilio/sendgrid/metadata.yaml @@ -0,0 +1,63 @@ +# yaml-language-server: $schema=../../../component-metadata-schema.json +schemaVersion: v1 +type: bindings +name: twilio.sendgrid +version: v1 +status: alpha +title: "Twilio SendGrid" +urls: + - title: Reference + url: https://docs.dapr.io/reference/components-reference/supported-bindings/sendgrid/ +binding: + output: true + input: false + operations: + - name: create + description: "Send email via SendGrid" +authenticationProfiles: + - title: "API Key Authentication" + description: | + Authenticate using SendGrid API key. + metadata: + - name: apiKey + required: true + sensitive: true + description: "The SendGrid API key" + example: "SG.api-key" +metadata: + - name: emailFrom + required: true + description: "The sender email address" + example: "sender@example.com" + - name: emailFromName + required: false + description: "The sender name" + example: "John Doe" + - name: emailTo + required: true + description: "The recipient email address" + example: "recipient@example.com" + - name: emailToName + required: false + description: "The recipient name" + example: "Jane Smith" + - name: subject + required: true + description: "The email subject" + example: "Hello from Dapr" + - name: emailCc + required: false + description: "The CC email address" + example: "cc@example.com" + - name: emailBcc + required: false + description: "The BCC email address" + example: "bcc@example.com" + - name: dynamicTemplateData + required: false + description: "The dynamic template data" + example: '{"name":"John","age":30}' + - name: dynamicTemplateId + required: false + description: "The dynamic template ID" + example: "your-template-id" diff --git a/bindings/twilio/sms/metadata.yaml b/bindings/twilio/sms/metadata.yaml new file mode 100644 index 0000000000..e0ba290454 --- /dev/null +++ b/bindings/twilio/sms/metadata.yaml @@ -0,0 +1,45 @@ +# yaml-language-server: $schema=../../../component-metadata-schema.json +schemaVersion: v1 +type: bindings +name: twilio.sms +version: v1 +status: stable +title: "Twilio SMS" +urls: + - title: Reference + url: https://docs.dapr.io/reference/components-reference/supported-bindings/twilio/ +binding: + output: true + input: false + operations: + - name: create + description: "Send SMS via Twilio" +authenticationProfiles: + - title: "Twilio Authentication" + description: | + Authenticate using Twilio account credentials. + metadata: + - name: accountSid + required: true + description: "The Twilio account SID" + example: "AC1234567890abcdef" + - name: authToken + required: true + sensitive: true + description: "The Twilio auth token" + example: "auth-token" +metadata: + - name: fromNumber + required: true + description: "The sender phone number" + example: "+1234567890" + - name: toNumber + required: true + description: "The recipient phone number" + example: "+0987654321" + - name: timeout + required: false + type: duration + description: "The timeout for the SMS request" + example: '30s' + default: '30s' diff --git a/bindings/twilio/sms/sms.go b/bindings/twilio/sms/sms.go index 2bd4a59609..42503d4ce3 100644 --- a/bindings/twilio/sms/sms.go +++ b/bindings/twilio/sms/sms.go @@ -33,10 +33,6 @@ import ( const ( toNumber = "toNumber" - fromNumber = "fromNumber" - accountSid = "accountSid" - authToken = "authToken" - timeout = "timeout" twilioURLBase = "https://api.twilio.com/2010-04-01/Accounts/" ) diff --git a/bindings/wasm/metadata.yaml b/bindings/wasm/metadata.yaml new file mode 100644 index 0000000000..451c587db1 --- /dev/null +++ b/bindings/wasm/metadata.yaml @@ -0,0 +1,26 @@ +# yaml-language-server: $schema=../../component-metadata-schema.json +schemaVersion: v1 +type: bindings +name: wasm +version: v1 +status: alpha +title: "WebAssembly (WASM)" +urls: + - title: Reference + url: https://docs.dapr.io/reference/components-reference/supported-bindings/wasm/ +binding: + output: true + input: false + operations: + - name: create + description: "Execute WASM function" +metadata: + - name: strictSandbox + required: false + description: "Strict sandbox mode. When true, uses fake sources to avoid vulnerabilities such as timing attacks." + example: true + default: false + - name: url + required: true + description: "The URL of the WASM file" + example: "https://example.com/function.wasm"