YAQL是很典型地用于简单条件验证和在Mistral工作流中进行数据转换。
在你没有制作出动作但是有需求需要根据动作结果来判定是否继续地场景会有很多,
或者有一个将结果转换为另一个值或者结构化用于工作流重下一次动作地需求存在。
下面是YAQL在Mistral工作流重的使用场景:
1) 定义传递给任务的输入值
2) 定义任务和工作流发布的输出值
3) 定义条件用来决定任务的转换
知道YAQL可以在Mistral工作流中哪里被使用,下面是一些YAQL可以做的很酷的事情:
1) 从一个字典列表重选择键值对
2) 当一个或多个字段满足条件时来过滤列表
3) 将一个列表转换未字典或者反过来
4) 简单的算法
5) 布尔逻辑的验证
6) 任何select, filter, transform和evaluate的组合
下面是工作流和任务定义中可接受YAQL的的声明:
task action input
task concurrency
task on-complete
task on-error
task on-success
task pause-before
task publish
task retry break-on
task retry continue-on
task retry count
task retry delay
task timeout
task wait-before
task wait-after
task with-items
workflow output
每一个声明可以接受一个携带有一个或多个YAQL表达式的字符串。
字符串重每个表达式应该用 <% %> 包裹。
当校验一个YAQL的表达式,Mistral也可以传入一个JSON字典到YAQL引擎。
上下文重包含了所有工作流的输入,发布的变量,工作流任务完成的结果,
包含当前的任务。YAQL表达式可以引用一个或多个变量到上下文重。
保留的符号$被用于引用上下文。例如,给丁的上下文
{"ip": "127.0.0.1", "port": 8080}
这个字符串 https://<% $.ip %>:<% $.port %>/api
会返回 https://127.0.0.1:8080/api 。
下面是一个在工作里重使用的相同的例子:
version: '2.0'
examples.yaql-basic:
type: direct
input:
- ip
- port
tasks:
task1:
action: examples.call-api
input:
endpoint: https://<% $.ip %>:<% $.port %>/api
Mistral重已经确定的声明例如: on-success和on-error可以验证布尔逻辑。
而on-condition相关的声明被用于一个任务到另一个任务的转换。如果一个布尔逻辑在这些
声明重被定义了,它可以被用于校验转换是否应该继续。服务的布尔逻辑使用了
not, and, or的组合,圆括号也是有可能的。以下面的工作流为例:
工作流重某个分支的执行依赖于 $.path 的值。如果 $.path = a, 接着任务
a会被执行。如果$.path =b, 接着任务b回被执行。如果上述都不符合,
最终任务c会被执行。
version: '2.0'
examples.mistral-branching:
description: >
A sample workflow that demonstrates how to use conditions
to determine which path in the workflow to take.
type: direct
input:
- which
tasks:
t1:
action: core.local
input:
cmd: "printf <% $.which %>"
publish:
path: <% task(t1).result.stdout %>
on-success:
- a: <% $.path = 'a' %>
- b: <% $.path = 'b' %>
- c: <% not $.path in list(a, b) %>
a:
action: core.local
input:
cmd: "echo 'Took path A.'"
publish:
stdout: <% task(a).result.stdout %>
b:
action: core.local
input:
cmd: "echo 'Took path B.'"
publish:
stdout: <% task(b).result.stdout %>
c:
action: core.local
input:
cmd: "echo 'Took path C.'"
publish:
stdout: <% task(c).result.stdout %>
Mistral重with-items的声明被用于在遍历一个或多个列表条目的时候执行动作。
下面是一个Mistral工作的例子,该例子遍历给丁names的列表,来调用动作去创建一个个人的虚机。
version: '2.0'
examples.create-vms:
type: direct
input:
- names
tasks:
task1:
with-items: name in <% $.names %>
action: examples.create-vm
input:
name: <% $.name %>
正如下面的例子所展示的,with-items可以接受不止一个列表。
在这种情况下,虚机列表和ip地址都被作为输入,并通过逐步地遍历来被传入。
version: '2.0'
examples.create-vms:
type: direct
input:
- names
- ips
tasks:
task1:
with-items:
- name in <% $.names %>
- ip in <% $.ips %>
action: examples.create-vm
input:
name: <% $.name %>
ip: <% $.ip %>
下面地章节包含了额外的YAQL使用列表和字典的例子,
这可以被用于更高级的with-items的使用场景。
为了创建一个字典,使用dict方法。例如,
<% dict(a=>123, b=>true) %>
返回了 {'a': 123, 'b': True}
。我们假设这个字典以dict1作为上下文被发布。关键的方法
<% $.dict1.keys() %>
返回 ['a', 'b']
并且 <% $.dict1.values() %>
返回了值 [123, true]
。也可以连接字典,例如:
<% dict(a=>123, b=>true) + dict(c=>xyz) %>
将返回:
{'a': 123, 'b': True, 'c': 'xyz'}
一个指定的键值对可以通过键名例如:
<% $.dict1.get(b) %> 来返回True。
给定可选的值:
<% $.dict1.get(b, false) %>
如果键b不存在,默认False将会返回。
为了创建一个列表,使用list方法。例如,
<% list(1,2,3) %> 返回[1, 2, 3],并且
<% list(abc, def) %>返回 ['abc', 'def']。
列表连接可以像这样做:
<% list(abc, def) + list(ijk, xyz) %>
将返回['abc', 'def', 'ijk', 'xyz']。
如果这个列表被list1作为上下文发布,那么条目可以通过下标
例如: <% $.list1[0] %>被访问到,将会返回abc。
将下面的上下文作为一个例子:
{
"vms": [
{
"name": "vmweb1",
"region": "us-east",
"role": "web"
},
{
"name": "vmdb1",
"region": "us-east",
"role": "db"
},
{
"name": "vmweb2",
"region": "us-west",
"role": "web"
},
{
"name": "vmdb2",
"region": "us-west",
"role": "db"
}
]
}
下面的YAQL表达式是一些YAQL可支持的查询样例:
<% $.vms.select($.name) %> 返回VM的names列表 ['vmweb1', 'vmdb1', 'vmweb2', 'vmdb2']
<% $.vms.select([$.name, $.role]) %> 返回一个包含names列表和roles列表的列表
[['vmweb1', 'web'], ['vmdb1', 'db'], ['vmweb2', 'web'], ['vmdb2', 'db']]
<% $.vms.select($.region).distinct() %> 返回去重后的regions列表 ['us-east', 'us-west']
<% $.vms.where($.region = 'us-east').select($.name) %> 仅仅选择us-east的虚机,返回
['vmweb1', 'vmdb1']
<% $.vms.where($.region = 'us-east' and $.role = 'web').select($.name) %>
选择在us-east的web服务器的名称 ['vmweb1']
<% let(myregion => 'us-east', myrole => 'web') -> $.vms.where($.region = $myregion and $.role = $myrole).select($.name) %> 仅仅选择在us-east的web服务器 ['vmweb1']。
有一些场景用字典比列表简单(例如:用key选择一个值)。让我们将上面相同的虚机记录列表转换为一个字典,
该字典的名称是虚机名称,值是record。
YAQL可以转换lists中的一个列表未字典,当每个列表包含了键和值。例如,表达式
<% dict(vms=>dict($.vms.select([$.name, $]))) %>
返回了下面的字典:
{
"vms": {
"vmweb1": {
"name": "vmweb1",
"region": "us-east",
"role": "web"
},
"vmdb1": {
"name": "vmdb1",
"region": "us-east",
"role": "db"
},
"vmweb2": {
"name": "vmweb2",
"region": "us-west",
"role": "web"
},
"vmdb2": {
"name": "vmdb2",
"region": "us-west",
"role": "db"
}
}
}
在这个表达式中,我们将原始的vms列表,转变未了一个[name, record]列表,
并且将它转换未一个字典。
YAQL又一个内置的list方法来处理字符串,字典,列表等。
这些中的其他都通过内置的Python方法来处理(例如: int, float, pow, regex, round等等)。
Mistral添加了额外的工作流相关的方法到列表中。例如,对方法
<% len(foobar) %> 的调用来获取字符串 foobar的长度,返回的值是6.
下面是一个常用的方法列表。请访问YAQL文档和GitHub残酷来探索更多选项。
对于所有的内置方法,请参见 https://yaql.readthedocs.io/en/latest/standard_library.html
一些值得注意的例子:
float(value) converts value to float.
int(value) converts value to integer.
str(number) converts number to a string.
len(list) and len(string) returns the length of the list and string respectively.
max(a, b) returns the larger value between a and b.
min(a, b) returns the smaller value between a and b.
regex(expression).match(pattern) returns True if expression matches pattern.
regex(expresssion).search(pattern) returns the first instance that matches the pattern.
'some string'.toUpper() converts the string to all upper case.
'some string'.toLower() converts the string to all lower case.
['some', 'list'].contains(value) returns True if list contains value.
"one, two, three, four".split(',').select(str($).trim()) converts a comma separated string to an array, trimming each element.
env()返回还将变量来传递给工作流的执行,例如st2_execution_id。
For example, the expression <% env().st2_action_api_url %>/actionexecutions/<% env().st2_execution_id %> returns the API endpoint for the current workflow execution in StackStorm as something like https://127.0.0.1:9101/v1/actionexecutions/874d3d5b3f024c1aa93225ef0bcfcf3a.
To access information about the parent action, the following expressions can be used <% env().get('__actions').get('st2.action').st2_context.parent.api_user %>, <% env().get('__actions').get('st2.action').st2_context.parent.source_channel %> or <% env().get('__actions').get('st2.action').st2_context.parent.user %>.
Note that this similar to the ActionChain expressions {{action_context.parent.source_channel}}, {{action_context.parent.user}} or {{action_context.parent.api_user}}.
task(task_name) returns the state, state_info, and the result of the given task_name.
上述没有翻译。
st2kv('st2_key_id')查询StackStorm的datastore并返回指定键的值。
例如,表达式: <% st2kv('system.shared_key_x') %>
返回了系统返回的命名为 shared_key_x的值,然而表达式:
<% st2kv('my_key_y') %>
返回了指定返回的键名称my_key_y的值。
请注意键名应该是在引号中的,否则YAQL将把它作为一个带有一个点号,类似
system.shared_key_x的名称作为字典访问。
在你的数据中,测试YAQL表达式的最快方法是使用在线的YAQL验证器:
http://yaqluator.com/
这个网站允许你提供样例数据和YAQL表达式,这可以让你实时验证,并看到结果。
这在处理复杂表达式的时候非常有用。
以上翻译自:
https://docs.stackstorm.com/mistral_yaql.html