Envoy 路由表检查工具 router_check_tool 详解:配置校验、断言模型与覆盖率机制
【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy
Envoy 提供了专门的路由表检查工具router_check_tool(位于 route_table_check_tool.rst),用于离线校验路由配置(RouteConfiguration)在给定请求输入下返回的路由参数是否符合预期,包括集群匹配、路径重定向、路径/主机重写等断言。读完本文,你将掌握该工具的完整命令行参数、测试配置文件的 proto 模式、路由覆盖率计算原理,以及如何将其集成到 CI 流程中做配置回归校验。
工具定位:离线校验路由器行为
该工具的核心目标是回答一个问题:给定一份路由配置和一组“请求特征”(域名 + 路径 + 方法等),Envoy 路由器实际会解析出什么路由?工具把请求输入送入 Envoy 真实的路由配置实现(Router::ConfigImpl),再把实际返回的路由参数与预期值逐项比较,任何一项不符都会使进程以EXIT_FAILURE退出——这使其天然适合接入 CI 做配置守护。
从源码结构看,该工具复用生产路由逻辑而非自行实现一套匹配算法:router.cc 中RouterCheckTool::create()通过TestUtility::loadFromFile加载RouteConfiguration,随后调用Router::ConfigImpl::create(...)构建与线上相同语义的路由表(见 router.cc#L129-L152)。因此工具校验的是 Envoy 真实的路由决策路径,而不是一个模拟实现。
命令行参数全解
工具用法签名为(引自 文档):
router_check_tool [-t <string>] [-c <string>] [-d] [-p] [--] [--version] [-h] <unlabelledConfigStrings>| 参数 | 说明 |
|---|---|
-t, --test-path <string> | 工具配置 JSON/YAML 文件路径,描述 URL(authority + path)及预期路由参数,模式见下文“测试配置模式” |
-c, --config-path <string> | 路由配置文件路径(YAML 或 JSON),文件扩展名必须与类型匹配(.json/.yaml)。模式遵循 route.proto 的RouteConfiguration |
-o, --output-path <string> | 将测试结果以二进制 proto 形式写入该文件;若文件已存在则尝试覆盖 |
-d, --details | 输出详细测试执行结果,首行为测试名 |
--only-show-failures | 仅显示失败测试;与--details同时设置时省略通过测试的测试名 |
-f, --fail-under <percent> | 设定路由测试覆盖率下限百分比,低于该值时本次运行判为失败 |
--covall | 启用全面覆盖率计算,把所有可能的断言字段纳入统计,并显示缺失的测试 |
--disable-deprecation-check | 禁用对 RouteConfiguration proto 的弃用字段检查 |
--detailed-coverage | 在非全面覆盖率模式下显示未被覆盖的路由明细 |
-h, --help | 显示用法信息并退出 |
参数解析由 TCLAP 库完成,且--config-path与--test-path二者都是必填的——源码中Options::Options在任一为空时会直接报错退出(见 router.cc#L702-L747)。
测试配置模式:Validation / ValidationItem / ValidationAssert
工具内部所有模式基于 proto3 定义 validation.proto,工具会把 JSON/YAML 输入透明地转换为该 proto 模式。核心消息结构如下:
Validation:顶层消息,包含repeated ValidationItem tests(至少一条测试)。ValidationItem:单个测试用例,含test_name(非空,允许重名)、input(输入约束,必填)、validate(断言,必填)。ValidationInput:送入路由器、决定返回路由的输入值:
| 字段 | 含义 |
|---|---|
authority | :authority伪头部,即目标 URI 的域名部分(必填) |
path | :path伪头部,路径 + query 部分,http/https 下不得为空(必填) |
method | HTTP 方法,至少 3 个字符(必填) |
random_value | 用于加权集群选择的随机标识,默认 0 |
ssl | 是否将x-forwarded-proto置为 https,默认 false(http) |
internal | 是否设置x-envoy-internal: true |
additional_request_headers/additional_response_headers | 附加请求/响应头;:authority、:path、:method、x-forwarded-proto、x-envoy-internal由上述专用字段控制,不应在此重复设置 |
dynamic_metadata | 以 set_metadata 语义写入请求的动态元数据 |
runtime | 测试用例要启用的 runtime 键。若路由依赖 runtime(runtime_fraction),路由是否生效由该值与random_value的分数比较决定 |
ValidationAssert:指定要匹配的路由返回参数,至少指定一个断言;使用空字符串""表示“预期无返回值”(例如{"cluster_name": ""}表示预期没有集群匹配)。
| 断言字段 | 匹配对象 |
|---|---|
cluster_name | 匹配到的集群名 |
virtual_cluster_name | 虚拟集群名 |
virtual_host_name | 虚拟主机名 |
host_rewrite | 重写后的 Host 头部 |
path_rewrite | 重写后的路径 |
path_redirect | 返回的重定向路径 |
code_redirect | 重定向响应码 |
timeout | 命中路由的 per-route 请求超时(RouteEntry::timeout()),Duration 类型 |
request_header_matches/response_header_matches | 复用HeaderMatcher(支持 exact/prefix/suffix/contains/safe_regex/range/present 及invert_match),在所有其他断言之后检查,因此对重定向/重写路由会检查改写后的头部 |
request_header_fields/response_header_fields | 已弃用,请用*_header_matches替代 |
断言的实际执行是一个固定顺序的检查器列表:compareCluster→compareVirtualCluster→compareVirtualHost→compareRewritePath→compareRewriteHost→compareRedirectPath→compareRedirectCode→compareTimeout→ 请求头匹配 → 响应头匹配(见 router.cc#L319-L348)。每一项只有在断言字段被显式设置时才参与比较,未设置的字段直接返回通过。值得注意的是:路径重写断言读取的是经过finalizeRequestHeaders处理后的:path头,主机重写断言读取的是处理后的 Host 头(见 router.cc#L439-L483),这正体现了“用真实路由管线而非字面配置做校验”的设计。
输出、退出码与结果 proto
- 若有任何测试用例不匹配预期,程序以
EXIT_FAILURE退出; - 测试失败时,配合
--details会打印冲突明细:第一字段为期望值,第二字段为实际值,第三字段为被比较的参数名。文档给出的示例输出如下:
Test_1 Test_2 default other virtual_host_name Test_3 Test_4 Test_5 locations ats cluster_name Test_6其中 Test_2、Test_5 失败,其余通过。
- 若指定
--output-path,则把ValidationResultproto(含每条测试的ValidationItemResult:test_name、test_passed、failure明细)以二进制 proto写入文件;若同时指定--only-show-failures,文件中仅包含失败测试的结果。写入逻辑见 router_check.cc#L49-L70。
失败明细的完整字段定义在ValidationFailure中,对每类断言都记录了expected_*与actual_*成对字段,头部匹配失败还单独记录HeaderMatchFailure(含原始header_matcher与实际头部值)。
路由覆盖率机制
工具除“期望 vs 实际”的断言比对外,还统计路由测试覆盖率——衡量你的测试用例覆盖了路由表中多少“可断言面”:
Coverage类(coverage.h)为每条路由维护一组覆盖位:cluster、virtual cluster、virtual host、path rewrite、host rewrite、redirect path、redirect code。某项断言匹配成功时调用对应的markXxxCovered(),例如集群名匹配成功后调用coverage_.markClusterCovered(...)(见 router.cc#L378-L381)。- 运行结束时打印
Current route coverage: <百分比>;若设置了-f/--fail-under,覆盖率低于阈值时额外打印Failed to meet coverage requirement: <阈值>%并返回EXIT_FAILURE(见 router_check.cc#L62-L70)。 --covall启用“全面”计算:把所有可能的断言字段都计入分母,并打印缺失测试;--detailed-coverage则在普通模式下也打印未覆盖路由。
为了让覆盖检查可以精确定位到具体路由,工具在加载配置后会做两件预处理:assignUniqueRouteNames()给每条路由的 name 附加随机 UUID,assignRuntimeFraction()把runtime_fraction默认分子为 0 的路由改成非零值,使得这类路由可以被“启用/禁用”两种状态测试(见 router.h#L104-L113 与 router.cc#L154-L176)。因此运行输出的路由名会形如route-uuid,这是正常现象。
缺失测试的输出形如:
Missing test for host: www2_staging, route: prefix: "/" Missing test for host: localhost, route name: new_endpoint2-xxxx实战示例:从仓库自带配置完整走一遍
仓库在 test/tools/router_check/test/config/ 下提供了多组“路由配置 + 期望文件”示例对,覆盖 ContentType、ClusterHeader、Redirect(1-4)、Runtime、Weighted、DirectResponse 等场景。以TestRoutes为例:
路由配置TestRoutes.yaml 定义了三个虚拟主机(www2、www2_staging、default兜底*),包含prefix_rewrite、host_rewrite_literal、direct_response、加权集群、虚拟集群正则匹配等典型特性,例如:
- name: default domains: - '*' routes: - match: prefix: /api/leads/me route: cluster: ats - match: prefix: /host/rewrite/me route: cluster: ats host_rewrite_literal: new_host virtual_clusters: - headers: - name: :path string_match: safe_regex: regex: ^/rides$ - name: :method string_match: exact: POST name: ride_request期望文件TestRoutes.golden.proto.json 则是Validation的 JSON 实例,30 余个测试用例各用input(authority/path/method)+validate(预期断言)描述一个路由场景,例如:
{ "test_name": "Test9", "input": { "authority": "api.lyft.com", "path": "/api/locations?works=true", "method": "GET" }, "validate": {"path_rewrite": "/rewrote?works=true"} }可以看到prefix_rewrite: /rewrote作用后 query 参数?works=true被保留,这正是通过真实路由管线校验得到的行为。测试用例还演示了头部断言写法:string_match.exact、range_match(content-length在 0-100)、present_match配合invert_match(断言某头部不存在)等。
构建与运行的标准流程(与 文档 一致):
# 本地构建(Bazel) bazel build //test/tools/router_check:router_check_tool # 运行示例 bazel-bin/test/tools/router_check/router_check_tool \ -c router_config.(yaml|json) -t tool_config.json --details # 覆盖率门槛示例 bazel-bin/test/tools/router_check/router_check_tool \ -c test/tools/router_check/test/config/Redirect.yaml \ -t test/tools/router_check/test/config/Redirect.golden.proto.json \ --details -f 100该工具也随 tools 镜像分发,可直接在镜像内使用。
回归测试如何守护工具自身
仓库用 bash 脚本测试 route_tests.sh 系统性地验证工具行为:
- 对 12 组“配置 + golden 文件”逐一断言全部通过;
- 验证
-f覆盖率阈值:低于阈值时必须打印Failed to meet coverage requirement: 100%,达标则打印Current route coverage: 100%; - 验证 YAML 与 proto-text 两种期望文件格式均被支持(
Weighted.golden.proto.yaml与Weighted.golden.proto.pb_text); - 验证错误处理:把期望文件错配为路由配置时应输出
INVALID_ARGUMENT类错误; - 验证失败输出格式:如
expected: [cluster1], actual: [instant-server], test type: cluster_name,以及--only-show-failures下不再打印通过测试的测试名; - 验证
--covall与--detailed-coverage的缺失测试打印行为。
运行方式:
bazel test //test/tools/router_check/...小结
router_check_tool是 Envoy 生态中少有的“路由配置单元测试器”:它用真实的路由实现执行断言,用 validation.proto 模式描述期望,用退出码与覆盖率门槛支撑 CI 门禁。将你的生产 RouteConfiguration(或其测试副本)与一份 golden 期望文件放入仓库,再仿照 route_tests.sh 的调用方式接入流水线,即可在路由配置变更时第一时间发现集群指向、重写规则或重定向行为的回归。
【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考