Pulumi: How can I retrieve function names from a Function App in Azure?

254 views Asked by At

Using Pulumi, how can I retrieve function names from a Function App in Azure?

Objective:

My objective is to retrieve all Azure functions and their associated API key for a given Function App.

Issue:

I am unable to find Pulumi documentation on how to programmatically retrieve function names from a Function App.

Then I can rely on the following function to accommodate my need:

await ListWebAppFunctionKeys.InvokeAsync(new ListWebAppFunctionKeysArgs {
    Name = appName,
    FunctionName = "?",
    ResourceGroupName = resourceGroupName
});

Alternative Approach:

I attempted to rely on an HTTP GET request (as a workaround) but observed an Unauthorized error:

  var current        = Pulumi.Azure.Core.GetClientConfig.InvokeAsync().Result;
  var subscriptionId = current.SubscriptionId;
  var appName        = functionApp.Name;

  var url = $"GET https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Web/sites/{appName}/functions?api-version=2022-03-01";

  var httpClient = new HttpClient();
  var result     = await httpClient.GetAsync(url);

  if (!result.IsSuccessStatusCode) throw new Exception($"Error: Failed to retrive Azure function names from {appName}");

  var json = result.Content.ReadAsStringAsync();

I'm unable to resolve the error. I think I need to create a bearer token but do not know the steps required.

1

There are 1 answers

0
Scott Nimrod On

First establish an authorization token:

var httpAuthClient = new HttpClient() { Timeout = new TimeSpan(0, 2, 0) };
httpAuthClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AuthToken.Value);

var functionNames = await FunctionNames.Get(resourceGroupName, functionAppName, httpAuthClient);

After an authorization token has been established the consider the following code:

public static class FunctionNames
{
    public static async Task<IEnumerable<string>> Get(string resourceGroupName, string appName, HttpClient httpAuthClient)
    {
        var url    = $"https://management.azure.com/subscriptions/{SubscriptionId.Value}/resourceGroups/{resourceGroupName}/providers/Microsoft.Web/sites/{appName}/functions?api-version=2022-03-01";
        var result = await httpAuthClient.GetAsync(url);

        if (!result.IsSuccessStatusCode) throw new Exception($"Error: Failed to retrive Azure function names from {appName}");

        var json = await result.Content.ReadAsStringAsync();
        var root = JsonConvert.DeserializeObject<JsonSupport.AzureFunctionItems.Root>(json);
        var functionNames = root.value.Select(v => v.properties.name);

        return functionNames;
    }

Here's some code for creating an auth token:

public static class BearerToken
{
    public async static Task<string> Create(string tenantId, string clientId, string clientSecret, string scope)
    {
        var tokenRequestBody = new Dictionary<string, string> {

            { "grant_type"   , "client_credentials" },
            { "client_id"    , clientId },
            { "client_secret", clientSecret },
            { "scope"        , scope }
            };

        var url      = $"https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token";
        var client   = new HttpClient() { BaseAddress = new Uri(url) };
        var content  = new FormUrlEncodedContent(tokenRequestBody);
        var response = await client.PostAsync("", content);

        if (response.IsSuccessStatusCode)
        {
            var tokenResponse = await response.Content.ReadAsStringAsync();
            var valueFor      = JsonConvert.DeserializeObject<JsonSupport.AccessToken.Root>(tokenResponse);

            return valueFor.access_token;
        }

        throw new Exception(response.ReasonPhrase);
    }
}

Here's the JSON root class for deserialization:

public class Root
{
    public string token_type { get; set; }
    public int expires_in { get; set; }
    public int ext_expires_in { get; set; }
    public string access_token { get; set; }
}