localstack / localstack

💻 A fully functional local AWS cloud stack. Develop and test your cloud & Serverless apps offline
https://localstack.cloud
Other
55.81k stars 3.97k forks source link

bug: LocalStack.NET all SNS operations fails on LocalStack 3.7.2 and 3.8.0 #11652

Closed Blind-Striker closed 19 hours ago

Blind-Striker commented 2 days ago

Is there an existing issue for this?

Current Behavior

Hello, I'm the maintainer of the LocalStack.NET client library. LocalStack.NET is a thin wrapper around the official aws-sdk-net just like localstack-python-client.

I've discovered issues related to any SNS-related operation when testing against LocalStack versions 3.7.2 and 3.8.0.

Notably, these operations are successful with the following previous version;

Description of the Problem: The operation fails when attempting any SN-related operation using the LocalStack.NET library. I think the logs provided below might offer more insight.

Test Scenario

Scenario Link: SnsService_Should_Create_A_Sns_Topic_Async

[Fact]
public async Task SnsService_Should_Create_A_Sns_Topic_Async()
{
    var topicName = Guid.NewGuid().ToString();
    CreateTopicResponse createTopicResponse = await CreateSnsTopicAsync(topicName).ConfigureAwait(false);

    Assert.Equal(HttpStatusCode.OK, createTopicResponse.HttpStatusCode);

    ListTopicsResponse listTopicsResponse = await AmazonSimpleNotificationService.ListTopicsAsync().ConfigureAwait(false);
    Topic? snsTopic = listTopicsResponse.Topics.SingleOrDefault(topic => topic.TopicArn == createTopicResponse.TopicArn);

    Assert.NotNull(snsTopic);
    Assert.EndsWith(topicName, snsTopic.TopicArn, StringComparison.Ordinal);

    await DeleteSnsTopicAsync(createTopicResponse.TopicArn).ConfigureAwait(false); //Cleanup
}

The test scenario above generates a GUID and uses it as the topic name when creating a SNS topic. The above is just an example. All other SNS-related operations also fail.

LocalStack Testcontainer setup

public static LocalStackBuilder LocalStackBuilder(string version)
{
    return new LocalStackBuilder().WithImage("localstack/localstack:{version}")
                                  .WithName($"localStack-{version}-{Guid.NewGuid().ToString().ToLower()}")
                                  .WithEnvironment("DOCKER_HOST", "unix:///var/run/docker.sock")
                                  .WithEnvironment("DEBUG", "1")
                                  .WithEnvironment("LS_LOG", "trace-internal")
                                  .WithPortBinding(4566, true)
                                  .WithCleanUp(true);
}

Mitmproxy raw request

POST http://sns.eu-central-1.amazonaws.com/ HTTP/1.1
User-Agent: aws-sdk-dotnet-coreclr/3.7.400.30 ua/2.0 os/windows#10.0.22631.0 md/ARCH#X64 lang/.NET_Core#7.0.20 md/aws-sdk-dotnet-core#3.7.400.30 api/SNS#3.7.400.30 cfg/retry-mode#legacy md/ClientAsync cfg/init-coll#1
amz-sdk-invocation-id: 6a851967-3e6a-4189-bdd0-db987e8287ee
amz-sdk-request: attempt=1; max=5
x-amz-security-token: my-AwsSessionToken
Host: sns.eu-central-1.amazonaws.com
X-Amz-Date: 20241007T205311Z
X-Amz-Content-SHA256: 2ffeb051066330394f37e0bb78e1f682f72e610ac51023a574614e249985621a
Authorization: AWS4-HMAC-SHA256 Credential=my-AwsAccessKeyId/20241007/eu-central-1/sns/aws4_request, SignedHeaders=content-type;host;user-agent;x-amz-content-sha256;x-amz-date;x-amz-security-token, Signature=82e9ade32ae6f4b139feab67f2fd9d2897cc840575831355ccf003e90ff8844f
Content-Length: 50
Content-Type: application/x-www-form-urlencoded; charset=utf-8

Action=CreateTopic&Name=MyTopic&Version=2010-03-31

Localstack container logs

2024-10-08 00:35:29 2024-10-07T21:35:29.711 DEBUG --- [  MainThread] localstack.dns.server      : Overwriting container DNS server to point to localhost
2024-10-08 00:35:29 2024-10-07T21:35:29.712 DEBUG --- [  MainThread] localstack.utils.ssl       : Attempting to download local SSL certificate file
2024-10-08 00:35:30 2024-10-07T21:35:30.229 DEBUG --- [  MainThread] localstack.utils.ssl       : SSL certificate downloaded successfully
2024-10-08 00:35:30 2024-10-07T21:35:30.230 DEBUG --- [  MainThread] plux.runtime.manager       : instantiating plugin PluginSpec(localstack.runtime.server.twisted = <class 'localstack.runtime.server.plugins.TwistedRuntimeServerPlugin'>)
2024-10-08 00:35:30 2024-10-07T21:35:30.230 DEBUG --- [  MainThread] plux.runtime.manager       : loading plugin localstack.runtime.server:twisted
2024-10-08 00:35:30 2024-10-07T21:35:30.385 DEBUG --- [ady_monitor)] plux.runtime.manager       : instantiating plugin PluginSpec(localstack.hooks.on_infra_ready._run_init_scripts_on_ready = <function _run_init_scripts_on_ready at 0x7f752a1791c0>)
2024-10-08 00:35:30 2024-10-07T21:35:30.385 DEBUG --- [ady_monitor)] plux.runtime.manager       : loading plugin localstack.hooks.on_infra_ready:_run_init_scripts_on_ready
2024-10-08 00:35:30 2024-10-07T21:35:30.385 DEBUG --- [ady_monitor)] plux.runtime.manager       : instantiating plugin PluginSpec(localstack.hooks.on_infra_ready.register_virtual_host_routes = <function register_virtual_host_routes at 0x7f751a239440>)
2024-10-08 00:35:30 2024-10-07T21:35:30.385 DEBUG --- [ady_monitor)] plux.runtime.manager       : plugin localstack.hooks.on_infra_ready:register_virtual_host_routes is disabled, reason: Load condition for plugin was false
2024-10-08 00:35:30 Ready.
2024-10-08 00:35:30 2024-10-07T21:35:30.646 DEBUG --- [et.reactor-0] rolo.gateway.wsgi          : GET 127.0.0.1:4566/_localstack/health
2024-10-08 00:35:30 2024-10-07T21:35:30.646 DEBUG --- [et.reactor-0] l.a.p.service_router       : building service catalog index cache file /var/lib/localstack/cache/service-catalog-3_8_0-1_35_29.pickle
2024-10-08 00:35:33 2024-10-07T21:35:33.930 DEBUG --- [et.reactor-0] rolo.gateway.wsgi          : GET localhost.localstack.cloud:4566/_localstack/health
2024-10-08 00:35:44 2024-10-07T21:35:44.267 DEBUG --- [et.reactor-0] rolo.gateway.wsgi          : GET localhost.localstack.cloud:4566/_localstack/health
2024-10-08 00:35:51 2024-10-07T21:35:51.263 DEBUG --- [et.reactor-0] rolo.gateway.wsgi          : POST sns.eu-central-1.amazonaws.comhttp://sns.eu-central-1.amazonaws.com/
2024-10-08 00:35:51 2024-10-07T21:35:51.304 DEBUG --- [et.reactor-0] plux.runtime.manager       : instantiating plugin PluginSpec(localstack.aws.provider.sns:default = <function sns at 0x7f74fcd2fec0>)
2024-10-08 00:35:51 2024-10-07T21:35:51.304 DEBUG --- [et.reactor-0] plux.runtime.manager       : loading plugin localstack.aws.provider:sns:default
2024-10-08 00:35:51 2024-10-07T21:35:51.671  INFO --- [et.reactor-0] localstack.aws.skeleton    : No moto route for service sns on path /ttp://sns.eu-central-1.amazonaws.com/ found.
2024-10-08 00:35:51 2024-10-07T21:35:51.671 DEBUG --- [et.reactor-0] l.aws.protocol.serializer  : No accept header given. Using request's Content-Type (application/x-www-form-urlencoded; charset=utf-8) as preferred response Content-Type.
2024-10-08 00:35:51 2024-10-07T21:35:51.672  INFO --- [et.reactor-0] localstack.request.aws     : AWS sns.CreateTopic => 501 (InternalFailure); 000000000000/eu-central-1; CreateTopicInput({'Name': 'MyTopic'}, headers={'User-Agent': 'aws-sdk-dotnet-coreclr/3.7.400.30 ua/2.0 os/windows#10.0.22631.0 md/ARCH#X64 lang/.NET_Core#8.0.8 md/aws-sdk-dotnet-core#3.7.400.30 api/SNS#3.7.400.30 cfg/retry-mode#legacy md/ClientAsync cfg/init-coll#1', 'amz-sdk-invocation-id': '958a6b90-2ee3-4f3b-ab30-95165e105042', 'amz-sdk-request': 'attempt=1; max=5', 'x-amz-security-token': 'my-AwsSessionToken', 'Host': 'sns.eu-central-1.amazonaws.com', 'X-Amz-Date': '20241007T213551Z', 'X-Amz-Content-SHA256': '2ffeb051066330394f37e0bb78e1f682f72e610ac51023a574614e249985621a', 'Authorization': 'AWS4-HMAC-SHA256 Credential=my-AwsAccessKeyId/20241007/eu-central-1/sns/aws4_request, SignedHeaders=content-type;host;user-agent;x-amz-content-sha256;x-amz-date;x-amz-security-token, Signature=647320b37090e9e1d418cf2c30eea0f5184ecf82a7af0400ca200248c398e144', 'Content-Length': '50', 'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8', 'x-moto-account-id': '000000000000'}); InternalFailure(No moto route for service sns on path /ttp://sns.eu-central-1.amazonaws.com/ found., headers={'Content-Type': 'text/xml', 'Content-Length': '323'})
2024-10-08 00:35:56 2024-10-07T21:35:56.488 DEBUG --- [et.reactor-0] rolo.gateway.wsgi          : GET localhost.localstack.cloud:4566/_localstack/health
2024-10-08 00:36:06 2024-10-07T21:36:06.770 DEBUG --- [et.reactor-0] rolo.gateway.wsgi          : GET localhost.localstack.cloud:4566/_localstack/health

AWS SDK.NET Exception

The No moto route for service sns on path /ttp://sns.eu-central-1.amazonaws.com/ found. exception message is interesting

Amazon.SimpleNotificationService.AmazonSimpleNotificationServiceException: No moto route for service sns on path /ttp://sns.eu-central-1.amazonaws.com/ found.
 ---> Amazon.Runtime.Internal.HttpErrorResponseException: Exception of type 'Amazon.Runtime.Internal.HttpErrorResponseException' was thrown.
   at Amazon.Runtime.HttpWebRequestMessage.ProcessHttpResponseMessage(HttpResponseMessage responseMessage)
   at Amazon.Runtime.HttpWebRequestMessage.GetResponseAsync(CancellationToken cancellationToken)
   at Amazon.Runtime.Internal.HttpHandler`1.InvokeAsync[T](IExecutionContext executionContext)
   at Amazon.Runtime.Internal.Unmarshaller.InvokeAsync[T](IExecutionContext executionContext)
   at Amazon.Runtime.Internal.ErrorHandler.InvokeAsync[T](IExecutionContext executionContext)
   --- End of inner exception stack trace ---
   at Amazon.Runtime.Internal.HttpErrorResponseExceptionHandler.HandleExceptionStream(IRequestContext requestContext, IWebResponseData httpErrorResponse, HttpErrorResponseException exception, Stream responseStream)
   at Amazon.Runtime.Internal.HttpErrorResponseExceptionHandler.HandleExceptionAsync(IExecutionContext executionContext, HttpErrorResponseException exception)
   at Amazon.Runtime.Internal.ExceptionHandler`1.HandleAsync(IExecutionContext executionContext, Exception exception)
   at Amazon.Runtime.Internal.ErrorHandler.ProcessExceptionAsync(IExecutionContext executionContext, Exception exception)
   at Amazon.Runtime.Internal.ErrorHandler.InvokeAsync[T](IExecutionContext executionContext)
   at Amazon.Runtime.Internal.CallbackHandler.InvokeAsync[T](IExecutionContext executionContext)
   at Amazon.Runtime.Internal.Signer.InvokeAsync[T](IExecutionContext executionContext)
   at Amazon.Runtime.Internal.EndpointDiscoveryHandler.InvokeAsync[T](IExecutionContext executionContext)
   at Amazon.Runtime.Internal.EndpointDiscoveryHandler.InvokeAsync[T](IExecutionContext executionContext)
   at Amazon.Runtime.Internal.CredentialsRetriever.InvokeAsync[T](IExecutionContext executionContext)
   at Amazon.Runtime.Internal.RetryHandler.InvokeAsync[T](IExecutionContext executionContext)
   at Amazon.Runtime.Internal.RetryHandler.InvokeAsync[T](IExecutionContext executionContext)
   at Amazon.Runtime.Internal.CallbackHandler.InvokeAsync[T](IExecutionContext executionContext)
   at Amazon.Runtime.Internal.CallbackHandler.InvokeAsync[T](IExecutionContext executionContext)
   at Amazon.Runtime.Internal.ErrorCallbackHandler.InvokeAsync[T](IExecutionContext executionContext)
   at Amazon.Runtime.Internal.MetricsHandler.InvokeAsync[T](IExecutionContext executionContext)
   at Program.<>c__DisplayClass0_0.<<<Main>$>g__CreateSnsTopicAsync|1>d.MoveNext() in E:\repos\my-projects\localstack-s3-sqs-issue-sandbox\Sandbox\Program.cs:line 49
--- End of stack trace from previous location ---
   at Program.<Main>$(String[] args) in E:\repos\my-projects\localstack-s3-sqs-issue-sandbox\Sandbox\Program.cs:line 28
   at Program.<Main>(String[] args)

Expected Behavior

Using the LocalStack.NET library, all SNS-related operations should be successful, consistent with the behavior observed on LocalStack versions between 3.4.0 and 3.7.1

How are you starting LocalStack?

Custom (please describe below)

Steps To Reproduce

How are you starting localstack (e.g., bin/localstack command, arguments, or docker-compose.yml)

Using TestContainers with the specific configurations mentioned above.

Client commands (e.g., AWS SDK code snippet, or sequence of "awslocal" commands)

I’ve created an example repository to demonstrate this bug. Please follow the instructions in the README to reproduce it.

Environment

- OS: Windows 11 x64
- LocalStack: 3.7.2 and 3.8.0
- Docker: Docker Desktop running on WSL 2

Anything else?

In the past, I had submitted two issues related to similar URL related problems: #8924 and #8928. These were resolved with PR #8962. I wanted to mention this in case it might be a similar problem.

Blind-Striker commented 18 hours ago

Hey @bentsku, thank you for your quick response and effort, much appreciated 🙏 Can I test this fix using the localstack/localstack:latest container image?

bentsku commented 16 hours ago

Hi @Blind-Striker! No worries, sorry for not catching this issue in the first place. You should be able to test the fix with the latest now, yes, the image has been published. Thanks again for your report, the reproducer was very appreciated 🙏

Blind-Striker commented 2 hours ago

Hey @bentsku,

If you find it necessary or believe it would be useful, I’d be happy to contribute integration tests for at least the core AWS services in the LocalStack repo using the AWS SDK for .NET. Let me know if that sounds helpful!

bentsku commented 1 hour ago

Hey @Blind-Striker, it does sounds really nice! We don't really have other languages tests in our core repo at the moment, so I'm not sure what shape it would take, but I'd like to rope in @alexrashed and @silv-io for their opinions on this, as it would be really useful.

I know we've had other repos where we ran some pipelines against LocalStack to look for regression, with Terraform for example.

alexrashed commented 1 hour ago

That's a great idea, and something we are missing. We do have some non-python integration tests using Lambdas as you can see here. And we do have some completely separated tests which run bash script tests for our helpers here.

I think it would make sense to run tests with other SDKs, maybe we could bootstrap a new pipeline / set of tests explicitly aiming at testing non-python SDKs? If this should become an acceptance criteria, we can move it into our main pipeline to block pushes of faulty images.