openapi: 3.1.0 info: title: Proxy Pool Admin API version: 1.0.0 description: | 运维状态与受控变更接口。该入口必须与 Distribution 分端口和权限。 已认证凭据可配置 `admin:read`(Status、审计)和 `admin:write`(变更); 未配置权限的旧凭据保留全权限行为。 servers: - url: http://127.0.0.1:8082 tags: - name: Status - name: Audit - name: Upstreams - name: Routing - name: Configuration security: - AdminApiKey: [] - BasicAuth: [] - BearerAuth: [] - {} paths: /api/v1/status: get: tags: [Status] operationId: getStatus summary: 获取控制面摘要状态 description: 需要 `admin:read`。 responses: '200': description: 不含 Proxy 地址、Client 标识或 Secret 的聚合状态 headers: X-Request-ID: {$ref: '#/components/headers/RequestID'} content: application/json: schema: $ref: '#/components/schemas/Status' '401': {$ref: '#/components/responses/Unauthorized'} '403': {$ref: '#/components/responses/Forbidden'} '400': {$ref: '#/components/responses/BadRequest'} '405': {$ref: '#/components/responses/MethodNotAllowed'} '500': {$ref: '#/components/responses/InternalServerError'} '503': {$ref: '#/components/responses/ServiceUnavailable'} /api/v1/audit: get: tags: [Audit] operationId: listAuditRecords summary: 按 ID 游标读取管理面审计记录 description: | 需要 `admin:read`。 仅返回权威管理面的变更审计记录,按 `id` 升序排列。`afterId` 是排他游标: 后续页面只包含 `id` 大于该值的记录。未传 `limit` 时返回 100 条,单页最多 1000 条。 审计接口不返回 Proxy、Upstream URL、凭据或活动池内容。 parameters: - name: afterId in: query required: false description: 排他游标;仅返回 ID 大于此值的记录。 schema: {type: integer, minimum: 0, default: 0} - name: limit in: query required: false description: 单页记录数;默认 100,最大 1000。 schema: {type: integer, minimum: 1, maximum: 1000, default: 100} responses: '200': description: 管理面审计记录页 headers: X-Request-ID: {$ref: '#/components/headers/RequestID'} content: application/json: schema: {$ref: '#/components/schemas/AuditPage'} '401': {$ref: '#/components/responses/Unauthorized'} '403': {$ref: '#/components/responses/Forbidden'} '400': {$ref: '#/components/responses/BadRequest'} '405': {$ref: '#/components/responses/MethodNotAllowed'} '500': {$ref: '#/components/responses/InternalServerError'} '503': {$ref: '#/components/responses/ServiceUnavailable'} /api/v1/upstreams/{name}/enable: post: tags: [Upstreams] operationId: enableUpstream summary: 启用 Upstream description: 需要 `admin:write`。 parameters: - $ref: '#/components/parameters/UpstreamName' - $ref: '#/components/parameters/RequestID' responses: '200': {$ref: '#/components/responses/MutationResult'} '401': {$ref: '#/components/responses/Unauthorized'} '403': {$ref: '#/components/responses/Forbidden'} '404': {$ref: '#/components/responses/NotFound'} '409': {$ref: '#/components/responses/Conflict'} '400': {$ref: '#/components/responses/BadRequest'} '405': {$ref: '#/components/responses/MethodNotAllowed'} '500': {$ref: '#/components/responses/InternalServerError'} '503': {$ref: '#/components/responses/ServiceUnavailable'} /api/v1/upstreams/{name}/disable: post: tags: [Upstreams] operationId: disableUpstream summary: 禁用 Upstream 并使已有资源自然 Drain description: 需要 `admin:write`。 parameters: - $ref: '#/components/parameters/UpstreamName' - $ref: '#/components/parameters/RequestID' responses: '200': {$ref: '#/components/responses/MutationResult'} '401': {$ref: '#/components/responses/Unauthorized'} '403': {$ref: '#/components/responses/Forbidden'} '404': {$ref: '#/components/responses/NotFound'} '409': {$ref: '#/components/responses/Conflict'} '400': {$ref: '#/components/responses/BadRequest'} '405': {$ref: '#/components/responses/MethodNotAllowed'} '500': {$ref: '#/components/responses/InternalServerError'} '503': {$ref: '#/components/responses/ServiceUnavailable'} /api/v1/routing/{name}/switch: post: tags: [Routing] operationId: switchRouting summary: 原子切换 Sequential Routing 当前 Upstream description: 需要 `admin:write`。 parameters: - name: name in: path required: true schema: {type: string, minLength: 1, maxLength: 128} - $ref: '#/components/parameters/RequestID' requestBody: required: true content: application/json: schema: type: object additionalProperties: false required: [expectedCurrent, target] properties: expectedCurrent: {type: string} target: {type: string} reason: {type: string, maxLength: 512} responses: '200': {$ref: '#/components/responses/MutationResult'} '401': {$ref: '#/components/responses/Unauthorized'} '403': {$ref: '#/components/responses/Forbidden'} '404': {$ref: '#/components/responses/NotFound'} '409': {$ref: '#/components/responses/Conflict'} '400': {$ref: '#/components/responses/BadRequest'} '405': {$ref: '#/components/responses/MethodNotAllowed'} '413': {$ref: '#/components/responses/RequestEntityTooLarge'} '415': {$ref: '#/components/responses/UnsupportedMediaType'} '422': {$ref: '#/components/responses/UnprocessableEntity'} '500': {$ref: '#/components/responses/InternalServerError'} '503': {$ref: '#/components/responses/ServiceUnavailable'} /api/v1/config/reload: post: tags: [Configuration] operationId: reloadConfiguration summary: 严格校验并原子发布新配置快照 description: 需要 `admin:write`。 parameters: - $ref: '#/components/parameters/RequestID' responses: '200': {$ref: '#/components/responses/MutationResult'} '401': {$ref: '#/components/responses/Unauthorized'} '403': {$ref: '#/components/responses/Forbidden'} '409': {$ref: '#/components/responses/Conflict'} '400': {$ref: '#/components/responses/BadRequest'} '405': {$ref: '#/components/responses/MethodNotAllowed'} '422': description: 新配置无效,旧配置继续运行 headers: X-Request-ID: {$ref: '#/components/headers/RequestID'} content: application/problem+json: schema: {$ref: '#/components/schemas/Problem'} '500': {$ref: '#/components/responses/InternalServerError'} '503': {$ref: '#/components/responses/ServiceUnavailable'} components: securitySchemes: AdminApiKey: {type: apiKey, in: header, name: X-Admin-Key} BasicAuth: {type: http, scheme: basic} BearerAuth: {type: http, scheme: bearer} parameters: UpstreamName: name: name in: path required: true schema: {type: string, minLength: 1, maxLength: 128} RequestID: name: X-Request-ID in: header required: false schema: {type: string, maxLength: 128} headers: RequestID: description: 服务端最终使用的请求标识。 schema: {type: string, maxLength: 128} schemas: AuditPage: type: object additionalProperties: false required: [records] properties: records: type: array description: 按 ID 升序的审计记录;没有更多记录时为空数组。 items: {$ref: '#/components/schemas/AuditRecord'} AuditRecord: type: object additionalProperties: false required: [id, requestId, actorId, action, resourceType, resourceName, changed, version, occurredAt] properties: id: {type: integer, minimum: 0} requestId: {type: string} actorId: {type: string} sourceIp: {type: string} action: {type: string} resourceType: {type: string} resourceName: {type: string} changed: {type: boolean} version: {type: integer, minimum: 0} reason: {type: string} occurredAt: {type: string, format: date-time} Status: type: object additionalProperties: false required: [configVersion, snapshotVersion, upstreams, workers] properties: configVersion: {type: string} snapshotVersion: {type: integer, minimum: 0} upstreams: type: array items: type: object additionalProperties: false required: [name, enabled, available, checking, suspect, draining, extracted] properties: name: {type: string} enabled: {type: boolean} available: {type: integer, minimum: 0} checking: {type: integer, minimum: 0} suspect: {type: integer, minimum: 0} draining: {type: integer, minimum: 0} extracted: {type: integer, minimum: 0} consecutiveEmptyFetch: {type: integer, minimum: 0} fetchErrorCount: {type: integer, minimum: 0} workers: type: array items: type: object additionalProperties: false required: [id, zone, connected, snapshotVersion] properties: id: {type: string} zone: {type: string} connected: {type: boolean} snapshotVersion: {type: integer, minimum: 0} staleSeconds: {type: integer, minimum: 0} MutationResult: type: object additionalProperties: false required: [requestId, changed, version] properties: requestId: {type: string} changed: {type: boolean} version: {type: integer, minimum: 0} message: {type: string} Problem: type: object required: [type, title, status, code] properties: type: {type: string, format: uri} title: {type: string} status: {type: integer} code: {type: string} detail: {type: string} requestId: {type: string} responses: MutationResult: description: 操作已提交或目标状态原本已满足 headers: X-Request-ID: {$ref: '#/components/headers/RequestID'} content: application/json: schema: {$ref: '#/components/schemas/MutationResult'} Unauthorized: description: 管理入口认证失败 headers: X-Request-ID: {$ref: '#/components/headers/RequestID'} WWW-Authenticate: {schema: {type: string}} content: application/problem+json: schema: {$ref: '#/components/schemas/Problem'} Forbidden: description: 调用主体无该管理权限 headers: X-Request-ID: {$ref: '#/components/headers/RequestID'} content: application/problem+json: schema: {$ref: '#/components/schemas/Problem'} NotFound: description: Upstream 或 Routing 不存在 headers: X-Request-ID: {$ref: '#/components/headers/RequestID'} content: application/problem+json: schema: {$ref: '#/components/schemas/Problem'} Conflict: description: 预期版本或 expectedCurrent 与权威状态不一致 headers: X-Request-ID: {$ref: '#/components/headers/RequestID'} content: application/problem+json: schema: {$ref: '#/components/schemas/Problem'} BadRequest: description: 请求标识或请求体无效 headers: X-Request-ID: {$ref: '#/components/headers/RequestID'} content: application/problem+json: schema: {$ref: '#/components/schemas/Problem'} MethodNotAllowed: description: 端点不支持该 HTTP 方法 headers: X-Request-ID: {$ref: '#/components/headers/RequestID'} Allow: {schema: {type: string}} content: application/problem+json: schema: {$ref: '#/components/schemas/Problem'} RequestEntityTooLarge: description: 请求体超过管理入口限制 headers: X-Request-ID: {$ref: '#/components/headers/RequestID'} content: application/problem+json: schema: {$ref: '#/components/schemas/Problem'} UnsupportedMediaType: description: Content-Type 不是 application/json headers: X-Request-ID: {$ref: '#/components/headers/RequestID'} content: application/problem+json: schema: {$ref: '#/components/schemas/Problem'} UnprocessableEntity: description: 命令字段或配置内容违反业务约束 headers: X-Request-ID: {$ref: '#/components/headers/RequestID'} content: application/problem+json: schema: {$ref: '#/components/schemas/Problem'} InternalServerError: description: 未分类的控制面错误 headers: X-Request-ID: {$ref: '#/components/headers/RequestID'} content: application/problem+json: schema: {$ref: '#/components/schemas/Problem'} ServiceUnavailable: description: 权威控制面暂时不可用 headers: X-Request-ID: {$ref: '#/components/headers/RequestID'} content: application/problem+json: schema: {$ref: '#/components/schemas/Problem'}