-
Notifications
You must be signed in to change notification settings - Fork 542
Feat/kinesis binding vmware go kcl v2 latest #4082
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
swatimodi-scout
wants to merge
19
commits into
dapr:main
Choose a base branch
from
swatimodi-scout:feat/kinesis-binding-vmware-go-kcl-v2-latest
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+250
−115
Open
Changes from 14 commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
2eddb15
make the v2 creds provider be the default
swatimodi-scout cabcec5
feat: Upgrade kinesis github.com/vmware/vmware-go-kcl-v1 to v2.
devendrapohekar-scout 112fd8d
Resolved conflicts
swatimodi-scout de8646f
Update common/authentication/aws/client.go
swatimodi-scout 90e071c
Update bindings/aws/kinesis/kinesis.go
swatimodi-scout 648a318
Resolved comments given by acroca
swatimodi-scout b686d94
Removed v1 credentials for kinesis
swatimodi-scout 9a70082
updated client.go
swatimodi-scout 9dafc6d
Update AWS SDK to v2 and refactor Kinesis integration
rideshnath-scout 8b93022
Merge branch 'main' into feat/kinesis-binding-vmware-go-kcl-v2-latest
swatimodi-scout 2ee207c
Merge branch 'main' into feat/kinesis-binding-vmware-go-kcl-v2-latest
swatimodi-scout 9b003aa
refactor: migrate Kinesis integration to AWS SDK v2 and update relate…
rideshnath-scout 6ebe1a4
refactor: streamline AWS Kinesis client creation and remove unused au…
rideshnath-scout c064187
feat: add applicationName metadata field to Kinesis binding
rideshnath-scout 716b8a1
refactor: update AWS SDK v2 dependencies and improve import organization
rideshnath-scout bf33f52
refactor: correct variable naming and improve context handling in tes…
rideshnath-scout d8f5103
refactor: reorder AWS SDK imports (resolve lint issues)
rideshnath-scout bd2639a
Merge branch 'main' into feat/kinesis-binding-vmware-go-kcl-v2-latest
swatimodi-scout d75c04c
Revert changes from '/common/authentication/aws'
rideshnath-scout File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,37 +22,41 @@ import ( | |
| "sync/atomic" | ||
| "time" | ||
|
|
||
| "github.com/aws/aws-sdk-go/aws" | ||
| "github.com/aws/aws-sdk-go/aws/request" | ||
| "github.com/aws/aws-sdk-go/service/kinesis" | ||
| awsv2 "github.com/aws/aws-sdk-go-v2/aws" | ||
| "github.com/aws/aws-sdk-go-v2/service/kinesis" | ||
| "github.com/aws/aws-sdk-go-v2/service/kinesis/types" | ||
| "github.com/cenkalti/backoff/v4" | ||
| aws "github.com/dapr/components-contrib/common/aws" | ||
mikeee marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| "github.com/google/uuid" | ||
| "github.com/vmware/vmware-go-kcl/clientlibrary/interfaces" | ||
| "github.com/vmware/vmware-go-kcl/clientlibrary/worker" | ||
| "github.com/vmware/vmware-go-kcl-v2/clientlibrary/config" | ||
| "github.com/vmware/vmware-go-kcl-v2/clientlibrary/interfaces" | ||
| "github.com/vmware/vmware-go-kcl-v2/clientlibrary/worker" | ||
|
|
||
| "github.com/dapr/components-contrib/bindings" | ||
| awsAuth "github.com/dapr/components-contrib/common/authentication/aws" | ||
| awsAuth "github.com/dapr/components-contrib/common/aws/auth" | ||
| "github.com/dapr/components-contrib/metadata" | ||
| "github.com/dapr/kit/logger" | ||
| kitmd "github.com/dapr/kit/metadata" | ||
| ) | ||
|
|
||
| // AWSKinesis allows receiving and sending data to/from AWS Kinesis stream. | ||
| type AWSKinesis struct { | ||
| authProvider awsAuth.Provider | ||
| metadata *kinesisMetadata | ||
|
|
||
| worker *worker.Worker | ||
|
|
||
| streamName string | ||
| consumerName string | ||
| consumerARN *string | ||
| logger logger.Logger | ||
| consumerMode string | ||
|
|
||
| closed atomic.Bool | ||
| closeCh chan struct{} | ||
| wg sync.WaitGroup | ||
| // authProvider awsAuth.Provider | ||
mikeee marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| metadata *kinesisMetadata | ||
|
|
||
| worker *worker.Worker | ||
| kinesisClient *kinesis.Client | ||
| v2Credentials awsv2.CredentialsProvider | ||
|
|
||
| streamName string | ||
| consumerName string | ||
| consumerARN *string | ||
| logger logger.Logger | ||
| consumerMode string | ||
| applicationName string | ||
| closed atomic.Bool | ||
| closeCh chan struct{} | ||
| wg sync.WaitGroup | ||
| } | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add kinesis client here and init with sdk v2
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Done |
||
|
|
||
| // 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 | ||
|
|
@@ -65,6 +69,7 @@ type kinesisMetadata struct { | |
| SecretKey string `json:"secretKey" mapstructure:"secretKey"` | ||
| SessionToken string `json:"sessionToken" mapstructure:"sessionToken"` | ||
| KinesisConsumerMode string `json:"mode" mapstructure:"mode"` | ||
| ApplicationName string `json:"applicationName" mapstructure:"applicationName"` | ||
| } | ||
|
|
||
| const ( | ||
|
|
@@ -116,6 +121,7 @@ func (a *AWSKinesis) Init(ctx context.Context, metadata bindings.Metadata) error | |
| a.consumerMode = m.KinesisConsumerMode | ||
| a.streamName = m.StreamName | ||
| a.consumerName = m.ConsumerName | ||
| a.applicationName = m.ApplicationName | ||
| a.metadata = m | ||
|
|
||
| opts := awsAuth.Options{ | ||
|
|
@@ -126,12 +132,13 @@ func (a *AWSKinesis) Init(ctx context.Context, metadata bindings.Metadata) error | |
| SecretKey: m.SecretKey, | ||
| SessionToken: "", | ||
| } | ||
| // extra configs needed per component type | ||
| provider, err := awsAuth.NewProvider(ctx, opts, awsAuth.GetConfig(opts)) | ||
|
|
||
| kinesisClient, err := a.createKinesisClient(ctx, opts) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| a.authProvider = provider | ||
| a.kinesisClient = kinesisClient | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
|
|
@@ -144,7 +151,7 @@ func (a *AWSKinesis) Invoke(ctx context.Context, req *bindings.InvokeRequest) (* | |
| if partitionKey == "" { | ||
| partitionKey = uuid.New().String() | ||
| } | ||
| _, err := a.authProvider.Kinesis().Kinesis.PutRecordWithContext(ctx, &kinesis.PutRecordInput{ | ||
| _, err := a.kinesisClient.PutRecord(ctx, &kinesis.PutRecordInput{ | ||
| StreamName: &a.metadata.StreamName, | ||
| Data: req.Data, | ||
| PartitionKey: &partitionKey, | ||
|
|
@@ -158,21 +165,23 @@ func (a *AWSKinesis) Read(ctx context.Context, handler bindings.Handler) (err er | |
| return errors.New("binding is closed") | ||
| } | ||
|
|
||
| if a.metadata.KinesisConsumerMode == SharedThroughput { | ||
| switch a.metadata.KinesisConsumerMode { | ||
| case SharedThroughput: | ||
| // initalize worker configuration | ||
| config := a.workerCfg(ctx, a.streamName, a.metadata.Region, a.consumerMode, a.applicationName) | ||
| // Configure the KCL worker with custom endpoints for LocalStack | ||
| config := a.authProvider.Kinesis().WorkerCfg(ctx, a.streamName, a.consumerName, a.consumerMode) | ||
| if a.metadata.Endpoint != "" { | ||
| config.KinesisEndpoint = a.metadata.Endpoint | ||
| config.DynamoDBEndpoint = a.metadata.Endpoint | ||
| config = config.WithKinesisEndpoint(a.metadata.Endpoint) | ||
| config = config.WithDynamoDBEndpoint(a.metadata.Endpoint) | ||
| } | ||
| a.worker = worker.NewWorker(a.recordProcessorFactory(ctx, handler), config) | ||
| err = a.worker.Start() | ||
| if err != nil { | ||
| return err | ||
| } | ||
| } else if a.metadata.KinesisConsumerMode == ExtendedFanout { | ||
| case ExtendedFanout: | ||
| var stream *kinesis.DescribeStreamOutput | ||
| stream, err = a.authProvider.Kinesis().Kinesis.DescribeStream(&kinesis.DescribeStreamInput{StreamName: &a.metadata.StreamName}) | ||
| stream, err = a.kinesisClient.DescribeStream(ctx, &kinesis.DescribeStreamInput{StreamName: &a.metadata.StreamName}) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
@@ -182,7 +191,7 @@ func (a *AWSKinesis) Read(ctx context.Context, handler bindings.Handler) (err er | |
| } | ||
| } | ||
|
|
||
| stream, err := a.authProvider.Kinesis().Stream(ctx, a.streamName) | ||
| stream, err := a.getStreamARN(ctx, a.streamName) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to get kinesis stream arn: %v", err) | ||
| } | ||
|
|
@@ -194,9 +203,10 @@ func (a *AWSKinesis) Read(ctx context.Context, handler bindings.Handler) (err er | |
| case <-ctx.Done(): | ||
| case <-a.closeCh: | ||
| } | ||
| if a.metadata.KinesisConsumerMode == SharedThroughput { | ||
| switch a.metadata.KinesisConsumerMode { | ||
| case SharedThroughput: | ||
| a.worker.Shutdown() | ||
| } else if a.metadata.KinesisConsumerMode == ExtendedFanout { | ||
| case ExtendedFanout: | ||
| a.deregisterConsumer(ctx, stream, a.consumerARN) | ||
| } | ||
| }() | ||
|
|
@@ -205,7 +215,7 @@ func (a *AWSKinesis) Read(ctx context.Context, handler bindings.Handler) (err er | |
| } | ||
|
|
||
| // Subscribe to all shards. | ||
| func (a *AWSKinesis) Subscribe(ctx context.Context, streamDesc kinesis.StreamDescription, handler bindings.Handler) error { | ||
| func (a *AWSKinesis) Subscribe(ctx context.Context, streamDesc types.StreamDescription, handler bindings.Handler) error { | ||
| consumerARN, err := a.ensureConsumer(ctx, streamDesc.StreamARN) | ||
| if err != nil { | ||
| a.logger.Error(err) | ||
|
|
@@ -216,7 +226,7 @@ func (a *AWSKinesis) Subscribe(ctx context.Context, streamDesc kinesis.StreamDes | |
|
|
||
| a.wg.Add(len(streamDesc.Shards)) | ||
| for i, shard := range streamDesc.Shards { | ||
| go func(idx int, s *kinesis.Shard) { | ||
| go func(idx int, s types.Shard) { | ||
| defer a.wg.Done() | ||
|
|
||
| // Reconnection backoff | ||
|
|
@@ -232,14 +242,14 @@ func (a *AWSKinesis) Subscribe(ctx context.Context, streamDesc kinesis.StreamDes | |
| return | ||
| default: | ||
| } | ||
| sub, err := a.authProvider.Kinesis().Kinesis.SubscribeToShardWithContext(ctx, &kinesis.SubscribeToShardInput{ | ||
| sub, err := a.kinesisClient.SubscribeToShard(ctx, &kinesis.SubscribeToShardInput{ | ||
| ConsumerARN: consumerARN, | ||
| ShardId: s.ShardId, | ||
| StartingPosition: &kinesis.StartingPosition{Type: aws.String(kinesis.ShardIteratorTypeLatest)}, | ||
| StartingPosition: &types.StartingPosition{Type: types.ShardIteratorTypeLatest}, | ||
| }) | ||
| if err != nil { | ||
| wait := bo.NextBackOff() | ||
| a.logger.Errorf("Error while reading from shard %v: %v. Attempting to reconnect in %s...", s.ShardId, err, wait) | ||
| a.logger.Errorf("Error while reading from shard %v: %v. Attempting to reconnect in %s...", *s.ShardId, err, wait) | ||
| select { | ||
| case <-ctx.Done(): | ||
| return | ||
|
|
@@ -252,10 +262,10 @@ func (a *AWSKinesis) Subscribe(ctx context.Context, streamDesc kinesis.StreamDes | |
| bo.Reset() | ||
|
|
||
| // Process events | ||
| for event := range sub.EventStream.Events() { | ||
| for event := range sub.GetStream().Events() { | ||
| switch e := event.(type) { | ||
| case *kinesis.SubscribeToShardEvent: | ||
| for _, rec := range e.Records { | ||
| case *types.SubscribeToShardEventStreamMemberSubscribeToShardEvent: | ||
| for _, rec := range e.Value.Records { | ||
| handler(ctx, &bindings.ReadResponse{ | ||
| Data: rec.Data, | ||
| }) | ||
|
|
@@ -274,17 +284,14 @@ func (a *AWSKinesis) Close() error { | |
| close(a.closeCh) | ||
| } | ||
| a.wg.Wait() | ||
| if a.authProvider != nil { | ||
| return a.authProvider.Close() | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| func (a *AWSKinesis) ensureConsumer(ctx context.Context, streamARN *string) (*string, error) { | ||
| // Only set timeout on consumer call. | ||
| conCtx, cancel := context.WithTimeout(ctx, 30*time.Second) | ||
| defer cancel() | ||
| consumer, err := a.authProvider.Kinesis().Kinesis.DescribeStreamConsumerWithContext(conCtx, &kinesis.DescribeStreamConsumerInput{ | ||
| consumer, err := a.kinesisClient.DescribeStreamConsumer(conCtx, &kinesis.DescribeStreamConsumerInput{ | ||
| ConsumerName: &a.metadata.ConsumerName, | ||
| StreamARN: streamARN, | ||
| }) | ||
|
|
@@ -296,7 +303,7 @@ func (a *AWSKinesis) ensureConsumer(ctx context.Context, streamARN *string) (*st | |
| } | ||
|
|
||
| func (a *AWSKinesis) registerConsumer(ctx context.Context, streamARN *string) (*string, error) { | ||
| consumer, err := a.authProvider.Kinesis().Kinesis.RegisterStreamConsumerWithContext(ctx, &kinesis.RegisterStreamConsumerInput{ | ||
| consumer, err := a.kinesisClient.RegisterStreamConsumer(ctx, &kinesis.RegisterStreamConsumerInput{ | ||
| ConsumerName: &a.metadata.ConsumerName, | ||
| StreamARN: streamARN, | ||
| }) | ||
|
|
@@ -319,7 +326,7 @@ func (a *AWSKinesis) deregisterConsumer(ctx context.Context, streamARN *string, | |
| if a.consumerARN != nil { | ||
| // Use a background context because the running context may have been canceled already | ||
| ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) | ||
| _, err := a.authProvider.Kinesis().Kinesis.DeregisterStreamConsumerWithContext(ctx, &kinesis.DeregisterStreamConsumerInput{ | ||
| _, err := a.kinesisClient.DeregisterStreamConsumer(ctx, &kinesis.DeregisterStreamConsumerInput{ | ||
| ConsumerARN: consumerARN, | ||
| StreamARN: streamARN, | ||
| ConsumerName: &a.metadata.ConsumerName, | ||
|
|
@@ -332,34 +339,19 @@ func (a *AWSKinesis) deregisterConsumer(ctx context.Context, streamARN *string, | |
| return nil | ||
| } | ||
|
|
||
| func (a *AWSKinesis) waitUntilConsumerExists(ctx aws.Context, input *kinesis.DescribeStreamConsumerInput, opts ...request.WaiterOption) error { | ||
| w := request.Waiter{ | ||
| Name: "WaitUntilConsumerExists", | ||
| MaxAttempts: 18, | ||
| Delay: request.ConstantWaiterDelay(10 * time.Second), | ||
| Acceptors: []request.WaiterAcceptor{ | ||
| { | ||
| State: request.SuccessWaiterState, | ||
| Matcher: request.PathWaiterMatch, Argument: "ConsumerDescription.ConsumerStatus", | ||
| Expected: "ACTIVE", | ||
| }, | ||
| }, | ||
| NewRequest: func(opts []request.Option) (*request.Request, error) { | ||
| var inCpy *kinesis.DescribeStreamConsumerInput | ||
| if input != nil { | ||
| tmp := *input | ||
| inCpy = &tmp | ||
| } | ||
| req, _ := a.authProvider.Kinesis().Kinesis.DescribeStreamConsumerRequest(inCpy) | ||
| req.SetContext(ctx) | ||
| req.ApplyOptions(opts...) | ||
|
|
||
| return req, nil | ||
| }, | ||
| func (a *AWSKinesis) waitUntilConsumerExists(ctx context.Context, input *kinesis.DescribeStreamConsumerInput) error { | ||
| // Poll until consumer is active | ||
| for i := 0; i < 18; i++ { | ||
| consumer, err := a.kinesisClient.DescribeStreamConsumer(ctx, input) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| if consumer.ConsumerDescription.ConsumerStatus == types.ConsumerStatusActive { | ||
| return nil | ||
| } | ||
| time.Sleep(10 * time.Second) | ||
| } | ||
| w.ApplyOptions(opts...) | ||
|
|
||
| return w.WaitWithContext(ctx) | ||
| return fmt.Errorf("consumer did not become active within timeout") | ||
| } | ||
|
|
||
| func (a *AWSKinesis) parseMetadata(meta bindings.Metadata) (*kinesisMetadata, error) { | ||
|
|
@@ -388,7 +380,7 @@ func (r *recordProcessorFactory) CreateProcessor() interfaces.IRecordProcessor { | |
| } | ||
|
|
||
| func (p *recordProcessor) Initialize(input *interfaces.InitializationInput) { | ||
| p.logger.Infof("Processing ShardId: %v at checkpoint: %v", input.ShardId, aws.StringValue(input.ExtendedSequenceNumber.SequenceNumber)) | ||
| p.logger.Infof("Processing ShardId: %v at checkpoint: %v", input.ShardId, *input.ExtendedSequenceNumber.SequenceNumber) | ||
| } | ||
|
|
||
| func (p *recordProcessor) ProcessRecords(input *interfaces.ProcessRecordsInput) { | ||
|
|
@@ -414,6 +406,35 @@ func (p *recordProcessor) Shutdown(input *interfaces.ShutdownInput) { | |
| } | ||
| } | ||
|
|
||
| func (a *AWSKinesis) createKinesisClient(ctx context.Context, opts awsAuth.Options) (*kinesis.Client, error) { | ||
|
|
||
| awsConfig, configErr := aws.NewConfig(ctx, opts) | ||
| if configErr != nil { | ||
| return nil, configErr | ||
| } | ||
|
|
||
| kinesisClient := kinesis.NewFromConfig(awsConfig) | ||
| return kinesisClient, nil | ||
| } | ||
|
|
||
| func (a *AWSKinesis) getStreamARN(ctx context.Context, streamName string) (*string, error) { | ||
| stream, err := a.kinesisClient.DescribeStream(ctx, &kinesis.DescribeStreamInput{ | ||
| StreamName: &streamName, | ||
| }) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| return stream.StreamDescription.StreamARN, nil | ||
| } | ||
|
|
||
| func (a *AWSKinesis) workerCfg(_ context.Context, stream, region, mode, applicationName string) *config.KinesisClientLibConfiguration { | ||
| const sharedMode = "shared" | ||
| if mode == sharedMode { | ||
| return config.NewKinesisClientLibConfigWithCredential(applicationName, stream, region, "", a.v2Credentials) | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| // GetComponentMetadata returns the metadata of the component. | ||
| func (a *AWSKinesis) GetComponentMetadata() (metadataInfo metadata.MetadataMap) { | ||
| metadataStruct := &kinesisMetadata{} | ||
|
|
||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.