Azure / Azure-Functions

1.11k stars 193 forks source link

proxies.json to "Azure API Management" in v4 migration guide? Local execution? #2165

Open JasonKleban opened 2 years ago

JasonKleban commented 2 years ago

I found this statement that Azure Functions v4 doesn't support proxies.json. Is there an explanation for this change? Is there a migration guide to Azure API Management? Is there a way to run the Azure API Management locally for apps that require the proxy behavior to operate correctly?

I see there is some idea of automatic migration Import an Azure Function App as an API in Azure API Management but I'm weary of even experimenting with changes to even the Dev environment of my Terraform-managed app for fear of corrupting it (could it be 100% undone after collecting the auto-migrated configurations?)

Here is a representation of the various proxies.json features I currently use. Default document, many-to-one resolution, wildcards, external routing, environment variable injection, query parameter passthrough. API Management can do these, and emulate them on the local developer machine?

{
  "$schema": "http://json.schemastore.org/proxies",
  "proxies": {
    "public-default": {
      "matchCondition": {
        "route": "/"
      },
      "backendUri": "http://localhost/api/assets/index.html"
    },
    "public-index": {
      "matchCondition": {
        "route": "/index.html"
      },
      "backendUri": "http://localhost/api/assets/index.html"
    },
    "other_assets": {
      "matchCondition": {
        "route": "/assets/{*any}"
      },
      "backendUri": "http://localhost/api/assets/other/{any}"
    },
    "third_party": {
      "matchCondition": {
        "methods": [ "GET" ],
        "route": "/example/third_party"
      },
      "backendUri": "https://www.example.com?auth=%example_license_key%&query={request.querystring.query}"
    }
  }
}
v-bbalaiagar commented 2 years ago

Tagging @anthonychu , for more inputs

aiden-liu commented 2 years ago

I also see no way of solving this issue locally, however if turning head to API Management (as official recommend) for alternative, can set redirect policy for operation(s), say index, acting like proxy.

<policies>
      <inbound>
          <base />
          <rewrite-uri template="/assets/index.html" />
      </inbound>
      <backend>
          <base />
      </backend>
      <outbound>
          <base />
      </outbound>
      <on-error>
          <base />
      </on-error>
  </policies>

Again, this could be a far simple solution that not apply to all scenarios, as I only dived deep enough to solve my problem.

JasonKleban commented 2 years ago

@anthonychu?

anthonychu commented 2 years ago

For serving static files, better options would be either hosting them in blob storage or using Azure Static Web Apps.

@kulkarnisonia16

JasonKleban commented 2 years ago

Better for whom?

For this application, some assets are dynamic, at least in the sense of a custom security check.

JasonKleban commented 2 years ago

Update your Azure Functions apps to use runtime version 4.x before 3 December 2022

On 3 December 2022, .NET Core 3.1 will be retired. As a result, Azure Functions runtime versions 2.x and 3.x, which use .NET Core 3.1, will also be retired on that date.

Your Functions applications that use runtime version 2.x or 3.x will continue to run and your existing workloads won't be affected. However, we'll no longer provide updates or customer service for applications that use these versions.

This issue is a blocker for Functions v4 adoption.

JasonKleban commented 2 years ago

@kulkarnisonia16 ?

JasonKleban commented 2 years ago

There is still no migration guide that I can find. How can this proxies.json wildcard path prefix redirect be expressed in api_management_api_operation & operation policy?

    "other_assets": {
      "matchCondition": {
        "route": "/assets/{*restOfPath}"
      },
      "backendUri": "http://localhost/api/assets/other/{restOfPath}"
    },

this seems to me to need some kind of support like:

resource "azurerm_api_management_api_operation" "example" {
  ...
  method              = "*"
  url_template        = "/assets/{*restOfPath}"
}

resource "azurerm_api_management_api_operation_policy" "example" {
  ...

  xml_content = <<XML
<policies>
  <inbound>
    <rewrite-uri template="/api/assets/other/{any}" />
    # or perhaps
    <set-backend-service base-url="/api/assets/other/" />
  </inbound>
</policies>
XML

}

but I cannot find documentation or examples on a wildcard method nor a {*restOfPath} concept on _urltemplate. I cannot find relevant documentation on Operation Template Parameters in case it supports a {*restOfPath} analog.

JesseDeBruijne commented 2 years ago

Gonna have to second this issue.

It's weird to recommend that you switch to Azure API Management because it "provides the same capabilities as Functions Proxies" but then provide no migration guide or as @JasonKleban already mentioned not even provide the same capabilities (wildcard forwarding is something I need as well).

