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

[Aspire.Microsoft.Azure.Cosmos] How to access the CosmosDB emulator data explorer? #5163

Open
hansmbakker opened this issue Aug 1, 2024 · 17 comments · May be fixed by #7048
Open

[Aspire.Microsoft.Azure.Cosmos] How to access the CosmosDB emulator data explorer? #5163

hansmbakker opened this issue Aug 1, 2024 · 17 comments · May be fixed by #7048
Labels
area-integrations Issues pertaining to Aspire Integrations packages azure Issues associated specifically with scenarios tied to using Azure azure-cosmosdb Issues related to Azure CosmosDB untriaged New issue has not been triaged

Comments

@hansmbakker
Copy link
Contributor

The Aspire.Microsoft.Azure.Cosmos component provides the

cosmosdb.RunAsEmulator();

method. Aspire.NET does recognize the 8081 port in the container (see screenshot). However, without any additional settings the emulator will only be exposed via a TCP endpoint which is not enough to access the data explorer dashboard from the emulator.

How can I expose the data explorer inside the emulator container best, during development? Can you please add this to the documentation?

image

@hansmbakker
Copy link
Contributor Author

hansmbakker commented Aug 1, 2024

A possible option I saw was doing the following:

var cosmos = builder.AddAzureCosmosDB("CosmosDb")
                                  .AddDatabase("mydatabase");

if (builder.Environment.IsDevelopment())
{
    cosmos.WithHttpsEndpoint(8081, 8081, "emulator-port")
          .RunAsEmulator();
}

However, doing the thing above results in 8081 being listed twice and it adds another emulator-port target port than I specified (see screenshot).

I would like to be confirmed that this is the correct approach, and have it in the documentation for reference.

image

@IEvangelist IEvangelist transferred this issue from dotnet/docs-aspire Aug 2, 2024
@samsp-msft samsp-msft added the area-integrations Issues pertaining to Aspire Integrations packages label Aug 7, 2024
@davidfowl davidfowl added enhancement azure Issues associated specifically with scenarios tied to using Azure azure-cosmosdb Issues related to Azure CosmosDB and removed area-dashboard labels Sep 7, 2024
@joperezr joperezr added the untriaged New issue has not been triaged label Oct 15, 2024
@obiwanjacobi
Copy link

A possible option I saw was doing the following:

var cosmos = builder.AddAzureCosmosDB("CosmosDb")
.AddDatabase("mydatabase");

if (builder.Environment.IsDevelopment())
{
cosmos.WithHttpsEndpoint(8081, 8081, "emulator-port")
.RunAsEmulator();
}
...

I did that but when I go to the endpoint in my browser it complains I need an authorization header.
How? Can I disable that somewhere?

@matt-goldman
Copy link

@obiwanjacobi per the docs for the Linux based emulator (which is what Aspire runs):

The emulator is comprised of two components:

  • Data explorer - interactively explore the data in the emulator. By default this runs on port 1234
  • Azure Cosmos DB emulator - a local version of the Azure Cosmos DB database service. By default, this runs on port 8081.

The emulator gateway endpoint is typically available on port 8081 at the address http://localhost:8081/. To navigate to the data explorer, use the address http://localhost:1234/ in your web browser. It may take a few seconds for data explorer to be available. The gateway endpoint is typically available immediately.

So mapping 8081 exposes emulator, not the dashboard, which is why you get that error. You have to map 1234 for the dashboard, using an HTTP endpoint, not an HTTPS endpoint. However, that still doesn't work, and it turns out it's due to an issue with the Cosmos DB emulator, not with Aspire. See: Azure/azure-cosmos-db-emulator-docker#135

That problem has actually been fixed as of yesterday, however the version with the fix is tagged as vnext-preview. So you'll need to wait until that gets promoted to latest. Or in the meantime you can do this:

var cosmos = builder.AddAzureCosmosDB("cosmos")
    .WithHttpEndpoint(51234, 1234, "explorer-port")
    .WithExternalHttpEndpoints()
    .RunAsEmulator(cfgContainer =>
    {
        cfgContainer
        .WithImageRegistry("mcr.microsoft.com")
        .WithImage("cosmosdb/linux/azure-cosmos-emulator")
        .WithImageTag("vnext-preview");
    });

Don't get me started on the kilometers of rabbit hole I've crawled through today to figure this out and get it to work - but it works:

Image

@davidfowl
Copy link
Member

Slight tweak:

var cosmos = builder.AddAzureCosmosDB("cosmos")
    .RunAsEmulator(cfgContainer =>
    {
        cfgContainer
        .WithHttpEndpoint(targetPort: 1234, "explorer-port")
        .WithImageRegistry("mcr.microsoft.com")
        .WithImage("cosmosdb/linux/azure-cosmos-emulator")
        .WithImageTag("vnext-preview");
    });

@obiwanjacobi
Copy link

obiwanjacobi commented Dec 7, 2024

This is what I got (AppHost)

var cosmos = builder.AddAzureCosmosDB("myaccount");
var cosmosDb = cosmos.AddDatabase("mydatabase");
if (builder.Environment.IsDevelopment())
{
    cosmos.RunAsEmulator(config => config
        .WithHttpEndpoint(targetPort: 1234, name: "explorer-port")
        .WithImageRegistry("mcr.microsoft.com")
        .WithImage("cosmosdb/linux/azure-cosmos-emulator")
        .WithImageTag("vnext-preview")
        //.WithLifetime(ContainerLifetime.Persistent)
        );
}

The container running cosmosDB is marked as unhealthy.

This is showing in the dashboard for the resource details:

Image

I would expect to see port 1234 in there somewhere in the endpoints...?

(I commented out the WithLifetime call because at first it just hung on 'starting...')

@davidfowl
Copy link
Member

@obiwanjacobi
Copy link

https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/networking-overview

Ah - so there's a proxy in front of it. Right, thanks.

But still, why does my container read unhealthy when I configure this?
Any suggestions where I could start to look?

@matt-goldman
Copy link

matt-goldman commented Dec 8, 2024

EDIT: I think this is probably wrong. It's more likely related to the SSL issue - I've spent a little bit of time on it but need to look into it more.

Original:

I'm still trying to get my head around why exactly this happens and what the fix might be, but the problem seems to be that when using a custom container image it doesn't publish the connection string, and Aspire is waiting for the publish event to mark it as healthy. Or more specifically, waiting for a CosmosClient to be created, which waits for the connection string publish event. See:

builder.ApplicationBuilder.Eventing.Subscribe<ConnectionStringAvailableEvent>(builder.Resource, async (@event, ct) =>

Without debugging Apsire locally, I can't determine whether the issue is caused by a difference in the container image, or a difference in the way Aspire instantiates it when you provide a custom container spec. See:

I can't see anything here that would cause it inherently, but it's possible that because this code is adding it as AzureCosmosDBEmulatorResource which doesn't implement IResourceWithConnectionString (required to publish the event, see:

private async Task PublishConnectionStringAvailableEvent(IResource resource, CancellationToken cancellationToken)
).

But I'm a little out of my depth here and mostly speculating. Either way I'm fairly sure that when using this image the connection string is either not published or the resource is not registered as an implementation of IResourceWithConnectionString and therefore even if it is published the event is not raised.

Maybe @davidfowl can help?

Obviously aside from the health check, we need the connection string and/or client to use the resource, but there's definitely a workaround for that. I don't have time to figure that out right now but I might get some time on the weekend to poke around at this a bit more.

@trulsmp
Copy link

trulsmp commented Dec 9, 2024

Got it working for me with an update to set https on container startup as detailed in notes on the docs for the linux emulator. Both explorer, health check, persistent lifetime and also client side with connection string resolving work as expected. The explorer however gives unsafe warning.
https://learn.microsoft.com/en-us/azure/cosmos-db/emulator-linux#running

Would be great for others to verify. Should any defaults change to use https or is this only part of the preview emulator container?

Example code:

var cosmos = builder.AddAzureCosmosDB("cosmos")
    .RunAsEmulator(cfgContainer =>
    {
        cfgContainer
            .WithHttpsEndpoint(targetPort: 1234, name: "explorer-port")
            .WithImageRegistry("mcr.microsoft.com")
            .WithImage("cosmosdb/linux/azure-cosmos-emulator")
            .WithImageTag("vnext-preview")
            .WithLifetime(ContainerLifetime.Persistent)
            .WithArgs("--protocol", "https");
    });

@matt-goldman
Copy link

@trulsmp working for me too!

@matt-goldman
Copy link

