1 Mistral
Mistral是一个用于管理和执行动作流的Openstack项目。Mistral是可以作为一个单独的
mistral服务在StackStorm中安装。一个Mistral工作流可以通过
https://docs.openstack.org/mistral/latest/user/wf_lang_v2.html
被定义为一个StackStorm动作。
表达式语言,例如YAQL被用于格式化变量和条件验证。从StackStorm2.2版本开始,
Jinja2也开始支持YAQL表达式。同样工作簿和工作流定义也是支持的。
在一个动作执行的时候,StackStorm编写Mistral定义并执行工作流。
一个工作流可以调用其他的StackStorm动作作为子任务。StackStorm处理
转化和在Mistral中显式调用并向Mistral轮询来获取执行结果。StackStorm
在工作流中的动作可以被追溯到原始的父动作,即调用工作的动作。
Essential Mistral Links:
Mistral workflow definition language, aka v2 WorkFlow Language
YAQL documentation and YAQL online evaluator
Jinja2 template engine documentation and Jinja2 online evaluator
2 基本工作流
与ActionChains相似,Mistral工作流在/opt/stackstorm/packs/<mypack>/actions
有一个动作元数据文件,工作流定义本身是在/opt/stackstorm/packs/<mypack>/actions/workflows。
让我们用一个非常基本的工作流调用一个StackStorm动作和在工作流完成时通知StackStorm的例子作为开始。
这个文件时在examples中,在/usr/share/doc/st2/examples的位置。
第一个任务叫做run-cmd。它在StackStorm安装的地方,在一个servier上执行了一个shell命令。
一个任务可以直接引用任何注册的StackStorm的动作。在例子中,这个run-cmd任务调用core.local,并传入
cmd作为输入。core.local是一个StackStorm安装时携带的动作。当工作流被调用时,StackStorm将会
在发送工作流给Mistral之前对工作流定定义进行合适地转换。让我们把它存储StackStorm的
/opt/stackstorm/packs/examples/actions/workflows/mistral-basic.yaml
version: ‘2.0’
examples.mistral-basic:
description: A basic workflow that runs an arbitrary linux command.
type: direct
input:
– cmd
– timeout
output:
stdout: <% $.stdout %>
tasks:
task1:
action: core.local cmd=<% $.cmd %> timeout=<% $.timeout %>
publish:
stdout: <% task(task1).result.stdout %>
stderr: <% task(task1).result.stderr %>
这是一个与StackStorm动作元数据相对应的例子。用于工作流动作的StackStorm的包叫做examples。
注意工作流在上述定义中以<pack>.<action>命名是完全合格的。StackStorm动作运行器是mistral-v2.
StackStorm的entry point指向工作流定义的YAML文件。我们将元数据保存为:
/opt/stackstorm/packs/examples/actions/mistral-basic.yaml
—
description: Run a local linux command
enabled: true
runner_type: mistral-v2
entry_point: workflows/mistral-basic.yaml
name: mistral-basic
pack: examples
parameters:
cmd:
required: true
type: string
timeout:
type: integer
default: 60
下面的可选参数列表可以被定义在工作流动作中。在例子中,这些可选参数被设置为
不可修改的。设置它们为不可修改的是一种良好的实践,即使它们为空。
options description
workflow 如果定义是一个包含了许多工作流的workbook,这个参数指定了要执行的主工作流。
task 如果工作流是逆序的,这个参数指定了要调用的任务。
context 一个包含额外工作流启动参数的字典。
下一步,运行 st2 action create /opt/stackstorm/packs/examples/actions/mistral-basic.yaml
来创建工作流动作。这将会注册动作流以examples.mistral-basic的形式到StackStorm中。
为了执行工作流,运行:
st2 run examples.mistral-basic cmd=date -a
而 -a告诉命令无需等待工作流完成即可返回。
如果工作流成功完成,工作流examples.mistral-basic和动作core.local
在StackStorm的动作执行列表中应该有一个succeeded状态。
默认,st2 execution list只返回顶级的执行。这意味着自任务并不会被展现。
+————————–+————–+————–+———–+—————–+—————+
| id | action.ref | context.user | status | start_timestamp | end_timestamp |
+————————–+————–+————–+———–+—————–+—————+
| 54ee54c61e2e24152b769a47 | examples | stanley | succeeded | Wed, 25 Feb | Wed, 25 Feb |
| | .mistral- | | | 2015 23:03:34 | 2015 23:03:34 |
| | basic | | | UTC | UTC |
+————————–+————–+————–+———–+—————–+—————+
为了展示子任务,运行:
st2 execution get <execution-id> –show-tasks
+————————–+————+————–+———–+——————————+——————————+
| id | action.ref | context.user | status | start_timestamp | end_timestamp |
+————————–+————+————–+———–+——————————+——————————+
| 54ee54c91e2e24152b769a49 | core.local | stanley | succeeded | Wed, 25 Feb 2015 23:03:37 | Wed, 25 Feb 2015 23:03:37 |
| | | | | UTC | UTC |
+————————–+————+————–+———–+——————————+——————————+
下面是基于先前工作流定义的简单扩展。在这个例子中,我们已经有第二个叫做”task2″的任务。
很自然地可以想到,按照顺序task2将会在task1后面执行。然而,当没有任务属性例如:
on-complete, on-success和on-error是被定义地,任务将会并行。这在Mistral中是可能地,
因为它提供了一个工作流加入控制,这允许我们同步多个并行地工作流分支,并可以巨基它们地数据。
version: ‘2.0’
examples.mistral-basic-two-tasks-with-notifications:
description: A basic workflow that runs two Linux commands (one in each task).
type: direct
output:
stdout: <% $.stdout %>
tasks:
task1:
action: core.local cmd=”echo task1″
publish:
stdout: <% task(task1).result.stdout %>
stderr: <% task(task1).result.stderr %>
task2:
action: core.local cmd=”echo task2″
publish:
stdout: <% task(task2).result.stdout %>
stderr: <% task(task2).result.stderr %>
3 发布变量
一个Mistral任务可以产生结果,并将一个任务以变量的形式在其他任务中使用:
tasks:
get_hostname:
action: core.local
input:
cmd: “hostname”
publish:
hostname: <% task(get_hostname).result.stdout %>
在上述的例子中,get_hostname是一个core.local动作,该动作运行命令 hostname。
这个 core.local动作产生了的输出由stdout, stderr, exit_code等字段构成。
我们仅仅将变量stdout发布,以供剩余的任务使用。为了在任务中引用结果,使用
task功能,该功能呢个返回一个包含任务属性的字典,例如: id, state, result
和其他信息。
另一个例子显示如下:
tasks:
create_new_node:
action: rackspace.create_vm
input:
name: <% $.hostname %>
flavor_id: <% $.vm_size_id %>
image_id: <% $.vm_image_id %>
key_material: <% $.ssh_pub_key %>
metadata:
asg: <% $.asg %>
publish:
ipv4_address: ‘<% task(create_new_node).result.result.public_ips[1] %>’
ipv6_address: ‘<% task(create_new_node).result.result.public_ips[0] %>’
在上述例子中,动作rackspace.create_vm是一个Python动作,该动作长生了一个result对象。
我们仅仅想要从result对象的public_ips的列表字段中将IP地址发布出去。
请注意result.result不是一个打印错误。这个Python动作提交了一个叫做result的key,用于st2
动作执行和Mistral 任务函数将Python动作的结果存储到输出字典的result中。
这样发布的变量是可以作为输入参数被工作流中其他任务获取的。在下面的其他任务中使用ipv3_address的例子如下:
tasks:
# … <snap>
setup_ipv4_dns:
action: rackspace.create_dns_record
wait-before: 1 # delay, in seconds
input:
name: ‘<% $.hostname %>.<% $.asg %>.<% $.domain %>’
zone_id: <% $.dns_zone_id %>
type: ‘A’
data: <% $.ipv4_address %>
# …. </snap>
4 一起构造一个复杂的工作流
下面是一个复杂工作流的仿制。在这个仿制中运行了简单的printf和sleep命令,
工作流展示了内迁的工作流,fork和join:
version: “2.0”
name: examples.mistral-workbook-complex
description: A sample workflow that demonstrates nested workflows, forks, and join.
workflows:
main:
type: direct
input:
– vm_name
– cpu_cores
– memory_mb
output:
vm_id: <% $.vm_id %>
ip: <% $.ip %>
tasks:
register_dns:
action: core.local
input:
cmd: “sleep 1; printf ‘Registering <% $.vm_name %>…'”
publish:
ip: “10.1.23.99”
status_message: “DNS for <% $.vm_name %> is registered.”
on-success:
– configure_vm
– notify
create_vm:
wait-before: 1
workflow: create_vm
input:
name: <% $.vm_name %>
cpu_cores: <% $.cpu_cores %>
memory_mb: <% $.memory_mb %>
publish:
vm_id: <% task(create_vm).result.vm_id %>
status_message: “VM <% $.vm_name %> is created.”
on-success:
– configure_vm
– notify
configure_vm:
join: all
workflow: configure_vm
input:
vm_id: <% $.vm_id %>
ip: <% $.ip %>
publish:
status_message: “VM <% $.vm_name %> is reconfigured.”
on-success:
– close_request
– notify
close_request:
action: std.noop
publish:
status_message: “VM request is fulfilled.”
on-success:
– notify
notify:
action: core.local
input:
cmd: “printf ‘<% $.status_message %>'”
create_vm:
type: direct
input:
– name
– cpu_cores
– memory_mb
output:
vm_id: <% $.vm_id %>
tasks:
create:
action: core.local
input:
cmd: “printf ‘vm1234’; sleep 5”
publish:
vm_id: <% task(create).result.stdout %>
configure_vm:
type: direct
input:
– vm_id
– ip
tasks:
add_disks:
action: core.local
input:
cmd: “sleep 1; printf ‘disks created'”
add_nics:
action: core.local
input:
cmd: “sleep 1; printf ‘nics created'”
install_apps:
action: core.local
input:
cmd: “sleep 1; printf ‘apps installed'”
在这个工作簿中有多个工作流被定义,工作流作者必须在元数据中指定要执行的工作流:
—
description: Run a series of simulated actions.
enabled: true
entry_point: workflows/mistral-workbook-complex.yaml
name: mistral-workbook-complex
pack: examples
parameters:
cpu_cores:
default: 1
type: integer
memory_mb:
default: 1024
type: integer
vm_name:
required: true
type: string
workflow:
default: examples.mistral-workbook-complex.main
immutable: true
type: string
runner_type: mistral-v2
为了测试工作流的输出,将元数据文件存储在
/opt/stackstorm/packs/examples/actions/
而工作流文件存储在
/opt/stackstorm/packs/examples/actions/workflows
。
运行
st2 action create /opt/stackstorm/packs/examples/actions/mistral-workbook-complex.yaml
来创建动作并执行
st2 run examples.mistral-workbook-complex vm_name=”vmtest1″ -a
用于测试。
5 验证
Mistral 命令行包含了用于执行逻辑高度清晰的工作流YAML文件工作:
# 验证一个工作流
mistral workflow-validate /path/to/workflow.yaml
# 验证一个工作簿
mistral workbook-validate /path/to/workbook.yaml
6 更多的例子
更多工作流的例子在
/usr/share/doc/st2/examples
。这些例子包含了错误处理,重复和重试。
一步一步的实验来在StackStorm重创建工作流请参见:
https://stackstorm.com/2015/07/08/automating-with-mistral-workflow/
更多关于Mistral的细节可以在下面找到:
https://docs.openstack.org/mistral/latest/
以上翻译自:
https://docs.stackstorm.com/mistral.html