如何以编程方式 Enable/Disable Azure Function

How to Enable/Disable Azure Function programmatically

有没有办法以编程方式 enable/disable Azure 函数?

我可以 enable/disable 使用 "Manage" 部分下门户的功能,这会导致将请求发送到 https://<myfunctionapp>.scm.azurewebsites.net/api/functions/<myfunction>

JSON 有效负载看起来有点像:

{
   "name":"SystemEventFunction",
   "config":{
      "disabled":true,
      "bindings":[ 
         // the bindings for this function
       ]
   }
  // lots of other properties (mostly URIs)
}

我正在门户之外创建一个管理工具,允许用户启用和禁用功能。

希望我可以避免手动创建 JSON 负载,所以我想知道 SDK(WebJobs??)中是否有具有此功能的东西。

不,这目前是不可能的。 function.json 中的 disabled 元数据 属性 决定功能是否启用。当您 enable/disable 在门户中时,门户只会更新该值。

不确定它是否能满足您的需求,但我会指出还有一个 host.json functions 数组可用于控制将要加载的函数集(记录 here)。因此,例如,如果您只想启用 10 个函数中的 2 个,则可以将此 属性 设置为仅包含这 2 个函数名称的数组(例如 "functions": [ "QueueProcessor", "GitHubWebHook" ]),并且只有那些 [=21] =].但是,这与 enable/disable 略有不同,因为您将无法通过门户调用排除的函数,而您可以通过门户调用 disabled 函数。

我想您可以使用 Kudu REST API(特别是 VFS)来更新 function.json 中的 disabled 元数据 属性。那会禁用该功能吗? 这是 Kudu REST API。 https://github.com/projectkudu/kudu/wiki/REST-API

根据@James Z. 的回答,我在 C# 中创建了以下 class,允许您以编程方式禁用/启用 Azure 函数。

functionsSiteRoot 构造函数参数是 Functions 应用程序的 Kudu 根,例如 https://your-functions-web-app.scm.azurewebsites.net/api/vfs/site/wwwroot/

用户名和密码可以在您的功能的应用服务设置中"Get publish profile"获得。

public class FunctionsHelper : IFunctionsHelper
{
    private readonly string _username;
    private readonly string _password;
    private readonly string _functionsSiteRoot;
    private WebClient _webClient;

    public FunctionsHelper(string username, string password, string functionsSiteRoot)
    {
        _username = username;
        _password = password;
        _functionsSiteRoot = functionsSiteRoot;

        _webClient = new WebClient
        {
            Headers = { ["ContentType"] = "application/json" },
            Credentials = new NetworkCredential(username, password),
            BaseAddress = functionsSiteRoot
        };
    }

    public void StopFunction(string functionName)
    {
        SetFunctionState(functionName, isDisabled: true);
    }

    public void StartFunction(string functionName)
    {
        SetFunctionState(functionName, isDisabled: false);
    }

    private void SetFunctionState(string functionName, bool isDisabled)
    {
        var functionJson =
            JsonConvert.DeserializeObject<FunctionSettings>(_webClient.DownloadString(GetFunctionJsonUrl(functionName)));
        functionJson.disabled = isDisabled;
        _webClient.Headers["If-Match"] = "*";
        _webClient.UploadString(GetFunctionJsonUrl(functionName), "PUT", JsonConvert.SerializeObject(functionJson));
    }

    private static string GetFunctionJsonUrl(string functionName)
    {
        return $"{functionName}/function.json";
    }
}

internal class FunctionSettings
{
    public bool disabled { get; set; }
    public List<Binding> bindings { get; set; }
}

internal class Binding
{
    public string name { get; set; }
    public string type { get; set; }
    public string direction { get; set; }
    public string queueName { get; set; }
    public string connection { get; set; }
    public string accessRights { get; set; }
}

除了上面@DavidGouge 的回答,他 post 编写的代码确实有效,我刚刚对其进行了测试,并将在我的应用程序中使用它。但是它需要一些调整:

  1. 移除对 IFunctionsHelper 的继承。我不确定那个界面是什么,但它不是必需的。

  2. 如下更改绑定的 class 定义:

        internal class Binding
        {
            public string name { get; set; }
            public string type { get; set; }
            public string direction { get; set; }
            public string queueName { get; set; }
            public string connection { get; set; }
            public string accessRights { get; set; }
            public string schedule { get; set; }
        }
    

    之后就可以了。

P.S。我会把它作为对原始答案的评论,但我在 Stack Overflow 上的声誉不足以 post 评论!

用于通过 CLI 禁用 Azure 功能的 CLI 命令 - 已记录 here

 az functionapp config appsettings set --name <myFunctionApp> \
    --resource-group <myResourceGroup> \
    --settings AzureWebJobs.QueueTrigger.Disabled=true

我在 运行 执行上述命令时捕获了 fiddler。 Azure CLI 在 Python 进程上运行 python 进程正在向

发出请求

https://management.azure.com 更新应用程序设置。

在以下 REST 端点中获得了对同一端点的引用: https://docs.microsoft.com/en-us/rest/api/appservice/webapps/updateapplicationsettings

请求 URI :

PUT https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Web/sites/{name}/config/appsettings?api-version=2019-08-01

Headers :

Authorization: Bearer <> ; Content-Type: application/json; charset=utf-8

请求Body:

{"kind": "<class 'str'>", "properties":JSON}

我们可以对属性进行硬编码或动态获取。要禁用该功能,必须更新属性的 JSON 节点:Azure.WebJobs.QueueTrigger.Disabled = True

要获取可以使用端点的属性,您可以参考 Web Apps - List Application Settings 输出如下所示:

希望这对您有所帮助:)

结合使用@Satya V 和@DavidGouge 的解决方案,我想出了这个:

public class FunctionsHelper
{
    private readonly ClientSecretCredential _tokenCredential;
    private readonly HttpClient _httpClient;

    public FunctionsHelper(string tenantId, string clientId, string clientSecret, string subscriptionId, string resourceGroup, string functionAppName)
    {
        var baseUrl =
            $"https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroup}/providers/Microsoft.Web/sites/{functionAppName}/";
        var httpClient = new HttpClient
        {
            BaseAddress = new Uri(baseUrl)
        };

        _httpClient = httpClient;
        
        _tokenCredential = new ClientSecretCredential(tenantId, clientId, clientSecret);
    }

    private async Task SetAuthHeader()
    {
        var accessToken = await GetAccessToken();
        _httpClient.DefaultRequestHeaders.Authorization = AuthenticationHeaderValue.Parse($"Bearer {accessToken}");
    }

    private async Task<string> GetAccessToken()
    {
        return (await _tokenCredential.GetTokenAsync(
            new TokenRequestContext(new[] {"https://management.azure.com/.default"}))).Token;
    }
    
    public async Task StopFunction(string functionName)
    {
        await SetFunctionState(functionName, isDisabled: true);
    }

    public async Task StartFunction(string functionName)
    {
        await SetFunctionState(functionName, isDisabled: false);
    }

    private async Task SetFunctionState(string functionName, bool isDisabled)
    {
        await SetAuthHeader();
        var appSettings = await GetAppSettings();
        appSettings.properties[$"AzureWebJobs.{functionName}.Disabled"] = isDisabled ? "1" : "0";

        var payloadJson = JsonConvert.SerializeObject(new
        {
            kind = "<class 'str'>", appSettings.properties
        });

        var stringContent = new StringContent(payloadJson, Encoding.UTF8, "application/json");
        
        await _httpClient.PutAsync("config/appsettings?api-version=2019-08-01", stringContent);
    }
    
    private async Task<AppSettings> GetAppSettings()
    {
        var res  = await _httpClient.PostAsync("config/appsettings/list?api-version=2019-08-01", null);
        
        var content = await res.Content.ReadAsStringAsync();
        
        return JsonConvert.DeserializeObject<AppSettings>(content);
    }
}

internal class AppSettings
{ 
    public Dictionary<string, string> properties { get; set; }
}

使用 Kudu api 更新 function.json 文件的问题是它会在任何后续部署中被覆盖。这使用 Azure 的 Rest Api 来更新应用程序的配置。不过,您首先需要 Azure 服务原则才能使用 api。

使用 Azure Cli,您可以 运行 az ad sp create-for-rbac 生成服务原则并获取客户端 ID 和客户端密码。因为 UpdateConfiguration 端点不允许您更新单个值,并且会用新值覆盖整个 Configuration 对象,所以您必须首先获取所有当前 Configuration 值,更新您想要的值,然后使用新值调用 Update 端点配置键和值。

这个怎么样:https://docs.microsoft.com/en-us/azure/azure-functions/disable-function?tabs=portal#localsettingsjson

这看起来是最简单的本地开发解决方案。