Ok so the dashboard works and the emu reports healthy. But I can't get any queries to work with the SDK. I spent a lot of time on this today and had to switch to an instance on Azure to get unblocked with my day job. Obviously not an Aspire issue, but @trulsmp just wondering whether you had this issue too? If it's not just me I'll try to find some time to create a small repro and report it on the emulator repo.

@trulsmp
Copy link

trulsmp commented Dec 10, 2024

@matt-goldman I got queries to work and tested with item create and retrieval. Using the client integration in Azure Function isolated project orchestrated by Aspire.

I can share some example codebits, nothing special here just following standard setup.

Program.cs in Functions project using the client from Aspire. Using same name for the resource as in AppHost. Package used is Aspire.Microsoft.Azure.Cosmos according to docs: https://learn.microsoft.com/en-us/dotnet/aspire/database/azure-cosmos-db-integration?tabs=dotnet-cli#get-started

using Microsoft.Azure.Functions.Worker.Builder;
using Microsoft.Extensions.Hosting;

var builder = FunctionsApplication.CreateBuilder(args);

builder.AddServiceDefaults();

builder.AddAzureCosmosClient("cosmos");

builder.ConfigureFunctionsWebApplication();

var host = builder.Build();

await host.RunAsync();

Using the client in a function. Checking and possibly creating database/container if needed. Note that "id" needs to match case in cosmos db.

record User(string userId, string id, string name, string address);

public class HttpTriggers(CosmosClient client)
{
    [Function("CreateItem")]
    public async Task<IActionResult> CreateItem([HttpTrigger(AuthorizationLevel.Anonymous, "get")] HttpRequest req)
    {
        await client.CreateDatabaseIfNotExistsAsync("cosmosdb");
        var db = client.GetDatabase("cosmosdb");
        await db.CreateContainerIfNotExistsAsync("user", "/userId");
        var container = db.GetContainer("user");

        var partitionKey = Guid.CreateVersion7().ToString();

        await container.CreateItemAsync(
            item: new User(partitionKey, "profile", "John Doe", "123 Main St"),
            partitionKey: new PartitionKey(partitionKey)
        );

        return new OkResult();
    }

@matt-goldman
Copy link

@trulsmp I can insert (or upsert) items, but I can't query anything. I think it's an SDK issue though, as I can via the explorer (with vnext-preview). But the SDK works with Azure Cosmos. So I'm not sure. This is all in a client project but if I get time over the weekend I'll see if I can replicate it in a minimal repro.

@obiwanjacobi
Copy link

You guys got the DataExplorer to work (port 1234)?

I use the same code as posted above earlier with only setting the isProxied to false. This made the port appear in docker and the dashboard. But going there is a no-show (empty response).

var cosmos = builder.AddAzureCosmosDB("cosmos")
    .RunAsEmulator(cfgContainer =>
    {
        cfgContainer
            .WithHttpsEndpoint(targetPort: 1234, name: "explorer-port", isProxied: false)
            .WithImageRegistry("mcr.microsoft.com")
            .WithImage("cosmosdb/linux/azure-cosmos-emulator")
            .WithImageTag("vnext-preview")
            .WithArgs("--protocol", "https");
            .WithLifetime(ContainerLifetime.Persistent)
    });

Upsert and reading of a document works fine and the instance is also healthy now (not sure what I did wrong before).

@obiwanjacobi
Copy link

I just noticed in the environment variables of the cosmos container that the protocol is set a weird value.

EXPLORER_PORT=1234
EXPLORER_PROTOCOL=PROTOCOL

Shouldn't that be http or https?

@matt-goldman
Copy link

@davidortinau FYI

@obiwanjacobi
Copy link

Adding .WithArgs("--explorer-protocol", "http") seem to have fixed it for me. The EXPLORER_PROTOCOL environment variable still has that weird PROTOCOL value - but the data explorer works now.

(Thanks to Egil Hansen on the Orleans Discord group.)

eerhardt added a commit to eerhardt/aspire that referenced this issue Jan 8, 2025
Added a new experimental API - RunAsPreviewEmulator. This will use the new Linux-based
emulator, which starts faster. And it also has support for a built-in Data Explorer
which can be enabled by calling WithDataExplorer on the emulator.

Fix dotnet#5163
@eerhardt eerhardt linked a pull request Jan 8, 2025 that will close this issue
10 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-integrations Issues pertaining to Aspire Integrations packages azure Issues associated specifically with scenarios tied to using Azure azure-cosmosdb Issues related to Azure CosmosDB untriaged New issue has not been triaged
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants