Mistral 主要特性

任务结果 / 数据流

Mistral 支持将数据从一个任务传递到另一个任务。换句话说,如果taskA产生一个值,那么紧随taskA之后的taskB可以使用它。为了使用这些数据,Mistral 依赖于一种名为 YAQL 的查询语言。YAQL 是一种功能强大但简单的工具,允许用户过滤信息、转换数据和调用函数。有关更多信息,请参阅 YAQL 官方文档。这种数据传递机制在工作流概念中起着核心作用,被称为数据流。

以下是 Mistral 工作流语言视角下 Mistral 数据流的简单示例

version: '2.0'

my_workflow:
  input:
    - host
    - username
    - password

  tasks:
    task1:
      action: std.ssh host=<% $.host %> username=<% $.username %> \
              password=<% $.password %>
      input:
        cmd: "cd ~ && ls"
      on-complete: task2

    task2:
      action: do_something data=<% task(task1).result %>

名为“task1”的任务产生一个结果,其中包含用户主文件夹中的文件列表(主机名和用户名都作为工作流输入提供),而任务“task2”使用 YAQL 表达式“task(task1).result”来使用此数据。“task()”是 Mistral 在 YAQL 中注册的一个函数,用于通过名称获取有关任务的信息。

任务亲和性

任务亲和性是一项功能,可用于在特定的 Mistral 执行器上执行特定任务。实际上,有两种情况

  1. 您需要在单个执行器上执行任务。

  2. 您需要在命名组内的任何执行器上执行任务。

要启用任务亲和性功能,请编辑配置文件中的“executor”部分中的“host”属性

[executor]
host = my_favorite_executor

然后启动(重新启动)执行器。使用 Mistral 工作流语言中的“target”任务属性来指定此执行器

... Workflow YAML ...
task1:
  ...
  target: my_favorite_executor
... Workflow YAML ...

任务策略

任何 Mistral 任务,无论其工作流类型如何,都可以选择性地配置策略。策略控制任务的流程——例如,策略可以在任务开始之前或任务完成后延迟任务执行。

YAML 示例

my_task:
  action: my_action
  pause-before: true
  wait-before: 2
  wait-after: 4
  fail-on: <% $.some_value < 4 %>
  timeout: 30
  retry:
    count: 10
    delay: 20
    break-on: <% $.my_var = true %>

Mistral 中有不同类型的策略。

  1. pause-before

指定 Mistral Engine 是否应该在启动任务之前暂停工作流。

  1. wait-before

指定 Mistral Engine 在启动任务之前应等待的秒数延迟。

  1. wait-after

指定 Mistral Engine 在任务完成后应等待的秒数延迟,然后再启动‘on-success’‘on-error’‘on-complete’ 中指定的任务。

  1. fail-on

指定任务将失败的条件,即使操作已成功完成。

  1. timeout

指定一个以秒为单位的时间段,如果任务未完成,引擎将自动使任务失败。

  1. retry

指定任务应如何重复的模式。

  • count - 指定任务可以重复的最大次数。

  • delay - 指定后续任务迭代之间的秒数延迟。

  • break-on - 指定一个 YAQL 表达式,如果评估结果为‘true’,则将中断迭代循环。如果触发,则认为任务遇到错误。

  • continue-on - 指定一个 YAQL 表达式,如果评估结果为‘true’,则将继续迭代循环。如果触发,则认为任务成功。

也可以在一行中配置单个行的重试策略,如下所示

task1:
  action: my_action
  retry: count=10 delay=5 break-on=<% $.foo = 'bar' %>

任何策略的所有参数值都可以定义为 YAQL 表达式。

注意:在同一个重试块中使用 break-on 和 continue-on 很少见。break-on 应该在预期操作在一段时间内处于 ERROR 状态时使用,但最终可能会进入 SUCCESS 状态,从而停止循环。但是,如果 break-on‘true’,则重试将停止,任务将处于 ERROR 状态。continue-on 应该在操作通常返回 SUCCESS 时使用,但操作有其他结果可用于指示是否继续循环。

Join

Join 流控制允许同步多个并行工作流分支并聚合它们的数据。

完全 Join (join: all).

YAML 示例

register_vm_in_load_balancer:
  ...
  on-success:
    - wait_for_all_registrations

register_vm_in_dns:
  ...
  on-success:
    - wait_for_all_registrations

try_to_do_something_without_registration:
  ...
  on-error:
    - wait_for_all_registrations

wait_for_all_registrations:
  join: all
  action: send_email

当任务具有分配了值 “all” 的属性 “join” 时,只有当所有上游任务(导致此任务的任务)都已完成并且相应的条件已触发时,该任务才会运行。如果任务 A 在任何 “on-success”“on-error”“on-complete” 子句中提到了任务 B,则任务 A 被认为是任务 B 的上游任务,无论 YAQL 保护表达式如何。

部分 Join (join: 2)

YAML 示例

register_vm_in_load_balancer:
  ...
  on-success:
    - wait_for_all_registrations

register_vm_in_dns:
  ...
  on-success:
    - wait_for_all_registrations

register_vm_in_zabbix:
  ...
  on-success:
    - wait_for_all_registrations

wait_for_two_registrations:
  join: 2
  action: send_email

当任务具有分配了数字值的属性 “join” 时,该任务将在至少完成这么多上游任务并且相应的条件已触发后运行。在上面的示例中,如果两个“register_vm_xxx”任务中的任何两个任务完成,则任务“wait_for_two_registrations”将运行。

Discriminator (join: one)

Discriminator 是 Partial Join 的特殊情况,其中 “join” 属性的值为 1。在这种情况下,可以使用特殊字符串值 “one”,它是为了与 “all” 对称而引入的。但是,用户是否使用 “1”“one” 由用户决定。

处理集合 (with-items)

YAML 示例

---
version: '2.0'

create_vms:
  description: Creating multiple virtual servers using "with-items".
  input:
    - vm_names
    - image_ref
    - flavor_ref
  output:
    vm_ids: <% $.vm_ids %>

  tasks:
    create_servers:
      with-items: vm_name in <% $.vm_names %>
      action: nova.servers_create name=<% $.vm_name %> \
              image=<% $.image_ref %> flavor=<% $.flavor_ref %>
      publish:
        vm_ids: <% task().result.id %>
      on-success:
        - wait_for_servers

    wait_for_servers:
      with-items: vm_id in <% $.vm_ids %>
      action: nova.servers_find id=<% $.vm_id %> status='ACTIVE'
      retry:
        delay: 5
        count: <% $.vm_names.len() * 10 %>

在此示例中,工作流 “create_vms” 根据我们在 “vm_names” 输入参数中提供的数量创建多个虚拟机。例如,如果指定 vm_names=[“vm1”, “vm2”],则它将基于相同的镜像和 flavor 创建具有这些名称的服务器。这是可能的,因为我们正在使用 “with-items” 关键字,该关键字将操作或工作流与多次运行的任务相关联。“with-items” 任务属性的值包含以下形式的表达式:<variable_name> in <% YAQL_expression %>

最常见的形式是

with-items:
  - var1 in <% YAQL_expression_1 %>
  - var2 in <% YAQL_expression_2 %>
  ...
  - varN in <% YAQL_expression_N %>

其中以 YAQL_expression_1、YAQL_expression_2、YAQL_expression_N 表示的集合必须大小相等。当任务启动时,Mistral 将并行迭代所有集合,即迭代次数将等于任何集合的长度。

请注意,在 “with-items” 的情况下,任务结果(在工作流上下文中可访问为 <% $.task_name %>)将是一个列表,其中包含相应操作/工作流调用的结果。如果至少一个操作/工作流调用失败,则整个任务将进入 ERROR 状态。也可以为具有 “with-items” 属性的任务应用重试策略。在这种情况下,重试策略将根据 “with-items” 配置重新启动所有操作/工作流调用。其他策略也可以以与常规非 “with-items” 任务相同的方式使用。

执行过期策略

当 Mistral 在生产中使用时,控制已完成的工作流执行的数量可能很困难。默认情况下,Mistral 将无限期地存储所有执行,并且随着时间的推移,存储的数量将不断累积。可以通过设置过期策略来解决此问题。

默认情况下,此功能已禁用。

此策略定义了自上次更新时间以来执行的最大年龄(分钟),以及已完成执行的最大数量。每次评估都将满足这些条件,因此过期的执行(超过指定时间)将被删除,并且完成状态下的执行数量(无论是否过期)将限制为 max_finished_executions。

要启用该策略,请编辑 Mistral 配置文件并指定 evaluation_intervalolder_thanevaluation_interval 选项中的至少一个。

[execution_expiration_policy]
evaluation_interval = 120  # 2 hours
older_than = 10080  # 1 week
max_finished_executions = 500
  • evaluation_interval

评估间隔定义了 Mistral 将检查并确保上述约束的频率。在上面的示例中,它设置为两个小时,因此每两个小时 Mistral 将删除超过 1 周的执行,并保留最新的 500 个已完成的执行。

  • older_than

定义自上次更新以来执行的最大年龄(分钟)。它必须大于或等于 1

  • max_finished_executions

定义已完成执行的最大数量。它必须大于或等于 1

工作流命名空间

Mistral 允许在命名空间中创建工作流。因此,只要它们位于不同的命名空间中,就可以创建许多具有相同名称的工作流。

有关更多信息,请参阅 工作流命名空间

任务跳过

Mistral 具有跳过 ERROR 状态任务的能力。任务从 ERROR 状态移动到 SKIPPED 状态,发布 publish-on-skip 部分中的变量,并且工作流从 on-skip 部分中指定的任务继续。要配置任务的跳过行为,请在任务定义中填写以下属性

  • on-skip - 可选。此参数指定在跳过此任务后应启动哪些任务。

  • publish-on-skip - 可选。此参数指定在跳过此任务后应发布哪些变量。

也可以跳过没有预定义上述参数的任务,在这种情况下,任务不会发布任何内容,并会通过 on-success 分支继续。这对于下一个任务来说可能不安全,因为它们可能缺少一些输入,因此在跳过此类任务之前请三思。

可以通过以下请求执行任务跳过

PUT /v2/tasks

{
  "id": "<task-id>",
  "state": "SKIPPED"
}