表达式语言
这篇文档描述了怎样使用 Mixer 配置表达式语言(CEXL)。
底层
Mixer 配置使用了一种表达式语言(CEXL) 去描述 match expressions 以及 mapping expressions。 CEXL 表达式为有类型的值映射了一组带类型的属性和常量。
语法
CEXL 使用 Go 表达式的一个子集作为语法。 CEXL 实现了一组 Go 操作符来限制这部分有限的 Go 表达式。 CEXL 同样支持任意的括号。
函数
CEXL 支持如下函数。
操作符/函数 | 定义 | 例子 | 描述 |
---|---|---|---|
== | 相等 | request.size == 200 | |
!= | 不等 | request.auth.principal != “admin” | |
|| | 逻辑或 | (request.size == 200) || (request.auth.principal == “admin”) | |
&& | 逻辑与 | (request.size == 200) && (request.auth.principal == “admin”) | |
[ ] | Map 取值 | request.headers[“x-request-id”] | |
+ | 加 | request.host + request.path | |
> | 大于 | response.code > 200 | |
>= | 大于等于 | request.size >= 100 | |
< | 小于 | response.code < 500 | |
<= | 小于等于 | request.size <= 100 | |
| | 取首个非空元素 | source.labels[“app”] | source.labels[“svc”] | “unknown” | |
match | 通配符匹配 | match(destination.service, “.ns1.svc.cluster.local”) | 以 的位置匹配前缀或后缀 |
email | 将文本类型的 e-mail 转换为 EMAIL_ADDRESS 类型 | email(“awesome@istio.io”) | 使用 email 函数创建一个 EMAIL_ADDRESS 字面量。 |
dnsName | 将文本类型的 DNS 转换为 DNS_NAME 类型 | dnsName(“www.istio.io”) | 使用 dnsName 函数创建一个 DNS_NAME 字面量。 |
ip | 将文本类型的 IPv4 地址转换为 IP_ADDRESS type | source.ip == ip(“10.11.12.13”) | 使用 ip 函数创建一个 IP_ADDRESS 字面量。 |
timestamp | 将文本类型的 RFC 3339 时间戳格式转换为 TIMESTAMP 类型 | timestamp(“2015-01-02T15:04:35Z”) | 使用 timestamp 函数创建一个 TIMESTAMP 字面量。 |
uri | 将文本类型的 URI 转换为 URI 类型 | uri(“http://istio.io“) | 使用 uri 函数创建一个 URI 字面量。 |
.matches | 正则表达式匹配 | “svc.“.matches(destination.service) | 通过正则表达式 “svc.“ 匹配 destination.service 。 |
.startsWith | 字符串前缀匹配 | destination.service.startsWith(“acme”) | 检查 destination.service 的值是否开始于 “acme” 。 |
.endsWith | 字符串后缀匹配 | destination.service.endsWith(“acme”) | 检查 destination.service 的值是否结束于 “acme” 。 |
emptyStringMap | 创建一个空的 string map | request.headers | emptyStringMap() | 为 request.headers 使用 emptyStringMap 去创建一个空的 string map 作为默认值。 |
conditional | 三元运算 | conditional((context.reporter.kind | “inbound”) == “outbound”, “client”, “server”) | report kind 是 outbound 时返回 “client” ,否则返回 “server” 。 |
toLower | 将字符串转换成小写 | toLower(“User-Agent”) | 返回 “user-agent” |
size | 字符串的长度 | size(“admin”) | 返回 5 |
类型检查
CEXL 变量是属性词汇表中的某个属性,常量是隐式类型,函数是显式类型。
Mixer 验证 CEXL 表达式的语法并在配置验证期间解析为一个类型。 选择器必须解析为 boolean 类型且 mapping expressions 必须解析为它所映射的类型。当选择器解析为 boolean 类型失败或 mapping expression 解析为不正确的类型时配置验证将失败。
比如,如果一个操作人员指定了一个 string 标签为 request.size | 200
,这个表达式解析为 integer 类型从而验证将失败。
属性缺失
如果表达式使用了一个在请求处理期间不可用的属性,则表达式将执行失败。如果属性可能缺失,请使用|
运算符提供默认值。
比如,如果表达式 request.auth.principal
属性是缺失的则 request.auth.principal == "user1"
将执行失败。|
(或) 运算符可以处理这个问题: (request.auth.principal | "nobody" ) == "user1"
。
例子
表达式 | 返回类型 | 描述 |
---|---|---|
request.size | 200 | int | request.size 在可用时返回其值,否则返回 200。 |
request.headers[“x-forwarded-host”] == “myhost” | boolean | |
(request.headers[“x-user-group”] == “admin”) || (request.auth.principal == “admin”) | boolean | user 是 admin 或属于 admin 组时,结果为 true。 |
(request.auth.principal | “nobody” ) == “user1” | boolean | 如果 request.auth.principal 是 “user1” 则结果是 true,且 request.auth.principal 属性缺失时不会报错。 |
source.labels[“app”]==”reviews” && source.labels[“version”]==”v3” | boolean | 如果 app label 是 reviews 且 version label 是 v3 则结果是 true,否则是 false。 |