Skip to content
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

S3Template fails to upload to Localstack S3 #1031

Closed
ASarco opened this issue Jan 29, 2024 · 2 comments
Closed

S3Template fails to upload to Localstack S3 #1031

ASarco opened this issue Jan 29, 2024 · 2 comments

Comments

@ASarco
Copy link

ASarco commented Jan 29, 2024

Type: Bug

Component:
"S3"

Describe the bug
I'm migrating an app using the SDK 1.x to Spring Cloud AWS. I did an SQS migration successfully, and the app now works perfect using SQSTemplate and @SQSListener, both in runtime and testing with Localstack through Testcontainers.
Then I moved to S3, trying to use the S3Template provided by Spring Cloud AWS. But in the integration test I wrote, while trying to upload a file to Localstack S3, I've got the error (with stack trace)

Caused by: java.lang.NullPointerException: host must not be null.
	at software.amazon.awssdk.utils.Validate.paramNotNull(Validate.java:156)
	at software.amazon.awssdk.http.DefaultSdkHttpFullRequest.<init>(DefaultSdkHttpFullRequest.java:56)
	at software.amazon.awssdk.http.DefaultSdkHttpFullRequest.<init>(DefaultSdkHttpFullRequest.java:44)
	at software.amazon.awssdk.http.DefaultSdkHttpFullRequest$Builder.build(DefaultSdkHttpFullRequest.java:482)
	at software.amazon.awssdk.http.DefaultSdkHttpFullRequest$Builder.build(DefaultSdkHttpFullRequest.java:250)
	at software.amazon.awssdk.services.s3.endpoints.internal.AwsEndpointProviderUtils.setUri(AwsEndpointProviderUtils.java:180)
	at software.amazon.awssdk.services.s3.endpoints.internal.S3RequestSetEndpointInterceptor.modifyHttpRequest(S3RequestSetEndpointInterceptor.java:35)
	at software.amazon.awssdk.core.interceptor.ExecutionInterceptorChain.modifyHttpRequestAndHttpContent(ExecutionInterceptorChain.java:90)
	at software.amazon.awssdk.core.internal.handler.BaseClientHandler.runModifyHttpRequestAndHttpContentInterceptors(BaseClientHandler.java:157)
	at software.amazon.awssdk.core.internal.handler.BaseClientHandler.finalizeSdkHttpFullRequest(BaseClientHandler.java:83)
	at software.amazon.awssdk.core.internal.handler.BaseSyncClientHandler.doExecute(BaseSyncClientHandler.java:151)
	at software.amazon.awssdk.core.internal.handler.BaseSyncClientHandler.lambda$execute$1(BaseSyncClientHandler.java:80)
	at software.amazon.awssdk.core.internal.handler.BaseSyncClientHandler.measureApiCallSuccess(BaseSyncClientHandler.java:182)
	at software.amazon.awssdk.core.internal.handler.BaseSyncClientHandler.execute(BaseSyncClientHandler.java:74)
	at software.amazon.awssdk.core.client.handler.SdkSyncClientHandler.execute(SdkSyncClientHandler.java:45)
	at software.amazon.awssdk.awscore.client.handler.AwsSyncClientHandler.execute(AwsSyncClientHandler.java:53)
	at software.amazon.awssdk.services.s3.DefaultS3Client.putObject(DefaultS3Client.java:9016)
	at io.awspring.cloud.s3.InMemoryBufferingS3OutputStream.putObject(InMemoryBufferingS3OutputStream.java:214)
	at io.awspring.cloud.s3.InMemoryBufferingS3OutputStream.close(InMemoryBufferingS3OutputStream.java:131)
	at io.awspring.cloud.s3.S3Template.upload(S3Template.java:172)
	... 194 common frames omitted

This happens even though I enabled S3 on localstack, and set the endpoint to the correct URL, provided by the Localstack Testcontainer (SQS works fine with this config):
"spring.cloud.aws.endpoint=" + localStackContainer.getEndpoint()

Adding spring.cloud.aws.s3.endpoint to the config doesn't help either.

This happens both with or without the CrossRegionS3Client (stack trace is without it).

Using Spring Boot 3.2.2 and Spring Cloud AWS 3.1.0

Is this a bug, or am I doing something wrong?

@ASarco
Copy link
Author

ASarco commented Jan 29, 2024

Doing a bit a debugging, I can see that in BaseSyncClientHandler.execute() the parameter executionParams contains a field discoveredEndpoint that is null. If I manually changed the value of this field to the correct URI during a breakpoint, the file is uploaded to Localstack S3. But I couldn't find where this field is populated.

@ASarco
Copy link
Author

ASarco commented Jan 30, 2024

After a lot of trial and error, I managed to make it work, by adding this property:
spring.cloud.aws.s3.path-style-access-enabled=true

However, I understand that path-style access is the old way to name buckets and files in S3.
And I still don't understand why I was getting a NPE for the null host, because if I was using host-style access, shouldn't the host be something like http://bucket_name.localhost:4566 ?

If I remove spring.cloud.aws.s3.path-style-access-enabled=true, then it works by setting:
spring.cloud.aws.s3.endpoint=http://s3.localhost.localstack.cloud:"+ localStackContainer.getFirstMappedPort()

and this is using the host-style path access. This is because Localstack requires the S3 prefix in the host.

@ASarco ASarco closed this as completed Jan 30, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant