调用 Azure 函数/REST API 检查

使用调用 Azure 函数/REST API 检查可以编写代码,以确定是否允许特定管道阶段访问受保护的资源。 这些检查可以在两种模式下运行:

  • 异步(建议):推送模式,在此模式下,Azure DevOps 等待 Azure 函数/REST API 实现通过阶段访问决策回调到 Azure DevOps
  • 同步:轮询模式,其中 Azure DevOps 定期调用 Azure 函数/REST API 以获取阶段访问决策

在本指南的其余部分,我们简单地将 Azure 函数/REST API 检查称为检查。

建议在异步模式下使用检查。 此模式提供对检查逻辑的最高控制级别,使你能够轻松推理系统处于什么状态,并将 Azure Pipelines 与检查实现分离,从而提供最佳可伸缩性。 可以使用异步检查模式实现所有同步检查。

异步检查

在异步模式下,Azure DevOps 调用 Azure 函数/REST API 检查,并使用资源访问决策等待回调。 在等待期间,Azure DevOps 与检查实现之间没有开放 HTTP 连接。

本节的其余部分将讨论 Azure 函数检查,除非另有说明,否则本指南也适用于调用 REST API 检查。

建议的异步模式有两个通信步骤:

  1. 传递检查有效负载。 Azure Pipelines 对 Azure 函数/REST API 进行 HTTP 调用只是为了传递检查有效负载,而不是当场接收决策。 函数应仅确认收到信息并终止与 Azure DevOps 的 HTTP 连接。 检查实现应在 3 秒内处理 HTTP 请求。
  2. 通过回调传递访问决策。 检查应异步运行,评估管道访问受保护资源所需的条件(可以在不同时间点执行多次评估)。 在做出最终决策后,Azure 函数会向 Azure DevOps 发出 HTTP REST 调用,以传达决策。 在任何时间点,Azure DevOps 与检查实现之间都应有单个开放 HTTP 连接。 这样做可节省 Azure 函数端和 Azure Pipelines 端的资源。

如果检查通过,则允许管道访问受保护的资源,阶段部署可以继续进行。 如果检查失败,则阶段失败。 如果在单个阶段中有多个检查,则需要通过所有检查,然后才允许访问受保护的资源,但单个故障足以使阶段失败。

下图描述了单个 Azure 函数检查异步模式的建议实现。

Diagram that shows the recommended implementation of the async mode for a single Azure Function check.

图中的步骤如下:

  1. 检查传递。 Azure Pipelines 准备部署管道阶段,并需要访问受保护的资源。 它调用相应的 Azure 函数检查,并期望通过以 HTTP 200 状态代码结束的调用确认接收。 阶段部署暂停,等待做出决策。
  2. 检查评估。 此步骤在 Azure 函数实现中执行,它在你自己的 Azure 资源上运行,其代码完全由你控制。 建议 Azure 函数执行以下步骤:
    • 2.1 启动异步任务并返回 HTTP 状态代码 200
    • 2.2 进入一个内部循环,可在其中执行多个条件评估
    • 2.3 评估访问条件
    • 2.4 如果无法达成最终决策,请稍后重新安排对条件的重新评估,然后转到步骤 2.3
  3. 决策沟通。 Azure 函数通过访问决策回调到 Azure Pipelines。 阶段部署可以继续

使用建议的实现时,管道运行详细信息页会显示最新的检查日志。

Screenshot of pipeline run details with check information.

在 Azure 函数/REST API 检查配置面板中,确保:

  • 为完成事件选择回调
  • 将“评估间隔时间(分钟)”设置为“0”

将“评估间隔时间”设置为非零值意味着检查决策(通过/失败)不是最终决策。 将重新评估检查,直到所有其他审批和检查达到最终状态。

将管道运行信息传递给检查

配置检查时,可以指定要发送到检查的管道运行信息。 至少应发送:

  • "PlanUrl": "$(system.CollectionUri)"
  • "ProjectId": "$(system.TeamProjectId)"
  • "HubName": "$(system.HostType)"
  • "PlanId": "$(system.PlanId)"
  • "JobId": "$(system.JobId)"
  • "TaskInstanceId": "$(system.TaskInstanceId)"
  • "AuthToken": "$(system.AccessToken)"

默认情况下,这些键值对在 Azure Pipelines 进行的 REST 调用的 Headers 中设置。

应使用 AuthToken 对 Azure DevOps 进行调用,例如检查回调决策时。

调用 Azure DevOps

若要做出决策,检查可能需要有关当前管道运行的信息,但无法传递给检查,因此检查需要检索它。 假设检查验证管道运行执行了特定任务,例如静态分析任务。 检查需要调用 Azure DevOps 并获取已执行的任务列表。

若要调用 Azure DevOps,建议使用为检查执行颁发的作业访问令牌,而不是使用个人访问令牌 (PAT)。 默认情况下,已在 AuthToken 标头中向检查提供令牌。

与 PAT 相比,作业访问令牌不太可能受到限制,不需要手动刷新,并且不绑定到个人帐户。 令牌有效期为 48 小时。

使用作业访问令牌可消除 Azure DevOps REST API 限制问题。 使用 PAT 时,对管道的所有运行使用相同的 PAT。 如果运行大量管道,则 PAT 会受到限制。 这不是作业访问令牌的问题,因为每次执行检查都会生成一个新令牌。

令牌是为用于运行管道的生成标识颁发的,例如 FabrikamFiberChat 生成服务 (FabrikamFiber)。 换句话说,令牌可用于访问主机管道可访问的相同存储库或管道运行。 如果启用了保护对 YAML 管道中的存储库的访问,则其范围将进一步限制为仅在管道运行中引用的存储库。

如果检查需要访问非管道相关资源(例如 Boards 用户情景),则应向管道的生成标识授予此类权限。 如果可以从多个项目触发检查,请确保所有项目中的所有管道都可以访问所需的资源。

将决策发送回 Azure DevOps

检查实现必须使用后期事件 REST API 调用将决策传达回 Azure Pipelines。 请确保指定以下属性:

  • HeadersBasic: {AuthToken}
  • Body
{
    "name": "TaskCompleted",
    "taskId": "{TaskInstanceId}",
    "jobId": "{JobId}",
    "result": "succeeded|failed"
}

通过检查将状态更新发送到 Azure DevOps

可以使用 Azure Pipelines REST API 在检查中向 Azure Pipelines 用户提供状态更新。 例如,如果希望让用户知道检查正在等待外部操作(例如有人需要批准 ServiceNow 票证),则此功能非常有用。

发送状态更新的步骤如下:

  1. 创建任务列表
  2. 追加到任务日志
  3. 更新时间线记录

所有 REST API 调用都需要进行身份验证。

示例

基本 Azure 函数检查

在此基本示例中,Azure 函数先检查调用管道运行是否执行了任务 CmdLine,然后再向其授予对受保护资源的访问权限。

Azure 函数执行以下步骤:

  1. 确认收到检查有效负载
  2. 将检查启动的状态更新发送到 Azure Pipelines
  3. 使用 {AuthToken} 对 Azure Pipelines 进行回调,以检索管道运行的时间线条目
  4. 检查时间线是否包含 "id": "D9BAFED4-0B18-4F58-968D-86655B4D2CE9"CmdLine 任务的 ID)
  5. 发送状态更新及搜索结果
  6. 将检查决策发送到 Azure Pipelines

可以从 GitHub 下载此示例。

若要使用此 Azure 函数检查,需要在配置检查时指定以下 Headers

{
    "Content-Type":"application/json", 
    "PlanUrl": "$(system.CollectionUri)", 
    "ProjectId": "$(system.TeamProjectId)", 
    "HubName": "$(system.HostType)", 
    "PlanId": "$(system.PlanId)", 
    "JobId": "$(system.JobId)", 
    "TimelineId": "$(system.TimelineId)", 
    "TaskInstanceId": "$(system.TaskInstanceId)", 
    "AuthToken": "$(system.AccessToken)",
    "BuildId": "$(build.BuildId)"
}

高级 Azure 函数检查

在此高级示例中,Azure 函数检查触发管道运行的提交消息中引用的 Azure Boards 工作项是否处于正确状态。

Azure 函数执行以下步骤:

  1. 确认收到检查有效负载
  2. 将检查启动的状态更新发送到 Azure Pipelines
  3. 使用 {AuthToken} 对 Azure Pipelines 进行回调,以检索触发管道运行的提交消息中引用的 Azure Boards 工作项的状态
  4. 检查工作项是否处于 Completed 状态
  5. 发送状态更新及检查结果
  6. 如果工作项不处于 Completed 状态,它会在 1 分钟内重新安排另一个评估
  7. 一旦工作项处于正确状态,它会向 Azure Pipelines 发送肯定决策

可以从 GitHub 下载此示例。

若要使用此 Azure 函数检查,需要在配置检查时指定以下 Headers

{
    "Content-Type":"application/json", 
    "PlanUrl": "$(system.CollectionUri)", 
    "ProjectId": "$(system.TeamProjectId)", 
    "HubName": "$(system.HostType)", 
    "PlanId": "$(system.PlanId)", 
    "JobId": "$(system.JobId)", 
    "TimelineId": "$(system.TimelineId)", 
    "TaskInstanceId": "$(system.TaskInstanceId)", 
    "AuthToken": "$(system.AccessToken)",
    "BuildId": "$(build.BuildId)"
}

错误处理

目前,Azure Pipelines 最多评估单个检查实例 2,000 次。

如果检查在配置的超时时间内未回调到 Azure Pipelines,则会跳过关联阶段。 还会跳过依赖于它的阶段。

同步检查

在同步模式下,Azure DevOps 调用 Azure 函数/REST API 检查,以立即决定是否允许访问受保护的资源。

下图描述了单个 Azure 函数检查异步模式的实现。

Diagram that shows the implementation of the sync mode for a single Azure Function check.

步骤如下:

  1. Azure Pipelines 准备部署管道阶段,并需要访问受保护的资源
  2. 它进入一个内部循环,其中:
  • 2.1. Azure Pipelines 调用相应的 Azure 函数检查并等待决策
  • 2.2. Azure 函数评估允许访问所需的条件,并返回决策
  • 2.3. 如果 Azure 函数响应正文不满足定义的成功条件,并且评估间隔时间不为零,则 Azure Pipelines 将在评估间隔时间之后重新安排另一个检查评估

配置同步检查

若要使用 Azure 函数/REST API 的同步模式,请在检查配置面板中,确保:

  • 为“高级”下的“完成事件”选择“ApiResponse”
  • 指定基于检查响应正文定义何时通过检查的成功条件
  • 在“控制选项”下,将“评估间隔时间”设置为“0”
  • 将“超时”设置为希望等待检查成功的时间。 如果没有肯定决策并且已超时,则跳过相应的管道阶段

“评估间隔时间”设置定义检查决策的有效时间。 值 0 表示是最终决策。 非零值表示在配置的间隔后,如果是否定决策,将重试检查。 运行多个审批和检查时,无论做出何种决策,都会重试检查。

最大评估数定义为“超时”和“评估间隔时间”之间的比率。 建议确保此比率最多为 10。

将管道运行信息传递给检查

配置检查时,可以指定要发送到 Azure 函数/REST API 检查的管道运行信息。 默认情况下,Azure Pipeline 会在它发出的 HTTP 调用的 Headers 中添加以下信息。

  • "PlanUrl": "$(system.CollectionUri)"
  • "ProjectId": "$(system.TeamProjectId)"
  • "HubName": "$(system.HostType)"
  • "PlanId": "$(system.PlanId)"
  • "JobId": "$(system.JobId)"
  • "TaskInstanceId": "$(system.TaskInstanceId)"
  • "AuthToken": "$(system.AccessToken)"

不建议在同步模式下调用 Azure DevOps,因为这可能会导致检查回复时间超过 3 秒,以致检查失败。

错误处理

目前,Azure Pipelines 最多评估单个检查实例 2,000 次。

何时使用异步检查和同步检查

我们来看一些示例用例,以及建议使用的检查类型。

外部信息必须正确

假设你与生产资源建立了服务连接,并且你希望确保仅当 ServiceNow 票证中的信息正确时才允许访问它。 在这种情况下,流如下所示:

  • 添加异步 Azure 函数检查,验证 ServiceNow 票证的正确性
  • 当一个想要使用服务连接的管道运行时:
    • Azure Pipelines 会调用检查函数
    • 如果信息不正确,检查将返回否定决策。 假设此结果
    • 管道阶段失败
    • 更新 ServiceNow 票证中的信息
    • 重启失败阶段
    • 检查再次运行,并且这次成功了
    • 管道运行继续

必须授予外部批准

假设你与生产资源建立了服务连接,并且你希望确保仅当管理员批准 ServiceNow 票证时才允许访问它。 在这种情况下,流如下所示:

  • 添加异步 Azure 函数检查,验证 ServiceNow 票证是否已获批准
  • 当一个想要使用服务连接的管道运行时:
    • Azure Pipelines 会调用检查函数。
    • 如果 ServiceNow 票证未获批准,Azure 函数会向 Azure Pipelines 发送更新,并重新安排自己在 15 分钟内检查票证状态
    • 一旦票证获得批准,检查会以肯定决策回调到 Azure Pipelines
    • 管道运行继续

遵循开发过程

假设你与生产资源建立了服务连接,并且你希望确保仅当代码覆盖率超过 80% 时才允许访问它。 在这种情况下,流如下所示:

  • 编写管道的方式是阶段故障会导致生成失败
  • 添加异步 Azure 函数检查,以验证关联管道运行的代码覆盖率
  • 当一个想要使用服务连接的管道运行时:
    • Azure Pipelines 会调用检查函数
    • 如果不满足代码覆盖率条件,检查将返回否定决策。 假设此结果
    • 检查失败会导致阶段失败,从而导致管道运行失败
  • 工程团队添加必要的单元测试,以达到 80% 的代码覆盖率
  • 触发新的管道运行,这次,检查通过
    • 管道运行继续

必须满足性能条件

假设你从 Canary 部署开始,分多个步骤部署新版本系统。 你希望确保 Canary 部署的性能足够好。 在这种情况下,流如下所示:

  • 添加异步 Azure 函数检查
  • 当一个想要使用服务连接的管道运行时:
    • Azure Pipelines 会调用检查函数
    • 检查启动 Canary 部署性能监视器
    • 检查安排多个评估检查点,以查看性能如何演变
    • 一旦对 Canary 部署性能有了足够的信心,Azure 函数就会以肯定决策回调到 Azure Pipelines
    • 管道运行继续

部署原因必须有效

假设你与生产环境资源建立了服务连接,并且希望确保仅在手动排队生成的情况下进行访问。 在这种情况下,流如下所示:

  • 添加同步 Azure 函数检查,以验证管道运行的 Build.Reason 是否为 Manual
  • 将 Azure 函数检查配置为将 Build.Reason 传入到它的 Headers
  • 将检查的“评估间隔时间”设置为“0”,届时失败或通过是最终决策,而无需重新评估
  • 当一个想要使用服务连接的管道运行时:
    • Azure Pipelines 会调用检查函数
    • 如果原因不是 Manual,则检查失败,并且管道运行失败

检查合规性

调用 Azure 函数和 REST API 检查现在包括匹配建议用法的规则。 检查需要遵循这些规则,具体取决于模式和重试次数:

  • 异步检查(回调模式):Azure Pipelines 不会重试异步检查。 在最终评估时,应异步提供结果。 要使异步检查符合要求,评估时间间隔需要为 0。

  • 同步检查(ApiResponse 模式):检查的最大重试次数为 10。 可以通过多种方式进行设置。 例如,可以将超时配置为 20,评估时间间隔设置为 2。 也可以将超时配置为 100,评估时间间隔设置为 10。 但是,如果将超时配置为 100 并将评估时间间隔设置为 2,则检查不符合要求,因为你要求重试 50 次。 超时与评估时间间隔的比率应小于或等于 10。

详细了解检查合规性的推出

多个检查

在 Azure Pipelines 在管道运行中部署阶段之前,可能需要通过多个检查。 受保护的资源可能关联了一个或多个检查。 一个阶段可能使用了多个受保护的资源。 Azure Pipelines 收集与阶段中使用的每个受保护资源关联的所有检查,同时对其进行评估。

仅当所有检查同时通过时,才允许管道运行部署到某个阶段。 单个最终否定决策会导致管道访问被拒绝,阶段失败。

当以建议的方式(异步,最终状态)使用检查时,访问决策将最终确定,并且易于理解系统状态。

有关示例,请查看多个审批和检查部分。

了解更多