Skip to content

Allow better modeling of external endpoints to enable resources to reference each other's non-external vs. external endpoints #2658

@DamianEdwards

Description

@DamianEdwards

As part of building out the HealthChecksUI sample and the addition of the EndpointAnnotation.IsExternal flag in preview.5, it's become clear we need to improve how we model a resource's endpoints such that another resource can explicitly reference its internal or external endpoint in cases where they differ.

In short, we should ensure that external endpoints are explicitly modeled in a consistent manner and our default experiences for resources result in discrete external endpoints being modeled (in addition to the default endpoints) when that resource is marked as external.

Strawman for proposed changes:

  • Add a new AsExternal() extension method to IResourceBuilder<T> where T : IResourceWithEndpoints that creates copies of all the resource's non-external endpoints but marked as external and named for the original endpoint but with a -external suffix. This can be used to easily expose external endpoints for any resource, e.g.:

    builder.AddProject<Projects.MyFrontend>("frontend")
       .WithReference(basketService)
       .WithReference(catalogService)
       .AsExternal();

    Assuming an ASP.NET Core project has a launch profile "https" with two endpoints defined in its "applicationUrl" property (one for https, one for http), and the AppHost project was launched using a launch profile named "https", the above would result in four endpoints being modeled for the project:

    1. "https": IsExternal = false
    2. "http": IsExternal = false
    3. "https-external": IsExternal = true
    4. "http-external": IsExternal = true
  • Update the Dcp.ApplicationExecutor such that resource endpoints with IsExternal and IsProxied set to true result in DCP launching the proxy configured to listen on the additional port for that "external" endpoint, but resolve to the usual target port for the application instance(s), i.e. the proxy terminates all endpoints marked as IsExternal and forwards them to the application instance(s) listen port(s).

  • Update the Dcp.ApplicationExecutor such that the logic for injecting the endpoint port into the application instance(s) is based on whether the EnivonrmentVariable property on the endpoint is set and some way for the resource to specialize how the value should be written to the variable. The default would be to group endpoint ports into a semi-colon delimited string for each environment variable specified but the ProjectResource would implement the hook (interface or annotation) to specify it wants the full endpoint URL written via a semi-colon delimited list if the environment variable is ASPNETCORE_URLS. The goal here is to remove all the custom logic in ApplicationExecutor for how the endpoint details are written into the environment variables.

  • Consider updating EndpointReference and adding convenience methods to allow easily retrieving the desired external endpoint for a resource, e.g. GetExternalEndpoint(string name) which will look for an endpoint where (Name == name || Name == $"{name}-external") && IsExternal == true`.

    • ❓ Should there be a concept of getting the "default" endpoint so that I can simply ask for a resource's default endpoint without needing to know its name? Maybe just GetExternalEndpoints() and GetEndpoints() that returns an IEnumerable<EndpointReference> would be enough, along with WithReference(IEnumerable<EndpointReference> endpoints), then one could do .WithReference(frontend.GetExternalEndpoints())
  • Update WithReference(IResourceBuilder<IResourceWithEndpoints> resource) to use only the non-external endpoints of the passed resource. Resources wishing to reference another resource's external endpoint will need to pass the EndpointReference of the external endpoint explicitly (see suggestion for GeExternalndpoint above), e.g.:

        builder.AddProject<Projects.MyFrontend>("frontend")
           .WithReference(basketService)
           .WithReference(catalogService)
           .AsExternal();
    
        builder.AddAvailabilityChecker("availabilitychecker")
            .WithReference(frontend.GetExternalEndpoint("http")); // See point above about whether we should introduce concept of "default" endpoint so names don't have to be hard-coded like this
  • ❓ Are any updates to manifest writing for endpoints needed (and by extension AZD)? e.g. how to make AZD understand that a reference to {frontend.bindings.http-external.url} means the externally resolvable FQDN assigned by ACA needs to be used?

    • I hit a couple of issues in AZD when building out the sample:
      • When trying to set the environment variable of a resource to just the host portion of another resource's endpoint, e.g. the manifest contained "env": { "AllowedHosts": "{apiservice.bindings.http.host};{apiservice.bindings.https.host}" ... , this resulted in the environment variable being set to just "apiservice;apiservice" rather than the full internal hostname from the binding URL.
      • For a container resource that had environment variable expressions that referenced other resources, it looked like AZD's own yaml templating syntax was being written into the resources.bicep file that's used to deploy the container resource, which resulted in that expression not being processed and just being directly to the ACA app environment variables config.

Related #2099

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-app-modelIssues pertaining to the APIs in Aspire.Hosting, e.g. DistributedApplication

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions