联系我们
18591797788
hubin@rlctech.com
北京市海淀区中关村南大街乙12号院天作国际B座1708室
18681942657
lvyuan@rlctech.com
上海市浦东新区商城路660号乐凯大厦26c-1
18049488781
xieyi@rlctech.com
广州市越秀区东风东路华宫大厦808号1608房
029-81109312
service@rlctech.com
西安市高新区天谷七路996号西安国家数字出版基地C座501
OCP API 支持 HTTP Basic Auth 和 AK/SK 签名 两种认证。本文档采用 HTTP Basic Auth。
| 对比项 | HTTP Basic Auth | AK/SK 签名认证 |
|---|---|---|
| 原理 | 用户名:密码 的 Base64 编码 | AccessKey ID + HMAC-SHA1 签名 |
| 请求头 | Authorization: Basic |
Authorization: OCP-ACCESS-KEY-HMACSHA1 {AK}:{Signature} |
| 安全性 | 密码存在 Base64 明文泄漏风险 | 避免明文传输密码,可授权他人而不共享密码 |
| 签名算法 | 无 | BASE64(HMAC-SHA1(AK_SECRET, string-to-sign)) |
| 适用场景 | 调试、脚本快速验证 (本文档采用此方式) | 生产环境自动化调用 |
| 获取方式 | OCP 用户账号密码 | 个人设置 → AccessKey 模块 → 一键创建 AccessKey |
AK/SK 认证需额外请求头 Date 和签名计算,本文档为简洁起见,所有命令均采用 HTTP Basic Auth。
本文档实验环境信息如下:
| 项目 | 值 |
|---|---|
| 目标服务器 | http://192.168.1.71:8080 |
| 认证方式 | HTTP Basic Auth |
| OCP版本 | OCP V4.3.5 |
| OB版本 | 4.4.2.0 |
| 验证集群 | obcp_test (3 Zone, 6 OBServer) |
source .env
.env 内容:
export OCP_HOST="http://192.168.1.71:8080"export OCP_USER="admin"export OCP_PASS="aaAA11__"export CLUSTER_NAME="obcp_test"export ZONE_NAME="zone3"export SERVER_ID=2000006export API_BASE="/api/v2"export API_CLUSTERS="${API_BASE}/ob/clusters"
获取集群 ID (几乎每个操作都需要):
OCP_ID=$(curl -s --user "${OCP_USER}:${OCP_PASS}" "${OCP_HOST}${API_CLUSTERS}" \| jq -r --arg name "$CLUSTER_NAME" '.data.contents[] | select(.name==$name) | .id')
检查命令:
echo "OCP_ID=$OCP_ID"
验证结果: OCP_ID=2000001 ✅
✅ 已验证
curl -s --user "${OCP_USER}:${OCP_PASS}" "${OCP_HOST}${API_CLUSTERS}" \| jq -r '.data.contents[] | "\(.name) id=\(.id) obClusterId=\(.obClusterId) \(.status) \(.obVersion)"'
检查命令:同上
真实输出:
akmetadb id=1 obClusterId=1766993439 RUNNING 4.2.1.7
obcp id=2000002 obClusterId=1766993446 RUNNING 4.4.2.0
obcp_exam id=1000005 obClusterId=1766993444 RUNNING 4.4.2.0
obcp_test id=2000001 obClusterId=1766993445 RUNNING 4.4.2.0
✅ 已验证
curl -s --user "${OCP_USER}:${OCP_PASS}" -X POST \"${OCP_HOST}${API_CLUSTERS}/${OCP_ID}/stop" | jq .
检查命令(循环检查,约 40 秒):
for i in $(seq 1 60); doS=$(curl -s --user "${OCP_USER}:${OCP_PASS}" "${OCP_HOST}${API_CLUSTERS}/${OCP_ID}" | jq -r '.data.status')echo "[$i] $S"[ "$S" = "STOPPED" ] && echo "=== 停止成功 ===" && breaksleep 5done
真实结果:停止耗时约 40 秒。状态变化: RUNNING -> STOPPING -> STOPPED
✅ 已验证
curl -s --user "${OCP_USER}:${OCP_PASS}" -X POST \"${OCP_HOST}${API_CLUSTERS}/${OCP_ID}/start" | jq .
检查命令(循环检查,约 2 分钟):
for i in $(seq 1 60); doS=$(curl -s --user "${OCP_USER}:${OCP_PASS}" "${OCP_HOST}${API_CLUSTERS}/${OCP_ID}" | jq -r '.data.status')echo "[$i] $S"[ "$S" = "RUNNING" ] && echo "=== 启动成功 ===" && breaksleep 5done
真实结果:启动耗时约 2 分钟。状态变化: STOPPED -> STARTING -> RUNNING
✅ 已验证
curl -s --user "${OCP_USER}:${OCP_PASS}" -X POST \-H "Content-Type: application/json" -d '{}' \"${OCP_HOST}${API_CLUSTERS}/${OCP_ID}/restart" | jq .
检查命令(循环检查,约 6.5 分钟):
for i in $(seq 1 180); doS=$(curl -s --user "${OCP_USER}:${OCP_PASS}" "${OCP_HOST}${API_CLUSTERS}/${OCP_ID}" | jq -r '.data.status')echo "[$i] $S"[ "$S" = "RUNNING" ] && echo "=== 重启成功 ===" && breaksleep 5done
真实结果:重启耗时约 6.5 分钟。状态变化: RUNNING -> RESTARTING -> RUNNING
> 必须带 -H "Content-Type: application/json" -d '{}',否则返回 HTML。
✅ 已验证
curl -s --user "${OCP_USER}:${OCP_PASS}" "${OCP_HOST}${API_CLUSTERS}/${OCP_ID}/servers" \| jq '.data.contents[] | {id, ip, port, zone: .zoneName, status}'
检查命令:同上
真实输出 (6 个):
{"id":2000001,"ip":"192.168.1.101","port":2882,"zone":"zone1","status":"RUNNING"}
{"id":2000004,"ip":"192.168.1.104","port":2882,"zone":"zone1","status":"RUNNING"}
{"id":2000002,"ip":"192.168.1.102","port":2882,"zone":"zone2","status":"RUNNING"}
{"id":2000005,"ip":"192.168.1.105","port":2882,"zone":"zone2","status":"RUNNING"}
{"id":2000003,"ip":"192.168.1.103","port":2882,"zone":"zone3","status":"RUNNING"}
{"id":2000006,"ip":"192.168.1.106","port":2882,"zone":"zone3","status":"RUNNING"}
✅ 已验证
curl -s --user "${OCP_USER}:${OCP_PASS}" "${OCP_HOST}${API_CLUSTERS}/${OCP_ID}/zones" \| jq '.data.contents[] | {name, status}'
检查命令:同上
真实输出:
{"name":"zone1","status":"RUNNING"}
{"name":"zone2","status":"RUNNING"}
{"name":"zone3","status":"RUNNING"}
✅ 已验证
curl -s --user "${OCP_USER}:${OCP_PASS}" -X POST \"${OCP_HOST}${API_CLUSTERS}/${OCP_ID}/zones/${ZONE_NAME}/stop" | jq .
检查命令(循环检查,约 1.2 分钟):
for i in $(seq 1 180); doS=$(curl -s --user "${OCP_USER}:${OCP_PASS}" "${OCP_HOST}${API_CLUSTERS}/${OCP_ID}/zones" \| jq -r --arg z "$ZONE_NAME" '.data.contents[] | select(.name==$z) | .status')echo "[$i] $ZONE_NAME: $S"[ "$S" = "STOPPED" ] && echo "=== 停止成功 ===" && breaksleep 5done
真实结果:停止耗时约 1.2 分钟。状态: RUNNING -> STOPPING -> STOPPED
✅ 已验证
curl -s --user "${OCP_USER}:${OCP_PASS}" -X POST \"${OCP_HOST}${API_CLUSTERS}/${OCP_ID}/zones/${ZONE_NAME}/start" | jq .
检查命令(循环检查,约 1.5 分钟):
for i in $(seq 1 60); doS=$(curl -s --user "${OCP_USER}:${OCP_PASS}" "${OCP_HOST}${API_CLUSTERS}/${OCP_ID}/zones" \| jq -r --arg z "$ZONE_NAME" '.data.contents[] | select(.name==$z) | .status')echo "[$i] $ZONE_NAME: $S"[ "$S" = "RUNNING" ] && echo "=== 启动成功 ===" && breaksleep 5done
真实结果:启动耗时约 1.5 分钟。状态: STOPPED -> STARTING -> RUNNING
✅ 已验证
curl -s --user "${OCP_USER}:${OCP_PASS}" -X POST \"${OCP_HOST}${API_CLUSTERS}/${OCP_ID}/zones/${ZONE_NAME}/restart" | jq .
检查命令(循环检查,约 2.5 分钟):
for i in $(seq 1 180); doS=$(curl -s --user "${OCP_USER}:${OCP_PASS}" "${OCP_HOST}${API_CLUSTERS}/${OCP_ID}/zones" \| jq -r --arg z "$ZONE_NAME" '.data.contents[] | select(.name==$z) | .status')echo "[$i] $ZONE_NAME: $S"[ "$S" = "RUNNING" ] && echo "=== 重启成功 ===" && breaksleep 5done
真实结果:重启耗时约 2.5 分钟。状态: RUNNING -> RESTARTING -> RUNNING
✅ 已验证
curl -s --user "${OCP_USER}:${OCP_PASS}" \"${OCP_HOST}${API_CLUSTERS}/${OCP_ID}/zones/${ZONE_NAME}/servers" \| jq '.data.contents[] | {id, ip, port, status}'
检查命令:同上
真实输出 (zone3 有 2 个):
{"id":2000003,"ip":"192.168.1.103","port":2882,"status":"RUNNING"}
{"id":2000006,"ip":"192.168.1.106","port":2882,"status":"RUNNING"}
✅ 已验证
curl -s --user "${OCP_USER}:${OCP_PASS}" "${OCP_HOST}/api/v2/arbitration/services" | jq .
检查命令:同上
真实结果:当前环境无仲裁服务,返回 {"successful":true,"data":{"contents":[],...}}
OBServer 操作通过 3 个 API 实现:stop、start、restart。
| API | 请求路径 | 必选参数 | 可选参数 |
|---|---|---|---|
| 停止 | POST /servers/{serverId}/stop |
freezeServer | type (STOP_SERVICE/STOP_PROCESS) |
| 启动 | POST /servers/{serverId}/start |
无 | 无 |
| 重启 | POST /servers/{serverId}/restart |
freezeServer | force |
参数说明:
freezeServer — 操作前执行 SSTable 转储,将内存数据写入磁盘。
type — STOP_SERVICE 停止 OB 服务(进程仍在),STOP_PROCESS 杀死 observer 进程。
force — 仅重启 API 支持,直接杀进程,适用于不满足多数派场景。
所有操作必须带 -H "Content-Type: application/json" -d '参数',否则返回 400。
状态说明:
| 状态 | 含义 | 恢复方式 |
|---|---|---|
| RUNNING | 正常运行 | — |
| SERVICE_STOPPED | OB 服务停止,进程仍在 | start API |
| PROCESS_STOPPED | observer 进程停止 | start API |
通用准备命令:
OCP_ID=$(curl -s --user "${OCP_USER}:${OCP_PASS}" "${OCP_HOST}${API_CLUSTERS}" \| jq -r --arg name "$CLUSTER_NAME" '.data.contents[] | select(.name==$name) | .id')
通用检查命令:
curl -s --user "${OCP_USER}:${OCP_PASS}" "${OCP_HOST}${API_CLUSTERS}/${OCP_ID}/servers" \| jq -r --argjson s "$SERVER_ID" '.data.contents[] | select(.id==$s) | .status'
✅ 已验证API: POST /api/v2/ob/clusters/{id}/servers/{serverId}/stop
停止 OB 服务,进程仍在。约 40 秒,6 个子任务。
curl -s --user "${OCP_USER}:${OCP_PASS}" -X POST \-H "Content-Type: application/json" \-d '{"freezeServer":false,"type":"STOP_SERVICE"}' \"${OCP_HOST}${API_CLUSTERS}/${OCP_ID}/servers/${SERVER_ID}/stop" | jq .
检查命令(循环检查,目标状态 SERVICE_STOPPED):
for i in $(seq 1 60); doS=$(curl -s --user "${OCP_USER}:${OCP_PASS}" "${OCP_HOST}${API_CLUSTERS}/${OCP_ID}/servers" \| jq -r --argjson s "$SERVER_ID" '.data.contents[] | select(.id==$s) | .status')echo "[$i] $S"[ "$S" = "SERVICE_STOPPED" ] && echo "=== 停止成功 ===" && breaksleep 5done
停止整个进程。约 3 分钟,8 个子任务。
curl -s --user "${OCP_USER}:${OCP_PASS}" -X POST \-H "Content-Type: application/json" \-d '{"freezeServer":false,"type":"STOP_PROCESS"}' \"${OCP_HOST}${API_CLUSTERS}/${OCP_ID}/servers/${SERVER_ID}/stop" | jq .
检查命令(循环检查,目标状态 PROCESS_STOPPED):
for i in $(seq 1 60); doS=$(curl -s --user "${OCP_USER}:${OCP_PASS}" "${OCP_HOST}${API_CLUSTERS}/${OCP_ID}/servers" \| jq -r --argjson s "$SERVER_ID" '.data.contents[] | select(.id==$s) | .status')echo "[$i] $S"[ "$S" = "PROCESS_STOPPED" ] && echo "=== 停止成功 ===" && breaksleep 5done
先转储再停止。约 5 分钟,9 个子任务。
curl -s --user "${OCP_USER}:${OCP_PASS}" -X POST \-H "Content-Type: application/json" \-d '{"freezeServer":true,"type":"STOP_PROCESS"}' \"${OCP_HOST}${API_CLUSTERS}/${OCP_ID}/servers/${SERVER_ID}/stop" | jq .
检查命令(循环检查,目标状态 PROCESS_STOPPED):
for i in $(seq 1 90); doS=$(curl -s --user "${OCP_USER}:${OCP_PASS}" "${OCP_HOST}${API_CLUSTERS}/${OCP_ID}/servers" \| jq -r --argjson s "$SERVER_ID" '.data.contents[] | select(.id==$s) | .status')echo "[$i] $S"[ "$S" = "PROCESS_STOPPED" ] && echo "=== 停止成功 ===" && breaksleep 5done
| 方式 | freezeServer | type | 目标状态 | Subtask 数 | 耗时 |
|---|---|---|---|---|---|
| 停止服务 | false | STOP_SERVICE | SERVICE_STOPPED | 6 | ~40 秒 |
| 停止进程 | false | STOP_PROCESS | PROCESS_STOPPED | 8 | ~3 分钟 |
| 转储+停止进程 | true | STOP_PROCESS | PROCESS_STOPPED | 9 | ~5 分钟 |
✅ 已验证API: POST /api/v2/ob/clusters/{id}/servers/{serverId}/start
无参数,自动适配 SERVICE_STOPPED 和 PROCESS_STOPPED。11 个子任务。
curl -s --user "${OCP_USER}:${OCP_PASS}" -X POST \-H "Content-Type: application/json" -d '{}' \"${OCP_HOST}${API_CLUSTERS}/${OCP_ID}/servers/${SERVER_ID}/start" | jq .
检查命令(循环检查,目标状态 RUNNING):
for i in $(seq 1 60); doS=$(curl -s --user "${OCP_USER}:${OCP_PASS}" "${OCP_HOST}${API_CLUSTERS}/${OCP_ID}/servers" \| jq -r --argjson s "$SERVER_ID" '.data.contents[] | select(.id==$s) | .status')echo "[$i] $S"[ "$S" = "RUNNING" ] && echo "=== 启动成功 ===" && breaksleep 5done
启动耗时对比:
| 初始状态 | 过程 | 耗时 |
|---|---|---|
| SERVICE_STOPPED | SERVICE_STOPPED → STARTING → RUNNING | ~10 秒 |
| PROCESS_STOPPED | PROCESS_STOPPED → STARTING → RUNNING | ~1 分钟 |
启动 API 官方文档无请求参数,实际调用需带 -H "Content-Type: application/json" -d '{}',否则返回 400。
✅ 已验证API: POST /api/v2/ob/clusters/{id}/servers/{serverId}/restart
约 2 分钟,13 个子任务。
curl -s --user "${OCP_USER}:${OCP_PASS}" -X POST \-H "Content-Type: application/json" -d '{"freezeServer":false}' \"${OCP_HOST}${API_CLUSTERS}/${OCP_ID}/servers/${SERVER_ID}/restart" | jq .
检查命令(循环检查,目标状态 RUNNING):
for i in $(seq 1 60); doS=$(curl -s --user "${OCP_USER}:${OCP_PASS}" "${OCP_HOST}${API_CLUSTERS}/${OCP_ID}/servers" \| jq -r --argjson s "$SERVER_ID" '.data.contents[] | select(.id==$s) | .status')echo "[$i] $S"[ "$S" = "RUNNING" ] && echo "=== 重启成功 ===" && breaksleep 5done
约 5 分钟,14 个子任务。
curl -s --user "${OCP_USER}:${OCP_PASS}" -X POST \-H "Content-Type: application/json" -d '{"freezeServer":true}' \"${OCP_HOST}${API_CLUSTERS}/${OCP_ID}/servers/${SERVER_ID}/restart" | jq .
检查命令(循环检查,目标状态 RUNNING):
for i in $(seq 1 120); doS=$(curl -s --user "${OCP_USER}:${OCP_PASS}" "${OCP_HOST}${API_CLUSTERS}/${OCP_ID}/servers" \| jq -r --argjson s "$SERVER_ID" '.data.contents[] | select(.id==$s) | .status')echo "[$i] $S"[ "$S" = "RUNNING" ] && echo "=== 重启成功 ===" && breaksleep 5done
直接杀进程重启。约 15 分钟,适用于不满足多数派场景。
curl -s --user "${OCP_USER}:${OCP_PASS}" -X POST \-H "Content-Type: application/json" -d '{"freezeServer":false,"force":true}' \"${OCP_HOST}${API_CLUSTERS}/${OCP_ID}/servers/${SERVER_ID}/restart" | jq .
检查命令(循环检查,目标状态 RUNNING):
for i in $(seq 1 180); doS=$(curl -s --user "${OCP_USER}:${OCP_PASS}" "${OCP_HOST}${API_CLUSTERS}/${OCP_ID}/servers" \| jq -r --argjson s "$SERVER_ID" '.data.contents[] | select(.id==$s) | .status')echo "[$i] $S"[ "$S" = "RUNNING" ] && echo "=== 重启成功 ===" && breaksleep 5done
| 方式 | freezeServer | force | Subtask 数 | 耗时 | 适用场景 |
|---|---|---|---|---|---|
| 优雅重启 | false | false | 13 | ~2 分钟 | 常规重启 |
| 转储+重启 | true | false | 14 | ~5 分钟 | 计划内维护 |
| 强制重启 | false | true | — | ~15 分钟 | 不满足多数派 |
✅ 已验证API: GET /api/v2/tasks/instances/{taskId}
所有 OBServer 操作都是异步任务,可通过任务 ID 查看子进度:
TASK_ID=# 查看任务概览curl -s --user "${OCP_USER}:${OCP_PASS}" "${OCP_HOST}${API_BASE}/tasks/instances/${TASK_ID}" \| jq '{id: .data.id, name: .data.name, status: .data.status, subtaskCount: (.data.subtasks | length)}'# 查看所有 subtaskscurl -s --user "${OCP_USER}:${OCP_PASS}" "${OCP_HOST}${API_BASE}/tasks/instances/${TASK_ID}" \| jq -r '.data.subtasks[] | "\(.id) | \(.status) | \(.name)"'
输出示例:
{"id":2083159,"name":"Stop OB server","status":"RUNNING","subtaskCount":9}
2098378 | SUCCESSFUL | Freeze observer
2098381 | SUCCESSFUL | Prepare stop observer process
2098377 | RUNNING | Stop observer process
2098383 | PENDING | Wait observer inactive
Subtask 状态:READY → RUNNING → SUCCESSFUL / FAILED,PENDING 表示等待前置任务。
✅ 已验证
curl -s --user "${OCP_USER}:${OCP_PASS}" "${OCP_HOST}${API_CLUSTERS}/${OCP_ID}/tenants" \| jq -r '.data.contents[] | "\(.name) id=\(.id) obTenantId=\(.obTenantId) \(.status) \(.mode)"'
检查命令:同上
真实输出:
t2_s id=2000018 obTenantId=1022 NORMAL MYSQL
tenant2 id=2000003 obTenantId=1004 NORMAL MYSQL
tenant1 id=2000002 obTenantId=1002 NORMAL MYSQL
sys id=2000001 obTenantId=1 NORMAL MYSQL
✅ 已验证
TENANT_ID=$(curl -s --user "${OCP_USER}:${OCP_PASS}" "${OCP_HOST}${API_CLUSTERS}/${OCP_ID}/tenants" \| jq -r --arg name "sys" '.data.contents[] | select(.name==$name) | .id')curl -s --user "${OCP_USER}:${OCP_PASS}" "${OCP_HOST}${API_CLUSTERS}/${OCP_ID}/tenants/${TENANT_ID}" \| jq '.data | {name, id, obTenantId, status, mode, primaryZone, charset, role, locked}'
检查命令:同上
真实输出:
{"name":"sys","id":2000001,"obTenantId":1,"status":"NORMAL","mode":"MYSQL","primaryZone":"zone1,zone2,zone3","charset":"utf8mb4","role":"PRIMARY","locked":false}
✅ 已验证
curl -s --user "${OCP_USER}:${OCP_PASS}" -X POST \-H "Content-Type: application/json" \-d '{"primaryZone":"zone3,zone2,zone1"}' \"${OCP_HOST}${API_CLUSTERS}/${OCP_ID}/tenants/${TENANT_ID}/modifyPrimaryZone" | jq .
检查命令:
curl -s --user "${OCP_USER}:${OCP_PASS}" "${OCP_HOST}${API_CLUSTERS}/${OCP_ID}/tenants/${TENANT_ID}" \| jq '.data.primaryZone'
> primaryZone 用逗号分隔,越靠前优先级越高。区别于 zoneList 的分号分隔。