|
| 1 | +# BK 插件 JSON Schema 检查 |
| 2 | + |
| 3 | +## 2026-06-09 更新 |
| 4 | + |
| 5 | +已按 `src/dashboard/apigateway/apigateway/fixtures/plugins.yaml` 中的 dashboard 插件配置补齐 operator 的 3.13 / 3.16 JSON schema。当前 dashboard 暴露的 16 个 `bk-*` 插件在两份 schema 中都能找到 `plugins.<name>.schema`,不会再落入“缺失 schema 的 `bk-*` 插件直接跳过校验”的分支。 |
| 6 | + |
| 7 | +本次补齐的 7 个插件: |
| 8 | + |
| 9 | +```text |
| 10 | +bk-status-rewrite |
| 11 | +bk-oauth2-protected-resource |
| 12 | +bk-oauth2-verify |
| 13 | +bk-oauth2-audience-validate |
| 14 | +bk-username-required |
| 15 | +bk-legacy-invalid-params |
| 16 | +bk-traffic-label |
| 17 | +``` |
| 18 | + |
| 19 | +说明:下文保留了初始排查时对远端 `blueking-apigateway-apisix` 全量 `bk-*` 插件的背景分析。远端仍有一些非 dashboard 配置入口的内部插件未纳入 operator schema;本次修复范围是 dashboard `plugins.yaml` 暴露的可配置插件。 |
| 20 | + |
| 21 | +## 结论 |
| 22 | + |
| 23 | +是的,operator 对 `bk-*` 插件有特殊逻辑:当插件名以 `bk-` 开头,并且在当前 APISIX 版本的 JSON schema 中找不到该插件 schema 时,operator 会跳过该插件配置校验。 |
| 24 | + |
| 25 | +因此,`src/operator/pkg/utils/schema/3.13/schema.json` 和 `src/operator/pkg/utils/schema/3.16/schema.json` 里只有 9 个 `bk-*` 插件 schema,并不代表 dashboard 只能发布这 9 个插件。operator 仍然会校验 route/service/plugin_metadata 等主资源结构,但对缺失 schema 的 `bk-*` 插件配置本身不做 JSON schema 校验。 |
| 26 | + |
| 27 | +## 关键代码证据 |
| 28 | + |
| 29 | +### 1. `bk-*` 被定义为内部插件 |
| 30 | + |
| 31 | +`src/operator/pkg/utils/schema/schema.go`: |
| 32 | + |
| 33 | +```go |
| 34 | +func IsInnerPlugin(pluginName string) bool { |
| 35 | + return strings.HasPrefix(pluginName, "bk-") |
| 36 | +} |
| 37 | +``` |
| 38 | + |
| 39 | +### 2. 插件 schema 查找逻辑 |
| 40 | + |
| 41 | +`src/operator/pkg/utils/schema/schema.go`: |
| 42 | + |
| 43 | +```go |
| 44 | +func GetPluginSchema(version constant.APISIXVersion, name, schemaType string) any { |
| 45 | + var ret any |
| 46 | + if schemaType == "consumer" || schemaType == "consumer_schema" { |
| 47 | + ret = schemaVersionMap[version].Get("plugins." + name + ".consumer_schema").Value() |
| 48 | + } |
| 49 | + if schemaType == "metadata" || schemaType == "metadata_schema" { |
| 50 | + return GetMetadataPluginSchema(version, "plugins."+name+".metadata_schema") |
| 51 | + } |
| 52 | + if schemaType == "stream" || schemaType == "stream_schema" { |
| 53 | + return schemaVersionMap[version].Get("stream_plugins." + name + ".schema").Value() |
| 54 | + } |
| 55 | + if ret == nil { |
| 56 | + ret = schemaVersionMap[version].Get("plugins." + name + ".schema").Value() |
| 57 | + } |
| 58 | + return ret |
| 59 | +} |
| 60 | +``` |
| 61 | + |
| 62 | +### 3. 缺失 schema 的 `bk-*` 插件会被跳过 |
| 63 | + |
| 64 | +`src/operator/pkg/utils/schema/validate.go`: |
| 65 | + |
| 66 | +```go |
| 67 | +schemaValue := GetPluginSchema(v.version, pluginName, schemaType) |
| 68 | +if schemaValue == nil && v.customizePluginSchemaMap != nil { |
| 69 | + schemaValue = v.customizePluginSchemaMap[pluginName] |
| 70 | +} |
| 71 | +// 如果是内置插件,且找不到schema,直接跳过校验 |
| 72 | +if IsInnerPlugin(pluginName) && schemaValue == nil { |
| 73 | + continue |
| 74 | +} |
| 75 | +if schemaValue == nil { |
| 76 | + return fmt.Errorf("资源:%s schema 验证失败: 未找到 schema, 路径: %s", |
| 77 | + resourceIdentification, "plugins."+pluginName) |
| 78 | +} |
| 79 | +``` |
| 80 | + |
| 81 | +含义: |
| 82 | + |
| 83 | +- 非 `bk-*` 插件:找不到 schema 会报错。 |
| 84 | +- `bk-*` 插件:找不到 schema 会 `continue`,即跳过该插件配置校验。 |
| 85 | +- 如果 `bk-*` 插件在 schema.json 里有条目,则仍然会校验该插件配置。 |
| 86 | + |
| 87 | +## 校验链路 |
| 88 | + |
| 89 | +operator 从 APIGW 控制面 etcd 读取 APISIX 原生资源后,会进入 schema 校验: |
| 90 | + |
| 91 | +- `src/operator/pkg/core/registry/apigw.go` |
| 92 | + - `ValueToStageResource()` 对 stage 资源调用 `ValidateApisixJsonSchema(...)` |
| 93 | + - `ValueToGlobalResource()` 对 global `plugin_metadata` 资源调用 `ValidateApisixJsonSchema(...)` |
| 94 | +- `src/operator/pkg/core/validator/validator.go` |
| 95 | + - `ValidateApisixJsonSchema()` 根据资源 label 中的 APISIX 版本选择 `3.13.X` 或 `3.16.X` schema |
| 96 | +- `src/operator/pkg/utils/schema/validate.go` |
| 97 | + - 先校验资源主 schema |
| 98 | + - 再逐个校验 plugins |
| 99 | + - 对缺失 schema 的 `bk-*` 插件跳过插件配置校验 |
| 100 | + |
| 101 | +所以不是“完全不校验包含 bk 插件的资源”,而是: |
| 102 | + |
| 103 | +1. route/service/plugin_metadata 等资源外层结构仍然校验; |
| 104 | +2. 已收录 schema 的 `bk-*` 插件配置会校验; |
| 105 | +3. 未收录 schema 的 `bk-*` 插件配置会跳过。 |
| 106 | + |
| 107 | +## 3.13 / 3.16 中的 `bk-*` schema 现状 |
| 108 | + |
| 109 | +两份 schema 中的 `bk-*` 插件条目完全一致,数量都是 9: |
| 110 | + |
| 111 | +```text |
| 112 | +bk-access-token-source |
| 113 | +bk-cors |
| 114 | +bk-header-rewrite |
| 115 | +bk-ip-restriction |
| 116 | +bk-mock |
| 117 | +bk-rate-limit |
| 118 | +bk-request-body-limit |
| 119 | +bk-user-restriction |
| 120 | +bk-verified-user-exempted-apps |
| 121 | +``` |
| 122 | + |
| 123 | +其中 `bk-header-rewrite` 和 `bk-rate-limit` 不直接对应远端 `src/apisix/plugins/` 下的顶层 `bk-*.lua` 文件名: |
| 124 | + |
| 125 | +- 远端有 `bk-stage-header-rewrite.lua` / `bk-resource-header-rewrite.lua`,schema 中是更泛化的 `bk-header-rewrite`。 |
| 126 | +- 远端目录中有 `bk-rate-limit/` 目录,同时顶层插件文件列表里没有 `bk-rate-limit.lua`。 |
| 127 | + |
| 128 | +## 远端 `blueking-apigateway-apisix` master 插件现状 |
| 129 | + |
| 130 | +检查来源: |
| 131 | + |
| 132 | +`https://github.com/TencentBlueKing/blueking-apigateway-apisix/tree/master/src/apisix/plugins` |
| 133 | + |
| 134 | +当前远端顶层 `bk-*.lua` 插件文件共 46 个: |
| 135 | + |
| 136 | +```text |
| 137 | +bk-access-token-source |
| 138 | +bk-auth-validate |
| 139 | +bk-auth-verify |
| 140 | +bk-backend-context |
| 141 | +bk-break-recursive-call |
| 142 | +bk-concurrency-limit |
| 143 | +bk-cors |
| 144 | +bk-debug |
| 145 | +bk-default-tenant |
| 146 | +bk-delete-cookie |
| 147 | +bk-delete-sensitive |
| 148 | +bk-error-wrapper |
| 149 | +bk-ip-restriction |
| 150 | +bk-jwt |
| 151 | +bk-legacy-invalid-params |
| 152 | +bk-log-context |
| 153 | +bk-mock |
| 154 | +bk-not-found-handler |
| 155 | +bk-oauth2-audience-validate |
| 156 | +bk-oauth2-protected-resource |
| 157 | +bk-oauth2-verify |
| 158 | +bk-opentelemetry |
| 159 | +bk-permission |
| 160 | +bk-proxy-rewrite |
| 161 | +bk-query-string-rewrite |
| 162 | +bk-real-ip |
| 163 | +bk-repl-debugger |
| 164 | +bk-request-body-limit |
| 165 | +bk-request-id |
| 166 | +bk-resource-context |
| 167 | +bk-resource-header-rewrite |
| 168 | +bk-resource-rate-limit |
| 169 | +bk-response-check |
| 170 | +bk-stage-context |
| 171 | +bk-stage-global-rate-limit |
| 172 | +bk-stage-header-rewrite |
| 173 | +bk-stage-rate-limit |
| 174 | +bk-status-rewrite |
| 175 | +bk-tenant-restriction |
| 176 | +bk-tenant-validate |
| 177 | +bk-tenant-validate-exempt |
| 178 | +bk-tenant-verify |
| 179 | +bk-traffic-label |
| 180 | +bk-user-restriction |
| 181 | +bk-username-required |
| 182 | +bk-verified-user-exempted-apps |
| 183 | +``` |
| 184 | + |
| 185 | +## 远端存在但 operator schema 缺失的顶层 `bk-*.lua` 插件 |
| 186 | + |
| 187 | +以下 39 个远端顶层插件名,在 `3.13/schema.json` 和 `3.16/schema.json` 中都没有对应 `plugins.<name>` 条目: |
| 188 | + |
| 189 | +```text |
| 190 | +bk-auth-validate |
| 191 | +bk-auth-verify |
| 192 | +bk-backend-context |
| 193 | +bk-break-recursive-call |
| 194 | +bk-concurrency-limit |
| 195 | +bk-debug |
| 196 | +bk-default-tenant |
| 197 | +bk-delete-cookie |
| 198 | +bk-delete-sensitive |
| 199 | +bk-error-wrapper |
| 200 | +bk-jwt |
| 201 | +bk-legacy-invalid-params |
| 202 | +bk-log-context |
| 203 | +bk-not-found-handler |
| 204 | +bk-oauth2-audience-validate |
| 205 | +bk-oauth2-protected-resource |
| 206 | +bk-oauth2-verify |
| 207 | +bk-opentelemetry |
| 208 | +bk-permission |
| 209 | +bk-proxy-rewrite |
| 210 | +bk-query-string-rewrite |
| 211 | +bk-real-ip |
| 212 | +bk-repl-debugger |
| 213 | +bk-request-id |
| 214 | +bk-resource-context |
| 215 | +bk-resource-header-rewrite |
| 216 | +bk-resource-rate-limit |
| 217 | +bk-response-check |
| 218 | +bk-stage-context |
| 219 | +bk-stage-global-rate-limit |
| 220 | +bk-stage-header-rewrite |
| 221 | +bk-stage-rate-limit |
| 222 | +bk-status-rewrite |
| 223 | +bk-tenant-restriction |
| 224 | +bk-tenant-validate |
| 225 | +bk-tenant-validate-exempt |
| 226 | +bk-tenant-verify |
| 227 | +bk-traffic-label |
| 228 | +bk-username-required |
| 229 | +``` |
| 230 | + |
| 231 | +这些插件如果出现在 route/service/plugin_metadata 的 `plugins` 中,因为插件名以 `bk-` 开头且 schema 找不到,会被 operator 的插件配置校验逻辑跳过。 |
| 232 | + |
| 233 | +## 为什么 schema 只有 9 个仍然能发布更多 bk 插件 |
| 234 | + |
| 235 | +原因是 operator 的校验策略对蓝鲸内置插件更宽松: |
| 236 | + |
| 237 | +- APISIX 官方插件要求 schema 必须存在,否则报错。 |
| 238 | +- 蓝鲸内置 `bk-*` 插件允许 schema 缺失,缺失时跳过插件配置校验。 |
| 239 | + |
| 240 | +这个策略解释了“dashboard 已支持几乎所有 bk 插件配置和发布,但 operator schema 只有 9 个”之间的差异。 |
| 241 | + |
| 242 | +## 风险说明 |
| 243 | + |
| 244 | +当前逻辑的风险不在发布失败,而在配置质量保障: |
| 245 | + |
| 246 | +- 对缺失 schema 的 `bk-*` 插件,operator 不会发现字段名错误、类型错误、必填字段缺失等问题。 |
| 247 | +- 这些错误可能要等 APISIX 加载插件配置或插件运行时才暴露。 |
| 248 | +- 对已有 schema 的 9 个 `bk-*` 插件,operator 仍会做配置校验。 |
| 249 | + |
| 250 | +## 建议 |
| 251 | + |
| 252 | +如果近期新增的 `bk-*` 插件已经稳定并由 dashboard 暴露给用户配置,建议逐步把这些插件的 schema 补进 `3.13` / `3.16`: |
| 253 | + |
| 254 | +1. 优先补用户可配置、容易配错、会影响请求链路的插件。 |
| 255 | +2. 对只由 operator/dashboard 固定生成、配置结构很简单的插件,可以继续依赖代码生成侧保障。 |
| 256 | +3. 如果继续保留跳过逻辑,建议至少增加一个覆盖测试,明确断言“缺失 schema 的 `bk-*` 插件会跳过,缺失 schema 的非 `bk-*` 插件会失败”,避免后续维护者误解。 |
| 257 | + |
0 commit comments