表达式语言

这篇文档描述了怎样使用 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&#34;)使用 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。