修正接口
This commit is contained in:
parent
c555b57c00
commit
663b458532
@ -48,6 +48,8 @@ description: 基于 PAM HOME/NODE 流程执行软件发布、下载、升级、
|
|||||||
8. Windows 脚本模式默认优先 `deploy.ps1`,不要默认使用 `deploy.bat`。
|
8. Windows 脚本模式默认优先 `deploy.ps1`,不要默认使用 `deploy.bat`。
|
||||||
9. 当前目录如果只有文档而没有真实脚本文件,先根据参考实现落地脚本,再决定是否执行。
|
9. 当前目录如果只有文档而没有真实脚本文件,先根据参考实现落地脚本,再决定是否执行。
|
||||||
10. `download-cloud` 只负责触发云下载任务;后续必须异步调用进度接口并持续展示状态/进度,直到成功、失败或超时。
|
10. `download-cloud` 只负责触发云下载任务;后续必须异步调用进度接口并持续展示状态/进度,直到成功、失败或超时。
|
||||||
|
11. 脚本模式下,每个关键方法执行前后都输出统一流程日志,至少包含 `[FLOW][START]`、`[FLOW][DONE]`、`[FLOW][FAIL]`。
|
||||||
|
12. 当检测到需要回滚时,脚本只标记 `PENDING_AGENT_CONFIRMATION(...)`,不得自动执行回滚;必须由 Agent 先向用户确认,再走手动回滚入口或直接调用回滚接口。
|
||||||
|
|
||||||
## 统一部署流程
|
## 统一部署流程
|
||||||
|
|
||||||
@ -61,10 +63,10 @@ description: 基于 PAM HOME/NODE 流程执行软件发布、下载、升级、
|
|||||||
| 2.3 | 发布版本 | `PUT {HOME_BASE_URL}/api/version/upgrade/profile?...` |
|
| 2.3 | 发布版本 | `PUT {HOME_BASE_URL}/api/version/upgrade/profile?...` |
|
||||||
| 3.1 | 获取 Node 地址 | `GET {HOME_BASE_URL}/api/mcp/airport/target-node?airportCode={airportCode}` |
|
| 3.1 | 获取 Node 地址 | `GET {HOME_BASE_URL}/api/mcp/airport/target-node?airportCode={airportCode}` |
|
||||||
| 3.2 | 获取在线工作站 IP | `GET {HOME_BASE_URL}/node-proxy/{airportCode}/api/mcp/version/upgrade/ips?...` |
|
| 3.2 | 获取在线工作站 IP | `GET {HOME_BASE_URL}/node-proxy/{airportCode}/api/mcp/version/upgrade/ips?...` |
|
||||||
| 3.3 | 下载软件包到 Node | `GET {HOME_BASE_URL}/node-proxy/{airportCode}/api/mcp/version/upgrade/download-cloud?...` |
|
| 3.3 | 下载软件包到 Node | `GET {HOME_BASE_URL}/node-proxy/{airportCode}/api/mcp/version/upgrade/download-cloud?...&timeOut=0` |
|
||||||
| 3.3b | 异步轮询并展示下载进度 | `GET {HOME_BASE_URL}/node-proxy/{airportCode}/api/mcp/version/upgrade/download-cloud/progress?...&versionNumer={versionNumber}` |
|
| 3.3b | 异步轮询并展示下载进度 | `GET {HOME_BASE_URL}/node-proxy/{airportCode}/api/mcp/version/upgrade/download-cloud/progress?...&versionNumber={versionNumber}` |
|
||||||
| 4.1 | 对每个 IP 执行升级 | `POST {HOME_BASE_URL}/node-proxy/{airportCode}/api/mcp/version/upgrade` |
|
| 4.1 | 对每个 IP 执行升级 | `POST {HOME_BASE_URL}/node-proxy/{airportCode}/api/mcp/version/upgrade?airportCode=...&targetIp=...` |
|
||||||
| 4.2 | 启动应用 | `POST {HOME_BASE_URL}/node-proxy/{airportCode}/api/mcp/version/upgrade/start-stop` |
|
| 4.2 | 启动应用 | `POST {HOME_BASE_URL}/node-proxy/{airportCode}/api/mcp/version/upgrade/start-stop?airportCode=...&targetIp=...&runStart=true` |
|
||||||
| 4.3 | 健康检测 | `GET {HOME_BASE_URL}/node-proxy/{airportCode}/api/mcp/version/upgrade/verify?...` |
|
| 4.3 | 健康检测 | `GET {HOME_BASE_URL}/node-proxy/{airportCode}/api/mcp/version/upgrade/verify?...` |
|
||||||
| 4.4 | 下载日志 | `GET {HOME_BASE_URL}/node-proxy/{airportCode}/api/mcp/version/upgrade/log-download?...` |
|
| 4.4 | 下载日志 | `GET {HOME_BASE_URL}/node-proxy/{airportCode}/api/mcp/version/upgrade/log-download?...` |
|
||||||
| 4.x | 失败回滚 | `POST {HOME_BASE_URL}/node-proxy/{airportCode}/api/mcp/version/upgrade/rollback` |
|
| 4.x | 失败回滚 | `POST {HOME_BASE_URL}/node-proxy/{airportCode}/api/mcp/version/upgrade/rollback` |
|
||||||
@ -83,6 +85,13 @@ description: 基于 PAM HOME/NODE 流程执行软件发布、下载、升级、
|
|||||||
|
|
||||||
当 `msg=success`、`step=DONE`、`rateOfProgress=100` 时,判定云下载完成;其中 `rateOfProgress` 就是下载进度值,应持续展示。
|
当 `msg=success`、`step=DONE`、`rateOfProgress=100` 时,判定云下载完成;其中 `rateOfProgress` 就是下载进度值,应持续展示。
|
||||||
|
|
||||||
|
接口参数约定补充:
|
||||||
|
|
||||||
|
- `POST /api/mcp/version/upgrade` 的业务参数直接拼到 `?query`,不要放在 body 表单里。
|
||||||
|
- `POST /api/mcp/version/upgrade/start-stop` 的业务参数直接拼到 `?query`,不要放在 body 表单里。
|
||||||
|
- 启停接口参数名统一使用 `runStart`,不要再用 `runstart`。
|
||||||
|
- `download-cloud` 创建任务接口固定传 `timeOut=0`,表示任务创建成功后立即返回,再通过进度接口异步轮询,不要等待长超时。
|
||||||
|
|
||||||
## MCP 模式
|
## MCP 模式
|
||||||
|
|
||||||
1. 直接调用 PAM MCP 提供的能力完成上述流程,不生成本地脚本文件。
|
1. 直接调用 PAM MCP 提供的能力完成上述流程,不生成本地脚本文件。
|
||||||
@ -110,13 +119,13 @@ description: 基于 PAM HOME/NODE 流程执行软件发布、下载、升级、
|
|||||||
## 失败处理与回滚
|
## 失败处理与回滚
|
||||||
|
|
||||||
1. `Step 2` 或 `Step 3` 失败时,终止整个部署,并指出失败阶段。
|
1. `Step 2` 或 `Step 3` 失败时,终止整个部署,并指出失败阶段。
|
||||||
2. `Step 4.1` 升级失败时,记录该 IP 失败原因,尝试回滚,然后继续处理其他在线 IP,除非用户要求全有或全无。
|
2. `Step 4.1` 升级失败时,记录该 IP 失败原因,并把回滚状态标记为 `PENDING_AGENT_CONFIRMATION(stopFirst=false)`;Agent 需要先向用户确认是否回滚,再决定是否调用 `rollback`。
|
||||||
3. `Step 4.3` 健康检测失败时,执行以下顺序:
|
3. `Step 4.3` 健康检测失败时,记录失败原因,并把回滚状态标记为 `PENDING_AGENT_CONFIRMATION(stopFirst=true)`;若用户确认回滚,再执行以下顺序:
|
||||||
- 调用 `start-stop` 停止应用,`runstart=false`
|
- 调用 `start-stop` 停止应用,`runStart=false`
|
||||||
- 调用 `rollback`
|
- 调用 `rollback`
|
||||||
- 再次执行健康检测
|
- 再次执行健康检测
|
||||||
- 下载回滚阶段日志
|
- 下载回滚阶段日志
|
||||||
4. 回滚是否成功也必须写入最终报告,不能仅记录“已尝试回滚”。
|
4. 最终报告必须写清楚回滚是“未执行”“待 Agent 确认”还是“已执行及结果”,不能只记录“已尝试回滚”。
|
||||||
|
|
||||||
## 输出要求
|
## 输出要求
|
||||||
|
|
||||||
@ -125,7 +134,7 @@ description: 基于 PAM HOME/NODE 流程执行软件发布、下载、升级、
|
|||||||
- 本次模式:`MCP` 或 `API脚本`
|
- 本次模式:`MCP` 或 `API脚本`
|
||||||
- 机场、应用、模块、版本
|
- 机场、应用、模块、版本
|
||||||
- 在线工作站总数、成功数、失败数
|
- 在线工作站总数、成功数、失败数
|
||||||
- 每个 IP 的状态、失败阶段、失败原因、回滚结果、日志位置或日志摘要
|
- 每个 IP 的状态、失败阶段、失败原因、回滚结果或 `PENDING_AGENT_CONFIRMATION(...)` 状态、日志位置或日志摘要
|
||||||
- 如果是脚本模式:实际生成或执行的文件名
|
- 如果是脚本模式:实际生成或执行的文件名
|
||||||
|
|
||||||
可按以下结构输出:
|
可按以下结构输出:
|
||||||
|
|||||||
@ -28,8 +28,10 @@
|
|||||||
- `config.txt`
|
- `config.txt`
|
||||||
- `deploy.sh` 或 `deploy.ps1`
|
- `deploy.sh` 或 `deploy.ps1`
|
||||||
- 仅在用户明确要求时再提供 `deploy.bat`
|
- 仅在用户明确要求时再提供 `deploy.bat`
|
||||||
7. NODE 侧接口路径统一使用 `node-proxy`;`download-cloud/progress` 需额外携带 `versionNumer`,并以异步轮询方式持续展示下载进度。
|
7. NODE 侧接口路径统一使用 `node-proxy`;`download-cloud/progress` 需额外携带 `versionNumber`,并以异步轮询方式持续展示下载进度。
|
||||||
8. `download-cloud/progress` 的完成判定优先读取 `msg`、`step`、`rateOfProgress`;当 `msg=success`、`step=DONE`、`rateOfProgress=100` 时代表下载完成,其中 `rateOfProgress` 即下载进度值。
|
8. `download-cloud/progress` 的完成判定优先读取 `msg`、`step`、`rateOfProgress`;当 `msg=success`、`step=DONE`、`rateOfProgress=100` 时代表下载完成,其中 `rateOfProgress` 即下载进度值。
|
||||||
|
9. 正式部署脚本不会自动执行回滚;发现需要回滚时,只输出 `PENDING_AGENT_CONFIRMATION(stopFirst=...)`,由 Agent 先和用户确认,再调用手动回滚入口。
|
||||||
|
10. `POST /api/mcp/version/upgrade` 和 `POST /api/mcp/version/upgrade/start-stop` 的业务参数都直接放在 URL query 中,不再使用 body 表单;启停接口参数名使用 `runStart`;`download-cloud` 固定传 `timeOut=0` 创建任务。
|
||||||
|
|
||||||
## 0.1 当前实现边界
|
## 0.1 当前实现边界
|
||||||
|
|
||||||
@ -382,14 +384,14 @@ main() {
|
|||||||
# Step 3.3: 下载软件包到 Node
|
# Step 3.3: 下载软件包到 Node
|
||||||
log_info "Step 3.3: 下载软件包到 Node..."
|
log_info "Step 3.3: 下载软件包到 Node..."
|
||||||
local download_url="${HOME_BASE_URL}/node-proxy/${AIRPORT_CODE}/api/mcp/version/upgrade/download-cloud"
|
local download_url="${HOME_BASE_URL}/node-proxy/${AIRPORT_CODE}/api/mcp/version/upgrade/download-cloud"
|
||||||
local download_params="?versionNumber=${VERSION_NUMBER}&applicationName=${APP_NAME}&moduleName=${MODULE_NAME}&timeOut=${TIMEOUT}"
|
local download_params="?versionNumber=${VERSION_NUMBER}&applicationName=${APP_NAME}&moduleName=${MODULE_NAME}&timeOut=0"
|
||||||
|
|
||||||
http_request "GET" "${download_url}${download_params}" \
|
http_request "GET" "${download_url}${download_params}" \
|
||||||
"" \
|
"" \
|
||||||
"airport-code:${AIRPORT_CODE},Target-Node:${NODE_URL}" > /dev/null
|
"airport-code:${AIRPORT_CODE},Target-Node:${NODE_URL}" > /dev/null
|
||||||
|
|
||||||
# 轮询下载进度
|
# 轮询下载进度
|
||||||
local progress_url="${HOME_BASE_URL}/node-proxy/${AIRPORT_CODE}/api/mcp/version/upgrade/download-cloud/progress?applicationName=${APP_NAME}&moduleName=${MODULE_NAME}&airportCode=${AIRPORT_CODE}&versionNumer=${VERSION_NUMBER}"
|
local progress_url="${HOME_BASE_URL}/node-proxy/${AIRPORT_CODE}/api/mcp/version/upgrade/download-cloud/progress?applicationName=${APP_NAME}&moduleName=${MODULE_NAME}&airportCode=${AIRPORT_CODE}&versionNumber=${VERSION_NUMBER}"
|
||||||
poll_progress "$progress_url" 60 2
|
poll_progress "$progress_url" 60 2
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
log_error "软件包下载失败"
|
log_error "软件包下载失败"
|
||||||
@ -407,11 +409,10 @@ main() {
|
|||||||
|
|
||||||
# 4.1: 执行升级
|
# 4.1: 执行升级
|
||||||
log_info "Step 4.1: 执行升级..."
|
log_info "Step 4.1: 执行升级..."
|
||||||
local upgrade_url="${HOME_BASE_URL}/node-proxy/${AIRPORT_CODE}/api/mcp/version/upgrade"
|
local upgrade_url="${HOME_BASE_URL}/node-proxy/${AIRPORT_CODE}/api/mcp/version/upgrade?airportCode=${AIRPORT_CODE}&targetIp=${ip}&applicationName=${APP_NAME}&moduleName=${MODULE_NAME}&versionNumber=${VERSION_NUMBER}&action=${ACTION_TYPE}&autoStart=false&timeOut=${TIMEOUT}"
|
||||||
local upgrade_data="airportCode=${AIRPORT_CODE}&targetIp=${ip}&applicationName=${APP_NAME}&moduleName=${MODULE_NAME}&versionNumber=${VERSION_NUMBER}&action=${ACTION_TYPE}&autoStart=false&timeOut=${TIMEOUT}"
|
|
||||||
|
|
||||||
local upgrade_response
|
local upgrade_response
|
||||||
upgrade_response=$(http_request "POST" "$upgrade_url" "$upgrade_data" "Target-Node:${NODE_URL}")
|
upgrade_response=$(http_request "POST" "$upgrade_url" "" "Target-Node:${NODE_URL}")
|
||||||
|
|
||||||
local upgrade_success
|
local upgrade_success
|
||||||
upgrade_success=$(echo $upgrade_response | jq -r '.success' 2>/dev/null)
|
upgrade_success=$(echo $upgrade_response | jq -r '.success' 2>/dev/null)
|
||||||
@ -420,19 +421,13 @@ main() {
|
|||||||
ip_status="FAILURE"
|
ip_status="FAILURE"
|
||||||
ip_message="Upgrade failed"
|
ip_message="Upgrade failed"
|
||||||
log_error "升级失败: $upgrade_response"
|
log_error "升级失败: $upgrade_response"
|
||||||
log_warn "尝试回滚..."
|
log_warn "需要回滚,但当前脚本不会自动执行。请由 Agent 与用户确认后,再调用手动回滚入口。"
|
||||||
|
rollback_result="PENDING_AGENT_CONFIRMATION(stopFirst=false)"
|
||||||
# 回滚逻辑
|
|
||||||
local rollback_url="${HOME_BASE_URL}/node-proxy/${AIRPORT_CODE}/api/mcp/version/upgrade/rollback"
|
|
||||||
local rollback_data="airportCode=${AIRPORT_CODE}&targetIp=${ip}&applicationName=${APP_NAME}&moduleName=${MODULE_NAME}&timeOut=${TIMEOUT}"
|
|
||||||
http_request "POST" "$rollback_url" "$rollback_data" "Target-Node:${NODE_URL}" > /dev/null
|
|
||||||
log_warn "已触发回滚"
|
|
||||||
else
|
else
|
||||||
# 4.2: 启动应用
|
# 4.2: 启动应用
|
||||||
log_info "Step 4.2: 启动应用..."
|
log_info "Step 4.2: 启动应用..."
|
||||||
local start_url="${HOME_BASE_URL}/node-proxy/${AIRPORT_CODE}/api/mcp/version/upgrade/start-stop"
|
local start_url="${HOME_BASE_URL}/node-proxy/${AIRPORT_CODE}/api/mcp/version/upgrade/start-stop?airportCode=${AIRPORT_CODE}&targetIp=${ip}&applicationName=${APP_NAME}&moduleName=${MODULE_NAME}&runStart=true"
|
||||||
local start_data="airportCode=${AIRPORT_CODE}&targetIp=${ip}&applicationName=${APP_NAME}&moduleName=${MODULE_NAME}&runstart=true"
|
http_request "POST" "$start_url" "" "Target-Node:${NODE_URL}" > /dev/null
|
||||||
http_request "POST" "$start_url" "$start_data" "Target-Node:${NODE_URL}" > /dev/null
|
|
||||||
|
|
||||||
# 4.3: 健康检测
|
# 4.3: 健康检测
|
||||||
log_info "Step 4.3: 健康检测..."
|
log_info "Step 4.3: 健康检测..."
|
||||||
@ -448,11 +443,9 @@ main() {
|
|||||||
ip_message=$(echo $verify_response | jq -r '.message // "Unknown error"' 2>/dev/null)
|
ip_message=$(echo $verify_response | jq -r '.message // "Unknown error"' 2>/dev/null)
|
||||||
log_error "健康检测失败: ${ip_message} (原始响应: $verify_response)"
|
log_error "健康检测失败: ${ip_message} (原始响应: $verify_response)"
|
||||||
|
|
||||||
# 健康检测失败也可触发回滚(可选)
|
# 健康检测失败时只标记待确认回滚,不自动执行
|
||||||
log_warn "尝试回滚..."
|
log_warn "需要回滚,但当前脚本不会自动执行。请由 Agent 与用户确认后,再调用手动回滚入口。"
|
||||||
local rollback_url="${HOME_BASE_URL}/node-proxy/${AIRPORT_CODE}/api/mcp/version/upgrade/rollback"
|
rollback_result="PENDING_AGENT_CONFIRMATION(stopFirst=true)"
|
||||||
local rollback_data="airportCode=${AIRPORT_CODE}&targetIp=${ip}&applicationName=${APP_NAME}&moduleName=${MODULE_NAME}&timeOut=${TIMEOUT}"
|
|
||||||
http_request "POST" "$rollback_url" "$rollback_data" "Target-Node:${NODE_URL}" > /dev/null
|
|
||||||
else
|
else
|
||||||
log_info "健康检测通过"
|
log_info "健康检测通过"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
param(
|
param(
|
||||||
[string]$ConfigPath = (Join-Path $PSScriptRoot 'config.txt'),
|
[string]$ConfigPath = (Join-Path $PSScriptRoot 'config.txt'),
|
||||||
|
[string]$RollbackIp = '',
|
||||||
|
[switch]$RollbackStopFirst,
|
||||||
[switch]$Help
|
[switch]$Help
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -11,6 +13,7 @@ function Show-DeployUsage {
|
|||||||
@'
|
@'
|
||||||
Usage:
|
Usage:
|
||||||
powershell -File .\deploy.ps1 [-ConfigPath .\config.txt]
|
powershell -File .\deploy.ps1 [-ConfigPath .\config.txt]
|
||||||
|
powershell -File .\deploy.ps1 [-ConfigPath .\config.txt] -RollbackIp 192.168.1.10 [-RollbackStopFirst]
|
||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
- deploy.bat is only a wrapper for this script.
|
- deploy.bat is only a wrapper for this script.
|
||||||
@ -22,6 +25,78 @@ Notes:
|
|||||||
function Write-Info([string]$Message) { Write-Host "[INFO] $Message" }
|
function Write-Info([string]$Message) { Write-Host "[INFO] $Message" }
|
||||||
function Write-WarnLog([string]$Message) { Write-Host "[WARN] $Message" }
|
function Write-WarnLog([string]$Message) { Write-Host "[WARN] $Message" }
|
||||||
function Write-ErrLog([string]$Message) { Write-Host "[ERROR] $Message" }
|
function Write-ErrLog([string]$Message) { Write-Host "[ERROR] $Message" }
|
||||||
|
$script:ActiveConfigPath = $ConfigPath
|
||||||
|
|
||||||
|
function Write-FlowStart([string]$Name, [string]$Detail = '') {
|
||||||
|
if ($Detail) {
|
||||||
|
Write-Info "[FLOW][START] $Name | $Detail"
|
||||||
|
} else {
|
||||||
|
Write-Info "[FLOW][START] $Name"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Write-FlowDone([string]$Name, [string]$Detail = '') {
|
||||||
|
if ($Detail) {
|
||||||
|
Write-Info "[FLOW][DONE] $Name | $Detail"
|
||||||
|
} else {
|
||||||
|
Write-Info "[FLOW][DONE] $Name"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Write-FlowFail([string]$Name, [string]$Detail = '') {
|
||||||
|
if ($Detail) {
|
||||||
|
Write-ErrLog "[FLOW][FAIL] $Name | $Detail"
|
||||||
|
} else {
|
||||||
|
Write-ErrLog "[FLOW][FAIL] $Name"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Invoke-FlowStep {
|
||||||
|
param(
|
||||||
|
[string]$Name,
|
||||||
|
[scriptblock]$Action,
|
||||||
|
[string]$Detail = ''
|
||||||
|
)
|
||||||
|
|
||||||
|
Write-FlowStart -Name $Name -Detail $Detail
|
||||||
|
try {
|
||||||
|
$result = & $Action
|
||||||
|
Write-FlowDone -Name $Name
|
||||||
|
return $result
|
||||||
|
} catch {
|
||||||
|
Write-FlowFail -Name $Name -Detail $_.Exception.Message
|
||||||
|
throw
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-ManualRollbackCommand {
|
||||||
|
param(
|
||||||
|
[string]$Ip,
|
||||||
|
[bool]$StopFirst
|
||||||
|
)
|
||||||
|
|
||||||
|
$command = "powershell -File .\deploy.ps1 -ConfigPath `"$script:ActiveConfigPath`" -RollbackIp `"$Ip`""
|
||||||
|
if ($StopFirst) {
|
||||||
|
$command += ' -RollbackStopFirst'
|
||||||
|
}
|
||||||
|
|
||||||
|
return $command
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-PendingRollbackStatus {
|
||||||
|
param(
|
||||||
|
[string]$Ip,
|
||||||
|
[string]$Stage,
|
||||||
|
[bool]$StopFirst,
|
||||||
|
[string]$Reason
|
||||||
|
)
|
||||||
|
|
||||||
|
$status = "PENDING_AGENT_CONFIRMATION(stopFirst=$($StopFirst.ToString().ToLowerInvariant()))"
|
||||||
|
$command = Get-ManualRollbackCommand -Ip $Ip -StopFirst $StopFirst
|
||||||
|
Write-WarnLog "检测到需要回滚: ip=$Ip stage=$Stage reason=$Reason stopFirst=$StopFirst"
|
||||||
|
Write-WarnLog "当前脚本不会自动执行回滚。请由 Agent 与用户确认后,再执行: $command"
|
||||||
|
return $status
|
||||||
|
}
|
||||||
|
|
||||||
function Convert-ResponseContent {
|
function Convert-ResponseContent {
|
||||||
param([AllowNull()][string]$Content)
|
param([AllowNull()][string]$Content)
|
||||||
@ -411,7 +486,7 @@ function Wait-DownloadProgress {
|
|||||||
applicationName = $Config.APP_NAME
|
applicationName = $Config.APP_NAME
|
||||||
moduleName = $Config.MODULE_NAME
|
moduleName = $Config.MODULE_NAME
|
||||||
airportCode = $Config.AIRPORT_CODE
|
airportCode = $Config.AIRPORT_CODE
|
||||||
versionNumer = $Config.VERSION_NUMBER
|
versionNumber = $Config.VERSION_NUMBER
|
||||||
})
|
})
|
||||||
$progressUrl = "$($Config.HOME_BASE_URL)/node-proxy/$($Config.AIRPORT_CODE)/api/mcp/version/upgrade/download-cloud/progress?$query"
|
$progressUrl = "$($Config.HOME_BASE_URL)/node-proxy/$($Config.AIRPORT_CODE)/api/mcp/version/upgrade/download-cloud/progress?$query"
|
||||||
|
|
||||||
@ -466,7 +541,7 @@ function Download-CloudToNode {
|
|||||||
versionNumber = $Config.VERSION_NUMBER
|
versionNumber = $Config.VERSION_NUMBER
|
||||||
applicationName = $Config.APP_NAME
|
applicationName = $Config.APP_NAME
|
||||||
moduleName = $Config.MODULE_NAME
|
moduleName = $Config.MODULE_NAME
|
||||||
timeOut = $Config.TIMEOUT
|
timeOut = '0'
|
||||||
})
|
})
|
||||||
|
|
||||||
[void](Invoke-PamWebRequest -Method GET -Url "$($Config.HOME_BASE_URL)/node-proxy/$($Config.AIRPORT_CODE)/api/mcp/version/upgrade/download-cloud?$query" -Token $Token -Headers @{
|
[void](Invoke-PamWebRequest -Method GET -Url "$($Config.HOME_BASE_URL)/node-proxy/$($Config.AIRPORT_CODE)/api/mcp/version/upgrade/download-cloud?$query" -Token $Token -Headers @{
|
||||||
@ -480,7 +555,7 @@ function Download-CloudToNode {
|
|||||||
function Invoke-UpgradeRequest {
|
function Invoke-UpgradeRequest {
|
||||||
param($Config, [string]$Token, [string]$NodeUrl, [string]$Ip)
|
param($Config, [string]$Token, [string]$NodeUrl, [string]$Ip)
|
||||||
|
|
||||||
$body = Join-RequestPairs ([ordered]@{
|
$query = Join-RequestPairs ([ordered]@{
|
||||||
airportCode = $Config.AIRPORT_CODE
|
airportCode = $Config.AIRPORT_CODE
|
||||||
targetIp = $Ip
|
targetIp = $Ip
|
||||||
applicationName = $Config.APP_NAME
|
applicationName = $Config.APP_NAME
|
||||||
@ -491,41 +566,41 @@ function Invoke-UpgradeRequest {
|
|||||||
timeOut = $Config.TIMEOUT
|
timeOut = $Config.TIMEOUT
|
||||||
})
|
})
|
||||||
|
|
||||||
Invoke-PamWebRequest -Method POST -Url "$($Config.HOME_BASE_URL)/node-proxy/$($Config.AIRPORT_CODE)/api/mcp/version/upgrade" -Token $Token -Headers @{
|
Invoke-PamWebRequest -Method POST -Url "$($Config.HOME_BASE_URL)/node-proxy/$($Config.AIRPORT_CODE)/api/mcp/version/upgrade?$query" -Token $Token -Headers @{
|
||||||
'Target-Node' = $NodeUrl
|
'Target-Node' = $NodeUrl
|
||||||
} -Body $body -ContentType 'application/x-www-form-urlencoded'
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function Start-Application {
|
function Start-Application {
|
||||||
param($Config, [string]$Token, [string]$NodeUrl, [string]$Ip)
|
param($Config, [string]$Token, [string]$NodeUrl, [string]$Ip)
|
||||||
|
|
||||||
$body = Join-RequestPairs ([ordered]@{
|
$query = Join-RequestPairs ([ordered]@{
|
||||||
airportCode = $Config.AIRPORT_CODE
|
airportCode = $Config.AIRPORT_CODE
|
||||||
targetIp = $Ip
|
targetIp = $Ip
|
||||||
applicationName = $Config.APP_NAME
|
applicationName = $Config.APP_NAME
|
||||||
moduleName = $Config.MODULE_NAME
|
moduleName = $Config.MODULE_NAME
|
||||||
runstart = 'true'
|
runStart = 'true'
|
||||||
})
|
})
|
||||||
|
|
||||||
[void](Invoke-PamWebRequest -Method POST -Url "$($Config.HOME_BASE_URL)/node-proxy/$($Config.AIRPORT_CODE)/api/mcp/version/upgrade/start-stop" -Token $Token -Headers @{
|
[void](Invoke-PamWebRequest -Method POST -Url "$($Config.HOME_BASE_URL)/node-proxy/$($Config.AIRPORT_CODE)/api/mcp/version/upgrade/start-stop?$query" -Token $Token -Headers @{
|
||||||
'Target-Node' = $NodeUrl
|
'Target-Node' = $NodeUrl
|
||||||
} -Body $body -ContentType 'application/x-www-form-urlencoded')
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function Stop-Application {
|
function Stop-Application {
|
||||||
param($Config, [string]$Token, [string]$NodeUrl, [string]$Ip)
|
param($Config, [string]$Token, [string]$NodeUrl, [string]$Ip)
|
||||||
|
|
||||||
$body = Join-RequestPairs ([ordered]@{
|
$query = Join-RequestPairs ([ordered]@{
|
||||||
airportCode = $Config.AIRPORT_CODE
|
airportCode = $Config.AIRPORT_CODE
|
||||||
targetIp = $Ip
|
targetIp = $Ip
|
||||||
applicationName = $Config.APP_NAME
|
applicationName = $Config.APP_NAME
|
||||||
moduleName = $Config.MODULE_NAME
|
moduleName = $Config.MODULE_NAME
|
||||||
runstart = 'false'
|
runStart = 'false'
|
||||||
})
|
})
|
||||||
|
|
||||||
[void](Invoke-PamWebRequest -Method POST -Url "$($Config.HOME_BASE_URL)/node-proxy/$($Config.AIRPORT_CODE)/api/mcp/version/upgrade/start-stop" -Token $Token -Headers @{
|
[void](Invoke-PamWebRequest -Method POST -Url "$($Config.HOME_BASE_URL)/node-proxy/$($Config.AIRPORT_CODE)/api/mcp/version/upgrade/start-stop?$query" -Token $Token -Headers @{
|
||||||
'Target-Node' = $NodeUrl
|
'Target-Node' = $NodeUrl
|
||||||
} -Body $body -ContentType 'application/x-www-form-urlencoded')
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function Verify-Ip {
|
function Verify-Ip {
|
||||||
@ -632,9 +707,13 @@ function Invoke-IpDeploy {
|
|||||||
Write-Info "Processing IP: $Ip"
|
Write-Info "Processing IP: $Ip"
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$upgrade = Invoke-UpgradeRequest -Config $Config -Token $Token -NodeUrl $NodeUrl -Ip $Ip
|
$upgrade = Invoke-FlowStep -Name "Invoke-UpgradeRequest[$Ip]" -Action {
|
||||||
|
Invoke-UpgradeRequest -Config $Config -Token $Token -NodeUrl $NodeUrl -Ip $Ip
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
$logFile = Download-DeployLog -Config $Config -Token $Token -NodeUrl $NodeUrl -Ip $Ip
|
$logFile = Invoke-FlowStep -Name "Download-DeployLog[$Ip]" -Action {
|
||||||
|
Download-DeployLog -Config $Config -Token $Token -NodeUrl $NodeUrl -Ip $Ip
|
||||||
|
}
|
||||||
return [pscustomobject]@{
|
return [pscustomobject]@{
|
||||||
Ip = $Ip
|
Ip = $Ip
|
||||||
Status = 'FAILED'
|
Status = 'FAILED'
|
||||||
@ -646,10 +725,12 @@ function Invoke-IpDeploy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((Get-ResponseValue -Response $upgrade -Candidates @('success')) -ne 'true') {
|
if ((Get-ResponseValue -Response $upgrade -Candidates @('success')) -ne 'true') {
|
||||||
$rollback = Invoke-Rollback -Config $Config -Token $Token -NodeUrl $NodeUrl -Ip $Ip -StopFirst:$false
|
|
||||||
$logFile = Download-DeployLog -Config $Config -Token $Token -NodeUrl $NodeUrl -Ip $Ip
|
|
||||||
$message = Get-ResponseValue -Response $upgrade -Candidates @('message')
|
$message = Get-ResponseValue -Response $upgrade -Candidates @('message')
|
||||||
if (-not $message) { $message = 'Upgrade failed' }
|
if (-not $message) { $message = 'Upgrade failed' }
|
||||||
|
$rollback = Get-PendingRollbackStatus -Ip $Ip -Stage 'UPGRADE' -StopFirst:$false -Reason $message
|
||||||
|
$logFile = Invoke-FlowStep -Name "Download-DeployLog[$Ip]" -Action {
|
||||||
|
Download-DeployLog -Config $Config -Token $Token -NodeUrl $NodeUrl -Ip $Ip
|
||||||
|
}
|
||||||
return [pscustomobject]@{
|
return [pscustomobject]@{
|
||||||
Ip = $Ip
|
Ip = $Ip
|
||||||
Status = 'FAILED'
|
Status = 'FAILED'
|
||||||
@ -661,10 +742,14 @@ function Invoke-IpDeploy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Start-Application -Config $Config -Token $Token -NodeUrl $NodeUrl -Ip $Ip
|
Invoke-FlowStep -Name "Start-Application[$Ip]" -Action {
|
||||||
|
Start-Application -Config $Config -Token $Token -NodeUrl $NodeUrl -Ip $Ip
|
||||||
|
} | Out-Null
|
||||||
} catch {
|
} catch {
|
||||||
$rollback = Invoke-Rollback -Config $Config -Token $Token -NodeUrl $NodeUrl -Ip $Ip -StopFirst:$true
|
$rollback = Get-PendingRollbackStatus -Ip $Ip -Stage 'START' -StopFirst:$true -Reason 'Application start failed'
|
||||||
$logFile = Download-DeployLog -Config $Config -Token $Token -NodeUrl $NodeUrl -Ip $Ip
|
$logFile = Invoke-FlowStep -Name "Download-DeployLog[$Ip]" -Action {
|
||||||
|
Download-DeployLog -Config $Config -Token $Token -NodeUrl $NodeUrl -Ip $Ip
|
||||||
|
}
|
||||||
return [pscustomobject]@{
|
return [pscustomobject]@{
|
||||||
Ip = $Ip
|
Ip = $Ip
|
||||||
Status = 'FAILED'
|
Status = 'FAILED'
|
||||||
@ -676,10 +761,14 @@ function Invoke-IpDeploy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$verify = Verify-Ip -Config $Config -Token $Token -NodeUrl $NodeUrl -Ip $Ip
|
$verify = Invoke-FlowStep -Name "Verify-Ip[$Ip]" -Action {
|
||||||
|
Verify-Ip -Config $Config -Token $Token -NodeUrl $NodeUrl -Ip $Ip
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
$rollback = Invoke-Rollback -Config $Config -Token $Token -NodeUrl $NodeUrl -Ip $Ip -StopFirst:$true
|
$rollback = Get-PendingRollbackStatus -Ip $Ip -Stage 'VERIFY' -StopFirst:$true -Reason 'Health check request failed'
|
||||||
$logFile = Download-DeployLog -Config $Config -Token $Token -NodeUrl $NodeUrl -Ip $Ip
|
$logFile = Invoke-FlowStep -Name "Download-DeployLog[$Ip]" -Action {
|
||||||
|
Download-DeployLog -Config $Config -Token $Token -NodeUrl $NodeUrl -Ip $Ip
|
||||||
|
}
|
||||||
return [pscustomobject]@{
|
return [pscustomobject]@{
|
||||||
Ip = $Ip
|
Ip = $Ip
|
||||||
Status = 'FAILED'
|
Status = 'FAILED'
|
||||||
@ -691,7 +780,9 @@ function Invoke-IpDeploy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((Get-ResponseValue -Response $verify -Candidates @('success')) -eq 'true') {
|
if ((Get-ResponseValue -Response $verify -Candidates @('success')) -eq 'true') {
|
||||||
$logFile = Download-DeployLog -Config $Config -Token $Token -NodeUrl $NodeUrl -Ip $Ip
|
$logFile = Invoke-FlowStep -Name "Download-DeployLog[$Ip]" -Action {
|
||||||
|
Download-DeployLog -Config $Config -Token $Token -NodeUrl $NodeUrl -Ip $Ip
|
||||||
|
}
|
||||||
return [pscustomobject]@{
|
return [pscustomobject]@{
|
||||||
Ip = $Ip
|
Ip = $Ip
|
||||||
Status = 'SUCCESS'
|
Status = 'SUCCESS'
|
||||||
@ -702,10 +793,12 @@ function Invoke-IpDeploy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$rollback = Invoke-Rollback -Config $Config -Token $Token -NodeUrl $NodeUrl -Ip $Ip -StopFirst:$true
|
|
||||||
$logFile = Download-DeployLog -Config $Config -Token $Token -NodeUrl $NodeUrl -Ip $Ip
|
|
||||||
$message = Get-ResponseValue -Response $verify -Candidates @('message')
|
$message = Get-ResponseValue -Response $verify -Candidates @('message')
|
||||||
if (-not $message) { $message = 'Health check failed' }
|
if (-not $message) { $message = 'Health check failed' }
|
||||||
|
$rollback = Get-PendingRollbackStatus -Ip $Ip -Stage 'VERIFY' -StopFirst:$true -Reason $message
|
||||||
|
$logFile = Invoke-FlowStep -Name "Download-DeployLog[$Ip]" -Action {
|
||||||
|
Download-DeployLog -Config $Config -Token $Token -NodeUrl $NodeUrl -Ip $Ip
|
||||||
|
}
|
||||||
return [pscustomobject]@{
|
return [pscustomobject]@{
|
||||||
Ip = $Ip
|
Ip = $Ip
|
||||||
Status = 'FAILED'
|
Status = 'FAILED'
|
||||||
@ -749,18 +842,37 @@ function Write-DeployReport {
|
|||||||
function Invoke-PamDeploy {
|
function Invoke-PamDeploy {
|
||||||
param([string]$ConfigPath)
|
param([string]$ConfigPath)
|
||||||
|
|
||||||
$config = Get-PamConfig -Path $ConfigPath
|
$script:ActiveConfigPath = $ConfigPath
|
||||||
Test-ZipFile -Config $config
|
$config = Invoke-FlowStep -Name 'Get-PamConfig' -Detail "path=$ConfigPath" -Action {
|
||||||
|
Get-PamConfig -Path $ConfigPath
|
||||||
|
}
|
||||||
|
Invoke-FlowStep -Name 'Test-ZipFile' -Action {
|
||||||
|
Test-ZipFile -Config $config
|
||||||
|
} | Out-Null
|
||||||
|
|
||||||
Write-Info "Deploy start: airport=$($config.AIRPORT_CODE), version=$($config.VERSION_NUMBER), module=$($config.APP_NAME)/$($config.MODULE_NAME)"
|
Write-Info "Deploy start: airport=$($config.AIRPORT_CODE), version=$($config.VERSION_NUMBER), module=$($config.APP_NAME)/$($config.MODULE_NAME)"
|
||||||
|
|
||||||
$token = Get-Token -Config $config
|
$token = Invoke-FlowStep -Name 'Get-Token' -Action {
|
||||||
New-VersionRecord -Config $config -Token $token
|
Get-Token -Config $config
|
||||||
$hashCode = Upload-Package -Config $config -Token $token
|
}
|
||||||
Publish-Version -Config $config -Token $token -HashCode $hashCode
|
Invoke-FlowStep -Name 'New-VersionRecord' -Action {
|
||||||
$nodeUrl = Get-NodeUrl -Config $config -Token $token
|
New-VersionRecord -Config $config -Token $token
|
||||||
$ips = Get-OnlineIps -Config $config -Token $token -NodeUrl $nodeUrl
|
} | Out-Null
|
||||||
Download-CloudToNode -Config $config -Token $token -NodeUrl $nodeUrl
|
$hashCode = Invoke-FlowStep -Name 'Upload-Package' -Action {
|
||||||
|
Upload-Package -Config $config -Token $token
|
||||||
|
}
|
||||||
|
Invoke-FlowStep -Name 'Publish-Version' -Action {
|
||||||
|
Publish-Version -Config $config -Token $token -HashCode $hashCode
|
||||||
|
} | Out-Null
|
||||||
|
$nodeUrl = Invoke-FlowStep -Name 'Get-NodeUrl' -Action {
|
||||||
|
Get-NodeUrl -Config $config -Token $token
|
||||||
|
}
|
||||||
|
$ips = Invoke-FlowStep -Name 'Get-OnlineIps' -Action {
|
||||||
|
Get-OnlineIps -Config $config -Token $token -NodeUrl $nodeUrl
|
||||||
|
}
|
||||||
|
Invoke-FlowStep -Name 'Download-CloudToNode' -Action {
|
||||||
|
Download-CloudToNode -Config $config -Token $token -NodeUrl $nodeUrl
|
||||||
|
} | Out-Null
|
||||||
|
|
||||||
$results = [System.Collections.Generic.List[object]]::new()
|
$results = [System.Collections.Generic.List[object]]::new()
|
||||||
foreach ($ip in $ips) {
|
foreach ($ip in $ips) {
|
||||||
@ -770,6 +882,33 @@ function Invoke-PamDeploy {
|
|||||||
Write-DeployReport -Config $config -Results $results -TotalCount $ips.Count
|
Write-DeployReport -Config $config -Results $results -TotalCount $ips.Count
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Invoke-PamManualRollback {
|
||||||
|
param(
|
||||||
|
[string]$ConfigPath,
|
||||||
|
[string]$Ip,
|
||||||
|
[bool]$StopFirst
|
||||||
|
)
|
||||||
|
|
||||||
|
$script:ActiveConfigPath = $ConfigPath
|
||||||
|
$config = Invoke-FlowStep -Name 'Get-PamConfig' -Detail "path=$ConfigPath" -Action {
|
||||||
|
Get-PamConfig -Path $ConfigPath
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Info "Manual rollback start: airport=$($config.AIRPORT_CODE), ip=$Ip, stopFirst=$StopFirst"
|
||||||
|
$token = Invoke-FlowStep -Name 'Get-Token' -Action {
|
||||||
|
Get-Token -Config $config
|
||||||
|
}
|
||||||
|
$nodeUrl = Invoke-FlowStep -Name 'Get-NodeUrl' -Action {
|
||||||
|
Get-NodeUrl -Config $config -Token $token
|
||||||
|
}
|
||||||
|
$result = Invoke-FlowStep -Name "Invoke-Rollback[$Ip]" -Action {
|
||||||
|
Invoke-Rollback -Config $config -Token $token -NodeUrl $nodeUrl -Ip $Ip -StopFirst:$StopFirst
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Info "Manual rollback done: ip=$Ip result=$result"
|
||||||
|
Write-Host "ROLLBACK RESULT: $result"
|
||||||
|
}
|
||||||
|
|
||||||
if ($Help) {
|
if ($Help) {
|
||||||
Show-DeployUsage
|
Show-DeployUsage
|
||||||
exit 0
|
exit 0
|
||||||
@ -777,7 +916,11 @@ if ($Help) {
|
|||||||
|
|
||||||
if ($MyInvocation.InvocationName -ne '.') {
|
if ($MyInvocation.InvocationName -ne '.') {
|
||||||
try {
|
try {
|
||||||
Invoke-PamDeploy -ConfigPath $ConfigPath
|
if ($RollbackIp) {
|
||||||
|
Invoke-PamManualRollback -ConfigPath $ConfigPath -Ip $RollbackIp -StopFirst:$RollbackStopFirst.IsPresent
|
||||||
|
} else {
|
||||||
|
Invoke-PamDeploy -ConfigPath $ConfigPath
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
Write-ErrLog $_
|
Write-ErrLog $_
|
||||||
exit 1
|
exit 1
|
||||||
|
|||||||
@ -6,6 +6,7 @@ set -uo pipefail
|
|||||||
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
DEFAULT_CONFIG_PATH="${SCRIPT_DIR}/config.txt"
|
DEFAULT_CONFIG_PATH="${SCRIPT_DIR}/config.txt"
|
||||||
|
ACTIVE_CONFIG_PATH="$DEFAULT_CONFIG_PATH"
|
||||||
|
|
||||||
TOKEN=""
|
TOKEN=""
|
||||||
HASH_CODE=""
|
HASH_CODE=""
|
||||||
@ -25,6 +26,7 @@ usage() {
|
|||||||
cat <<'EOF'
|
cat <<'EOF'
|
||||||
用法:
|
用法:
|
||||||
./deploy.sh [--config /path/to/config.txt]
|
./deploy.sh [--config /path/to/config.txt]
|
||||||
|
./deploy.sh [--config /path/to/config.txt] --rollback-ip 192.168.1.10 [--rollback-stop-first]
|
||||||
|
|
||||||
配置项:
|
配置项:
|
||||||
HOME_BASE_URL
|
HOME_BASE_URL
|
||||||
@ -45,6 +47,97 @@ log_info() { printf '[INFO] %s\n' "$*"; }
|
|||||||
log_warn() { printf '[WARN] %s\n' "$*"; }
|
log_warn() { printf '[WARN] %s\n' "$*"; }
|
||||||
log_error() { printf '[ERROR] %s\n' "$*" >&2; }
|
log_error() { printf '[ERROR] %s\n' "$*" >&2; }
|
||||||
|
|
||||||
|
log_flow_start() {
|
||||||
|
local name="$1"
|
||||||
|
shift || true
|
||||||
|
if (($#)); then
|
||||||
|
log_info "[FLOW][START] ${name} | $*"
|
||||||
|
else
|
||||||
|
log_info "[FLOW][START] ${name}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
log_flow_done() {
|
||||||
|
local name="$1"
|
||||||
|
shift || true
|
||||||
|
if (($#)); then
|
||||||
|
log_info "[FLOW][DONE] ${name} | $*"
|
||||||
|
else
|
||||||
|
log_info "[FLOW][DONE] ${name}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
log_flow_fail() {
|
||||||
|
local name="$1"
|
||||||
|
shift || true
|
||||||
|
if (($#)); then
|
||||||
|
log_error "[FLOW][FAIL] ${name} | $*"
|
||||||
|
else
|
||||||
|
log_error "[FLOW][FAIL] ${name}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
run_flow_step() {
|
||||||
|
local flow_name="$1"
|
||||||
|
shift
|
||||||
|
|
||||||
|
log_flow_start "$flow_name"
|
||||||
|
if "$@"; then
|
||||||
|
log_flow_done "$flow_name"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local exit_code=$?
|
||||||
|
log_flow_fail "$flow_name" "exit=${exit_code}"
|
||||||
|
return "$exit_code"
|
||||||
|
}
|
||||||
|
|
||||||
|
run_flow_capture() {
|
||||||
|
local __var_name="$1"
|
||||||
|
local flow_name="$2"
|
||||||
|
shift 2
|
||||||
|
|
||||||
|
local output=""
|
||||||
|
log_flow_start "$flow_name"
|
||||||
|
if output="$("$@")"; then
|
||||||
|
printf -v "$__var_name" '%s' "$output"
|
||||||
|
log_flow_done "$flow_name"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local exit_code=$?
|
||||||
|
printf -v "$__var_name" '%s' "$output"
|
||||||
|
local detail="exit=${exit_code}"
|
||||||
|
if [[ -n "$output" ]]; then
|
||||||
|
detail="${detail} output=${output//$'\n'/ }"
|
||||||
|
fi
|
||||||
|
log_flow_fail "$flow_name" "$detail"
|
||||||
|
return "$exit_code"
|
||||||
|
}
|
||||||
|
|
||||||
|
manual_rollback_command() {
|
||||||
|
local ip="$1"
|
||||||
|
local stop_first="$2"
|
||||||
|
local command="./deploy.sh --config \"$ACTIVE_CONFIG_PATH\" --rollback-ip \"$ip\""
|
||||||
|
if [[ "$stop_first" == "true" ]]; then
|
||||||
|
command="${command} --rollback-stop-first"
|
||||||
|
fi
|
||||||
|
printf '%s' "$command"
|
||||||
|
}
|
||||||
|
|
||||||
|
pending_rollback_status() {
|
||||||
|
local ip="$1"
|
||||||
|
local stage="$2"
|
||||||
|
local reason="$3"
|
||||||
|
local stop_first="$4"
|
||||||
|
local command
|
||||||
|
|
||||||
|
command="$(manual_rollback_command "$ip" "$stop_first")"
|
||||||
|
printf '[WARN] 检测到需要回滚: ip=%s, stage=%s, reason=%s, stopFirst=%s\n' "$ip" "$stage" "$reason" "$stop_first" >&2
|
||||||
|
printf '[WARN] 当前脚本不会自动执行回滚。请由 Agent 与用户确认后,再执行: %s\n' "$command" >&2
|
||||||
|
printf 'PENDING_AGENT_CONFIRMATION(stopFirst=%s)' "$stop_first"
|
||||||
|
}
|
||||||
|
|
||||||
timestamp_now() {
|
timestamp_now() {
|
||||||
date '+%Y-%m-%d %H:%M:%S'
|
date '+%Y-%m-%d %H:%M:%S'
|
||||||
}
|
}
|
||||||
@ -730,7 +823,7 @@ poll_download_progress() {
|
|||||||
download_cloud_to_node() {
|
download_cloud_to_node() {
|
||||||
log_info "Step 3.3: 下载软件包到 Node..."
|
log_info "Step 3.3: 下载软件包到 Node..."
|
||||||
http_request "GET" \
|
http_request "GET" \
|
||||||
"${HOME_BASE_URL}/node-proxy/${AIRPORT_CODE}/api/mcp/version/upgrade/download-cloud?versionNumber=${VERSION_NUMBER}&applicationName=${APP_NAME}&moduleName=${MODULE_NAME}&timeOut=${TIMEOUT}" \
|
"${HOME_BASE_URL}/node-proxy/${AIRPORT_CODE}/api/mcp/version/upgrade/download-cloud?versionNumber=${VERSION_NUMBER}&applicationName=${APP_NAME}&moduleName=${MODULE_NAME}&timeOut=0" \
|
||||||
"" \
|
"" \
|
||||||
"" \
|
"" \
|
||||||
"Target-Node: ${NODE_URL}" \
|
"Target-Node: ${NODE_URL}" \
|
||||||
@ -742,27 +835,27 @@ download_cloud_to_node() {
|
|||||||
upgrade_ip() {
|
upgrade_ip() {
|
||||||
local ip="$1"
|
local ip="$1"
|
||||||
http_request "POST" \
|
http_request "POST" \
|
||||||
"${HOME_BASE_URL}/node-proxy/${AIRPORT_CODE}/api/mcp/version/upgrade" \
|
"${HOME_BASE_URL}/node-proxy/${AIRPORT_CODE}/api/mcp/version/upgrade?airportCode=${AIRPORT_CODE}&targetIp=${ip}&applicationName=${APP_NAME}&moduleName=${MODULE_NAME}&versionNumber=${VERSION_NUMBER}&action=${ACTION_TYPE}&autoStart=false&timeOut=${TIMEOUT}" \
|
||||||
"airportCode=${AIRPORT_CODE}&targetIp=${ip}&applicationName=${APP_NAME}&moduleName=${MODULE_NAME}&versionNumber=${VERSION_NUMBER}&action=${ACTION_TYPE}&autoStart=false&timeOut=${TIMEOUT}" \
|
"" \
|
||||||
"application/x-www-form-urlencoded" \
|
"" \
|
||||||
"Target-Node: ${NODE_URL}"
|
"Target-Node: ${NODE_URL}"
|
||||||
}
|
}
|
||||||
|
|
||||||
start_application() {
|
start_application() {
|
||||||
local ip="$1"
|
local ip="$1"
|
||||||
http_request "POST" \
|
http_request "POST" \
|
||||||
"${HOME_BASE_URL}/node-proxy/${AIRPORT_CODE}/api/mcp/version/upgrade/start-stop" \
|
"${HOME_BASE_URL}/node-proxy/${AIRPORT_CODE}/api/mcp/version/upgrade/start-stop?airportCode=${AIRPORT_CODE}&targetIp=${ip}&applicationName=${APP_NAME}&moduleName=${MODULE_NAME}&runStart=true" \
|
||||||
"airportCode=${AIRPORT_CODE}&targetIp=${ip}&applicationName=${APP_NAME}&moduleName=${MODULE_NAME}&runstart=true" \
|
"" \
|
||||||
"application/x-www-form-urlencoded" \
|
"" \
|
||||||
"Target-Node: ${NODE_URL}" >/dev/null
|
"Target-Node: ${NODE_URL}" >/dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
stop_application() {
|
stop_application() {
|
||||||
local ip="$1"
|
local ip="$1"
|
||||||
http_request "POST" \
|
http_request "POST" \
|
||||||
"${HOME_BASE_URL}/node-proxy/${AIRPORT_CODE}/api/mcp/version/upgrade/start-stop" \
|
"${HOME_BASE_URL}/node-proxy/${AIRPORT_CODE}/api/mcp/version/upgrade/start-stop?airportCode=${AIRPORT_CODE}&targetIp=${ip}&applicationName=${APP_NAME}&moduleName=${MODULE_NAME}&runStart=false" \
|
||||||
"airportCode=${AIRPORT_CODE}&targetIp=${ip}&applicationName=${APP_NAME}&moduleName=${MODULE_NAME}&runstart=false" \
|
"" \
|
||||||
"application/x-www-form-urlencoded" \
|
"" \
|
||||||
"Target-Node: ${NODE_URL}" >/dev/null
|
"Target-Node: ${NODE_URL}" >/dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -865,6 +958,28 @@ rollback_ip() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
run_manual_rollback() {
|
||||||
|
local config_path="$1"
|
||||||
|
local ip="$2"
|
||||||
|
local stop_first="$3"
|
||||||
|
local rollback_result=""
|
||||||
|
|
||||||
|
ACTIVE_CONFIG_PATH="$config_path"
|
||||||
|
init_runtime
|
||||||
|
load_config "$config_path"
|
||||||
|
ensure_dependencies
|
||||||
|
|
||||||
|
log_info "PAM 手动回滚开始"
|
||||||
|
log_info "机场: ${AIRPORT_CODE}, 目标IP: ${ip}, stopFirst=${stop_first}"
|
||||||
|
|
||||||
|
run_flow_step "get_token" get_token || return 1
|
||||||
|
run_flow_step "get_node_url" get_node_url || return 1
|
||||||
|
run_flow_capture rollback_result "rollback_ip[${ip}]" rollback_ip "$ip" "$stop_first" || return 1
|
||||||
|
|
||||||
|
log_info "手动回滚完成: ip=${ip}, result=${rollback_result}"
|
||||||
|
printf 'ROLLBACK RESULT: %s\n' "$rollback_result"
|
||||||
|
}
|
||||||
|
|
||||||
add_result() {
|
add_result() {
|
||||||
local ip="$1"
|
local ip="$1"
|
||||||
local status="$2"
|
local status="$2"
|
||||||
@ -892,59 +1007,59 @@ deploy_one_ip() {
|
|||||||
local ip="$1"
|
local ip="$1"
|
||||||
log_info "处理工作站: $ip"
|
log_info "处理工作站: $ip"
|
||||||
|
|
||||||
local upgrade_response
|
local upgrade_response=""
|
||||||
if ! upgrade_response=$(upgrade_ip "$ip"); then
|
if ! run_flow_capture upgrade_response "upgrade_ip[${ip}]" upgrade_ip "$ip"; then
|
||||||
local log_file
|
local log_file=""
|
||||||
log_file="$(download_log "$ip")"
|
run_flow_capture log_file "download_log[${ip}]" download_log "$ip" || true
|
||||||
add_result "$ip" "FAILED" "UPGRADE" "Upgrade request failed" "ROLLBACK_NOT_RUN" "$log_file"
|
add_result "$ip" "FAILED" "UPGRADE" "Upgrade request failed" "ROLLBACK_NOT_RUN" "$log_file"
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$(json_value "$upgrade_response" '.success')" != "true" ]]; then
|
if [[ "$(json_value "$upgrade_response" '.success')" != "true" ]]; then
|
||||||
local rollback_result
|
|
||||||
rollback_result="$(rollback_ip "$ip" "false")"
|
|
||||||
local log_file
|
|
||||||
log_file="$(download_log "$ip")"
|
|
||||||
local message
|
local message
|
||||||
message="$(json_value "$upgrade_response" '.message')"
|
message="$(json_value "$upgrade_response" '.message')"
|
||||||
[[ -z "$message" ]] && message="Upgrade failed"
|
[[ -z "$message" ]] && message="Upgrade failed"
|
||||||
|
local rollback_result
|
||||||
|
rollback_result="$(pending_rollback_status "$ip" "UPGRADE" "$message" "false")"
|
||||||
|
local log_file=""
|
||||||
|
run_flow_capture log_file "download_log[${ip}]" download_log "$ip" || true
|
||||||
add_result "$ip" "FAILED" "UPGRADE" "$message" "$rollback_result" "$log_file"
|
add_result "$ip" "FAILED" "UPGRADE" "$message" "$rollback_result" "$log_file"
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! start_application "$ip"; then
|
if ! run_flow_step "start_application[${ip}]" start_application "$ip"; then
|
||||||
local rollback_result
|
local rollback_result
|
||||||
rollback_result="$(rollback_ip "$ip" "true")"
|
rollback_result="$(pending_rollback_status "$ip" "START" "Application start failed" "true")"
|
||||||
local log_file
|
local log_file=""
|
||||||
log_file="$(download_log "$ip")"
|
run_flow_capture log_file "download_log[${ip}]" download_log "$ip" || true
|
||||||
add_result "$ip" "FAILED" "START" "Application start failed" "$rollback_result" "$log_file"
|
add_result "$ip" "FAILED" "START" "Application start failed" "$rollback_result" "$log_file"
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local verify_response
|
local verify_response=""
|
||||||
if ! verify_response="$(verify_ip "$ip")"; then
|
if ! run_flow_capture verify_response "verify_ip[${ip}]" verify_ip "$ip"; then
|
||||||
local rollback_result
|
local rollback_result
|
||||||
rollback_result="$(rollback_ip "$ip" "true")"
|
rollback_result="$(pending_rollback_status "$ip" "VERIFY" "Health check request failed" "true")"
|
||||||
local log_file
|
local log_file=""
|
||||||
log_file="$(download_log "$ip")"
|
run_flow_capture log_file "download_log[${ip}]" download_log "$ip" || true
|
||||||
add_result "$ip" "FAILED" "VERIFY" "Health check request failed" "$rollback_result" "$log_file"
|
add_result "$ip" "FAILED" "VERIFY" "Health check request failed" "$rollback_result" "$log_file"
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$(json_value "$verify_response" '.success')" == "true" ]]; then
|
if [[ "$(json_value "$verify_response" '.success')" == "true" ]]; then
|
||||||
local log_file
|
local log_file=""
|
||||||
log_file="$(download_log "$ip")"
|
run_flow_capture log_file "download_log[${ip}]" download_log "$ip" || true
|
||||||
add_result "$ip" "SUCCESS" "-" "-" "-" "$log_file"
|
add_result "$ip" "SUCCESS" "-" "-" "-" "$log_file"
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local rollback_result
|
|
||||||
rollback_result="$(rollback_ip "$ip" "true")"
|
|
||||||
local log_file
|
|
||||||
log_file="$(download_log "$ip")"
|
|
||||||
local message
|
local message
|
||||||
message="$(json_value "$verify_response" '.message')"
|
message="$(json_value "$verify_response" '.message')"
|
||||||
[[ -z "$message" ]] && message="Health check failed"
|
[[ -z "$message" ]] && message="Health check failed"
|
||||||
|
local rollback_result
|
||||||
|
rollback_result="$(pending_rollback_status "$ip" "VERIFY" "$message" "true")"
|
||||||
|
local log_file=""
|
||||||
|
run_flow_capture log_file "download_log[${ip}]" download_log "$ip" || true
|
||||||
add_result "$ip" "FAILED" "VERIFY" "$message" "$rollback_result" "$log_file"
|
add_result "$ip" "FAILED" "VERIFY" "$message" "$rollback_result" "$log_file"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -979,6 +1094,8 @@ init_runtime() {
|
|||||||
|
|
||||||
main() {
|
main() {
|
||||||
local config_path="$DEFAULT_CONFIG_PATH"
|
local config_path="$DEFAULT_CONFIG_PATH"
|
||||||
|
local manual_rollback_ip=""
|
||||||
|
local manual_rollback_stop_first="false"
|
||||||
|
|
||||||
while (($#)); do
|
while (($#)); do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
@ -987,6 +1104,15 @@ main() {
|
|||||||
config_path="$2"
|
config_path="$2"
|
||||||
shift 2
|
shift 2
|
||||||
;;
|
;;
|
||||||
|
--rollback-ip)
|
||||||
|
[[ $# -lt 2 ]] && { log_error "--rollback-ip 缺少IP"; exit 1; }
|
||||||
|
manual_rollback_ip="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--rollback-stop-first)
|
||||||
|
manual_rollback_stop_first="true"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
-h|--help)
|
-h|--help)
|
||||||
usage
|
usage
|
||||||
exit 0
|
exit 0
|
||||||
@ -999,6 +1125,12 @@ main() {
|
|||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
|
ACTIVE_CONFIG_PATH="$config_path"
|
||||||
|
if [[ -n "$manual_rollback_ip" ]]; then
|
||||||
|
run_manual_rollback "$config_path" "$manual_rollback_ip" "$manual_rollback_stop_first"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
init_runtime
|
init_runtime
|
||||||
load_config "$config_path"
|
load_config "$config_path"
|
||||||
ensure_dependencies
|
ensure_dependencies
|
||||||
@ -1007,13 +1139,13 @@ main() {
|
|||||||
log_info "PAM 智能部署开始"
|
log_info "PAM 智能部署开始"
|
||||||
log_info "机场: ${AIRPORT_CODE}, 版本: ${VERSION_NUMBER}, 模块: ${APP_NAME}/${MODULE_NAME}"
|
log_info "机场: ${AIRPORT_CODE}, 版本: ${VERSION_NUMBER}, 模块: ${APP_NAME}/${MODULE_NAME}"
|
||||||
|
|
||||||
get_token
|
run_flow_step "get_token" get_token || exit 1
|
||||||
create_version
|
run_flow_step "create_version" create_version || exit 1
|
||||||
upload_package
|
run_flow_step "upload_package" upload_package || exit 1
|
||||||
publish_version
|
run_flow_step "publish_version" publish_version || exit 1
|
||||||
get_node_url
|
run_flow_step "get_node_url" get_node_url || exit 1
|
||||||
get_online_ips
|
run_flow_step "get_online_ips" get_online_ips || exit 1
|
||||||
download_cloud_to_node
|
run_flow_step "download_cloud_to_node" download_cloud_to_node || exit 1
|
||||||
|
|
||||||
for ip in "${ONLINE_IPS[@]}"; do
|
for ip in "${ONLINE_IPS[@]}"; do
|
||||||
deploy_one_ip "$ip"
|
deploy_one_ip "$ip"
|
||||||
|
|||||||
@ -42,9 +42,15 @@
|
|||||||
9. 启动应用
|
9. 启动应用
|
||||||
10. 健康检查
|
10. 健康检查
|
||||||
11. 下载日志
|
11. 下载日志
|
||||||
12. 失败时触发回滚
|
12. 失败时标记回滚待确认,由 Agent 与用户确认后再执行手动回滚
|
||||||
13. 输出最终部署报告
|
13. 输出最终部署报告
|
||||||
|
|
||||||
|
当前接口约定补充:
|
||||||
|
|
||||||
|
- `/api/mcp/version/upgrade` 使用 query 参数,不再使用 body 表单。
|
||||||
|
- `/api/mcp/version/upgrade/start-stop` 使用 query 参数,不再使用 body 表单,且参数名使用 `runStart`。
|
||||||
|
- `download-cloud` 固定传 `timeOut=0`,仅用于创建下载任务;后续进度通过 `download-cloud/progress` 异步查询。
|
||||||
|
|
||||||
### 2.2 测试脚本
|
### 2.2 测试脚本
|
||||||
|
|
||||||
`test_deploy.sh` / `test_deploy.ps1` 当前支持:
|
`test_deploy.sh` / `test_deploy.ps1` 当前支持:
|
||||||
@ -70,6 +76,16 @@
|
|||||||
12. `api/mcp/version/upgrade/log-download`
|
12. `api/mcp/version/upgrade/log-download`
|
||||||
13. `api/mcp/version/upgrade/rollback`
|
13. `api/mcp/version/upgrade/rollback`
|
||||||
|
|
||||||
|
正式部署脚本当前不会自动执行 `rollback`,而是输出待确认状态;需要实际回滚时,应由 Agent 与用户确认后,再调用手动回滚入口:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash ./deploy.sh --config ./config.txt --rollback-ip 192.168.1.10 --rollback-stop-first
|
||||||
|
```
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
powershell -File .\deploy.ps1 -ConfigPath .\config.txt -RollbackIp 192.168.1.10 -RollbackStopFirst
|
||||||
|
```
|
||||||
|
|
||||||
## 3. 当前运行方式
|
## 3. 当前运行方式
|
||||||
|
|
||||||
### 3.1 Windows
|
### 3.1 Windows
|
||||||
@ -231,6 +247,14 @@ bash ./test_deploy.sh --config ./config.txt --mode full --max-ips 1
|
|||||||
|
|
||||||
### 5.1 业务日志
|
### 5.1 业务日志
|
||||||
|
|
||||||
|
正式部署脚本与手动回滚入口当前会输出统一流程日志,例如:
|
||||||
|
|
||||||
|
```text
|
||||||
|
[FLOW][START] Get-Token
|
||||||
|
[FLOW][DONE] Get-Token
|
||||||
|
[FLOW][FAIL] Verify-Ip[192.168.1.10] | ...
|
||||||
|
```
|
||||||
|
|
||||||
测试脚本当前会在控制台边跑边打印:
|
测试脚本当前会在控制台边跑边打印:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user