isaacrlevin commented 2 years ago

FWIW I added my Function to a new API Management Instance and I have no idea what policies to set. My use case is that I have a UrlShortener that takes a url like this

https://isaacl.dev/presence-light

and transforms it into

https://www.theurlist.com/presencelight

I WAS doing this in Functions v3 with proxies like so

{
  "$schema": "http://json.schemastore.org/proxies",
  "proxies": {
    "Domain Redirect": {
      "disabled": false,
      "matchCondition": {
        "route": "/{*shortUrl}"
      },
      "backendUri": "http://localhost/api/UrlRedirect/{shortUrl}"
    },
    "Api": {
      "disabled": false,
      "matchCondition": {
        "route": "/api/{*path}"
      },
      "backendUri": "http://localhost/api/{path}"
    }
  }
}

I have no idea how to use this with transform policies. If I just test, it doesn't seem to do the rewrite and I just get routed to a fallback url I set in the Function. Some help would be greatly appreciated

JasonKleban commented 2 years ago

Hello? @kulkarnisonia16? @anthonychu? @v-bbalaiagar? Time's ticking toward this December Drop-Dead date. While this is github and open source, it exists solely to support Microsoft's Azure paid platform. Long-term stability of APIs that enable businesses to operate is a crucial responsibility of this product team (I'm not sure if any of the tagged folks are on that team).

Note to that product team - It would be my preference to carry the proxies.json support forward because it is a good and useful tool and you still get paid for it as function executions.

JesseDeBruijne commented 2 years ago

I have now made the switch to an Azure Static Web App for my app. They provide Routing Configuration within the app which was enough to satisfy the needs for my app. It includes stuff like wildcard routing, response headers, URL rewrites/redirects, even Authentication and Authorization.

Maybe it helps someone else.

vyzvam commented 1 year ago

as for the deprecation on December. it is mentioned that "Extended support for .NET Core 3.1 in Azure Functions is retiring on December 3rd 2022" Will i still be able to provision function apps using runtime version 2. My existing apps are still using proxies and expecting to use the same code for new provisioning.

MacMcDell commented 1 year ago

We really need some support on this issue. I have read rumours that proxy support is returning to V4. We need to understand when proxy support is returning. Not being able to test functions/route paths locally is at least for me a show stopper. Can this thread please by updated.

shambhu-svyc commented 1 year ago

As per latest update, proxy can be re-enable usingAzureWebJobsFeatureFlags = EnableProxies see: https://learn.microsoft.com/en-us/azure/azure-functions/legacy-proxies

jlocans commented 1 year ago

Added "AzureWebJobsFeatureFlags": "EnableProxies" to local.settings.json, but now the application won't start.

This is the log I get.

Azure Functions Core Tools
Core Tools Version:       4.0.4895 Commit hash: N/A  (64-bit)
Function Runtime Version: 4.13.0.19486

Warning: Proxies are not supported in Azure Functions v4. Instead of 'proxies.json', try Azure API Management: https://aka.ms/AAfiueq
[2022-11-23T14:47:37.661Z] Found C:\work\my-proj\MyProj.Api\MyProj.Api.csproj. Using for user secrets file configuration.
[2022-11-23T14:47:38.697Z] Unsupported service transport type: . Use default Transient instead.
[2022-11-23T14:47:41.618Z] A host error has occurred during startup operation '30720274-af87-45ce-a08c-1a51d03fa49e'.
[2022-11-23T14:47:41.619Z] Autofac: An error occurred during the activation of a particular registration. See the inner exception for details. Registration: Activator = ProxyHandler (ReflectionActivator), Services = [Microsoft.Azure.AppService.Proxy.Runtime.ProxyHandler], Lifetime = Autofac.Core.Lifetime.RootScopeLifetime, Sharing = Shared, Ownership = OwnedByLifetimeScope ---> An error occurred during the activation of a particular registration. See the inner exception for details. Registration: Activator = ITelemetryListener[] (DelegateActivator), Services = [Microsoft.Azure.AppService.Proxy.Runtime.Logging.ITelemetryListener[]], Lifetime = Autofac.Core.Lifetime.CurrentScopeLifetime, Sharing = None, Ownership = ExternallyOwned ---> An error occurred during the activation of a particular registration. See the inner exception for details. Registration: Activator = KpiLogService (ReflectionActivator), Services = [Microsoft.Azure.AppService.Proxy.Runtime.Logging.ITelemetryListener], Lifetime = Autofac.Core.Lifetime.RootScopeLifetime, Sharing = Shared, Ownership = OwnedByLifetimeScope ---> An exception was thrown while invoking the constructor 'Void .ctor(Microsoft.Azure.AppService.Proxy.Runtime.Settings)' on type 'KpiLogService'. ---> Could not load file or assembly 'System.Reactive.Core, Version=3.0.3000.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263'. The system cannot find the file specified. (See inner exception for details.) (See inner exception for details.) (See inner exception for details.) (See inner exception for details.). Autofac: An error occurred during the activation of a particular registration. See the inner exception for details. Registration: Activator = ITelemetryListener[] (DelegateActivator), Services = [Microsoft.Azure.AppService.Proxy.Runtime.Logging.ITelemetryListener[]], Lifetime = Autofac.Core.Lifetime.CurrentScopeLifetime, Sharing = None, Ownership = ExternallyOwned ---> An error occurred during the activation of a particular registration. See the inner exception for details. Registration: Activator = KpiLogService (ReflectionActivator), Services = [Microsoft.Azure.AppService.Proxy.Runtime.Logging.ITelemetryListener], Lifetime = Autofac.Core.Lifetime.RootScopeLifetime, Sharing = Shared, Ownership = OwnedByLifetimeScope ---> An exception was thrown while invoking the constructor 'Void .ctor(Microsoft.Azure.AppService.Proxy.Runtime.Settings)' on type 'KpiLogService'. ---> Could not load file or assembly 'System.Reactive.Core, Version=3.0.3000.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263'. The system cannot find the file specified. (See inner exception for details.) (See inner exception for details.) (See inner exception for details.). Autofac: An error occurred during the activation of a particular registration. See the inner exception for details. Registration: Activator = KpiLogService (ReflectionActivator), Services = [Microsoft.Azure.AppService.Proxy.Runtime.Logging.ITelemetryListener], Lifetime = Autofac.Core.Lifetime.RootScopeLifetime, Sharing = Shared, Ownership = OwnedByLifetimeScope ---> An exception was thrown while invoking the constructor 'Void .ctor(Microsoft.Azure.AppService.Proxy.Runtime.Settings)' on type 'KpiLogService'. ---> Could not load file or assembly 'System.Reactive.Core, Version=3.0.3000.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263'. The system cannot find the file specified. (See inner exception for details.) (See inner exception for details.). Autofac: An exception was thrown while invoking the constructor 'Void .ctor(Microsoft.Azure.AppService.Proxy.Runtime.Settings)' on type 'KpiLogService'. ---> Could not load file or assembly 'System.Reactive.Core, Version=3.0.3000.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263'. The system cannot find the file specified. (See inner exception for details.). Microsoft.Azure.AppService.Proxy.Runtime: Could not load file or assembly 'System.Reactive.Core, Version=3.0.3000.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263'. The system cannot find the file specified.
[2022-11-23T14:47:41.636Z] Failed to stop host instance 'bd4f2f1a-92b7-4121-bf35-99eecdfd8c78'.
[2022-11-23T14:47:41.637Z] Microsoft.Azure.WebJobs.Host: The host has not yet started.
Value cannot be null. (Parameter 'provider')
Press any key to continue....

And it goes in an endless cycle trying to start. I'm also not sure how to target the latest Function Runtime Version. I've specified "FUNCTIONS_EXTENSION_VERSION": "4.15.0" in local settings, but as you can see, it is still using 4.13.0.19486

Can't find which is the version where this is supposed to be fixed either. None of the releases mention anything about proxies.

Misiu commented 1 year ago

As per latest update, proxy can be re-enable usingAzureWebJobsFeatureFlags = EnableProxies see: https://learn.microsoft.com/en-us/azure/azure-functions/legacy-proxies

this works in the azure portal, but how to do this in Visual Studio when developing and testing locally?

jlocans commented 1 year ago

Update Azure Functions Core Tools to the latest version. Previously it didn't have these changes yet, but now it does. The flag will work locally as well.

Misiu commented 1 year ago

@jlocans I tried adding this in host.json, not in local.settings.json. Now it works. Thank You!

MacMcDell commented 11 months ago

for local testing: FWIW.. I had a ticket to get proxies working again. I updated azure function core tools.. not sure I needed to but whatever.. didn't work. Added the appsetting of "AzureWebJobsFeatureFlags" : "EnableProxies", still didn't work looked at my proxies file again.. it had this:

  "backendUri": "%API_HOSTNAME%/api/v1/somecontroller/{id}"
  ...

added "API_HOSTNAME" : "http://localhost:7071" and it started to work