piotr-rojek / devopsifyme-sbemulator

MIT License
63 stars 12 forks source link

Cannot create queues and connection issues #18

Open mikeST9981 opened 1 year ago

mikeST9981 commented 1 year ago

Hi, this is awesome you created this as Microsoft should have done this a long time ago. I am doing this on a M1 MacBook. I am using Docker Desktop 4.19.0 (106363). I could not get docker compose to build unless I updated the Dockerfiles to use arm64 instead of amd64. Once I did that, they build and RabbitMQ is up. However, if I add in the "EmulatorQueuesandTopics" environment field to the docker-compose.yml, none of the queues or topics I specified (I did "EmulatorQueuesAndTopics=test-queue;test-topic/Subscriptions/test-sub1;test-topic/Subscriptions/test-sub2") shows up. I am running the docker compose up without doing "detach" to see the logs and everything looks good there. I am able to go to the RabbitMQ web app and login, but no queues or topics there.

I created a basic C# console app where I do the following:

var client = new ServiceBusAdministrationClient(CONNECTION_STRING);
await client.QueueExistsAsync("myqueue");

Where I put in the connection string in "CONNECTION_STRING". For "Endpoint=sb://localhost/;SharedAccessKeyName=all;SharedAccessKey=CLwo3FQ3S39Z4pFOQDefaiUd1dSsli4XOAj3Y9Uh1E=;EnableAmqpLinkRedirect=false", it raises an exception saying it refuses to connect. If I use "Endpoint=sb://devopsifyme-local.servicebus.windows.net/;SharedAccessKeyName=all;SharedAccessKey=CLwo3FQ3S39Z4pFOQDefaiUd1dSsli4XOAj3Y9Uh1E=;EnableAmqpLinkRedirect=false", it cannot connect. If I use either "Endpoint=sb://sbemulator/;SharedAccessKeyName=all;SharedAccessKey=CLwo3FQ3S39Z4pFOQDefaiUd1dSsli4XOAj3Y9Uh1E=;EnableAmqpLinkRedirect=false" or "Endpoint=sb://emulator/;SharedAccessKeyName=all;SharedAccessKey=CLwo3FQ3S39Z4pFOQDefaiUd1dSsli4XOAj3Y9Uh1E=;EnableAmqpLinkRedirect=false", it just freezes.

I should have mentioned I imported the cert into KeyChain and set it to trust.

I would love to get this working so any insights would be appreciated into what is happening.

piotr-rojek commented 1 year ago

Hey @mikeST9981, thanks for all the kind words ;)

There are a couple of things here: 1) emulator is lazy and connects to rabbitmq only on the first SB connection; only then do queues get created => which is why you don't see anything in the web admin portal. Try, for example connecting a listener to a queue. 2) management endpoints are not supported now (they are REST on port 443); only the AMQP endpoint is implemented for actual messaging. Can you tell me a bit about your use case? Do you need these endpoints? I would like to know how you use ServiceBusAdministrationClient to see what can be done in the emulator. From a brief investigation, it is doable :)

/Piotr

mikeST9981 commented 1 year ago

Piotr,

Thanks for the quick response! My use case is I am just trying to get this to work at all. Like anybody else, it would be nice to be able to have a fully functioning Service Bus emulator that has all the interfaces as Azure Service Bus Namespace so that any code I have, I can unit test/integration test with it locally before ever having to connect to Azure for it.

I would have figured management endpoints would have worked since this is a Service Bus emulator and those work on regular Azure Service bus, but that is ok as it sounds like this emulator has only been out a few months. I would be great if ServiceBusAdministrationClient and AzureServiceBusManager would be able to work with it in the future.

Here is where I am at and it is not working.

  1. I updated the docker-compose.yml to have "EMULATORQueuesAndTopics=myqueue;mytopic/Subscriptions/subscription;mytopic/Subscriptions/subscription2" in it under "environment" (the EMULATORRABBITMQ__PASSWORD does not work as i changed it to something other than "guest" and that did not work).
  2. Performed "docker compose -f docker-compose.yml build". That builds successfully.
  3. Performed "docker compose -f docker-compose.yml up" and that seems to start up things fine. In RabbitMQ web app, no queues even though it is specified in the docker-compose.yml, but you are indicating that it is "lazy" and to make a listener connection.
  4. Created a "local.settings.json" for the "Example.AzureFuction" function app to be able to startup since it cannot without one. It's connection string is set to "Endpoint=sb://sbemulator/\;SharedAccessKeyName=all\;SharedAccessKey=CLwo3FQ3S39Z4pFOQDefaiUd1dSsli4XOAj3Y9Uh1E=\;EnableAmqpLinkRedirect=false".

The function app starts up and had to make a connection since it has ServiceBusTriggers. However, I do not see any queues in RabbitMQ web app even with the function app started up and of course those queues and topics specified in the docker-compose.yml file. Can you provide me step by step on how I can get queues and topics into the Service Bus emulator so that I can send a message to a queue to see the Example.AzureFunction work? It would be greatly appreciated.

piotr-rojek commented 1 year ago

I am adding management endpoint support to the backlog, I think ServiceBusAdministrationClient is doable, while ServiceBusManager would require some dirty coding on the client side, as by design it talks to management.azure.com endpoint directly. I see value in having the same setup code used both with the emulator as well as real resources.

At the same time note that the intent of this emulator is to primarily enable message flow and to ease both local development experience and CI - it is not meant to be a faithful SB emulator where behavior must be exactly the same. There are features supported by Service Bus, that the emulator's backend RabbitMQ does not support - so there will always be a gap. Whatsmore I don't see any kind of emulator being used with unit tests, as these should be kept in memory only, so no need for any external system communication. This is just to set some expectations ;) That said I will keep on adding features based on popular demand, my time availability, and help I get from others ;)

piotr-rojek commented 1 year ago

As to how to get it running, unfortunately, I don't have a Mac machine to test on, so you will have to help me out a bit :)

Some idea / asks:

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated",
    "EmulatorConnectionString": "Endpoint=sb://localhost/;SharedAccessKeyName=all;SharedAccessKey=CLwo3FQ3S39Z4pFOQDefaiUd1dSsli4XOAj3Y9Uh1E=;EnableAmqpLinkRedirect=false"
  }
}
mikeST9981 commented 1 year ago

Hi,

Thanks for all the help on this so far! I am not sure what you mean by "Could you try trusting emulator's cert directly instead of the issuing CA?". If I get that "cert.pfx" and try to add it to the Keychain, it asks for a password which I don't know the "cert.pfx" password.

I attached the docker output. Emulator.log

When I run the Azure Function with "Endpoint=sb://localhost/;SharedAccessKeyName=all;SharedAccessKey=CLwo3FQ3S39Z4pFOQDefaiUd1dSsli4XOAj3Y9Uh1E=;EnableAmqpLinkRedirect=false", the Azure Function is not able to startup and just shows over and over again: [2023-05-29T15:03:19.289Z] Message processing error (Action=Receive, EntityPath=myqueue, Endpoint=localhost) [2023-05-29T15:03:19.289Z] System.Private.CoreLib: The remote certificate is invalid according to the validation procedure: RemoteCertificateNameMismatch. If change "localhost" to "sbemulator" in the connection string, the Azure Function output shows as the following, but no queues or topics show up in the RabbitMQ web app even though the docker-compose.yaml I ran set them to be created: ` [2023-05-29T15:14:00.254Z] Azure Functions .NET Worker (PID: 9079) initialized in debug mode. Waiting for debugger to attach...

Functions:

    Function1: serviceBusTrigger

    Function2: serviceBusTrigger

    Function3: serviceBusTrigger

For detailed output, run func with --verbose flag. [2023-05-29T15:14:05.857Z] Worker process started and initialized. If I try to run the integration tests via command "docker compose -f ./docker-compose.yml -f ./docker-compose.integration.yml up --build integration", it is working (it wasn't before) and I do see queues from that which is cool! So then I add the following function to the Azure Function (using sbemulator connection string) as seen below, the Azure Function starts up fine, but if I publish a message (via RabbitMQ web app) to "test-queue", this new function does not pick it up. [Function("Function4")] public void Run4([ServiceBusTrigger("test-queue", Connection = "EmulatorConnectionString")] string myQueueItem) { _logger.LogInformation($"Test here {myQueueItem}"); } `

Jmorjsm commented 1 year ago

I am adding management endpoint support to the backlog, I think ServiceBusAdministrationClient is doable, while ServiceBusManager would require some dirty coding on the client side, as by design it talks to management.azure.com endpoint directly. I see value in having the same setup code used both with the emulator as well as real resources.

I'd be interested in working on this if that helps?

mikeST9981 commented 1 year ago

If I try the following code to just try to send a message to the queue the integration tests created, it does not work. If the endpoint has "localhost" or "https://devopsifyme-local.servicebus.windows.net/", it gives the error "The remote certificate is invalid according to the validation procedure: RemoteCertificateNameMismatch, RemoteCertificateChainErrors". If the endpoint has "sbemulator" or "emulator" in it, it gives an exception of "Operation timed out ErrorCode: TimedOut (ServiceCommunicationProblem). For troubleshooting information, see https://aka.ms/azsdk/net/servicebus/exceptions/troubleshoot.". The "testca" cert is trusted in Key Chain. Any thoughts why this is not working?

string ConnectionString = "Endpoint=sb://sbemualtor/;SharedAccessKeyName=all;SharedAccessKey=CLwo3FQ3S39Z4pFOQDefaiUd1dSsli4XOAj3Y9Uh1E=;EnableAmqpLinkRedirect=false";

var clientOptions = new ServiceBusClientOptions { TransportType = ServiceBusTransportType.AmqpTcp };

try { var client = new ServiceBusClient(ConnectionString, clientOptions); var sender = client.CreateSender("test-queue"); await sender.SendMessageAsync(new ServiceBusMessage("Hello")); await sender.DisposeAsync(); await client.DisposeAsync(); } catch (Exception e) { Console.WriteLine(e); throw; }

mikeST9981 commented 1 year ago

I was able to get it working for me. Once I found the password to the generated server pfx cert looking at the Dockerfiles, I added that into KeyChain and then had to trust that as well for it to work. It works with "localhost" in the endpoint.

For me to get this working on an M1 Mac, I had:

Before this is closed, I do have a couple of questions:

  1. Is it on the roadmap or possible to add the functionality of "topic filters"? https://learn.microsoft.com/en-us/azure/service-bus-messaging/topic-filters shows how it is done programmatically, but it can also of course be setup in Portal Azure for a Service Bus Namespace topic.
  2. Is it on the roadmap to allow "Managed Identity" type of connections where it is just the fully qualified name and not the connection string? https://learn.microsoft.com/en-us/azure/azure-functions/functions-identity-based-connections-tutorial-2#configure-your-service-bus-trigger-with-a-managed-identity discusses that.
piotr-rojek commented 1 year ago

I am adding management endpoint support to the backlog, I think ServiceBusAdministrationClient is doable, while ServiceBusManager would require some dirty coding on the client side, as by design it talks to management.azure.com endpoint directly. I see value in having the same setup code used both with the emulator as well as real resources.

I'd be interested in working on this if that helps?

Lets connect on LinkedIn and discuss the details, some help would be much appreciated!

piotr-rojek commented 1 year ago

I was able to get it working for me. Once I found the password to the generated server pfx cert looking at the Dockerfiles, I added that into KeyChain and then had to trust that as well for it to work. It works with "localhost" in the endpoint.

For me to get this working on an M1 Mac, I had:

  • Update all the Dockerfiles to pull images from platform arm64
  • Use "localhost" in the endpoint
  • Add the "cer" and "pfx" certificates to KeyChain under "System" and set them each to fully trusted

Before this is closed, I do have a couple of questions:

  1. Is it on the roadmap or possible to add the functionality of "topic filters"? https://learn.microsoft.com/en-us/azure/service-bus-messaging/topic-filters shows how it is done programmatically, but it can also of course be setup in Portal Azure for a Service Bus Namespace topic.
  2. Is it on the roadmap to allow "Managed Identity" type of connections where it is just the fully qualified name and not the connection string? https://learn.microsoft.com/en-us/azure/azure-functions/functions-identity-based-connections-tutorial-2#configure-your-service-bus-trigger-with-a-managed-identity discusses that.

Glad that it eventually worked for you :) I will add some FAQ with your findings about arm64 platform, thanks!

  1. I will have to look at it in detail, but it seems doable once management API is implemented
  2. Why would you need that? What is your use case? Managed Identities work only for apps deployed on Azure, and so far the main idea with this emulator was to support local dev experience and testing.
mikeST9981 commented 1 year ago

Thanks! For number 2, you are right that it is only for apps deployed. But it would be nice if this emulator would allow those type of connection string formats to work here too.

Luiz-Monad commented 4 months ago

Hi,

Thanks for all the help on this so far! I am not sure what you mean by "Could you try trusting emulator's cert directly instead of the issuing CA?". If I get that "cert.pfx" and try to add it to the Keychain, it asks for a password which I don't know the "cert.pfx" password.

I attached the docker output. Emulator.log

When I run the Azure Function with "Endpoint=sb://localhost/;SharedAccessKeyName=all;SharedAccessKey=CLwo3FQ3S39Z4pFOQDefaiUd1dSsli4XOAj3Y9Uh1E=;EnableAmqpLinkRedirect=false", the Azure Function is not able to startup and just shows over and over again: [2023-05-29T15:03:19.289Z] Message processing error (Action=Receive, EntityPath=myqueue, Endpoint=localhost) [2023-05-29T15:03:19.289Z] System.Private.CoreLib: The remote certificate is invalid according to the validation procedure: RemoteCertificateNameMismatch. If change "localhost" to "sbemulator" in the connection string, the Azure Function output shows as the following, but no queues or topics show up in the RabbitMQ web app even though the docker-compose.yaml I ran set them to be created: ` [2023-05-29T15:14:00.254Z] Azure Functions .NET Worker (PID: 9079) initialized in debug mode. Waiting for debugger to attach...

Functions:

    Function1: serviceBusTrigger

    Function2: serviceBusTrigger

    Function3: serviceBusTrigger

For detailed output, run func with --verbose flag. [2023-05-29T15:14:05.857Z] Worker process started and initialized. If I try to run the integration tests via command "docker compose -f ./docker-compose.yml -f ./docker-compose.integration.yml up --build integration", it is working (it wasn't before) and I do see queues from that which is cool! So then I add the following function to the Azure Function (using sbemulator connection string) as seen below, the Azure Function starts up fine, but if I publish a message (via RabbitMQ web app) to "test-queue", this new function does not pick it up. [Function("Function4")] public void Run4([ServiceBusTrigger("test-queue", Connection = "EmulatorConnectionString")] string myQueueItem) { _logger.LogInformation($"Test here {myQueueItem}"); } `

I was having this same problem with certificates. This is how I solved it https://github.com/Luiz-Monad/asb-emulator/commit/313d8f31eb8e6c20d40060651b0b7d27a11282b9

Just another harmony patch.