表达式语言

这篇文档描述了怎样使用 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 typesource.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 maprequest.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 | 200intrequest.size 在可用时返回其值,否则返回 200。
request.headers["x-forwarded-host"] == "myhost"boolean
(request.headers["x-user-group"] == "admin") || (request.auth.principal == "admin")booleanuser 是 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。
这些信息有用吗?
Do you have any suggestions for improvement?

Thanks for your feedback!