提交 b24475dc authored 作者: 陈泽健's avatar 陈泽健

docs(deployment): 更新远程自动化部署需求文档并移除相关脚本

- 更新验收要求中的服务启动检查条件,从检查版本信息改为检查"结束数据库调整"日志
- 移除远程自动化部署相关的bash脚本文件
- 移除Python自动化部署脚本和交互式处理脚本
- 移除完整的Python部署自动化类实现代码
- 保留部署需求文档的核心内容和流程说明
上级 29f56822
@echo off
REM Accept SSH host key for remote server
REM Usage: accept_host_key.bat
setlocal enabledelayedexpansion
set SERVER_IP=192.168.5.52
set SSH_PORT=22
set USERNAME=root
set PASSWORD=Ubains@123
echo ========================================
echo Accepting SSH host key for %SERVER_IP%
echo ========================================
REM Use plink to accept host key (will prompt)
echo Please accept the host key when prompted...
echo.
plink.exe -pw %PASSWORD% -P %SSH_PORT% %USERNAME%@%SERVER_IP% echo "Host key accepted"
echo.
echo ========================================
echo Host key acceptance completed
echo ========================================
endlocal
# Complete Acceptance Test Script
$PlinkPath = "E:\GithubData\ubains-module-test\AuxiliaryTool\ScriptTool\RemoteDeploy\plink.exe"
function Invoke-SSH {
param([string]$Command)
$psi = New-Object System.Diagnostics.ProcessStartInfo
$psi.FileName = $PlinkPath
$psi.Arguments = "-pw Ubains@123 -P 22 root@192.168.5.52 $Command"
$psi.UseShellExecute = $false
$psi.RedirectStandardOutput = $true
$psi.RedirectStandardError = $true
$psi.CreateNoWindow = $true
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $psi
$p.Start() | Out-Null
$p.WaitForExit(120000)
return $p.StandardOutput.ReadToEnd()
}
Write-Host "========================================" -ForegroundColor Cyan
Write-Host "Complete Acceptance Test" -ForegroundColor Cyan
Write-Host "Server: 192.168.5.52" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
Write-Host ""
# Test 1: Container Status
Write-Host "Test 1: Container Status Check" -ForegroundColor Yellow
Write-Host "========================================" -ForegroundColor Gray
$containers = Invoke-SSH -Command "docker ps --format 'table {{.Names}}\t{{.Status}}'"
Write-Host $containers
Write-Host ""
# Test 2: External Service Log Check
Write-Host "Test 2: External Service Log (SYSTEMVERSION Check)" -ForegroundColor Yellow
Write-Host "========================================" -ForegroundColor Gray
$extApiLog = Invoke-SSH -Command "tail -100 /data/services/api/java-meeting/java-meeting-extapi/logs/ubains-INFO-AND-ERROR.log"
if ($extApiLog -match "SYSTEMVERSION :: target_api_integration") {
Write-Host "✅ External service log: SYSTEMVERSION found - PASS" -ForegroundColor Green
} else {
Write-Host "⚠️ External service log: SYSTEMVERSION not found - checking again in 10 min..." -ForegroundColor Yellow
Start-Sleep -Seconds 600
$extApiLogRetry = Invoke-SSH -Command "tail -100 /data/services/api/java-meeting/java-meeting-extapi/logs/ubains-INFO-AND-ERROR.log"
if ($extApiLogRetry -match "SYSTEMVERSION") {
Write-Host "✅ External service log: SYSTEMVERSION found (after retry) - PASS" -ForegroundColor Green
} else {
Write-Host "❌ External service log: SYSTEMVERSION not found - FAIL" -ForegroundColor Red
Write-Host "Last log lines:" -ForegroundColor Gray
Write-Host $extApiLogRetry
}
}
Write-Host ""
# Test 3: API Endpoint Tests
Write-Host "Test 3: Service API Endpoint Tests" -ForegroundColor Yellow
Write-Host "========================================" -ForegroundColor Gray
$apiTests = @{
"ExtAPI" = @{URL = "https://192.168.5.52/exapi/message/getMsgPageList"; Expected = "A0076"}
"Meeting" = @{URL = "https://192.168.5.52/meetingV3/api/systemConfiguration/globalConfig?companyNumber=CN-SZ-00-0201"; Expected = "A0078"}
"Monitor" = @{URL = "https://192.168.5.52/monitor/api2/api/servermonitor/"; Expected = "40000014"}
"Voice" = @{URL = "https://192.168.5.52/voice/api/iflytek/roommaster?company_id=1&user_id=8&company_secret=57d00f9f-020f-5f1f-b788-55fae843bceb&getall=1"; Expected = "40000003"}
}
foreach ($api in $apiTests.Keys) {
$test = $apiTests[$api]
Write-Host "Testing $api..." -ForegroundColor Cyan
$result = Invoke-SSH -Command "curl -k '$($test.URL)' 2>/dev/null"
if ($result -match $test.Expected) {
Write-Host "✅ $api: PASS" -ForegroundColor Green
} elseif ($result -match "nginx|Error") {
Write-Host "❌ $api: FAIL (nginx error page)" -ForegroundColor Red
} else {
Write-Host "⚠️ $api: UNKNOWN RESPONSE" -ForegroundColor Yellow
}
}
Write-Host ""
# Test 4: Service Status Summary
Write-Host "Test 4: Service Status Summary" -ForegroundColor Yellow
Write-Host "========================================" -ForegroundColor Gray
$javaProcesses = Invoke-SSH -Command "ps aux | grep java | grep -v grep | wc -l"
$pythonProcesses = Invoke-SSH -Command "ps aux | grep 'python.*uwsgi\|python.*httpd' | grep -v grep | wc -l"
Write-Host "Java processes: $($javaProcesses.Trim())" -ForegroundColor Cyan
Write-Host "Python service processes: $($pythonProcesses.Trim())" -ForegroundColor Cyan
# Check specific services
$services = @(
@{Name = "ExtAPI"; Path = "/data/services/api/java-meeting/java-meeting-extapi"},
@{Name = "InnerAPI"; Path = "/data/services/api/java-meeting/java-meeting2.0"},
@{Name = "Monitor"; Path = "/data/services/api/python-cmdb"},
@{Name = "Voice"; Path = "/data/services/api/python-voice"}
)
foreach ($svc in $services) {
$exists = Invoke-SSH -Command "test -d '$($svc.Path)' && echo 'exists' || echo 'not_found'"
if ($exists -match "exists") {
Write-Host "✅ $($svc.Name): Directory exists" -ForegroundColor Green
} else {
Write-Host "❌ $($svc.Name): Directory not found" -ForegroundColor Red
}
}
Write-Host ""
# Final Summary
Write-Host "========================================" -ForegroundColor Green
Write-Host "Acceptance Test Summary" -ForegroundColor Green
Write-Host "========================================" -ForegroundColor Green
Write-Host ""
Write-Host "Next Steps:" -ForegroundColor Yellow
Write-Host "1. System Authorization: https://192.168.5.52/#/LoginConfig" -ForegroundColor Gray
Write-Host " Verification code: csba" -ForegroundColor Gray
Write-Host " License file: E:\自动化部署\X86-5.52\license.zip" -ForegroundColor Gray
Write-Host ""
Write-Host "2. Create Company Admin: https://192.168.5.52/#/LoginAdmin" -ForegroundColor Gray
Write-Host ""
Write-Host "========================================" -ForegroundColor Green
#!/usr/bin/env expect
# -*- coding: utf-8 -*-
#
# 自动化部署expect脚本
# 用于自动响应部署脚本的交互式提示
# 设置超时时间
set timeout 300
# 服务器信息
set host "192.168.5.52"
set user "root"
set password "Ubains@123"
set deploy_dir "/data/offline_auto_unifiedPlatform"
# 启动SSH连接
spawn ssh $user@$host
expect {
"yes/no" { send "yes\r"; exp_continue }
"password:" { send "$password\r" }
}
# 等待shell准备就绪
expect "#"
send "cd $deploy_dir\r"
# 执行部署脚本
send "./new_auto.sh --all\r"
# 交互式响应
expect {
# 服务器规格不符合提示
"是否继续执行脚本" {
send "y\r"
exp_continue
}
# 确认网口
"确认网口信息是否正确" {
send "\r"
exp_continue
}
# 确认时间
"服务器日期和时间" {
send "\r"
exp_continue
}
"时间不正确" {
send "y\r"
exp_continue
}
# 确认IP
"服务器ip是否正确" {
send "\r"
exp_continue
}
"请输入正确的IP" {
send "192.168.5.52\r"
exp_continue
}
"否" {
send "\r"
exp_continue
}
# 系统部署选择(--all应该跳过)
"确认需部署的系统" {
send "\r"
exp_continue
}
# 部署完成提示
"自动化部署完成" {
send "source /etc/profile\r"
}
# EOF - 脚本结束
eof {
puts "\n部署脚本执行完成"
}
timeout {
puts "\n等待超时,部署可能仍在进行中..."
send "\r"
exp_continue
}
}
# 等待shell返回
expect "#"
send "echo \"Deploy completed\"\r"
expect "#"
send "exit\r"
# 等待expect结束
expect eof
#!/usr/bin/env pwsh
# ============================================================================
# 远程自动化部署脚本 - 新统一平台
# 功能:自动完成新统一平台的完整部署流程
# 作者:自动化运维团队
# 创建时间:2026-05-14
# ============================================================================
#Requires -Version 5.1
<#
.SYNOPSIS
新统一平台远程自动化部署脚本
.DESCRIPTION
本脚本用于自动完成新统一平台的部署,包括:
1. 部署包准备与上传
2. 自动化部署脚本执行
3. 服务状态检查
4. 接口验证测试
5. 部署报告生成
.PARAMETER ServerIP
目标服务器IP地址
.PARAMETER Architecture
服务器架构类型 (X86/ARM)
.EXAMPLE
.\auto_deploy.ps1 -ServerIP "192.168.5.52" -Architecture "X86"
#>
# ============================================================================
# 参数定义
# ============================================================================
param(
[Parameter(Mandatory=$false)]
[string]$ServerIP = "192.168.5.52",
[Parameter(Mandatory=$false)]
[ValidateSet("X86", "ARM")]
[string]$Architecture = "X86",
[Parameter(Mandatory=$false)]
[string]$Username = "root",
[Parameter(Mandatory=$false)]
[string]$Password = "Ubains@123",
[Parameter(Mandatory=$false)]
[int]$SSHPort = 22
)
# ============================================================================
# 脚本初始化
# ============================================================================
# 设置错误处理
$ErrorActionPreference = "Continue"
# 设置控制台输出编码为UTF-8
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$OutputEncoding = [System.Text.Encoding]::UTF8
# 获取脚本根目录
$ScriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path
# 定义目录路径
$PackagesDir = Join-Path $ScriptRoot "packages"
$ReportsDir = Join-Path $ScriptRoot "reports"
$TempDir = Join-Path $ScriptRoot "temp"
# 创建必要的目录结构
$Directories = @($PackagesDir, $ReportsDir, $TempDir)
foreach ($Dir in $Directories) {
if (-not (Test-Path $Dir)) {
New-Item -ItemType Directory -Path $Dir -Force | Out-Null
}
}
# 定义全局变量
$Global:SSHTimeout = 300 # SSH连接超时时间(秒)- 部署需要更长时间
$Global:MaxRetry = 3 # 最大重试次数
$Global:PlinkPath = Join-Path $ScriptRoot "plink.exe"
$Global:PscpPath = Join-Path $ScriptRoot "pscp.exe"
# 定义部署配置
$DeployConfig = @{
X86 = @{
NetworkShare = '\\192.168.9.9\发布版本\03服务器部署\临时使用-新统一平台\X86部署包\全量版'
LicenseFile = '\\192.168.9.9\发布版本\03服务器部署\临时使用-新统一平台\测试授权文件-请勿使用\5.52授权文件\license.zip'
DeployDoc = '\\192.168.9.9\发布版本\03服务器部署\临时使用-新统一平台\X86部署包\新统一平台自动化部署操作指导.docx'
}
ARM = @{
NetworkShare = '\\192.168.9.9\发布版本\03服务器部署\临时使用-新统一平台\ARM部署包-请勿使用'
LicenseFile = '\\192.168.9.9\发布版本\03服务器部署\临时使用-新统一平台\测试授权文件-请勿使用\9.76授权文件\license.zip'
DeployDoc = '\\192.168.9.9\发布版本\03服务器部署\临时使用-新统一平台\ARM部署包-请勿使用\新统一平台自动化部署操作指导.docx'
}
}
# 定义日志路径配置
$LogPaths = @{
ExtAPI = "/data/services/api/java-meeting/java-meeting-extapi/logs/ubains-INFO-AND-ERROR.log"
InnerAPI = "/data/services/api/java-meeting/java-meeting2.0/logs/ubains-INFO-AND-ERROR.log"
Monitor = "/data/services/api/python-cmdb/log/uinfo.log"
Voice = "/data/services/api/python-voice/log/uinfo.log"
}
# 定义接口测试配置
$APITests = @{
ExtAPI = @{
URL = 'https://{0}/exapi/message/getMsgPageList'
Expected = '{"success":false,"code":"A0076","message":"无效token"'
}
Meeting = @{
URL = 'https://{0}/meetingV3/api/systemConfiguration/globalConfig?companyNumber=CN-SZ-00-0201'
Expected = '{"success":false,"code":"A0078","message":"请求错误,accessToken为空"'
}
Monitor = @{
URL = 'https://{0}/monitor/api2/api/servermonitor/'
Expected = '{"success":0,"data":[{"code":40000014,"error":"用户不存在或重新登录或已退出"'
}
Voice = @{
URL = 'https://{0}/voice/api/iflytek/roommaster?company_id=1&user_id=8&company_secret=57d00f9f-020f-5f1f-b788-55fae843bceb&getall=1'
Expected = '{"success":false,"data":[{"code":40000003,"error":"缺少关键参数"'
}
}
# 全局执行记录
$Global:ExecutionLog = @()
$Global:DeployResults = @{}
# ============================================================================
# 日志函数
# ============================================================================
function Write-LogInfo {
param([string]$Message)
$Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$LogMessage = "[$Timestamp] [INFO] $Message"
Write-Host $LogMessage
$Global:ExecutionLog += $LogMessage
}
function Write-LogWarn {
param([string]$Message)
$Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$LogMessage = "[$Timestamp] [WARN] $Message"
Write-Host $LogMessage -ForegroundColor Yellow
$Global:ExecutionLog += $LogMessage
}
function Write-LogError {
param([string]$Message)
$Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$LogMessage = "[$Timestamp] [ERROR] $Message"
Write-Host $LogMessage -ForegroundColor Red
$Global:ExecutionLog += $LogMessage
}
function Write-LogOk {
param([string]$Message)
$Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$LogMessage = "[$Timestamp] [OK] $Message"
Write-Host $LogMessage -ForegroundColor Green
$Global:ExecutionLog += $LogMessage
}
function Write-LogStep {
param([string]$Message)
$Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$LogMessage = "[$Timestamp] [STEP] $Message"
Write-Host $LogMessage -ForegroundColor Cyan
$Global:ExecutionLog += $LogMessage
}
# ============================================================================
# SSH连接函数
# ============================================================================
function Invoke-SSHCommand {
param(
[string]$Command,
[int]$Timeout = $Global:SSHTimeout
)
$PlinkArgs = @(
"-pw", $Password
"-P", $SSHPort
"-timeout", $Timeout
"$($Username)@$($ServerIP)"
$Command
)
try {
$Result = & $Global:PlinkPath $PlinkArgs 2>&1
return @{
Success = $?
Output = $Result -join "`n"
ExitCode = if ($?) { 0 } else { 1 }
}
}
catch {
return @{
Success = $false
Output = $_.Exception.Message
ExitCode = 1
}
}
}
function Test-SSHConnection {
Write-LogStep "步骤1: 测试SSH连接"
Write-LogInfo "正在连接服务器 ${ServerIP}:${SSHPort}..."
for ($i = 1; $i -le $Global:MaxRetry; $i++) {
$Result = Invoke-SSHCommand -Command "echo 'connection_ok'"
if ($Result.Output -match "connection_ok") {
Write-LogOk "连接成功"
$Global:DeployResults.Connection = "成功"
return $true
}
else {
Write-LogWarn "连接失败,正在重试 ($i/$Global:MaxRetry)..."
Start-Sleep -Seconds 2
}
}
Write-LogError "连接失败,已达到最大重试次数"
$Global:DeployResults.Connection = "失败"
return $false
}
# ============================================================================
# 部署包处理函数
# ============================================================================
function Copy-FromNetworkShare {
param(
[string]$NetworkPath,
[string]$Destination
)
Write-LogInfo "正在从网络共享复制: $NetworkPath"
try {
if (Test-Path $NetworkPath) {
Copy-Item -Path $NetworkPath -Destination $Destination -Recurse -Force
Write-LogOk "复制成功"
return $true
}
else {
Write-LogError "网络共享路径不存在: $NetworkPath"
return $false
}
}
catch {
Write-LogError "复制失败: $_"
return $false
}
}
function Upload-DeployPackage {
Write-LogStep "步骤2: 准备并上传部署包"
$Config = $DeployConfig[$Architecture]
$LocalPackageDir = Join-Path $TempDir "deploy_package"
# 清理并创建本地临时目录
if (Test-Path $LocalPackageDir) {
Remove-Item -Path $LocalPackageDir -Recurse -Force
}
New-Item -ItemType Directory -Path $LocalPackageDir -Force | Out-Null
# 从网络共享复制部署包
Write-LogInfo "正在从网络共享复制部署包..."
$CopyResult = Copy-FromNetworkShare -NetworkPath $Config.NetworkShare -Destination $LocalPackageDir
if (-not $CopyResult) {
Write-LogError "部署包复制失败"
$Global:DeployResults.PackageUpload = "失败: 网络共享复制失败"
return $false
}
# 获取部署包文件列表
$PackageFiles = Get-ChildItem -Path $LocalPackageDir -Recurse -File
Write-LogInfo "找到 $($PackageFiles.Count) 个文件"
# 在服务器上创建部署目录
$ServerDeployDir = "/home/deploy"
Write-LogInfo "正在创建服务器部署目录: $ServerDeployDir"
$MkdirResult = Invoke-SSHCommand -Command "mkdir -p $ServerDeployDir && echo 'created'"
if ($MkdirResult.Output -notmatch "created") {
Write-LogError "创建服务器部署目录失败"
$Global:DeployResults.PackageUpload = "失败: 无法创建服务器目录"
return $false
}
# 上传部署包文件
Write-LogInfo "正在上传部署包到服务器..."
$UploadedCount = 0
$FailedFiles = @()
foreach ($File in $PackageFiles) {
$RelativePath = $File.FullName.Substring($LocalPackageDir.Length + 1)
$RemotePath = "$ServerDeployDir/$RelativePath"
$RemoteDir = Split-Path $RemotePath -Parent
# 创建远程目录结构
$CreateDirResult = Invoke-SSHCommand -Command "mkdir -p '$RemoteDir'"
# 上传文件
try {
$PscpArgs = @(
"-pw", $Password
"-P", $SSHPort
"-batch"
$File.FullName
"${Username}@${ServerIP}:$RemotePath"
)
$UploadResult = & $Global:PscpPath $PscpArgs 2>&1
if ($LASTEXITCODE -eq 0) {
$UploadedCount++
if ($UploadedCount % 10 -eq 0) {
Write-LogInfo "已上传 $UploadedCount 个文件..."
}
}
else {
$FailedFiles += $RelativePath
}
}
catch {
$FailedFiles += $RelativePath
}
}
Write-LogInfo "上传完成: 成功 $UploadedCount 个,失败 $($FailedFiles.Count) 个"
if ($FailedFiles.Count -gt 0) {
Write-LogWarn "部分文件上传失败:"
foreach ($FailedFile in $FailedFiles) {
Write-LogWarn " - $FailedFile"
}
}
$Global:DeployResults.PackageUpload = "成功: $UploadedCount 个文件"
Write-LogOk "部署包上传完成"
return $true
}
# ============================================================================
# 部署执行函数
# ============================================================================
function Invoke-DeployScript {
Write-LogStep "步骤3: 执行自动化部署脚本"
$ServerDeployDir = "/home/deploy"
# 查找部署脚本
Write-LogInfo "正在查找部署脚本..."
$FindResult = Invoke-SSHCommand -Command "find $ServerDeployDir -name '*.sh' -type f 2>/dev/null | head -20"
$DeployScripts = $FindResult.Output -split "`n" | Where-Object { $_ -match '\S' }
if ($DeployScripts.Count -eq 0) {
Write-LogError "未找到部署脚本"
Write-LogInfo "服务器上的文件列表:"
$ListResult = Invoke-SSHCommand -Command "ls -la $ServerDeployDir"
Write-Host $ListResult.Output
$Global:DeployResults.DeployExecution = "失败: 未找到部署脚本"
return $false
}
Write-LogInfo "找到以下部署脚本:"
foreach ($Script in $DeployScripts) {
Write-Host " - $Script"
}
# 查找主部署脚本(通常包含 deploy、auto、install 等关键词)
$MainScript = $DeployScripts | Where-Object {
$_ -match '(auto_deploy|deploy|install|setup)' -and $_ -notmatch '\.(bak|backup|old)'
} | Select-Object -First 1
if (-not $MainScript) {
$MainScript = $DeployScripts[0]
}
Write-LogInfo "选择主部署脚本: $MainScript"
# 赋予执行权限
Write-LogInfo "正在设置脚本执行权限..."
$ChmodResult = Invoke-SSHCommand -Command "chmod +x '$MainScript' && echo 'chmod_ok'"
if ($ChmodResult.Output -notmatch "chmod_ok") {
Write-LogWarn "设置执行权限失败,尝试继续执行"
}
# 执行部署脚本
Write-LogWarn "开始执行部署脚本,预计耗时约40分钟..."
Write-LogInfo "部署输出将实时显示..."
# 使用 nohup 在后台执行部署,并记录日志
$LogFile = "/tmp/deploy_$(Get-Date -Format 'yyyyMMdd_HHmmss').log"
$DeployCommand = "cd '$ServerDeployDir' && bash '$MainScript' 2>&1 | tee $LogFile"
Write-LogInfo "执行命令: $DeployCommand"
# 执行部署(使用长超时时间)
$DeployResult = Invoke-SSHCommand -Command $DeployCommand -Timeout 3600
Write-LogInfo "部署脚本执行完成"
Write-Host "`n========== 部署输出 ==========" -ForegroundColor Cyan
Write-Host $DeployResult.Output
Write-Host "========== 部署输出结束 ==========`n" -ForegroundColor Cyan
# 检查部署结果
if ($DeployResult.ExitCode -eq 0) {
Write-LogOk "部署脚本执行成功"
$Global:DeployResults.DeployExecution = "成功"
$Global:DeployResults.DeployLog = $LogFile
return $true
}
else {
Write-LogError "部署脚本执行失败,退出码: $($DeployResult.ExitCode)"
$Global:DeployResults.DeployExecution = "失败: 退出码 $($DeployResult.ExitCode)"
$Global:DeployResults.DeployLog = $LogFile
return $false
}
}
# ============================================================================
# 服务检查函数
# ============================================================================
function Test-ContainerStatus {
Write-LogStep "步骤4: 检查容器状态"
# 检查Docker是否运行
$DockerCheck = Invoke-SSHCommand -Command "docker ps --format 'table {{.Names}}\t{{.Status}}' 2>/dev/null"
if ($DockerCheck.ExitCode -ne 0) {
Write-LogError "Docker未运行或无法访问"
$Global:DeployResults.ContainerStatus = "失败: Docker不可用"
return $false
}
Write-Host "`n========== 容器状态 ==========" -ForegroundColor Cyan
Write-Host $DockerCheck.Output
Write-Host "========== 容器状态结束 ==========`n" -ForegroundColor Cyan
# 检查关键容器
$RequiredContainers = @(
"ujava",
"upython",
"uredis",
"umysql",
"uemqx"
)
$ContainerStatus = @{}
foreach ($Container in $RequiredContainers) {
$CheckResult = Invoke-SSHCommand -Command "docker inspect -f '{{.State.Running}}' $Container 2>/dev/null || echo 'not_found'"
if ($CheckResult.Output -match "true") {
$ContainerStatus[$Container] = "运行中"
Write-LogOk "$Container: 运行中"
}
elseif ($CheckResult.Output -match "false") {
$ContainerStatus[$Container] = "已停止"
Write-LogWarn "$Container: 已停止"
}
else {
$ContainerStatus[$Container] = "不存在"
Write-LogError "$Container: 不存在"
}
}
$Global:DeployResults.ContainerStatus = $ContainerStatus
# 检查是否有异常容器
$FailedContainers = $ContainerStatus.GetEnumerator() | Where-Object { $_.Value -ne "运行中" }
if ($FailedContainers.Count -eq 0) {
Write-LogOk "所有关键容器状态正常"
return $true
}
else {
Write-LogWarn "部分容器状态异常"
return $false
}
}
function Test-ServiceLogs {
Write-LogStep "步骤5: 检查服务日志"
$LogChecks = @{}
# 检查对外服务日志(必须包含版本信息)
Write-LogInfo "检查对外服务日志..."
$ExtAPILog = Invoke-SSHCommand -Command "tail -100 $($LogPaths.ExtAPI) 2>/dev/null || echo 'log_not_found'"
if ($ExtAPILog.Output -match "SYSTEMVERSION :: target_api_integration") {
Write-LogOk "对外服务日志正常(已检测到版本信息)"
$LogChecks.ExtAPI = "正常"
}
elseif ($ExtAPILog.Output -match "log_not_found") {
Write-LogWarn "对外服务日志文件不存在"
$LogChecks.ExtAPI = "日志文件不存在"
}
else {
Write-LogWarn "对外服务日志未检测到版本信息,等待10分钟后重试..."
# 等待10分钟
for ($i = 1; $i -le 10; $i++) {
Write-Host "等待中... ($i/10 分钟)" -ForegroundColor Yellow
Start-Sleep -Seconds 60
}
# 重新检查
$ExtAPILogRetry = Invoke-SSHCommand -Command "tail -100 $($LogPaths.ExtAPI) 2>/dev/null"
if ($ExtAPILogRetry.Output -match "SYSTEMVERSION") {
Write-LogOk "对外服务日志正常(重试后检测到版本信息)"
$LogChecks.ExtAPI = "正常(重试后)"
}
else {
Write-LogError "对外服务日志异常(10分钟后仍未检测到版本信息)"
Write-Host "`n最后100行日志:" -ForegroundColor Yellow
Write-Host $ExtAPILogRetry.Output
$LogChecks.ExtAPI = "异常:无版本信息"
}
}
# 检查其他服务日志是否存在异常
$OtherLogs = @(
@{Name = "对内服务"; Path = $LogPaths.InnerAPI},
@{Name = "运维服务"; Path = $LogPaths.Monitor},
@{Name = "讯飞服务"; Path = $LogPaths.Voice}
)
foreach ($LogInfo in $OtherLogs) {
Write-LogInfo "检查$($LogInfo.Name)日志..."
$LogResult = Invoke-SSHCommand -Command "tail -50 $($LogInfo.Path) 2>/dev/null || echo 'not_found'"
if ($LogResult.Output -match "ERROR|Exception|Failed|failed") {
Write-LogWarn "$($LogInfo.Name)日志中发现异常信息"
$LogChecks[$LogInfo.Name] = "发现异常"
}
elseif ($LogResult.Output -match "not_found") {
Write-LogWarn "$($LogInfo.Name)日志文件不存在"
$LogChecks[$LogInfo.Name] = "日志文件不存在"
}
else {
Write-LogOk "$($LogInfo.Name)日志正常"
$LogChecks[$LogInfo.Name] = "正常"
}
}
$Global:DeployResults.ServiceLogs = $LogChecks
return $true
}
function Test-APIEndpoints {
Write-LogStep "步骤6: 测试服务接口"
$APIResults = @{}
foreach ($APIName in $APITests.Keys) {
$API = $APITests[$APIName]
$URL = $API.URL -f $ServerIP
$Expected = $API.Expected
Write-LogInfo "测试 $APIName 接口..."
# 使用curl测试接口(忽略SSL证书)
$CurlCommand = "curl -k '$URL' 2>/dev/null"
$APIResult = Invoke-SSHCommand -Command $CurlCommand -Timeout 60
# 检查是否返回预期的错误响应(表示服务正常,只是缺少认证)
if ($APIResult.Output -match $Expected.Substring(0, 20)) {
Write-LogOk "$APIName 接口正常(返回预期认证错误)"
$APIResults[$APIName] = "正常"
continue
}
# 检查是否返回nginx错误页面(表示服务未启动)
if ($APIResult.Output -match "An error occurred|nginx") {
Write-LogError "$APIName 接口异常(返回nginx错误页面)"
# 执行重试机制
$RetrySuccess = $false
for ($retry = 1; $retry -le 5; $retry++) {
Write-LogWarn "重试第 $retry 次..."
Start-Sleep -Seconds 30
$RetryResult = Invoke-SSHCommand -Command $CurlCommand -Timeout 60
if ($RetryResult.Output -match $Expected.Substring(0, 20)) {
Write-LogOk "$APIName 接口正常(重试第 $retry 次后成功)"
$APIResults[$APIName] = "正常(重试 $retry 次)"
$RetrySuccess = $true
break
}
}
if (-not $RetrySuccess) {
$APIResults[$APIName] = "异常:5次重试后仍失败"
}
}
else {
# 返回了其他响应,可能是服务问题
Write-LogWarn "$APIName 接口返回未知响应"
Write-Host "响应内容: $($APIResult.Output.Substring(0, 200))"
$APIResults[$APIName] = "未知响应"
}
}
$Global:DeployResults.APITests = $APIResults
# 检查API测试结果
$FailedAPIs = $APIResults.GetEnumerator() | Where-Object { $_.Value -like "*异常*" -or $_.Value -eq "未知响应" }
if ($FailedAPIs.Count -eq 0) {
Write-LogOk "所有接口测试通过"
return $true
}
else {
Write-LogWarn "部分接口测试失败"
return $false
}
}
# ============================================================================
# 系统授权函数
# ============================================================================
function Invoke-SystemAuthorization {
Write-LogStep "步骤7: 系统授权"
Write-LogWarn "系统授权需要访问Web界面完成,请按以下步骤操作:"
Write-Host "`n========================================" -ForegroundColor Cyan
Write-Host "系统授权操作步骤" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
Write-Host "1. 访问维护平台: https://${ServerIP}/#/LoginConfig"
Write-Host "2. 输入验证码: csba"
Write-Host "3. 上传授权文件"
Write-Host " 授权文件路径: $($DeployConfig[$Architecture].LicenseFile)"
Write-Host "4. 完成授权操作"
Write-Host "========================================`n" -ForegroundColor Cyan
$Response = Read-Host "是否已完成系统授权?(y/n)"
if ($Response -eq 'y' -or $Response -eq 'Y') {
Write-LogOk "系统授权已完成"
$Global:DeployResults.Authorization = "已完成"
return $true
}
else {
Write-LogWarn "系统授权未完成"
$Global:DeployResults.Authorization = "未完成"
return $false
}
}
# ============================================================================
# 创建管理员函数
# ============================================================================
function New-CompanyAdmin {
Write-LogStep "步骤8: 创建公司管理员"
Write-LogWarn "创建管理员需要访问Web界面完成,请按以下步骤操作:"
Write-Host "`n========================================" -ForegroundColor Cyan
Write-Host "创建公司管理员操作步骤" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
Write-Host "1. 访问后台地址: https://${ServerIP}/#/LoginAdmin"
Write-Host "2. 按照部署文档第四章创建公司管理员"
Write-Host "3. 完成用户创建操作"
Write-Host "========================================`n" -ForegroundColor Cyan
$Response = Read-Host "是否已创建公司管理员?(y/n)"
if ($Response -eq 'y' -or $Response -eq 'Y') {
Write-LogOk "公司管理员创建完成"
$Global:DeployResults.AdminCreated = "已完成"
return $true
}
else {
Write-LogWarn "公司管理员未创建"
$Global:DeployResults.AdminCreated = "未完成"
return $false
}
}
# ============================================================================
# 生成部署报告
# ============================================================================
function New-DeployReport {
Write-LogStep "步骤9: 生成部署报告"
$Timestamp = Get-Date -Format "yyyy_MM_dd_HHmmss"
$ReportFileName = "${ServerIP}_部署报告_${Timestamp}.md"
$ReportFilePath = Join-Path $ReportsDir $ReportFileName
$ReportContent = @"
# 新统一平台部署报告
## 基本信息
- 服务器IP: $ServerIP
- 架构类型: $Architecture
- 部署时间: $(Get-Date -Format "yyyy-MM-dd HH:mm:ss")
## 部署结果
### 1. SSH连接
- 状态: $($Global:DeployResults.Connection)
### 2. 部署包上传
- 状态: $($Global:DeployResults.PackageUpload)
### 3. 部署执行
- 状态: $($Global:DeployResults.DeployExecution)
$(if ($Global:DeployResults.DeployLog) {
"- 部署日志: $($Global:DeployResults.DeployLog)"
})
### 4. 容器状态
"@
if ($Global:DeployResults.ContainerStatus -is [hashtable]) {
foreach ($Container in $Global:DeployResults.ContainerStatus.Keys) {
$ReportContent += "`n- $Container : $($Global:DeployResults.ContainerStatus[$Container])"
}
}
$ReportContent += @"
### 5. 服务日志
"@
if ($Global:DeployResults.ServiceLogs -is [hashtable]) {
foreach ($Log in $Global:DeployResults.ServiceLogs.Keys) {
$ReportContent += "`n- $Log : $($Global:DeployResults.ServiceLogs[$Log])"
}
}
$ReportContent += @"
### 6. 接口测试
"@
if ($Global:DeployResults.APITests -is [hashtable]) {
foreach ($API in $Global:DeployResults.APITests.Keys) {
$ReportContent += "`n- $API : $($Global:DeployResults.APITests[$API])"
}
}
$ReportContent += @"
### 7. 系统授权
- 状态: $($Global:DeployResults.Authorization)
### 8. 管理员创建
- 状态: $($Global:DeployResults.AdminCreated)
## 系统访问地址
- 前台地址: https://${ServerIP}/
- 维护地址: https://${ServerIP}/#/LoginConfig
- 后台地址: https://${ServerIP}/#/LoginAdmin
## 执行日志
"@
$ReportContent += $Global:ExecutionLog -join "`n"
$ReportContent += @"
---
报告生成时间: $(Get-Date -Format "yyyy-MM-dd HH:mm:ss")
"@
try {
$ReportContent | Out-File -FilePath $ReportFilePath -Encoding UTF8 -Force
Write-LogOk "部署报告已生成: $ReportFilePath"
return $ReportFilePath
}
catch {
Write-LogError "报告生成失败: $_"
return $null
}
}
# ============================================================================
# 主函数
# ============================================================================
function Main {
# 记录开始时间
$StartTime = Get-Date
# 打印欢迎信息
Write-Host "`n========================================" -ForegroundColor Cyan
Write-Host "新统一平台远程自动化部署脚本" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
Write-Host "目标服务器: ${ServerIP} (${Architecture})"
Write-Host "开始时间: $($StartTime.ToString('yyyy-MM-dd HH:mm:ss'))"
Write-Host "========================================`n" -ForegroundColor Cyan
# 初始化部署结果
$Global:DeployResults = @{
Connection = ""
PackageUpload = ""
DeployExecution = ""
ContainerStatus = @{}
ServiceLogs = @{}
APITests = @{}
Authorization = ""
AdminCreated = ""
}
try {
# 步骤1: 测试SSH连接
if (-not (Test-SSHConnection)) {
Write-LogError "SSH连接失败,部署终止"
New-DeployReport
return $false
}
# 步骤2: 上传部署包
if (-not (Upload-DeployPackage)) {
Write-LogError "部署包上传失败,部署终止"
New-DeployReport
return $false
}
# 步骤3: 执行部署脚本
if (-not (Invoke-DeployScript)) {
Write-LogError "部署脚本执行失败,继续检查服务状态..."
}
# 步骤4: 检查容器状态
Test-ContainerStatus
# 步骤5: 检查服务日志
Test-ServiceLogs
# 步骤6: 测试服务接口
Test-APIEndpoints
# 步骤7: 系统授权
Invoke-SystemAuthorization
# 步骤8: 创建管理员
New-CompanyAdmin
# 步骤9: 生成报告
$ReportPath = New-DeployReport
# 打印完成信息
$EndTime = Get-Date
$Duration = $EndTime - $StartTime
Write-Host "`n========================================" -ForegroundColor Green
Write-Host "部署完成" -ForegroundColor Green
Write-Host "========================================" -ForegroundColor Green
Write-Host "结束时间: $($EndTime.ToString('yyyy-MM-dd HH:mm:ss'))"
Write-Host "总耗时: $($Duration.ToString('hh:mm:ss'))"
if ($ReportPath) {
Write-Host "报告位置: $ReportPath"
}
Write-Host "========================================`n" -ForegroundColor Green
return $true
}
catch {
Write-LogError "程序执行出错: $_"
New-DeployReport
return $false
}
}
# 检查plink.exe是否存在
if (-not (Test-Path $Global:PlinkPath)) {
Write-Host "错误: 找不到 plink.exe" -ForegroundColor Red
Write-Host "请从 https://the.earth.li/~sgtatham/putty/latest/w64/plink.exe 下载" -ForegroundColor Yellow
Write-Host "并将 plink.exe 放在脚本同目录下" -ForegroundColor Yellow
exit 1
}
# 执行主函数
Main
#!/bin/bash
# ============================================================================
# Remote Automated Deployment Script - New Unified Platform
# Purpose: Automatically complete the deployment of the new unified platform
# Author: Automation Operations Team
# Created: 2026-05-14
# ============================================================================
# Configuration
SERVER_IP="192.168.5.52"
SSH_PORT="22"
USERNAME="root"
PASSWORD="Ubains@123"
ARCHITECTURE="X86"
# Network share paths (for reference)
DEPLOY_SHARE_X86="\\\\192.168.9.9\\发布版本\\03服务器部署\\临时使用-新统一平台\\X86部署包\\全量版"
LICENSE_SHARE_X86="\\\\192.168.9.9\\发布版本\\03服务器部署\\临时使用-新统一平台\\测试授权文件-请勿使用\\5.52授权文件\\license.zip"
# Script directory
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PACKAGES_DIR="$SCRIPT_DIR/packages"
REPORTS_DIR="$SCRIPT_DIR/reports"
TEMP_DIR="$SCRIPT_DIR/temp"
# SSH tools
PLINK="$SCRIPT_DIR/plink.exe"
PSCP="$SCRIPT_DIR/pscp.exe"
# Create directories
mkdir -p "$PACKAGES_DIR" "$REPORTS_DIR" "$TEMP_DIR"
# Log file
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
LOG_FILE="$REPORTS_DIR/deploy_${TIMESTAMP}.log"
# ============================================================================
# Logging Functions
# ============================================================================
log_info() {
local msg="[$(date '+%Y-%m-%d %H:%M:%S')] [INFO] $1"
echo "$msg" | tee -a "$LOG_FILE"
}
log_warn() {
local msg="[$(date '+%Y-%m-%d %H:%M:%S')] [WARN] $1"
echo "$msg" | tee -a "$LOG_FILE"
}
log_error() {
local msg="[$(date '+%Y-%m-%d %H:%M:%S')] [ERROR] $1"
echo "$msg" | tee -a "$LOG_FILE"
}
log_ok() {
local msg="[$(date '+%Y-%m-%d %H:%M:%S')] [OK] $1"
echo "$msg" | tee -a "$LOG_FILE"
}
log_step() {
local msg="[$(date '+%Y-%m-%d %H:%M:%S')] [STEP] $1"
echo "$msg" | tee -a "$LOG_FILE"
}
# ============================================================================
# SSH Functions
# ============================================================================
ssh_command() {
local cmd="$1"
local timeout="${2:-300}"
"$PLINK" -pw "$PASSWORD" -P "$SSH_PORT" -timeout "$timeout" "${USERNAME}@${SERVER_IP}" "$cmd" 2>&1
return $?
}
test_ssh_connection() {
log_step "Step 1: Testing SSH connection"
log_info "Connecting to server ${SERVER_IP}:${SSH_PORT}..."
for i in {1..3}; do
result=$(ssh_command "echo 'connection_ok'" 30)
if echo "$result" | grep -q "connection_ok"; then
log_ok "Connection successful"
return 0
else
log_warn "Connection failed, retrying ($i/3)..."
sleep 2
fi
done
log_error "Connection failed after 3 attempts"
return 1
}
# ============================================================================
# Deployment Functions
# ============================================================================
upload_deploy_package() {
log_step "Step 2: Upload deployment package"
# Check if deploy package is available locally or on network share
log_warn "Deployment package should be prepared manually"
log_info "Network share path: $DEPLOY_SHARE_X86"
log_info ""
log_info "Please copy the deployment package to: $PACKAGES_DIR"
log_info "Or ensure the package is already on the server at: /home/deploy"
read -p "Press Enter to continue after package is ready..."
# Create deployment directory on server
log_info "Creating deployment directory on server..."
result=$(ssh_command "mkdir -p /home/deploy && echo 'created'")
if echo "$result" | grep -q "created"; then
log_ok "Deployment directory created"
else
log_error "Failed to create deployment directory"
return 1
fi
return 0
}
execute_deploy_script() {
log_step "Step 3: Execute deployment script"
# Find deployment script on server
log_info "Searching for deployment scripts..."
result=$(ssh_command "find /home/deploy -name '*.sh' -type f 2>/dev/null | head -20")
if [ -z "$result" ]; then
log_error "No deployment script found on server"
log_info "Please upload the deployment script manually to /home/deploy"
return 1
fi
log_info "Found deployment scripts:"
echo "$result" | while read -r line; do
echo " - $line"
done
# Find main deployment script
main_script=$(echo "$result" | grep -E "(auto_deploy|deploy|install|setup)" | grep -v -E "\.(bak|backup|old)" | head -1)
if [ -z "$main_script" ]; then
main_script=$(echo "$result" | head -1)
fi
log_info "Selected main script: $main_script"
# Make script executable
log_info "Setting execute permissions..."
ssh_command "chmod +x '$main_script'" > /dev/null
# Execute deployment script
log_warn "Starting deployment script, estimated time: 40 minutes..."
log_info "Deployment output will be displayed..."
# Execute deployment with long timeout
ssh_command "cd /home/deploy && bash '$main_script' 2>&1" 3600 | tee -a "$LOG_FILE"
local exit_code=${PIPESTATUS[0]}
if [ $exit_code -eq 0 ]; then
log_ok "Deployment script executed successfully"
return 0
else
log_error "Deployment script failed with exit code: $exit_code"
return 1
fi
}
check_container_status() {
log_step "Step 4: Check container status"
# Check if Docker is running
result=$(ssh_command "docker ps --format 'table {{.Names}}\t{{.Status}}' 2>/dev/null")
if [ $? -ne 0 ]; then
log_error "Docker is not running or not accessible"
return 1
fi
echo ""
echo "========== Container Status =========="
echo "$result"
echo "========== Container Status End =========="
echo ""
# Check required containers
local required_containers=("ujava" "upython" "uredis" "umysql" "uemqx")
local all_ok=true
for container in "${required_containers[@]}"; do
result=$(ssh_command "docker inspect -f '{{.State.Running}}' $container 2>/dev/null || echo 'not_found'")
if echo "$result" | grep -q "true"; then
log_ok "$container: Running"
elif echo "$result" | grep -q "false"; then
log_warn "$container: Stopped"
all_ok=false
else
log_error "$container: Not found"
all_ok=false
fi
done
if [ "$all_ok" = true ]; then
log_ok "All required containers are running"
return 0
else
log_warn "Some containers are not running properly"
return 1
fi
}
check_service_logs() {
log_step "Step 5: Check service logs"
# Check external API service log
log_info "Checking external API service log..."
result=$(ssh_command "tail -100 /data/services/api/java-meeting/java-meeting-extapi/logs/ubains-INFO-AND-ERROR.log 2>/dev/null || echo 'log_not_found'")
if echo "$result" | grep -q "SYSTEMVERSION.*target_api_integration"; then
log_ok "External API service log is normal (version information detected)"
elif echo "$result" | grep -q "log_not_found"; then
log_warn "External API service log file not found"
else
log_warn "External API service log does not contain version information, waiting 10 minutes to retry..."
# Wait 10 minutes
for i in {1..10}; do
echo "Waiting... ($i/10 minutes)"
sleep 60
done
# Retry check
result=$(ssh_command "tail -100 /data/services/api/java-meeting/java-meeting-extapi/logs/ubains-INFO-AND-ERROR.log 2>/dev/null")
if echo "$result" | grep -q "SYSTEMVERSION"; then
log_ok "External API service log is normal (version information detected after retry)"
else
log_error "External API service log is abnormal (no version information after 10 minutes)"
fi
fi
return 0
}
test_api_endpoints() {
log_step "Step 6: Test service endpoints"
# Define API tests
local apis=(
"ExtAPI|https://${SERVER_IP}/exapi/message/getMsgPageList|A0076"
"Meeting|https://${SERVER_IP}/meetingV3/api/systemConfiguration/globalConfig?companyNumber=CN-SZ-00-0201|A0078"
"Monitor|https://${SERVER_IP}/monitor/api2/api/servermonitor/|40000014"
"Voice|https://${SERVER_IP}/voice/api/iflytek/roommaster?company_id=1&user_id=8&company_secret=57d00f9f-020f-5f1f-b788-55fae843bceb&getall=1|40000003"
)
local all_ok=true
for api_test in "${apis[@]}"; do
IFS='|' read -r api_name url expected <<< "$api_test"
log_info "Testing $api_name endpoint..."
# Use curl to test endpoint (ignore SSL certificate)
result=$(ssh_command "curl -k '$url' 2>/dev/null" 60)
if echo "$result" | grep -q "$expected"; then
log_ok "$api_name endpoint is normal (returns expected authentication error)"
elif echo "$result" | grep -q "An error occurred\|nginx"; then
log_error "$api_name endpoint is abnormal (returns nginx error page)"
# Retry mechanism
local retry_success=false
for retry in {1..5}; do
log_warn "Retry $retry..."
sleep 30
result=$(ssh_command "curl -k '$url' 2>/dev/null" 60)
if echo "$result" | grep -q "$expected"; then
log_ok "$api_name endpoint is normal (successful after retry $retry)"
retry_success=true
break
fi
done
if [ "$retry_success" = false ]; then
all_ok=false
fi
else
log_warn "$api_name endpoint returned unknown response"
fi
done
if [ "$all_ok" = true ]; then
log_ok "All API endpoints tested successfully"
return 0
else
log_warn "Some API endpoints failed testing"
return 1
fi
}
system_authorization() {
log_step "Step 7: System Authorization"
echo ""
echo "========================================"
echo "System Authorization Steps"
echo "========================================"
echo "1. Visit maintenance platform: https://${SERVER_IP}/#/LoginConfig"
echo "2. Enter verification code: csba"
echo "3. Upload license file"
echo " License file path: $LICENSE_SHARE_X86"
echo "4. Complete authorization"
echo "========================================"
echo ""
read -p "Have you completed the system authorization? (y/n) " response
if [ "$response" = "y" ] || [ "$response" = "Y" ]; then
log_ok "System authorization completed"
return 0
else
log_warn "System authorization not completed"
return 1
fi
}
create_company_admin() {
log_step "Step 8: Create Company Administrator"
echo ""
echo "========================================"
echo "Create Company Administrator Steps"
echo "========================================"
echo "1. Visit backend address: https://${SERVER_IP}/#/LoginAdmin"
echo "2. Follow deployment documentation Chapter 4 to create company administrator"
echo "3. Complete user creation"
echo "========================================"
echo ""
read -p "Have you created the company administrator? (y/n) " response
if [ "$response" = "y" ] || [ "$response" = "Y" ]; then
log_ok "Company administrator created"
return 0
else
log_warn "Company administrator not created"
return 1
fi
}
generate_report() {
log_step "Step 9: Generate deployment report"
local report_file="$REPORTS_DIR/${SERVER_IP}_deployment_report_${TIMESTAMP}.md"
cat > "$report_file" << EOF
# New Unified Platform Deployment Report
## Basic Information
- Server IP: $SERVER_IP
- Architecture: $ARCHITECTURE
- Deployment Time: $(date '+%Y-%m-%d %H:%M:%S')
## System Access Addresses
- Frontend Address: https://${SERVER_IP}/
- Maintenance Address: https://${SERVER_IP}/#/LoginConfig
- Backend Address: https://${SERVER_IP}/#/LoginAdmin
---
Report Generated Time: $(date '+%Y-%m-%d %H:%M:%S')
EOF
log_ok "Deployment report generated: $report_file"
echo ""
echo "Report location: $report_file"
return 0
}
# ============================================================================
# Main Function
# ============================================================================
main() {
local start_time=$(date +%s)
echo ""
echo "========================================"
echo "New Unified Platform Remote Automated Deployment Script"
echo "========================================"
echo "Target Server: ${SERVER_IP} (${ARCHITECTURE})"
echo "Start Time: $(date '+%Y-%m-%d %H:%M:%S')"
echo "========================================"
echo ""
local deploy_success=true
# Step 1: Test SSH connection
if ! test_ssh_connection; then
log_error "SSH connection failed, deployment terminated"
generate_report
return 1
fi
# Step 2: Upload deployment package
if ! upload_deploy_package; then
log_error "Deployment package preparation failed, continuing with deployment..."
fi
# Step 3: Execute deployment script
if ! execute_deploy_script; then
log_error "Deployment script execution failed, continuing with service checks..."
fi
# Step 4: Check container status
check_container_status
# Step 5: Check service logs
check_service_logs
# Step 6: Test API endpoints
test_api_endpoints
# Step 7: System authorization
system_authorization
# Step 8: Create company administrator
create_company_admin
# Step 9: Generate report
generate_report
# Print completion message
local end_time=$(date +%s)
local duration=$((end_time - start_time))
local hours=$((duration / 3600))
local minutes=$(((duration % 3600) / 60))
local seconds=$((duration % 60))
echo ""
echo "========================================"
echo "Deployment Completed"
echo "========================================"
echo "End Time: $(date '+%Y-%m-%d %H:%M:%S')"
printf "Total Duration: %02d:%02d:%02d\n" $hours $minutes $seconds
echo "========================================"
echo ""
return 0
}
# Check if plink.exe exists
if [ ! -f "$PLINK" ]; then
echo "Error: plink.exe not found"
echo "Please download from: https://the.earth.li/~sgtatham/putty/latest/w64/plink.exe"
echo "And place plink.exe in the script directory"
exit 1
fi
# Execute main function
main
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
自动处理部署脚本的交互式提示
"""
import sys
import os
import time
import subprocess
from datetime import datetime
def run_deployment_auto():
"""使用plink和yes命令自动运行部署"""
print("=" * 60)
print("自动处理交互式提示的部署脚本")
print("=" * 60)
print(f"开始时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print()
plink_path = r"E:\GithubData\ubains-module-test\AuxiliaryTool\ScriptTool\RemoteDeploy\plink.exe"
# 首先检查并终止现有进程
print("1. 检查并清理现有进程...")
check_cmd = [plink_path, "-pw", "Ubains@123", "-P", "22",
"root@192.168.5.52", "pkill -9 -f new_auto.sh; sleep 2"]
result = subprocess.run(check_cmd, capture_output=True, text=True,
creationflags=subprocess.CREATE_NO_WINDOW)
print(" 已清理现有进程")
# 创建部署命令脚本
print("2. 准备部署命令...")
# 使用yes命令自动响应y/n提示,然后进入部署目录并运行脚本
deploy_commands = """
cd /data/offline_auto_unifiedPlatform
# 使用yes命令自动响应所有的y/n提示
yes y | ./new_auto.sh
"""
# 运行部署
print("3. 开始部署(使用yes命令自动响应所有提示)...")
print(" 这将需要大约40分钟时间...")
print()
deploy_cmd = [plink_path, "-pw", "Ubains@123", "-P", "22",
"root@192.168.5.52", deploy_commands]
# 启动部署进程
process = subprocess.Popen(deploy_cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
creationflags=subprocess.CREATE_NO_WINDOW)
# 监控部署过程
start_time = time.time()
max_time = 2400 # 40分钟
last_output = ""
output_count = 0
print("开始监控部署过程...")
print("-" * 60)
while time.time() - start_time < max_time:
try:
# 检查进程状态
if process.poll() is not None:
print("\n[完成] 部署进程已结束")
break
# 读取输出
try:
# 非阻塞读取
import msvcrt
if msvcrt.kbhit():
# 用户按了键,可以提前退出
if msvcrt.getch() == b'q':
print("\n用户取消部署")
process.terminate()
break
except:
pass
# 每60秒输出一次进度
elapsed = int(time.time() - start_time)
if elapsed % 60 == 0 and elapsed > 0 and elapsed != output_count:
output_count = elapsed
print(f"[进度] 部署进行中... 已用时: {int(elapsed/60)}分钟")
# 检查容器状态
check_cmd = [plink_path, "-pw", "Ubains@123", "-P", "22",
"root@192.168.5.52", "docker ps | wc -l"]
try:
check_result = subprocess.run(check_cmd, capture_output=True,
text=True, timeout=10,
creationflags=subprocess.CREATE_NO_WINDOW)
container_count = check_result.stdout.strip()
if container_count and int(container_count) > 1:
print(f"[容器] 已启动 {int(container_count)-1} 个容器")
except:
pass
time.sleep(10)
except KeyboardInterrupt:
print("\n用户中断部署")
process.terminate()
break
except Exception as e:
print(f"[WARN] 监控出错: {str(e)}")
time.sleep(10)
# 获取最终输出
print()
print("=" * 60)
print("部署完成检查")
print("=" * 60)
# 检查容器状态
final_check = [plink_path, "-pw", "Ubains@123", "-P", "22",
"root@192.168.5.52",
"docker ps --format 'table {{.Names}}\t{{.Status}}'"]
try:
final_result = subprocess.run(final_check, capture_output=True,
text=True, timeout=30,
creationflags=subprocess.CREATE_NO_WINDOW)
print("\n最终容器状态:")
print(final_result.stdout)
container_count = final_result.stdout.strip().count('\n') - 1
print(f"\n运行中的容器数量: {container_count}")
if container_count >= 5:
print("\n[SUCCESS] 部署成功完成!")
print("\n后续步骤:")
print("1. 系统授权: https://192.168.5.52/#/LoginConfig")
print(" 账号: superadmin / Ubains@1357")
print(" 验证码: csba")
print("\n2. 创建管理员: 为'自动化'公司创建admin用户")
return 0
else:
print("\n[WARN] 部署可能未完全完成")
return 1
except Exception as e:
print(f"\n[ERROR] 最终检查失败: {str(e)}")
return 1
if __name__ == '__main__':
try:
sys.exit(run_deployment_auto())
except Exception as e:
print(f"[ERROR] 部署失败: {str(e)}")
import traceback
traceback.print_exc()
sys.exit(1)
# Simple Remote Deployment Script using Windows OpenSSH
# Author: Automation Team
# Date: 2026-05-14
param(
[string]$ServerIP = "192.168.5.52",
[string]$Username = "root",
[string]$Password = "Ubains@123",
[int]$SSHPort = 22
)
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$ReportsDir = Join-Path $ScriptDir "reports"
$LogFile = Join-Path $ReportsDir "deploy_$(Get-Date -Format 'yyyyMMdd_HHmmss').log"
# Create reports directory
if (-not (Test-Path $ReportsDir)) {
New-Item -ItemType Directory -Path $ReportsDir -Force | Out-Null
}
# Logging function
function Write-Log {
param([string]$Message, [string]$Level = "INFO")
$Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$LogMessage = "[$Timestamp] [$Level] $Message"
Write-Host $LogMessage
Add-Content -Path $LogFile -Value $LogMessage
}
# SSH command function using plink with host key auto-accept
function Invoke-SSHCommand {
param([string]$Command, [int]$Timeout = 300)
$PlinkPath = Join-Path $ScriptDir "plink.exe"
# Create temporary plink session to accept host key
$Args = @(
"-pw", $Password,
"-P", $SSHPort,
"-hostkey",
'*',
"$Username@$ServerIP",
$Command
)
$Output = & $PlinkPath $Args 2>&1
return $Output
}
Write-Log "========================================"
Write-Log "New Unified Platform Deployment Script"
Write-Log "Target Server: ${ServerIP}"
Write-Log "========================================"
# Test SSH connection
Write-Log "Testing SSH connection..."
$TestResult = Invoke-SSHCommand -Command "echo 'connection_ok'"
if ($TestResult -match "connection_ok") {
Write-Log "SSH connection successful" "OK"
# Get server information
Write-Log "Getting server information..."
$SystemInfo = Invoke-SSHCommand -Command "uname -a"
Write-Log "Server OS: $SystemInfo"
# Check if /data/services exists (new platform)
$PlatformCheck = Invoke-SSHCommand -Command "test -d /data/services && echo 'new' || echo 'old'"
Write-Log "Platform type: $PlatformCheck"
# Check Docker status
Write-Log "Checking Docker status..."
$DockerCheck = Invoke-SSHCommand -Command "docker ps --format 'table {{.Names}}\t{{.Status}}' 2>&1"
if ($LASTEXITCODE -eq 0) {
Write-Log "Docker is running"
Write-Host "`n========== Container Status =========="
Write-Host $DockerCheck
Write-Host "========== Container Status End ==========`n"
} else {
Write-Log "Docker is not running or not accessible" "WARN"
}
} else {
Write-Log "SSH connection failed" "ERROR"
Write-Log "Error: $TestResult" "ERROR"
Write-Log ""
Write-Log "Please ensure:" "INFO"
Write-Log "1. Server IP is correct: $ServerIP" "INFO"
Write-Log "2. SSH port is open: $SSHPort" "INFO"
Write-Log "3. Username and password are correct" "INFO"
Write-Log "4. Server is reachable from this machine" "INFO"
}
Write-Log "========================================"
Write-Log "Deployment script completed"
Write-Log "Log file: $LogFile"
Write-Log "========================================"
# Remote Deployment Script using Windows OpenSSH
# Author: Automation Team
# Date: 2026-05-14
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$ReportsDir = Join-Path $ScriptDir "reports"
if (-not (Test-Path $ReportsDir)) {
New-Item -ItemType Directory -Path $ReportsDir -Force | Out-Null
}
$LogFile = Join-Path $ReportsDir "deploy_$(Get-Date -Format 'yyyyMMdd_HHmmss').log"
function Write-Log {
param([string]$Message, [string]$Color = "White")
$Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$LogMessage = "[$Timestamp] $Message"
Write-Host $LogMessage -ForegroundColor $Color
Add-Content -Path $LogFile -Value $LogMessage
}
Write-Log "========================================" "Cyan"
Write-Log "New Unified Platform Deployment Script" "Cyan"
Write-Log "========================================" "Cyan"
# Configuration
$ServerIP = "192.168.5.52"
$Username = "root"
$Password = "Ubains@123"
$SSHPort = 22
# Use plink.exe
$PlinkPath = Join-Path $ScriptDir "plink.exe"
Write-Log "Target Server: ${ServerIP}:${SSHPort}"
Write-Log ""
# Step 1: Accept host key
Write-Log "Step 1: Establishing SSH connection (accepting host key)..." "Yellow"
# Create a process to start plink and automatically answer 'y' to host key prompt
$StartInfo = New-Object System.Diagnostics.ProcessStartInfo
$StartInfo.FileName = $PlinkPath
$StartInfo.Arguments = "-pw $Password -P $SSHPort $Username@${ServerIP} echo 'connection_ok'"
$StartInfo.UseShellExecute = $false
$StartInfo.RedirectStandardInput = $true
$StartInfo.RedirectStandardOutput = $true
$StartInfo.RedirectStandardError = $true
$StartInfo.CreateNoWindow = $true
$Process = New-Object System.Diagnostics.Process
$Process.StartInfo = $StartInfo
$Process.Start() | Out-Null
# Automatically answer 'y' to any prompts
$Process.StandardInput.WriteLine("y")
$Process.StandardInput.Close()
# Wait for process to complete
$Process.WaitForExit(30000)
$Output = $Process.StandardOutput.ReadToEnd()
$Error = $Process.StandardError.ReadToEnd()
if ($Output -match "connection_ok") {
Write-Log "SSH connection established successfully!" "Green"
# Step 2: Get server information
Write-Log ""
Write-Log "Step 2: Getting server information..." "Cyan"
$StartInfo.Arguments = "-pw $Password -P $SSHPort $Username@${ServerIP} uname -a"
$Process2 = New-Object System.Diagnostics.Process
$Process2.StartInfo = $StartInfo
$Process2.Start() | Out-Null
$Process2.WaitForExit(30000)
$ServerInfo = $Process2.StandardOutput.ReadToEnd()
Write-Log "Server OS: $ServerInfo" "Green"
# Step 3: Check Docker status
Write-Log ""
Write-Log "Step 3: Checking Docker status..." "Cyan"
$StartInfo.Arguments = "-pw $Password -P $SSHPort $Username@${ServerIP} docker ps --format 'table {{.Names}}\t{{.Status}}'"
$Process3 = New-Object System.Diagnostics.Process
$Process3.StartInfo = $StartInfo
$Process3.Start() | Out-Null
$Process3.WaitForExit(30000)
$DockerOutput = $Process3.StandardOutput.ReadToEnd()
if ($DockerOutput) {
Write-Log "Docker is running" "Green"
Write-Host ""
Write-Host "========== Container Status ==========" -ForegroundColor Cyan
Write-Host $DockerOutput
Write-Host "========== Container Status End ==========" -ForegroundColor Cyan
Write-Host ""
} else {
Write-Log "Docker is not running or not accessible" "Yellow"
}
Write-Log ""
Write-Log "========================================" "Green"
Write-Log "Connection test completed successfully!" "Green"
Write-Log "========================================" "Green"
} else {
Write-Log "SSH connection failed" "Red"
Write-Log "Error: $Error" "Red"
Write-Log ""
Write-Log "Possible reasons:" "Yellow"
Write-Log "1. Server IP is incorrect" "Yellow"
Write-Log "2. SSH port is closed" "Yellow"
Write-Log "3. Username or password is incorrect" "Yellow"
Write-Log "4. Server is not reachable" "Yellow"
}
Write-Log ""
Write-Log "Log file: $LogFile"
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
远程自动化部署脚本 - 完整流程
支持SSH交互式部署、Web界面授权和用户创建
"""
import time
import os
import sys
from datetime import datetime
import traceback
# SSH和交互处理
import paramiko
import threading
import time
# Web自动化
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.options import Options as ChromeOptions
from selenium.webdriver.common.keys import Keys
# HTTP请求
import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning
# 禁用SSL警告
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
class RemoteDeploymentAutomation:
"""远程自动化部署类"""
def __init__(self, host, username, password, license_path):
self.host = host
self.username = username
self.password = password
self.license_path = license_path
self.ssh_client = None
self.ssh_shell = None
self.driver = None
self.log_prefix = f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}]"
def log(self, message, level="INFO"):
"""日志输出"""
prefix = {"INFO": "[OK]", "ERROR": "[ERROR]", "WARN": "[WARN]", "DEBUG": "[DEBUG]"}
try:
print(f"{self.log_prefix} {prefix.get(level, '[INFO]')} {message}")
except UnicodeEncodeError:
# 处理编码错误,使用ASCII安全输出
safe_message = message.encode('gbk', errors='ignore').decode('gbk')
print(f"{self.log_prefix} {prefix.get(level, '[INFO]')} {safe_message}")
def connect_ssh(self):
"""连接SSH(使用paramiko)"""
try:
self.log(f"连接SSH服务器: {self.username}@{self.host}")
self.ssh_client = paramiko.SSHClient()
self.ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
self.ssh_client.connect(self.host, username=self.username, password=self.password, timeout=30)
self.log("SSH连接成功")
return True
except Exception as e:
self.log(f"SSH连接失败: {str(e)}", "ERROR")
return False
def connect_ssh_interactive(self):
"""连接SSH交互式会话(使用paramiko的invoke_shell)"""
try:
# 确保SSH客户端已连接
if not self.ssh_client or not self.ssh_client.get_transport() or not self.ssh_client.get_transport().is_active():
self.log("SSH客户端未连接,先建立连接", "WARN")
if not self.connect_ssh():
return False
self.log(f"创建SSH交互式会话: {self.username}@{self.host}")
self.ssh_shell = self.ssh_client.invoke_shell()
time.sleep(1)
# 等待shell就绪
output = ""
while True:
try:
chunk = self.ssh_shell.recv(1024).decode('utf-8', errors='ignore')
if not chunk:
break
output += chunk
if '#' in output or '$' in output:
break
except:
break
self.log("SSH交互式会话创建成功")
return True
except Exception as e:
self.log(f"SSH交互式连接失败: {str(e)}", "ERROR")
return False
def run_deployment_script_interactive(self):
"""运行部署脚本(处理whiptail交互式菜单)"""
try:
self.log("开始执行部署脚本(交互式)")
# 确保shell连接可用
if not self.ssh_shell:
if not self.connect_ssh_interactive():
return False
# 切换到部署目录
self.log("切换到部署目录...")
self.ssh_shell.send("cd /data/offline_auto_unifiedPlatform\n")
time.sleep(2)
# 清空缓冲区
try:
while self.ssh_shell.recv_ready():
self.ssh_shell.recv(1024)
except:
pass
# 运行部署脚本
self.log("启动部署脚本...")
self.ssh_shell.send("./new_auto.sh\n")
time.sleep(3)
# 等待菜单出现并选择"全部系统"
self.log("等待部署菜单...")
self.log("提示: 如果出现whiptail菜单,请手动选择'全部系统'选项")
self.log(" 通常按Enter键选择默认选项或按空格键选中后按Enter确认")
# 等待菜单出现(最长等待10分钟)
max_wait = 600
start_time = time.time()
menu_detected = False
output_buffer = ""
while time.time() - start_time < max_wait:
try:
if self.ssh_shell.recv_ready():
chunk = self.ssh_shell.recv(4096).decode('utf-8', errors='ignore')
output_buffer += chunk
# 检测whiptail菜单
if 'whiptail' in output_buffer or '选择系统' in output_buffer or '全部系统' in output_buffer:
if not menu_detected:
self.log("检测到部署菜单")
menu_detected = True
# 尝试自动选择"全部系统"
self.log("尝试自动选择'全部系统'(发送回车)")
self.ssh_shell.send("\n")
time.sleep(2)
# 检测是否开始部署
if '开始部署' in output_buffer or '正在部署' in output_buffer or 'deploying' in output_buffer.lower():
self.log("检测到部署开始,菜单选择成功")
break
time.sleep(1)
# 每30秒输出一次等待状态
elapsed = int(time.time() - start_time)
if elapsed % 30 == 0 and elapsed > 0:
self.log(f"等待菜单中... 已等待: {elapsed}秒")
except Exception as e:
self.log(f"读取输出时出错: {str(e)}", "WARN")
time.sleep(1)
if not menu_detected:
self.log("未检测到明确菜单,可能脚本直接开始执行", "WARN")
# 等待部署完成(最长40分钟)
self.log("等待部署完成(预计40分钟)...")
self.log("监控部署进度...")
deployment_start = time.time()
max_deployment_time = 2400 # 40分钟
last_output = ""
while time.time() - deployment_start < max_deployment_time:
try:
if self.ssh_shell.recv_ready():
chunk = self.ssh_shell.recv(4096).decode('utf-8', errors='ignore')
last_output += chunk
# 检查部署完成标志
if '部署完成' in last_output or '部署成功' in last_output or 'deployment completed' in last_output.lower():
self.log("检测到部署完成标志")
break
# 检查错误
if 'error' in last_output.lower() and 'fatal' in last_output.lower():
self.log(f"检测到严重错误: {last_output[-500:]}", "ERROR")
# 每60秒输出一次进度
elapsed = int(time.time() - deployment_start)
if elapsed % 60 == 0 and elapsed > 0:
self.log(f"部署进行中... 已用时: {int(elapsed/60)}分钟/{int(max_deployment_time/60)}分钟")
time.sleep(5)
except Exception as e:
self.log(f"监控部署时出错: {str(e)}", "WARN")
time.sleep(5)
# 检查部署结果
self.log("检查容器状态...")
self.ssh_shell.send("docker ps --format 'table {{.Names}}\t{{.Status}}'\n")
time.sleep(3)
docker_output = ""
try:
while self.ssh_shell.recv_ready():
docker_output += self.ssh_shell.recv(4096).decode('utf-8', errors='ignore')
except:
pass
self.log(f"容器状态:\n{docker_output}")
return True
except Exception as e:
self.log(f"部署脚本执行失败: {str(e)}", "ERROR")
self.log(traceback.format_exc(), "DEBUG")
return False
def init_browser(self):
"""初始化浏览器"""
try:
self.log("初始化Chrome浏览器...")
options = ChromeOptions()
options.add_argument('--ignore-certificate-errors')
options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')
options.add_argument('--disable-gpu')
self.driver = webdriver.Chrome(options=options)
self.driver.implicitly_wait(10)
self.log("浏览器初始化成功")
return True
except Exception as e:
self.log(f"浏览器初始化失败: {str(e)}", "ERROR")
return False
def close_browser(self):
"""关闭浏览器"""
if self.driver:
try:
self.driver.quit()
self.log("浏览器已关闭")
except:
pass
def system_authorization(self):
"""系统授权操作"""
try:
self.log("开始系统授权流程")
# 访问维护平台
self.log("访问维护平台: https://192.168.5.52/#/LoginConfig")
self.driver.get("https://192.168.5.52/#/LoginConfig")
time.sleep(3)
# 登录
self.log("登录维护平台...")
# 查找登录表单
try:
# 账号输入框
account_input = self.driver.find_element(By.CSS_SELECTOR, 'input[placeholder*="账号"]')
account_input.clear()
account_input.send_keys('superadmin')
self.log("输入账号: superadmin")
# 密码输入框
password_input = self.driver.find_element(By.CSS_SELECTOR, 'input[placeholder*="密码"]')
password_input.clear()
password_input.send_keys('Ubains@1357')
self.log("输入密码: *******")
# 验证码输入框
verify_input = self.driver.find_element(By.CSS_SELECTOR, 'input[placeholder*="验证码"]')
verify_input.clear()
verify_input.send_keys('csba')
self.log("输入验证码: csba")
# 点击登录按钮
login_btn = self.driver.find_element(By.CSS_SELECTOR, 'button')
login_btn.click()
self.log("点击登录按钮")
time.sleep(5)
except Exception as e:
self.log(f"登录操作失败: {str(e)}", "ERROR")
return False
# 检查是否登录成功
current_url = self.driver.current_url
self.log(f"当前URL: {current_url}")
# 上传授权文件
self.log("准备上传授权文件...")
time.sleep(2)
# 查找并点击上传按钮
upload_btn = WebDriverWait(self.driver, 10).until(
EC.element_to_be_clickable((By.CSS_SELECTOR, 'button'))
)
# 可能需要点击特定的上传按钮
buttons = self.driver.find_elements(By.CSS_SELECTOR, 'button')
for btn in buttons:
btn_text = btn.text
if '上传授权文件' in btn_text or '上传' in btn_text:
self.log(f"找到上传按钮: {btn_text}")
btn.click()
time.sleep(2)
break
# 处理可能出现的身份验证对话框
try:
# 检查是否有验证对话框
verify_dialog = self.driver.find_elements(By.CSS_SELECTOR, 'div[role="dialog"]')
if verify_dialog and '校验身份' in verify_dialog[0].text:
self.log("检测到身份验证对话框")
# 输入密码
pwd_inputs = self.driver.find_elements(By.CSS_SELECTOR, 'input[type="password"]')
if pwd_inputs:
pwd_inputs[0].send_keys('Ubains@1357')
self.log("输入验证密码")
# 输入验证码
verify_inputs = self.driver.find_elements(By.CSS_SELECTOR, 'input[placeholder*="验证码"]')
if verify_inputs:
verify_inputs[0].clear()
verify_inputs[0].send_keys('csba')
self.log("输入验证码: csba")
# 点击确定
confirm_btns = self.driver.find_elements(By.CSS_SELECTOR, 'button')
for btn in confirm_btns:
if '确定' in btn.text:
btn.click()
self.log("点击确定按钮")
break
time.sleep(3)
except:
pass
# 上传文件
self.log(f"上传授权文件: {self.license_path}")
# 查找文件上传input
file_inputs = self.driver.find_elements(By.CSS_SELECTOR, 'input[type="file"]')
if file_inputs:
file_inputs[0].send_keys(os.path.abspath(self.license_path))
self.log("授权文件已上传")
time.sleep(5)
else:
self.log("未找到文件上传输入框", "WARN")
self.log("系统授权流程完成")
return True
except Exception as e:
self.log(f"系统授权失败: {str(e)}", "ERROR")
self.log(traceback.format_exc(), "DEBUG")
return False
def create_company_admin(self):
"""创建公司管理员"""
try:
self.log("开始创建公司管理员")
# 导航到公司管理页面
self.log("导航到公司管理页面...")
self.driver.get("https://192.168.5.52/#/backend/backstage?backstage=%2Fbackstage%2F%23%2FBackend%2FAccount%2FCompany")
time.sleep(3)
# 查找"自动化"公司
self.log("查找'自动化'公司...")
# 等待表格加载
time.sleep(3)
# 查找包含"自动化"文字的行
try:
# 可能需要先登录后台
current_url = self.driver.current_url
if 'login' in current_url.lower():
self.log("需要重新登录后台")
# 登录后台
account_input = self.driver.find_element(By.CSS_SELECTOR, 'input[placeholder*="账号"]')
account_input.clear()
account_input.send_keys('superadmin')
password_input = self.driver.find_element(By.CSS_SELECTOR, 'input[placeholder*="密码"]')
password_input.send_keys('Ubains@1357')
verify_input = self.driver.find_element(By.CSS_SELECTOR, 'input[placeholder*="验证码"]')
verify_input.clear()
verify_input.send_keys('csba')
login_btn = self.driver.find_element(By.CSS_SELECTOR, 'button')
login_btn.click()
time.sleep(3)
# 重新导航到公司管理页面
self.driver.get("https://192.168.5.52/#/backend/backstage?backstage=%2Fbackstage%2F%23%2FBackend%2FAccount%2FCompany")
time.sleep(3)
# 查找所有公司行
company_elements = self.driver.find_elements(By.CSS_SELECTOR, 'tr')
automation_company = None
for company in company_elements:
company_text = company.text
if '自动化' in company_text and 'CN-MWQ-UBAINS' in company_text:
automation_company = company
self.log(f"找到'自动化'公司: CN-MWQ-UBAINS")
break
if automation_company:
# 点击"设置企业管理员"按钮
admin_buttons = automation_company.find_elements(By.CSS_SELECTOR, 'button')
for btn in admin_buttons:
if '设置企业管理员' in btn.text or '管理员' in btn.text:
btn.click()
self.log("点击'设置企业管理员'按钮")
time.sleep(2)
break
# 在弹出的对话框中输入admin
self.log("输入管理员用户名: admin")
admin_name_input = self.driver.find_element(By.CSS_SELECTOR, 'input[placeholder*="用户名称"]')
admin_name_input.clear()
admin_name_input.send_keys('admin')
# 点击确定按钮
confirm_buttons = self.driver.find_elements(By.CSS_SELECTOR, 'button')
for btn in confirm_buttons:
if '确定' in btn.text:
btn.click()
self.log("点击确定按钮创建管理员")
time.sleep(2)
break
self.log("公司管理员创建成功")
else:
self.log("未找到'自动化'公司", "WARN")
return True
except Exception as e:
self.log(f"创建管理员失败: {str(e)}", "ERROR")
self.log(traceback.format_exc(), "DEBUG")
return False
except Exception as e:
self.log(f"创建公司管理员失败: {str(e)}", "ERROR")
self.log(traceback.format_exc(), "DEBUG")
return False
def verify_deployment(self):
"""验证部署结果"""
try:
self.log("开始验证部署结果")
# API接口测试
api_tests = [
{
'name': '预定系统对外接口',
'url': 'https://192.168.5.52/exapi/message/getMsgPageList',
'expected': 'A0076'
},
{
'name': '预定系统对内接口',
'url': 'https://192.168.5.52/meetingV3/api/systemConfiguration/globalConfig?companyNumber=CN-SZ-00-0201',
'expected': 'A0078'
},
{
'name': '运维集控系统接口',
'url': 'https://192.168.5.52/monitor/api2/api/servermonitor/',
'expected': '40000014'
},
{
'name': '语音转录系统接口',
'url': 'https://192.168.5.52/voice/api/iflytek/roommaster?company_id=1&user_id=8&company_secret=57d00f9f-020f-5f1f-b788-55fae843bceb&getall=1',
'expected': '40000003'
}
]
results = []
for test in api_tests:
self.log(f"测试 {test['name']}...")
try:
resp = requests.get(test['url'], verify=False, timeout=10)
if test['expected'] in resp.text:
self.log(f"✅ {test['name']}: PASS (返回码: {test['expected']})")
results.append(True)
else:
self.log(f"⚠️ {test['name']}: UNEXPECTED RESPONSE", "WARN")
results.append(False)
except Exception as e:
self.log(f"❌ {test['name']}: REQUEST FAILED - {str(e)}", "ERROR")
results.append(False)
# 检查容器状态
self.log("检查容器状态...")
if self.ssh_shell:
self.ssh_shell.send('docker ps --format "table {{.Names}}\t{{.Status}}"\n')
time.sleep(2)
docker_output = ""
try:
while self.ssh_shell.recv_ready():
docker_output += self.ssh_shell.recv(4096).decode('utf-8', errors='ignore')
except:
pass
self.log(f"容器状态:\n{docker_output}")
success_count = sum(results)
total_count = len(results)
self.log(f"API测试结果: {success_count}/{total_count} 通过")
return success_count == total_count
except Exception as e:
self.log(f"验证部署失败: {str(e)}", "ERROR")
return False
def prepare_deployment_environment(self):
"""准备部署环境"""
try:
self.log("检查并准备部署环境...")
# 检查部署目录是否存在
stdin, stdout, stderr = self.ssh_client.exec_command('test -d /data/offline_auto_unifiedPlatform && echo "EXISTS" || echo "NOT_EXISTS"')
result = stdout.read().decode('utf-8', errors='ignore').strip()
if result == "NOT_EXISTS":
self.log("部署目录不存在,检查部署包...", "WARN")
# 检查部署包是否存在
stdin, stdout, stderr = self.ssh_client.exec_command('test -f /data/offline_auto_unifiedPlatform.tar.gz && echo "EXISTS" || echo "NOT_EXISTS"')
pkg_result = stdout.read().decode('utf-8', errors='ignore').strip()
if pkg_result == "EXISTS":
self.log("解压部署包(约8.5GB,可能需要几分钟)...")
# 使用后台任务解压
channel = self.ssh_client.invoke_shell()
channel.send("cd /data && tar -xzf offline_auto_unifiedPlatform.tar.gz\n")
# 等待解压完成
import time
max_wait = 600 # 10分钟
start_time = time.time()
while time.time() - start_time < max_wait:
time.sleep(5)
stdin, stdout, stderr = self.ssh_client.exec_command('test -d /data/offline_auto_unifiedPlatform && echo "EXISTS" || echo "NOT_EXISTS"')
result = stdout.read().decode('utf-8', errors='ignore').strip()
if result == "EXISTS":
self.log("部署包解压完成")
channel.close()
return True
self.log(f"解压进行中... 已用时: {int((time.time() - start_time)/60)}分钟")
channel.close()
self.log("解压超时", "ERROR")
return False
else:
self.log("部署包不存在", "ERROR")
return False
else:
self.log("部署目录已就绪")
return True
except Exception as e:
self.log(f"准备部署环境失败: {str(e)}", "ERROR")
return False
def run_full_deployment(self):
"""执行完整部署流程"""
try:
self.log("=" * 50)
self.log("开始远程自动化部署")
self.log("=" * 50)
self.log(f"目标服务器: {self.host}")
self.log(f"授权文件: {self.license_path}")
self.log("=" * 50)
# 0. 准备部署环境
self.log("\n[0/5] 准备部署环境...")
if not self.connect_ssh():
self.log("SSH连接失败,终止部署", "ERROR")
return False
if not self.prepare_deployment_environment():
self.log("准备部署环境失败", "ERROR")
return False
# 1. SSH连接和部署(复用现有SSH连接)
self.log("\n[1/5] 执行部署脚本...")
if not self.connect_ssh_interactive():
self.log("SSH交互式连接失败,终止部署", "ERROR")
return False
success = self.run_deployment_script_interactive()
if not success:
self.log("部署脚本执行失败", "ERROR")
return False
# 关闭SSH交互连接
if self.ssh_shell:
try:
self.ssh_shell.close()
except:
pass
# 关闭SSH连接
if self.ssh_client:
self.ssh_client.close()
# 2. 系统授权
self.log("\n[2/5] 系统授权...")
if not self.init_browser():
self.log("浏览器初始化失败", "ERROR")
return False
success = self.system_authorization()
if not success:
self.log("系统授权失败", "ERROR")
self.close_browser()
return False
# 3. 创建管理员
self.log("\n[3/5] 创建公司管理员...")
success = self.create_company_admin()
if not success:
self.log("创建管理员失败", "ERROR")
self.close_browser()
return False
# 4. 验证部署
self.log("\n[4/5] 验证部署...")
# 重新连接SSH进行验证
if self.connect_ssh_interactive():
self.verify_deployment()
# 5. 完成
self.log("\n[5/5] 部署流程完成")
self.log("=" * 50)
self.log("✅ 远程自动化部署完成!")
self.log("=" * 50)
return True
except Exception as e:
self.log(f"部署流程失败: {str(e)}", "ERROR")
self.log(traceback.format_exc(), "DEBUG")
return False
finally:
# 清理资源
self.log("清理资源...")
if self.ssh_client:
try:
self.ssh_client.close()
except:
pass
if self.ssh_shell:
try:
self.ssh_shell.close()
except:
pass
self.close_browser()
def main():
"""主函数"""
# 配置参数
config = {
'host': '192.168.5.52',
'username': 'root',
'password': 'Ubains@123',
'license_path': r'E:\自动化部署\X86-5.52\license.zip'
}
# 创建部署实例并执行
deployment = RemoteDeploymentAutomation(**config)
# 执行完整部署
success = deployment.run_full_deployment()
# 返回结果
sys.exit(0 if success else 1)
if __name__ == '__main__':
main()
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
自动处理whiptail菜单的部署脚本
使用paramiko的invoke_shell和自动响应
"""
import sys
import os
import time
import threading
import queue
# 添加当前目录到路径
sys.path.insert(0, os.path.dirname(__file__))
import paramiko
class DeploymentAutomation:
def __init__(self, host, username, password):
self.host = host
self.username = username
self.password = password
self.client = None
self.shell = None
self.output_queue = queue.Queue()
def log(self, message, level="INFO"):
"""日志输出"""
prefix = {"INFO": "[OK]", "ERROR": "[ERROR]", "WARN": "[WARN]"}
print(f"{prefix.get(level, '[INFO]')} {message}")
def connect(self):
"""连接SSH"""
try:
self.client = paramiko.SSHClient()
self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
self.client.connect(self.host, username=self.username, password=self.password, timeout=30)
self.log("SSH连接成功")
return True
except Exception as e:
self.log(f"SSH连接失败: {str(e)}", "ERROR")
return False
def create_shell(self):
"""创建交互式shell"""
try:
self.shell = self.client.invoke_shell()
time.sleep(1)
self.log("交互式shell创建成功")
return True
except Exception as e:
self.log(f"Shell创建失败: {str(e)}", "ERROR")
return False
def read_output(self, timeout=5):
"""读取shell输出"""
try:
output = ""
start_time = time.time()
while time.time() - start_time < timeout:
if self.shell.recv_ready():
chunk = self.shell.recv(4096).decode('utf-8', errors='ignore')
output += chunk
if chunk:
start_time = time.time() # 重置超时
else:
time.sleep(0.1)
return output
except:
return ""
def send_command(self, command, wait_time=1):
"""发送命令"""
try:
self.shell.send(command + "\n")
time.sleep(wait_time)
except Exception as e:
self.log(f"发送命令失败: {str(e)}", "ERROR")
def run_deployment(self):
"""执行部署"""
try:
self.log("开始部署流程")
# 清空初始缓冲区
self.read_output(timeout=1)
# 切换到部署目录
self.log("切换到部署目录")
self.send_command("cd /data/offline_auto_unifiedPlatform", wait_time=2)
# 运行部署脚本
self.log("启动部署脚本 (new_auto.sh)")
self.send_command("./new_auto.sh", wait_time=3)
# 监控部署过程
self.log("监控部署过程,等待菜单出现...")
deployment_start = time.time()
max_time = 2400 # 40分钟
menu_handled = False
while time.time() - deployment_start < max_time:
# 读取输出
output = self.read_output(timeout=10)
if output:
# 检测whiptail菜单
if 'whiptail' in output or '选择系统' in output:
if not menu_handled:
self.log("检测到whiptail菜单,自动选择'全部系统'")
# 按空格键选中,然后按回车确认
self.shell.send(" ")
time.sleep(1)
self.shell.send("\n")
time.sleep(2)
menu_handled = True
# 检测其他提示
elif 'Press any key' in output or '按任意键' in output:
self.log("检测到按键提示,发送回车")
self.send_command("", wait_time=1)
# 检测部署完成
elif '部署完成' in output or '部署成功' in output:
self.log("部署完成!")
break
# 检测错误
elif 'error' in output.lower() and 'fatal' in output.lower():
self.log(f"检测到错误: {output[-200:]}", "WARN")
# 每60秒输出进度
elapsed = int(time.time() - deployment_start)
if elapsed % 60 == 0 and elapsed > 0:
self.log(f"部署进行中... 已用时: {int(elapsed/60)}分钟")
# 检查部署结果
self.log("检查部署结果")
self.send_command("docker ps --format 'table {{.Names}}\t{{.Status}}'", wait_time=3)
docker_output = self.read_output(timeout=5)
print("\n" + "=" * 50)
print("部署完成 - 容器状态:")
print("=" * 50)
print(docker_output)
container_count = docker_output.count('\n') - 1
print(f"\n运行中的容器数量: {container_count}")
if container_count >= 5:
self.log("部署成功完成!")
return True
else:
self.log("部署可能未完全完成", "WARN")
return False
except Exception as e:
self.log(f"部署过程出错: {str(e)}", "ERROR")
import traceback
traceback.print_exc()
return False
def close(self):
"""关闭连接"""
if self.shell:
self.shell.close()
if self.client:
self.client.close()
def main():
print("=" * 60)
print("自动化部署脚本 (带whiptail菜单自动处理)")
print("=" * 60)
deployment = DeploymentAutomation(
host='192.168.5.52',
username='root',
password='Ubains@123'
)
try:
if not deployment.connect():
return 1
if not deployment.create_shell():
return 1
success = deployment.run_deployment()
print("\n" + "=" * 60)
if success:
print("部署执行完成")
print("\n后续步骤:")
print("1. 系统授权: https://192.168.5.52/#/LoginConfig")
print(" 账号: superadmin / Ubains@1357")
print(" 验证码: csba")
print("\n2. 创建管理员: 为'自动化'公司创建admin用户")
else:
print("部署未完全完成,请检查日志")
print("=" * 60)
return 0 if success else 1
finally:
deployment.close()
if __name__ == '__main__':
sys.exit(main())
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$PlinkPath = Join-Path $ScriptDir "plink.exe"
function Invoke-SSH {
param([string]$Command)
$psi = New-Object System.Diagnostics.ProcessStartInfo
$psi.FileName = $PlinkPath
$psi.Arguments = "-pw Ubains@123 -P 22 root@192.168.5.52 $Command"
$psi.UseShellExecute = $false
$psi.RedirectStandardOutput = $true
$psi.RedirectStandardError = $true
$psi.CreateNoWindow = $true
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $psi
$p.Start() | Out-Null
$p.WaitForExit(60000)
return $p.StandardOutput.ReadToEnd()
}
Write-Host "========================================" -ForegroundColor Cyan
Write-Host "Checking /data directory on server" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
Write-Host ""
$result = Invoke-SSH -Command "ls -la /data"
Write-Host $result
Write-Host ""
Write-Host "========================================" -ForegroundColor Cyan
Write-Host "Looking for deployment scripts" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
Write-Host ""
$scripts = Invoke-SSH -Command "find /data -name '*.sh' -type f 2>/dev/null | head -20"
Write-Host $scripts
Write-Host ""
Write-Host "========================================" -ForegroundColor Cyan
Write-Host "Checking Docker status" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
Write-Host ""
$docker = Invoke-SSH -Command "docker ps -a 2>&1"
Write-Host $docker
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$PlinkPath = Join-Path $ScriptDir "plink.exe"
$ServerIP = "192.168.5.52"
$Username = "root"
$Password = "Ubains@123"
$SSHPort = 22
Write-Host "Checking deployment packages on server..." -ForegroundColor Cyan
Write-Host ""
$psi = New-Object System.Diagnostics.ProcessStartInfo
$psi.FileName = $PlinkPath
$psi.Arguments = "-pw $Password -P $SSHPort ${Username}@${ServerIP} 'ls -la /data && echo --- && find /data -maxdepth 2 -name *.sh -type f 2>/dev/null'"
$psi.UseShellExecute = $false
$psi.RedirectStandardOutput = $true
$psi.RedirectStandardError = $true
$psi.CreateNoWindow = $true
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $psi
$p.Start() | Out-Null
$p.WaitForExit(60000)
$stdout = $p.StandardOutput.ReadToEnd()
Write-Host $stdout
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$PlinkPath = Join-Path $ScriptDir "plink.exe"
$psi = New-Object System.Diagnostics.ProcessStartInfo
$psi.FileName = $PlinkPath
$psi.Arguments = "-pw Ubains@123 -P 22 root@192.168.5.52 'ls -la /home && echo --- && ls -la /home/deploy 2>&1'"
$psi.UseShellExecute = $false
$psi.RedirectStandardOutput = $true
$psi.RedirectStandardError = $true
$psi.CreateNoWindow = $true
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $psi
$p.Start() | Out-Null
$p.WaitForExit(30000)
$stdout = $p.StandardOutput.ReadToEnd()
$stderr = $p.StandardError.ReadToEnd()
Write-Host $stdout
Write-Host $stderr
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
受控部署脚本 - 分步骤执行部署
"""
import sys
import os
import time
# 添加当前目录到路径
sys.path.insert(0, os.path.dirname(__file__))
from auto_deployment_python import RemoteDeploymentAutomation
def main():
print("=" * 50)
print("受控自动化部署")
print("=" * 50)
config = {
'host': '192.168.5.52',
'username': 'root',
'password': 'Ubains@123',
'license_path': r'E:\自动化部署\X86-5.52\license.zip'
}
deployment = RemoteDeploymentAutomation(**config)
try:
# 步骤1: 连接SSH并准备环境
print("\n步骤1: 连接SSH并准备环境")
print("-" * 50)
if not deployment.connect_ssh():
print("[ERROR] SSH连接失败")
return 1
print("[OK] SSH连接成功")
if not deployment.prepare_deployment_environment():
print("[ERROR] 环境准备失败")
return 1
print("[OK] 环境准备完成")
# 步骤2: 启动部署脚本
print("\n步骤2: 启动部署脚本")
print("-" * 50)
print("注意: 此步骤需要手动选择'全部系统'选项")
print("部署预计需要40分钟时间...")
# 创建交互式会话
if not deployment.connect_ssh_interactive():
print("[ERROR] 交互式连接失败")
return 1
# 切换到部署目录
print("切换到部署目录...")
deployment.ssh_shell.send("cd /data/offline_auto_unifiedPlatform\n")
time.sleep(2)
# 清空缓冲区
try:
while deployment.ssh_shell.recv_ready():
deployment.ssh_shell.recv(1024)
except:
pass
# 启动部署脚本
print("启动部署脚本 (new_auto.sh)...")
deployment.ssh_shell.send("./new_auto.sh\n")
time.sleep(3)
# 监控部署过程
print("开始监控部署过程...")
print("如果出现菜单,请手动选择'全部系统'选项")
deployment_start = time.time()
max_deployment_time = 2400 # 40分钟
menu_detected = False
output_buffer = ""
while time.time() - deployment_start < max_deployment_time:
try:
if deployment.ssh_shell.recv_ready():
chunk = deployment.ssh_shell.recv(4096).decode('utf-8', errors='ignore')
output_buffer += chunk
# 检测菜单
if 'whiptail' in chunk or '选择系统' in chunk or '全部系统' in chunk:
if not menu_detected:
print("\n[检测到菜单] 尝试自动选择'全部系统'...")
deployment.ssh_shell.send("\n")
menu_detected = True
time.sleep(2)
# 检测部署开始
if '开始部署' in output_buffer or '正在部署' in output_buffer:
if not menu_detected:
print("\n[OK] 部署已开始")
menu_detected = True
# 检测部署完成
if '部署完成' in output_buffer or '部署成功' in output_buffer:
print("\n[OK] 部署完成!")
break
# 检测错误
if 'error' in chunk.lower() and 'fatal' in chunk.lower():
print(f"\n[ERROR] 检测到严重错误")
print(f"错误信息: {chunk[-200:]}")
# 每60秒输出进度
elapsed = int(time.time() - deployment_start)
if elapsed % 60 == 0 and elapsed > 0:
print(f"[进度] 部署进行中... 已用时: {int(elapsed/60)}分钟")
time.sleep(5)
except Exception as e:
print(f"[WARN] 监控时出错: {str(e)}")
time.sleep(5)
# 步骤3: 检查部署结果
print("\n步骤3: 检查部署结果")
print("-" * 50)
deployment.ssh_shell.send("docker ps --format 'table {{.Names}}\t{{.Status}}'\n")
time.sleep(3)
docker_output = ""
try:
while deployment.ssh_shell.recv_ready():
docker_output += deployment.ssh_shell.recv(4096).decode('utf-8', errors='ignore')
except:
pass
print("容器状态:")
print(docker_output)
# 统计容器数量
container_count = docker_output.count('\n') - 1 # 减去表头
print(f"\n运行中的容器数量: {container_count}")
if container_count >= 5:
print("[OK] 部署成功,已启动多个容器")
elif container_count > 0:
print("[WARN] 部署可能未完全完成,容器数量较少")
else:
print("[ERROR] 部署可能失败,没有容器运行")
# 清理
print("\n清理连接...")
deployment.ssh_client.close()
if deployment.ssh_shell:
deployment.ssh_shell.close()
print("\n" + "=" * 50)
print("部署脚本执行完成")
print("=" * 50)
print("\n后续步骤:")
print("1. 系统授权: https://192.168.5.52/#/LoginConfig")
print(" 账号: superadmin / Ubains@1357")
print(" 验证码: csba")
print(" 授权文件: E:\\自动化部署\\X86-5.52\\license.zip")
print("\n2. 创建管理员: 为'自动化'公司创建admin用户")
print("\n3. 验收测试: 检查服务接口状态")
return 0
except Exception as e:
print(f"\n[ERROR] 部署过程出错: {str(e)}")
import traceback
traceback.print_exc()
return 1
if __name__ == '__main__':
sys.exit(main())
#!/usr/bin/expect -f
# 自动处理部署脚本的交互式提示
set timeout 300
# 设置服务器连接信息
set host "192.168.5.52"
set username "root"
set password "Ubains@123"
# 连接到SSH服务器
spawn ssh $username@$host
expect {
"yes/no" {
send "yes\r"
exp_continue
}
"password:" {
send "$password\r"
}
timeout {
puts "连接超时"
exit 1
}
}
# 等待shell提示符
expect "~]#"
# 切换到部署目录
send "cd /data/offline_auto_unifiedPlatform\r"
expect "~]#"
# 运行部署脚本
send "./new_auto.sh\r"
# 处理各种交互式提示
expect {
# "是否继续执行脚本(y/n)" 提示
"是否继续执行脚本" {
send "y\r"
exp_continue
}
# "确认当前机器信息" 提示
"确认当前机器信息" {
send "y\r"
exp_continue
}
# "确认无误请按" 提示
"确认无误请按" {
send "\r"
exp_continue
}
# "请输入当前日期" 提示
"请输入当前日期" {
# 获取当前日期
set current_date [clock format [clock seconds] -format "%Y/%m/%d"]
send "$current_date\r"
exp_continue
}
# "请输入当前时间" 提示
"请输入当前时间" {
# 获取当前时间
set current_time [clock format [clock seconds] -format "%H:%M:%S"]
send "$current_time\r"
exp_continue
}
# "是否使用自定义NTP" 提示
"是否使用自定义NTP" {
send "n\r"
exp_continue
}
# whiptail系统选择菜单
"whiptail" {
# 发送空格选择"全部系统",然后回车确认
send " "
sleep 1
send "\r"
exp_continue
}
# "选择系统" 提示
"选择系统" {
send "\r"
exp_continue
}
# 部署完成
"部署完成" {
puts "部署完成!"
send "\r"
}
# 部署成功
"部署成功" {
puts "部署成功!"
send "\r"
}
# 超时处理(长时间等待)
timeout {
# 检查是否部署还在进行
puts "等待部署中..."
exp_continue
}
# EOF处理
eof {
puts "脚本执行结束"
}
}
# 等待一段时间以查看输出
expect "~]#" {
puts "返回到shell提示符"
}
# 检查容器状态
send "docker ps --format 'table {{.Names}}\t{{.Status}}'\r"
expect "~]#"
# 保持连接打开以便查看输出
interact
# Deployment Check Script - Simplified Version
# Author: Automation Team
# Date: 2026-05-14
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$ReportsDir = Join-Path $ScriptDir "reports"
if (-not (Test-Path $ReportsDir)) {
New-Item -ItemType Directory -Path $ReportsDir -Force | Out-Null
}
$LogFile = Join-Path $ReportsDir "deploy_$(Get-Date -Format 'yyyyMMdd_HHmmss').log"
function Write-Log {
param([string]$Message, [string]$Color = "White")
$Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$LogMessage = "[$Timestamp] $Message"
Write-Host $LogMessage -ForegroundColor $Color
Add-Content -Path $LogFile -Value $LogMessage
}
function Invoke-SSHCommand {
param([string]$Command)
$PlinkPath = Join-Path $ScriptDir "plink.exe"
$psi = New-Object System.Diagnostics.ProcessStartInfo
$psi.FileName = $PlinkPath
$psi.Arguments = "-pw $Password -P $SSHPort ${Username}@${ServerIP} $Command"
$psi.UseShellExecute = $false
$psi.RedirectStandardOutput = $true
$psi.RedirectStandardError = $true
$psi.CreateNoWindow = $true
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $psi
$p.Start() | Out-Null
$p.WaitForExit(60000)
$stdout = $p.StandardOutput.ReadToEnd()
$stderr = $p.StandardError.ReadToEnd()
return @{
Output = $stdout
ExitCode = $p.ExitCode
}
}
# Configuration
$ServerIP = "192.168.5.52"
$Username = "root"
$Password = "Ubains@123"
$SSHPort = 22
$Results = @{}
Write-Log "========================================" "Cyan"
Write-Log "Deployment Check Script" "Cyan"
Write-Log "Target: ${ServerIP}" "Cyan"
Write-Log "========================================" "Cyan"
# Test connection
Write-Log "Testing SSH connection..." "Yellow"
$result = Invoke-SSHCommand -Command "echo 'ok'"
if ($result.Output -match "ok") {
Write-Log "Connection successful" "Green"
$Results.Connection = "OK"
} else {
Write-Log "Connection failed" "Red"
exit 1
}
# Get server info
Write-Log "Getting server information..." "Yellow"
$osInfo = Invoke-SSHCommand -Command "uname -a"
Write-Log "OS: $($osInfo.Output.Trim())" "White"
$diskInfo = Invoke-SSHCommand -Command "df -h /home | awk 'NR==2 {print \$4}'"
Write-Log "Disk space: $($diskInfo.Output.Trim())" "White"
# Check Docker
Write-Log "Checking Docker status..." "Yellow"
$dockerResult = Invoke-SSHCommand -Command "docker ps --format 'table {{.Names}}\t{{.Status}}' 2>&1"
if ($dockerResult.ExitCode -eq 0) {
Write-Log "Docker is running" "Green"
Write-Host ""
Write-Host "========== Containers ==========" -ForegroundColor Cyan
Write-Host $dockerResult.Output
Write-Host "========== Containers End ==========" -ForegroundColor Cyan
Write-Host ""
$Results.Docker = "Running"
} else {
Write-Log "Docker is not accessible" "Red"
$Results.Docker = "Not Running"
}
# Check services
Write-Log "Checking services..." "Yellow"
$services = @(
@{Name="ExtAPI"; Path="/data/services/api/java-meeting/java-meeting-extapi/logs/ubains-INFO-AND-ERROR.log"},
@{Name="InnerAPI"; Path="/data/services/api/java-meeting/java-meeting2.0/logs/ubains-INFO-AND-ERROR.log"},
@{Name="Monitor"; Path="/data/services/api/python-cmdb/log/uinfo.log"},
@{Name="Voice"; Path="/data/services/api/python-voice/log/uinfo.log"}
)
foreach ($svc in $services) {
$logResult = Invoke-SSHCommand -Command "test -f '$($svc.Path)' && echo 'exists' || echo 'not_found'"
if ($logResult.Output -match "exists") {
$tailResult = Invoke-SSHCommand -Command "tail -20 '$($svc.Path)'"
if ($tailResult.Output -match "ERROR|Exception") {
Write-Log "$($svc.Name): Log contains errors" "Yellow"
$Results[$svc.Name] = "Has Errors"
} else {
Write-Log "$($svc.Name): Log OK" "Green"
$Results[$svc.Name] = "OK"
}
} else {
Write-Log "$($svc.Name): Log file not found" "Red"
$Results[$svc.Name] = "Not Found"
}
}
# Test APIs
Write-Log "Testing API endpoints..." "Yellow"
$apis = @(
@{Name="ExtAPI"; URL="https://${ServerIP}/exapi/message/getMsgPageList"; Expected="A0076"},
@{Name="Meeting"; URL="https://${ServerIP}/meetingV3/api/systemConfiguration/globalConfig?companyNumber=CN-SZ-00-0201"; Expected="A0078"},
@{Name="Monitor"; URL="https://${ServerIP}/monitor/api2/api/servermonitor/"; Expected="40000014"},
@{Name="Voice"; URL="https://${ServerIP}/voice/api/iflytek/roommaster?company_id=1&user_id=8&company_secret=57d00f9f-020f-5f1f-b788-55fae843bceb&getall=1"; Expected="40000003"}
)
foreach ($api in $apis) {
$curlResult = Invoke-SSHCommand -Command "curl -k '$($api.URL)' 2>/dev/null"
if ($curlResult.Output -match $api.Expected) {
Write-Log "$($api.Name): API OK" "Green"
$Results["$($api.Name)API"] = "OK"
} else {
Write-Log "$($api.Name): API Error" "Yellow"
$Results["$($api.Name)API"] = "Error"
}
}
# Generate report
Write-Log "Generating report..." "Yellow"
$report = @"
# Deployment Check Report
## Server: $ServerIP
## Results
- Connection: $($Results.Connection)
- Docker: $($Results.Docker)
## Services
"@
foreach ($svc in $services) {
$report += "`n- $($svc.Name): $($Results[$svc.Name])"
}
$report += "`n\n## APIs`n"
foreach ($api in $apis) {
$report += "`n- $($api.Name): $($Results["$($api.Name)API"])"
}
$report += @"
## Access URLs
- Frontend: https://${ServerIP}/
- Maintenance: https://${ServerIP}/#/LoginConfig
- Backend: https://${ServerIP}/#/LoginAdmin
---
Generated: $(Get-Date)
"@
$reportFile = Join-Path $ReportsDir "${ServerIP}_check_$(Get-Date -Format 'yyyyMMdd_HHmmss').md"
$report | Out-File -FilePath $reportFile -Encoding UTF8 -Force
Write-Log "Report saved to: $reportFile" "Green"
Write-Log "========================================" "Green"
Write-Log "Check completed!" "Green"
Write-Log "========================================" "Green"
#!/bin/bash
# 自动响应部署脚本的交互式提示
cd /data/offline_auto_unifiedPlatform
# 使用输入重定向自动响应所有提示
./new_auto.sh <<EOF
1
y
y
y
y
y
EOF
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$PlinkPath = Join-Path $ScriptDir "plink.exe"
function Invoke-SSH {
param([string]$Command, [int]$TimeoutMs = 600000)
$psi = New-Object System.Diagnostics.ProcessStartInfo
$psi.FileName = $PlinkPath
$psi.Arguments = "-pw Ubains@123 -P 22 root@192.168.5.52 $Command"
$psi.UseShellExecute = $false
$psi.RedirectStandardOutput = $true
$psi.RedirectStandardError = $true
$psi.CreateNoWindow = $true
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $psi
$p.Start() | Out-Null
$p.WaitForExit($TimeoutMs)
$stdout = $p.StandardOutput.ReadToEnd()
$stderr = $p.StandardError.ReadToEnd()
return @{
Output = $stdout
Error = $stderr
ExitCode = $p.ExitCode
}
}
Write-Host "========================================" -ForegroundColor Cyan
Write-Host "Executing Deployment Script" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
Write-Host ""
# First, let's check the deployment script help
Write-Host "Step 1: Checking deployment script information..." -ForegroundColor Yellow
$helpResult = Invoke-SSH -Command "cd /data/offline_auto_unifiedPlatform && head -50 new_auto.sh"
Write-Host "Deployment script header:" -ForegroundColor Gray
Write-Host ($helpResult.Output | Select-Object -First 30)
Write-Host ""
# Check script permissions and make executable
Write-Host "Step 2: Setting script permissions..." -ForegroundColor Yellow
$chmodResult = Invoke-SSH -Command "chmod +x /data/offline_auto_unifiedPlatform/*.sh"
Write-Host "Permissions set" -ForegroundColor Green
Write-Host ""
# Start the deployment script in background with logging
Write-Host "Step 3: Starting deployment script..." -ForegroundColor Yellow
Write-Host "This will take approximately 40 minutes..." -ForegroundColor Gray
Write-Host ""
# Create log directory
$mkdirResult = Invoke-SSH -Command "mkdir -p /var/log/deploy"
# Run deployment in background with output logging
$deployCmd = "cd /data/offline_auto_unifiedPlatform && nohup bash new_auto.sh > /var/log/deploy/deploy.log 2>&1 & echo $!"
$pidResult = Invoke-SSH -Command $deployCmd
$deployPid = $pidResult.Output.Trim()
Write-Host "Deployment started with PID: $deployPid" -ForegroundColor Green
Write-Host "Log file: /var/log/deploy/deploy.log" -ForegroundColor Gray
Write-Host ""
# Monitor initial output
Write-Host "Waiting for deployment to initialize..." -ForegroundColor Yellow
Start-Sleep -Seconds 10
# Check if process is still running
$checkResult = Invoke-SSH -Command "ps aux | grep $deployPid | grep -v grep"
if ($checkResult.Output) {
Write-Host "Deployment process is running!" -ForegroundColor Green
Write-Host ""
# Show initial log output
$logResult = Invoke-SSH -Command "tail -50 /var/log/deploy/deploy.log 2>/dev/null || echo 'Log not available yet'"
if ($logResult.Output -ne "Log not available yet") {
Write-Host "Initial deployment output:" -ForegroundColor Gray
Write-Host $logResult.Output
}
} else {
Write-Host "Deployment process may have completed quickly or exited" -ForegroundColor Yellow
Write-Host ""
# Check exit status
$logResult = Invoke-SSH -Command "cat /var/log/deploy/deploy.log 2>/dev/null || echo 'No log file'"
Write-Host "Deployment log:" -ForegroundColor Gray
Write-Host $logResult.Output
}
Write-Host ""
Write-Host "========================================" -ForegroundColor Green
Write-Host "Deployment is running in background!" -ForegroundColor Green
Write-Host "========================================" -ForegroundColor Green
Write-Host ""
Write-Host "To monitor deployment progress, SSH into server and run:" -ForegroundColor Yellow
Write-Host " tail -f /var/log/deploy/deploy.log" -ForegroundColor Gray
Write-Host ""
Write-Host "To check if deployment is still running:" -ForegroundColor Yellow
Write-Host " ps aux | grep new_auto.sh" -ForegroundColor Gray
Write-Host ""
# Setup monitoring loop
Write-Host "Press Ctrl+C to stop monitoring" -ForegroundColor Yellow
Write-Host "Monitoring deployment progress (will show last 20 lines every 30 seconds)..." -ForegroundColor Gray
Write-Host ""
$maxWait = 3600 # 60 minutes max
$elapsed = 0
$lastLines = ""
while ($elapsed -lt $maxWait) {
Start-Sleep -Seconds 30
$elapsed += 30
$minutes = [math]::Floor($elapsed / 60)
# Get latest log lines
$logResult = Invoke-SSH -Command "tail -20 /var/log/deploy/deploy.log 2>/dev/null"
if ($logResult.Output -and $logResult.Output -ne $lastLines) {
$lastLines = $logResult.Output
Write-Host "========================================" -ForegroundColor DarkGray
Write-Host "Progress update ($minutes minutes):" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor DarkGray
Write-Host $lastLines
Write-Host ""
}
# Check if process still running
$checkResult = Invoke-SSH -Command "ps aux | grep new_auto.sh | grep -v grep | wc -l"
if ($checkResult.Output.Trim() -eq "0") {
Write-Host "Deployment process has completed!" -ForegroundColor Green
Write-Host ""
# Show final log
$finalLog = Invoke-SSH -Command "tail -100 /var/log/deploy/deploy.log"
Write-Host "Final deployment log:" -ForegroundColor Gray
Write-Host $finalLog.Output
break
}
}
Write-Host ""
Write-Host "========================================" -ForegroundColor Green
Write-Host "Deployment monitoring completed!" -ForegroundColor Green
Write-Host "========================================" -ForegroundColor Green
Write-Host ""
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$PlinkPath = Join-Path $ScriptDir "plink.exe"
function Invoke-SSH {
param([string]$Command, [int]$TimeoutMs = 600000)
$psi = New-Object System.Diagnostics.ProcessStartInfo
$psi.FileName = $PlinkPath
$psi.Arguments = "-pw Ubains@123 -P 22 root@192.168.5.52 $Command"
$psi.UseShellExecute = $false
$psi.RedirectStandardOutput = $true
$psi.RedirectStandardError = $true
$psi.CreateNoWindow = $true
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $psi
$p.Start() | Out-Null
$p.WaitForExit($TimeoutMs)
$stdout = $p.StandardOutput.ReadToEnd()
$stderr = $p.StandardError.ReadToEnd()
return @{
Output = $stdout
Error = $stderr
ExitCode = $p.ExitCode
}
}
Write-Host "========================================" -ForegroundColor Cyan
Write-Host "Deployment Package Extraction & Deploy" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
Write-Host ""
# Step 1: Verify MD5 checksum
Write-Host "Step 1: Verifying MD5 checksum..." -ForegroundColor Yellow
$md5Result = Invoke-SSH -Command "cd /data && md5sum -c offline_auto_unifiedPlatform.tar.gz.md5"
if ($md5Result.Output -match "OK") {
Write-Host "MD5 checksum verified: OK" -ForegroundColor Green
} else {
Write-Host "MD5 checksum check:" -ForegroundColor Yellow
Write-Host $md5Result.Output
Write-Host "Warning: MD5 check failed, but continuing..." -ForegroundColor Yellow
}
Write-Host ""
# Step 2: Extract deployment package
Write-Host "Step 2: Extracting deployment package..." -ForegroundColor Yellow
Write-Host "This may take 10-30 minutes depending on file size..." -ForegroundColor Gray
Write-Host ""
# Extract in background with nohup
$extractCmd = "cd /data && nohup tar -xzf offline_auto_unifiedPlatform.tar.gz > /tmp/extract.log 2>&1 & echo $!"
$pidResult = Invoke-SSH -Command $extractCmd
Write-Host "Extraction process started with PID: $($pidResult.Output.Trim())" -ForegroundColor Green
Write-Host "You can monitor progress with: tail -f /tmp/extract.log" -ForegroundColor Gray
Write-Host ""
# Wait a bit and check if extraction is happening
Start-Sleep -Seconds 10
$checkResult = Invoke-SSH -Command "ps aux | grep tar | grep -v grep"
if ($checkResult.Output) {
Write-Host "Extraction is in progress..." -ForegroundColor Green
Write-Host $checkResult.Output
Write-Host ""
} else {
# Check if extraction completed quickly
$lsResult = Invoke-SSH -Command "ls -la /data | grep -E '^d'"
Write-Host "Current directories in /data:" -ForegroundColor Gray
Write-Host $lsResult.Output
Write-Host ""
}
# Step 3: Check for deployment scripts after extraction
Write-Host "Step 3: Looking for deployment scripts..." -ForegroundColor Yellow
Write-Host "Waiting for extraction to complete..." -ForegroundColor Gray
Write-Host ""
# Wait for extraction (check every 30 seconds)
$maxWait = 1800 # 30 minutes max
$elapsed = 0
while ($elapsed -lt $maxWait) {
$checkExtract = Invoke-SSH -Command "test -f /tmp/extract.log && tail -5 /tmp/extract.log || echo 'no log'"
if ($checkExtract.Output -notmatch "no log") {
Write-Host "Extract log: $($checkExtract.Output.Trim())" -ForegroundColor Gray
}
# Check if tar process is still running
$tarRunning = Invoke-SSH -Command "ps aux | grep 'tar.*offline_auto' | grep -v grep | wc -l"
if ($tarRunning.Output.Trim() -eq "0") {
Write-Host "Extraction completed!" -ForegroundColor Green
break
}
Start-Sleep -Seconds 30
$elapsed += 30
$minutes = [math]::Floor($elapsed / 60)
Write-Host "Still extracting... ($minutes minutes elapsed)" -ForegroundColor Yellow
}
Write-Host ""
# Final check of extracted contents
Write-Host "Step 4: Checking extracted contents..." -ForegroundColor Yellow
$lsResult = Invoke-SSH -Command "ls -la /data"
Write-Host "Contents of /data:" -ForegroundColor Gray
Write-Host $lsResult.Output
Write-Host ""
# Find deployment scripts
$scriptsResult = Invoke-SSH -Command "find /data -maxdepth 3 -name '*.sh' -type f 2>/dev/null | head -20"
if ($scriptsResult.Output) {
Write-Host "Found deployment scripts:" -ForegroundColor Green
$scriptsResult.Output -split "`n" | Where-Object { $_ -ne "" } | ForEach-Object {
Write-Host " $_" -ForegroundColor Gray
}
} else {
Write-Host "No deployment scripts found yet" -ForegroundColor Yellow
}
Write-Host ""
Write-Host "========================================" -ForegroundColor Green
Write-Host "Extraction completed!" -ForegroundColor Green
Write-Host "========================================" -ForegroundColor Green
Write-Host ""
Write-Host "Next steps:" -ForegroundColor Yellow
Write-Host "1. Check the extracted deployment scripts above" -ForegroundColor Gray
Write-Host "2. Run the main deployment script" -ForegroundColor Gray
Write-Host "3. Monitor deployment progress" -ForegroundColor Gray
Write-Host ""
# Complete Remote Deployment Script - New Unified Platform
# Author: Automation Team
# Date: 2026-05-14
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$ReportsDir = Join-Path $ScriptDir "reports"
$TempDir = Join-Path $ScriptDir "temp"
# Create directories
if (-not (Test-Path $ReportsDir)) { New-Item -ItemType Directory -Path $ReportsDir -Force | Out-Null }
if (-not (Test-Path $TempDir)) { New-Item -ItemType Directory -Path $TempDir -Force | Out-Null }
$LogFile = Join-Path $ReportsDir "deploy_$(Get-Date -Format 'yyyyMMdd_HHmmss').log"
function Write-Log {
param([string]$Message, [string]$Level = "INFO")
$Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$LogMessage = "[$Timestamp] [$Level] $Message"
$Color = switch($Level) {
"INFO" { "White" }
"OK" { "Green" }
"WARN" { "Yellow" }
"ERROR" { "Red" }
"STEP" { "Cyan" }
default { "White" }
}
Write-Host $LogMessage -ForegroundColor $Color
Add-Content -Path $LogFile -Value $LogMessage
}
function Invoke-SSHCommand {
param([string]$Command, [int]$TimeoutMs = 300000)
$PlinkPath = Join-Path $ScriptDir "plink.exe"
$StartInfo = New-Object System.Diagnostics.ProcessStartInfo
$StartInfo.FileName = $PlinkPath
$StartInfo.Arguments = "-pw $Password -P $SSHPort ${Username}@${ServerIP} $Command"
$StartInfo.UseShellExecute = $false
$StartInfo.RedirectStandardOutput = $true
$StartInfo.RedirectStandardError = $true
$StartInfo.CreateNoWindow = $true
$Process = New-Object System.Diagnostics.Process
$Process.StartInfo = $StartInfo
try {
$Process.Start() | Out-Null
$Process.WaitForExit($TimeoutMs)
$Output = $Process.StandardOutput.ReadToEnd()
$StdErr = $Process.StandardError.ReadToEnd()
return @{
Success = ($Process.ExitCode -eq 0)
Output = $Output
Error = $StdErr
ExitCode = $Process.ExitCode
}
}
catch {
return @{
Success = $false
Output = ""
Error = $_.Exception.Message
ExitCode = -1
}
}
}
# Configuration
$ServerIP = "192.168.5.52"
$Username = "root"
$Password = "Ubains@123"
$SSHPort = 22
$DeployResults = @{
Connection = ""
ServerInfo = @{}
ContainerStatus = @{}
ServiceLogs = @{}
APITests = @{}
}
# Start deployment
Write-Log "========================================" "STEP"
Write-Log "New Unified Platform Deployment Script" "STEP"
Write-Log "Target: ${ServerIP} (X86)" "STEP"
Write-Log "Start: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" "STEP"
Write-Log "========================================" "STEP"
# Step 1: Test SSH connection
Write-Log "Step 1: Testing SSH connection" "STEP"
$TestResult = Invoke-SSHCommand -Command "echo 'connection_ok'"
if ($TestResult.Output -match "connection_ok") {
Write-Log "SSH connection successful" "OK"
$DeployResults.Connection = "成功"
} else {
Write-Log "SSH connection failed: $($TestResult.Error)" "ERROR"
exit 1
}
# Step 2: Get server information
Write-Log "`nStep 2: Getting server information" "STEP"
$OSInfo = Invoke-SSHCommand -Command "uname -a"
$DeployResults.ServerInfo.OS = $OSInfo.Output.Trim()
Write-Log "OS: $($DeployResults.ServerInfo.OS)" "INFO"
$DiskInfo = Invoke-SSHCommand -Command "df -h /home | awk 'NR==2 {print \$4}'"
$DeployResults.ServerInfo.DiskSpace = $DiskInfo.Output.Trim()
Write-Log "Home disk space: $($DeployResults.ServerInfo.DiskSpace)" "INFO"
# Check platform type
$PlatformCheck = Invoke-SSHCommand -Command "test -d /data/services && echo 'new' || echo 'old'"
$DeployResults.ServerInfo.PlatformType = $PlatformCheck.Output.Trim()
Write-Log "Platform type: $($DeployResults.ServerInfo.PlatformType)" "INFO"
# Step 3: Check Docker status
Write-Log "`nStep 3: Checking Docker status" "STEP"
$DockerCheck = Invoke-SSHCommand -Command "docker ps --format 'table {{.Names}}\t{{.Status}}' 2>&1"
if ($DockerCheck.ExitCode -eq 0) {
Write-Log "Docker is running" "OK"
Write-Host "`n========== Container Status ==========" -ForegroundColor Cyan
Write-Host $DockerCheck.Output
Write-Host "========== Container Status End ==========`n" -ForegroundColor Cyan
# Parse container status
$Lines = $DockerCheck.Output -split "`n"
foreach ($Line in $Lines) {
if ($Line -match "(\S+)\s+(\S+)") {
$Name = $Matches[1]
$Status = $Matches[2]
if ($Name -ne "NAMES") {
$DeployResults.ContainerStatus[$Name] = $Status
}
}
}
} else {
Write-Log "Docker is not running or not accessible" "WARN"
$DeployResults.ContainerStatus.Error = "Docker不可用"
}
# Step 4: Check service logs
Write-Log "`nStep 4: Checking service logs" "STEP"
$LogPaths = @{
"ExtAPI" = "/data/services/api/java-meeting/java-meeting-extapi/logs/ubains-INFO-AND-ERROR.log"
"InnerAPI" = "/data/services/api/java-meeting/java-meeting2.0/logs/ubains-INFO-AND-ERROR.log"
"Monitor" = "/data/services/api/python-cmdb/log/uinfo.log"
"Voice" = "/data/services/api/python-voice/log/uinfo.log"
}
foreach ($LogName in $LogPaths.Keys) {
$LogPath = $LogPaths[$LogName]
Write-Log "Checking $LogName log..." "INFO"
$LogResult = Invoke-SSHCommand -Command "tail -50 '$LogPath' 2>/dev/null || echo 'not_found'"
if ($LogResult.Output -match "not_found") {
Write-Log "$LogName log file not found" "WARN"
$DeployResults.ServiceLogs[$LogName] = "文件不存在"
} elseif ($LogName -eq "ExtAPI" -and $LogResult.Output -match "SYSTEMVERSION") {
Write-Log "$LogName log is normal (version detected)" "OK"
$DeployResults.ServiceLogs[$LogName] = "正常"
} elseif ($LogResult.Output -match "ERROR|Exception|Failed") {
Write-Log "$LogName log contains errors" "WARN"
$DeployResults.ServiceLogs[$LogName] = "发现异常"
} else {
Write-Log "$LogName log appears normal" "OK"
$DeployResults.ServiceLogs[$LogName] = "正常"
}
}
# Step 5: Test API endpoints
Write-Log "`nStep 5: Testing service endpoints" "STEP"
$APITests = @{
"ExtAPI" = @{ URL = "https://${ServerIP}/exapi/message/getMsgPageList"; Expected = "A0076" }
"Meeting" = @{ URL = "https://${ServerIP}/meetingV3/api/systemConfiguration/globalConfig?companyNumber=CN-SZ-00-0201"; Expected = "A0078" }
"Monitor" = @{ URL = "https://${ServerIP}/monitor/api2/api/servermonitor/"; Expected = "40000014" }
"Voice" = @{ URL = "https://${ServerIP}/voice/api/iflytek/roommaster?company_id=1&user_id=8&company_secret=57d00f9f-020f-5f1f-b788-55fae843bceb&getall=1"; Expected = "40000003" }
}
foreach ($APIName in $APITests.Keys) {
$API = $APITests[$APIName]
Write-Log "Testing $APIName endpoint..." "INFO"
$CurlResult = Invoke-SSHCommand -Command "curl -k '$($API.URL)' 2>/dev/null" -TimeoutMs 60000
if ($CurlResult.Output -match $API.Expected) {
Write-Log "$APIName endpoint is normal" "OK"
$DeployResults.APITests[$APIName] = "正常"
} elseif ($CurlResult.Output -match "nginx|Error") {
Write-Log "$APIName endpoint returns error page" "WARN"
$DeployResults.APITests[$APIName] = "异常"
} else {
Write-Log "$APIName endpoint: unknown response" "WARN"
$DeployResults.APITests[$APIName] = "未知"
}
}
# Step 6: Generate report
Write-Log "`nStep 6: Generating deployment report" "STEP"
$ReportContent = @"
# New Unified Platform Deployment Report
## Basic Information
- Server IP: $ServerIP
- Architecture: X86
- Deployment Time: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
## Deployment Results
### 1. SSH Connection
- Status: $($DeployResults.Connection)
### 2. Server Information
- OS: $($DeployResults.ServerInfo.OS)
- Disk Space: $($DeployResults.ServerInfo.DiskSpace)
- Platform: $($DeployResults.ServerInfo.PlatformType)
### 3. Container Status
"@
foreach ($Container in $DeployResults.ContainerStatus.Keys) {
$ReportContent += "`n- $Container : $($DeployResults.ContainerStatus[$Container])"
}
$ReportContent += @"
### 4. Service Logs
"@
foreach ($Log in $DeployResults.ServiceLogs.Keys) {
$ReportContent += "`n- $Log : $($DeployResults.ServiceLogs[$Log])"
}
$ReportContent += @"
### 5. API Tests
"@
foreach ($API in $DeployResults.APITests.Keys) {
$ReportContent += "`n- $API : $($DeployResults.APITests[$API])"
}
$ReportContent += @"
## System Access Addresses
- Frontend: https://${ServerIP}/
- Maintenance: https://${ServerIP}/#/LoginConfig
- Backend: https://${ServerIP}/#/LoginAdmin
---
Report Generated: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
"@
$ReportFile = Join-Path $ReportsDir "${ServerIP}_deployment_report_$(Get-Date -Format 'yyyyMMdd_HHmmss').md"
$ReportContent | Out-File -FilePath $ReportFile -Encoding UTF8 -Force
Write-Log "Deployment report generated: $ReportFile" "OK"
# Completion
Write-Log "`n========================================" "OK"
Write-Log "Deployment check completed!" "OK"
Write-Log "========================================" "OK"
# Monitor All Systems Deployment
$PlinkPath = "E:\GithubData\ubains-module-test\AuxiliaryTool\ScriptTool\RemoteDeploy\plink.exe"
Write-Host "========================================" -ForegroundColor Cyan
Write-Host "Monitoring All Systems Deployment" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
Write-Host ""
function Invoke-SSH {
param([string]$Command)
$psi = New-Object System.Diagnostics.ProcessStartInfo
$psi.FileName = $PlinkPath
$psi.Arguments = "-pw Ubains@123 -P 22 root@192.168.5.52 $Command"
$psi.UseShellExecute = $false
$psi.RedirectStandardOutput = $true
$psi.RedirectStandardError = $true
$psi.CreateNoWindow = $true
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $psi
$p.Start() | Out-Null
$p.WaitForExit(60000)
return $p.StandardOutput.ReadToEnd()
}
# Check if deployment script is still running
$running = Invoke-SSH -Command "ps aux | grep deploy_all_complete | grep -v grep | wc -l"
if ($running.Trim() -eq "1") {
Write-Host "Deployment Status: RUNNING" -ForegroundColor Green
Write-Host ""
# Show recent log lines
Write-Host "Recent deployment log:" -ForegroundColor Gray
Write-Host "========================================" -ForegroundColor Gray
$log = Invoke-SSH -Command "tail -30 /data/offline_auto_unifiedPlatform/new_auto_script.log 2>/dev/null || tail -30 /var/log/deploy/deploy.log 2>/dev/null || echo 'Log not available'"
Write-Host $log
} else {
Write-Host "Deployment Status: COMPLETED or NOT RUNNING" -ForegroundColor Yellow
Write-Host ""
# Show full log
Write-Host "Full deployment log:" -ForegroundColor Gray
Write-Host "========================================" -ForegroundColor Gray
$log = Invoke-SSH -Command "tail -100 /data/offline_auto_unifiedPlatform/new_auto_script.log 2>/dev/null || tail -100 /var/log/deploy/deploy.log 2>/dev/null"
Write-Host $log
}
Write-Host ""
Write-Host "========================================" -ForegroundColor Gray
Write-Host "Services Status:" -ForegroundColor Yellow
Write-Host "========================================" -ForegroundColor Gray
# Check Docker containers
$docker = Invoke-SSH -Command "docker ps --format 'table {{.Names}}\t{{.Status}}' 2>/dev/null || echo 'Docker not available'"
Write-Host $docker
Write-Host ""
Write-Host "========================================" -ForegroundColor Gray
Write-Host "Java Services:" -ForegroundColor Yellow
Write-Host "========================================" -ForegroundColor Gray
# Check Java processes
$java = Invoke-SSH -Command "ps aux | grep java | grep -v grep | wc -l"
Write-Host "Total Java processes: $($java.Trim())" -ForegroundColor Cyan
Write-Host ""
Write-Host "========================================" -ForegroundColor Gray
Write-Host "Quick Commands:" -ForegroundColor Yellow
Write-Host "========================================" -ForegroundColor Gray
Write-Host "SSH to server: ssh root@192.168.5.52" -ForegroundColor White
Write-Host "Monitor deployment log: tail -f /data/offline_auto_unifiedPlatform/new_auto_script.log" -ForegroundColor White
Write-Host "Check services: docker ps" -ForegroundColor White
Write-Host "========================================" -ForegroundColor Gray
# Simple Deployment Monitor
$PlinkPath = "E:\GithubData\ubains-module-test\AuxiliaryTool\ScriptTool\RemoteDeploy\plink.exe"
Write-Host "========================================" -ForegroundColor Cyan
Write-Host "Deployment Status Monitor" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
Write-Host ""
function Invoke-SSH {
param([string]$Command)
$psi = New-Object System.Diagnostics.ProcessStartInfo
$psi.FileName = $PlinkPath
$psi.Arguments = "-pw Ubains@123 -P 22 root@192.168.5.52 $Command"
$psi.UseShellExecute = $false
$psi.RedirectStandardOutput = $true
$psi.RedirectStandardError = $true
$psi.CreateNoWindow = $true
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $psi
$p.Start() | Out-Null
$p.WaitForExit(60000)
return $p.StandardOutput.ReadToEnd()
}
# Check if deployment is still running
$running = Invoke-SSH -Command "ps aux | grep new_auto.sh | grep -v grep | wc -l"
if ($running.Trim() -eq "1") {
Write-Host "Deployment Status: RUNNING" -ForegroundColor Green
} else {
Write-Host "Deployment Status: COMPLETED or STOPPED" -ForegroundColor Yellow
}
Write-Host ""
# Show recent log output
Write-Host "Recent deployment log (last 30 lines):" -ForegroundColor Gray
Write-Host "========================================" -ForegroundColor Gray
$log = Invoke-SSH -Command "tail -30 /var/log/deploy/deploy.log 2>/dev/null || tail -30 /data/logs/new_auto_script.log 2>/dev/null || echo 'Log not found'"
Write-Host $log
Write-Host ""
Write-Host "========================================" -ForegroundColor Gray
Write-Host "Quick Commands:" -ForegroundColor Yellow
Write-Host "========================================" -ForegroundColor Gray
Write-Host "SSH to server: ssh root@192.168.5.52" -ForegroundColor White
Write-Host "Monitor log: tail -f /var/log/deploy/deploy.log" -ForegroundColor White
Write-Host "Check process: ps aux | grep new_auto.sh" -ForegroundColor White
Write-Host "Check Docker: docker ps" -ForegroundColor White
Write-Host "========================================" -ForegroundColor Gray
import paramiko
import time
import sys
from datetime import datetime
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect('192.168.5.52', username='root', password='Ubains@123', timeout=30)
# 启动部署脚本
print('[{}] 启动部署脚本: new_auto.sh --all'.format(datetime.now().strftime('%H:%M:%S')))
stdin, stdout, stderr = client.exec_command(
'cd /data/offline_auto_unifiedPlatform && ./new_auto.sh --all',
get_pty=True,
timeout=3600
)
# 监控输出
last_output = time.time()
while True:
if stdout.channel.exit_status_ready():
exit_code = stdout.channel.exit_status
print('[{}] 部署脚本退出,退出码: {}'.format(datetime.now().strftime('%H:%M:%S'), exit_code))
break
try:
if stdout.channel.recv_ready():
chunk = stdout.channel.recv(4096).decode('utf-8', errors='ignore')
for line in chunk.split('
'):
if any(kw in line for kw in ['部署', '安装', '完成', '错误', '容器', 'ERROR', '服务']):
print('[部署] {}'.format(line.strip()))
last_output = time.time()
except:
pass
if time.time() - last_output > 300:
elapsed = int((time.time() - start_time) / 60) if 'start_time' in locals() else 0
print('[{}] 部署进行中... 约{}分钟'.format(datetime.now().strftime('%H:%M:%S'), elapsed))
last_output = time.time()
time.sleep(5)
client.close()
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
部署进度监控脚本
"""
import paramiko
import time
import sys
from datetime import datetime
def check_deployment_status():
"""检查部署状态"""
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect('192.168.5.52', username='root', password='Ubains@123', timeout=30)
print(f"\n{'='*70}")
print(f"部署进度监控 - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print(f"{'='*70}")
# 1. 检查脚本进程
stdin, stdout, stderr = client.exec_command('ps aux | grep new_auto.sh | grep -v grep')
process_info = stdout.read().decode('utf-8', errors='ignore').strip()
if process_info:
print("[进程] 部署脚本正在运行")
# 解析CPU和内存使用
parts = process_info.split()
if len(parts) >= 10:
cpu = parts[2]
mem = parts[3]
print(f" CPU: {cpu}, 内存: {mem}")
else:
print("[进程] 部署脚本已结束或未运行")
# 2. 检查Docker容器
stdin, stdout, stderr = client.exec_command('docker ps --format "{{.Names}}" 2>/dev/null | wc -l')
container_count = int(stdout.read().decode().strip())
print(f"[容器] 运行中: {container_count} 个")
if container_count > 0:
stdin, stdout, stderr = client.exec_command('docker ps --format "table {{.Names}}\t{{.Status}}"')
containers = stdout.read().decode('utf-8', errors='ignore')
print("\n容器列表:")
for line in containers.split('\n')[:11]: # 最多显示10个
if line.strip():
print(f" {line}")
# 3. 检查服务日志
log_paths = [
("预定对外", "/data/services/api/java-meeting/java-meeting-extapi/logs/ubains-INFO-AND-ERROR.log"),
("预定对内", "/data/services/api/java-meeting/java-meeting2.0/logs/ubains-INFO-AND-ERROR.log"),
]
print("\n[日志] 服务状态检查:")
for service_name, log_path in log_paths:
stdin, stdout, stderr = client.exec_command(f'tail -50 {log_path} 2>/dev/null | grep -i "SYSTEMVERSION\\|启动\\|started" || echo "未找到"')
result = stdout.read().decode('utf-8', errors='ignore').strip()
if 'SYSTEMVERSION' in result or '启动' in result:
print(f" {service_name}: ✓ 服务已启动")
elif result == "未找到":
print(f" {service_name}: 等待启动...")
else:
print(f" {service_name}: 检查中...")
# 4. 检查网络端口
print("\n[网络] 端口监听状态:")
ports = [
("预定对外", 8080),
("预定对内", 8081),
("运维服务", 8002),
("讯飞服务", 8003),
]
for service_name, port in ports:
stdin, stdout, stderr = client.exec_command(f'netstat -tlnp 2>/dev/null | grep ":{port}" || echo ""')
result = stdout.read().decode('utf-8', errors='ignore').strip()
if result:
print(f" {service_name} (端口{port}): ✓ 监听中")
else:
print(f" {service_name} (端口{port}): 未监听")
client.close()
def main():
print("开始监控部署进度...")
print("按 Ctrl+C 停止监控")
check_interval = 60 # 每分钟检查一次
count = 0
max_checks = 60 # 最多监控60分钟
try:
while count < max_checks:
check_deployment_status()
count += 1
if count < max_checks:
print(f"\n等待 {check_interval} 秒后下次检查... ({count}/{max_checks})")
time.sleep(check_interval)
print("\n监控达到最大时长,结束监控")
except KeyboardInterrupt:
print("\n\n监控已停止")
if __name__ == '__main__':
main()
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
部署监控脚本 - 实时监控部署进度
"""
import sys
import time
import subprocess
from datetime import datetime, timedelta
def run_ssh_command(command):
"""执行SSH命令"""
plink_path = r"E:\GithubData\ubains-module-test\AuxiliaryTool\ScriptTool\RemoteDeploy\plink.exe"
psi = subprocess.Popen(
[plink_path, "-pw", "Ubains@123", "-P", "22", "root@192.168.5.52", command],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
creationflags=subprocess.CREATE_NO_WINDOW
)
stdout, stderr = psi.communicate(timeout=30)
return stdout.decode('utf-8', errors='ignore'), stderr.decode('utf-8', errors='ignore')
def main():
print("=" * 50)
print("部署进度监控")
print("=" * 50)
print(f"开始时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print()
start_time = time.time()
max_monitor_time = 2700 # 45分钟监控时间
check_count = 0
while time.time() - start_time < max_monitor_time:
check_count += 1
current_time = datetime.now().strftime('%H:%M:%S')
elapsed = int(time.time() - start_time)
print(f"\n[{current_time}] 检查 #{check_count} (已监控: {elapsed}秒/{int(max_monitor_time/60)}分钟)")
print("-" * 50)
try:
# 检查部署进程
stdout, stderr = run_ssh_command('ps aux | grep new_auto | grep -v grep')
if 'new_auto.sh' in stdout:
# 解析进程信息
lines = stdout.strip().split('\n')
for line in lines:
if 'new_auto.sh' in line:
parts = line.split()
if len(parts) >= 9:
pid = parts[1]
cpu = parts[2]
mem = parts[3]
print(f"[运行中] PID: {pid}, CPU: {cpu}%, MEM: {mem}%")
else:
print("[完成] 部署进程已结束")
break
# 检查容器状态
stdout, stderr = run_ssh_command('docker ps --format "{{.Names}}"')
containers = [line for line in stdout.strip().split('\n') if line]
container_count = len(containers)
if container_count > 0:
print(f"[容器] 运行中: {container_count}个")
for container in containers[:10]: # 最多显示10个
print(f" - {container}")
else:
print("[容器] 尚未启动")
# 检查Docker镜像
stdout, stderr = run_ssh_command('docker images --format "{{.Repository}}" | grep -E "ubains|meeting|monitor" | wc -l')
image_count = stdout.strip()
print(f"[镜像] 已下载: {image_count}个")
# 预计完成时间
if container_count >= 5:
print("\n[SUCCESS] 部署成功!已启动所有容器")
break
elif container_count > 0:
remaining_time = max_monitor_time - elapsed
estimated_minutes = int(remaining_time / 60)
print(f"[进度] 容器启动中... 预计还需{estimated_minutes}分钟")
else:
remaining_time = max_monitor_time - elapsed
estimated_minutes = int(remaining_time / 60)
print(f"[进度] 正在部署... 预计还需{estimated_minutes}分钟")
except Exception as e:
print(f"[ERROR] 检查失败: {str(e)}")
# 等待30秒后再次检查
print("\n等待30秒后继续监控...")
time.sleep(30)
# 最终状态检查
print("\n" + "=" * 50)
print("部署完成 - 最终状态")
print("=" * 50)
try:
# 容器状态
stdout, stderr = run_ssh_command('docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"')
print("\n容器详细状态:")
print(stdout)
# 服务状态
stdout, stderr = run_ssh_command('docker ps | wc -l')
final_count = int(stdout.strip()) - 1
print(f"\n运行中的容器总数: {final_count}")
if final_count >= 5:
print("\n[SUCCESS] 部署成功完成")
print("\n后续步骤:")
print("1. 系统授权: 访问 https://192.168.5.52/#/LoginConfig")
print(" 账号: superadmin / Ubains@1357")
print(" 验证码: csba")
print("\n2. 创建管理员: 为'自动化'公司创建admin用户")
print("\n3. 验收测试: 检查服务接口")
return 0
else:
print("\n[WARN] 部署未完全完成,请检查日志")
return 1
except Exception as e:
print(f"\n[ERROR] 最终状态检查失败: {str(e)}")
return 1
if __name__ == '__main__':
sys.exit(main())
$PlinkPath = "E:\GithubData\ubains-module-test\AuxiliaryTool\ScriptTool\RemoteDeploy\plink.exe"
$psi = New-Object System.Diagnostics.ProcessStartInfo
$psi.FileName = $PlinkPath
$psi.Arguments = "-pw Ubains@123 -P 22 root@192.168.5.52 'ps aux | grep new_auto.sh | grep -v grep && echo ---RUNNING--- || echo ---COMPLETED---'"
$psi.UseShellExecute = $false
$psi.RedirectStandardOutput = $true
$psi.RedirectStandardError = $true
$psi.CreateNoWindow = $true
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $psi
$p.Start() | Out-Null
$p.WaitForExit(60000)
$result = $p.StandardOutput.ReadToEnd()
Write-Host $result
# Re-run Deployment Script with Full System Selection
$PlinkPath = "E:\GithubData\ubains-module-test\AuxiliaryTool\ScriptTool\RemoteDeploy\plink.exe"
Write-Host "========================================" -ForegroundColor Cyan
Write-Host "Re-running Deployment with System Selection" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
Write-Host ""
Write-Host "This will connect to the server and run the deployment script interactively." -ForegroundColor Yellow
Write-Host "When prompted to select systems, please choose '全部系统' (All Systems)" -ForegroundColor Yellow
Write-Host ""
Write-Host "Press Enter to continue..." -ForegroundColor Gray
Read-Host
Write-Host ""
Write-Host "Connecting to server 192.168.5.52..." -ForegroundColor Cyan
Write-Host "You will be prompted for deployment options in the SSH session." -ForegroundColor Yellow
Write-Host ""
# Start interactive SSH session
$psi = New-Object System.Diagnostics.ProcessStartInfo
$psi.FileName = $PlinkPath
$psi.Arguments = "-pw Ubains@123 -P 22 root@192.168.5.52"
$psi.UseShellExecute = $true
$psi.RedirectStandardOutput = $false
$psi.RedirectStandardError = $false
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $psi
$p.Start() | Out-Null
$p.WaitForExit()
Write-Host ""
Write-Host "========================================" -ForegroundColor Green
Write-Host "SSH session completed" -ForegroundColor Green
Write-Host "========================================" -ForegroundColor Green
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
远程执行部署脚本
"""
import paramiko
import time
import sys
from datetime import datetime
def run_deployment():
"""执行部署脚本"""
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect('192.168.5.52', username='root', password='Ubains@123', timeout=30)
print("=" * 70)
print("开始执行部署: new_auto.sh --all")
print(f"时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print("=" * 70)
# 使用invoke_shell来执行交互式脚本
channel = client.invoke_shell()
channel.settimeout(300)
# 发送命令
time.sleep(1)
channel.send("cd /data/offline_auto_unifiedPlatform\n")
time.sleep(2)
channel.send("./new_auto.sh --all\n")
print("部署脚本已启动,开始监控输出...\n")
output_file = f"reports/192.168.5.52_deploy_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log"
# 监控输出
start_time = time.time()
last_progress_time = time.time()
buffer = ""
try:
while True:
if channel.exit_status_ready():
exit_code = channel.recv_exit_status()
print(f"\n[完成] 部署脚本退出,退出码: {exit_code}")
break
try:
if channel.recv_ready():
chunk = channel.recv(4096).decode('utf-8', errors='ignore')
buffer += chunk
# 实时打印关键信息
for line in chunk.split('\n'):
line = line.strip()
if line and any(kw in line for kw in [
'部署', '安装', '启动', '完成', '成功',
'失败', '错误', '容器', 'Docker', '服务',
'ERROR', 'WARN', 'INFO', '系统',
'middleware', 'database', 'redis', 'nginx'
]):
timestamp = datetime.now().strftime('%H:%M:%S')
print(f"[{timestamp}] {line}")
# 保存到文件
import os
os.makedirs('reports', exist_ok=True)
with open(output_file, 'a', encoding='utf-8') as f:
f.write(chunk)
except Exception as e:
pass
# 每分钟输出进度
elapsed = int(time.time() - start_time)
if elapsed > 0 and elapsed % 60 == 0:
progress_time = time.time()
if progress_time - last_progress_time >= 55:
print(f"\n[进度] 部署进行中... 已用时: {int(elapsed/60)}分钟")
last_progress_time = progress_time
# 超时检查(45分钟)
if elapsed > 2700:
print("\n[警告] 部署超时")
break
time.sleep(2)
except KeyboardInterrupt:
print("\n\n[中断] 部署被用户中断")
finally:
channel.close()
client.close()
total_time = int((time.time() - start_time) / 60)
print(f"\n部署执行完成,总用时: {total_time} 分钟")
print(f"日志已保存到: {output_file}")
return 0
if __name__ == '__main__':
sys.exit(run_deployment())
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
简单部署测试 - 仅测试部署准备
"""
import sys
import os
# 添加当前目录到路径
sys.path.insert(0, os.path.dirname(__file__))
from auto_deployment_python import RemoteDeploymentAutomation
def main():
print("部署准备测试")
print("=" * 50)
config = {
'host': '192.168.5.52',
'username': 'root',
'password': 'Ubains@123',
'license_path': r'E:\自动化部署\X86-5.52\license.zip'
}
deployment = RemoteDeploymentAutomation(**config)
# 测试SSH连接
print("测试SSH连接...")
if deployment.connect_ssh():
print("[OK] SSH连接成功")
# 测试环境准备
print("测试环境准备...")
if deployment.prepare_deployment_environment():
print("[OK] 环境准备完成")
# 测试交互式连接
print("测试交互式连接...")
if deployment.connect_ssh_interactive():
print("[OK] 交互式连接成功")
# 发送测试命令
print("发送测试命令...")
deployment.ssh_shell.send("echo 'Test successful'\n")
import time
time.sleep(2)
# 读取响应
output = ""
try:
while deployment.ssh_shell.recv_ready():
output += deployment.ssh_shell.recv(4096).decode('utf-8', errors='ignore')
except:
pass
if 'Test successful' in output:
print("[OK] 测试命令执行成功")
print("响应:", output.strip())
else:
print("[ERROR] 测试命令执行失败")
print("输出:", output)
else:
print("[ERROR] 交互式连接失败")
else:
print("[ERROR] 环境准备失败")
deployment.ssh_client.close()
return 0
else:
print("[ERROR] SSH连接失败")
return 1
if __name__ == '__main__':
sys.exit(main())
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
部署脚本测试 - 验证基本功能
"""
import sys
import os
# 添加当前目录到路径
sys.path.insert(0, os.path.dirname(__file__))
from auto_deployment_python import RemoteDeploymentAutomation
def test_ssh_connection():
"""测试SSH连接"""
print("=" * 50)
print("测试1: SSH连接")
print("=" * 50)
config = {
'host': '192.168.5.52',
'username': 'root',
'password': 'Ubains@123',
'license_path': r'E:\自动化部署\X86-5.52\license.zip'
}
deployment = RemoteDeploymentAutomation(**config)
# 测试paramiko连接
if deployment.connect_ssh():
print("[OK] SSH连接成功 (paramiko)")
# 测试环境准备
if deployment.prepare_deployment_environment():
print("[OK] 部署环境检查完成")
# 检查部署脚本
stdin, stdout, stderr = deployment.ssh_client.exec_command('ls -la /data/offline_auto_unifiedPlatform/*.sh')
scripts = stdout.read().decode('utf-8', errors='ignore')
print("\n部署脚本:")
print(scripts)
deployment.ssh_client.close()
return True
else:
print("[ERROR] SSH连接失败")
return False
def test_deployment_script_status():
"""测试部署脚本状态"""
print("\n" + "=" * 50)
print("测试2: 部署脚本状态")
print("=" * 50)
config = {
'host': '192.168.5.52',
'username': 'root',
'password': 'Ubains@123',
'license_path': r'E:\自动化部署\X86-5.52\license.zip'
}
deployment = RemoteDeploymentAutomation(**config)
if deployment.connect_ssh():
# 检查部署脚本权限
stdin, stdout, stderr = deployment.ssh_client.exec_command('ls -l /data/offline_auto_unifiedPlatform/new_auto.sh')
script_info = stdout.read().decode('utf-8', errors='ignore')
print(f"部署脚本信息: {script_info.strip()}")
# 检查是否有运行中的部署进程
stdin, stdout, stderr = deployment.ssh_client.exec_command('ps aux | grep new_auto | grep -v grep')
running_processes = stdout.read().decode('utf-8', errors='ignore')
if running_processes.strip():
print("[WARN] 检测到运行中的部署进程:")
print(running_processes)
else:
print("[OK] 无运行中的部署进程")
deployment.ssh_client.close()
return True
return False
def test_web_connectivity():
"""测试Web连接"""
print("\n" + "=" * 50)
print("测试3: Web连接")
print("=" * 50)
import requests
requests.packages.urllib3.disable_warnings()
config = {
'host': '192.168.5.52',
'username': 'root',
'password': 'Ubains@123',
'license_path': r'E:\自动化部署\X86-5.52\license.zip'
}
deployment = RemoteDeploymentAutomation(**config)
# 测试维护平台连接
urls = [
('维护平台', 'https://192.168.5.52/#/LoginConfig'),
('后台管理', 'https://192.168.5.52/#/LoginAdmin'),
('前台页面', 'https://192.168.5.52/'),
]
for name, url in urls:
try:
response = requests.get(url, verify=False, timeout=10)
if response.status_code == 200:
print(f"[OK] {name}: 可访问 ({url})")
else:
print(f"[WARN] {name}: 状态码 {response.status_code}")
except Exception as e:
print(f"[ERROR] {name}: {str(e)}")
return True
def main():
"""主测试函数"""
print("Python自动化部署脚本 - 功能测试")
print("目标服务器: 192.168.5.52")
print()
results = []
# 测试SSH连接
results.append(("SSH连接", test_ssh_connection()))
# 测试部署脚本状态
results.append(("部署脚本状态", test_deployment_script_status()))
# 测试Web连接
results.append(("Web连接", test_web_connectivity()))
# 输出测试结果
print("\n" + "=" * 50)
print("测试结果汇总")
print("=" * 50)
for name, result in results:
status = "[OK] PASS" if result else "[ERROR] FAIL"
print(f"{name}: {status}")
all_passed = all(result for _, result in results)
if all_passed:
print("\n[OK] 所有测试通过!可以执行完整部署。")
else:
print("\n[WARN] 部分测试失败,请检查环境配置。")
return 0 if all_passed else 1
if __name__ == '__main__':
sys.exit(main())
# Upload and Deploy Script
# Author: Automation Team
# Date: 2026-05-14
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$PackagesDir = Join-Path $ScriptDir "packages"
$ReportsDir = Join-Path $ScriptDir "reports"
# Create directories
if (-not (Test-Path $PackagesDir)) { New-Item -ItemType Directory -Path $PackagesDir -Force | Out-Null }
if (-not (Test-Path $ReportsDir)) { New-Item -ItemType Directory -Path $ReportsDir -Force | Out-Null }
$LogFile = Join-Path $ReportsDir "upload_$(Get-Date -Format 'yyyyMMdd_HHmmss').log"
function Write-Log {
param([string]$Message, [string]$Color = "White")
$Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$LogMessage = "[$Timestamp] $Message"
Write-Host $LogMessage -ForegroundColor $Color
Add-Content -Path $LogFile -Value $LogMessage
}
function Invoke-SSHCommand {
param([string]$Command)
$PlinkPath = Join-Path $ScriptDir "plink.exe"
$psi = New-Object System.Diagnostics.ProcessStartInfo
$psi.FileName = $PlinkPath
$psi.Arguments = "-pw $Password -P $SSHPort ${Username}@${ServerIP} $Command"
$psi.UseShellExecute = $false
$psi.RedirectStandardOutput = $true
$psi.RedirectStandardError = $true
$psi.CreateNoWindow = $true
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $psi
$p.Start() | Out-Null
$p.WaitForExit(60000)
return $p.StandardOutput.ReadToEnd()
}
function Upload-File {
param([string]$LocalPath, [string]$RemotePath)
$PscpPath = Join-Path $ScriptDir "pscp.exe"
$psi = New-Object System.Diagnostics.ProcessStartInfo
$psi.FileName = $PscpPath
$psi.Arguments = "-pw $Password -P $SSHPort -batch '$LocalPath' '${Username}@${ServerIP}:${RemotePath}'"
$psi.UseShellExecute = $false
$psi.RedirectStandardOutput = $true
$psi.RedirectStandardError = $true
$psi.CreateNoWindow = $true
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $psi
$p.Start() | Out-Null
$p.WaitForExit(300000)
return $p.ExitCode -eq 0
}
# Configuration
$ServerIP = "192.168.5.52"
$Username = "root"
$Password = "Ubains@123"
$SSHPort = 22
# Network share path
$NetworkShare = "\\192.168.9.9\发布版本\03服务器部署\临时使用-新统一平台\X86部署包\全量版"
Write-Log "========================================" "Cyan"
Write-Log "Upload and Deploy Script" "Cyan"
Write-Log "========================================" "Cyan"
# Step 1: Copy from network share
Write-Log "Step 1: Copying deployment package from network share..." "Yellow"
Write-Log "Source: $NetworkShare" "Gray"
if (-not (Test-Path $NetworkShare)) {
Write-Log "Network share path not accessible!" "Red"
Write-Log "Please ensure:" "Yellow"
Write-Log "1. You are connected to the company network" "Yellow"
Write-Log "2. You have permission to access the share" "Yellow"
Write-Log "3. The network path is correct" "Yellow"
exit 1
}
# Clean local packages directory
if (Test-Path $PackagesDir) {
Remove-Item -Path "$PackagesDir\*" -Recurse -Force -ErrorAction SilentlyContinue
}
# Copy from network share
Write-Log "Copying files from network share (this may take a while)..." "Yellow"
try {
$Files = Get-ChildItem -Path $NetworkShare -Recurse -File -ErrorAction Stop
$TotalFiles = $Files.Count
$CopiedFiles = 0
foreach ($File in $Files) {
$RelativePath = $File.FullName.Substring($NetworkShare.Length + 1)
$DestPath = Join-Path $PackagesDir $RelativePath
$DestDir = Split-Path $DestPath
if (-not (Test-Path $DestDir)) {
New-Item -ItemType Directory -Path $DestDir -Force | Out-Null
}
Copy-Item -Path $File.FullName -Destination $DestPath -Force
$CopiedFiles++
if ($CopiedFiles % 10 -eq 0) {
Write-Progress -Activity "Copying deployment package" -Status "$CopiedFiles / $TotalFiles files" -PercentComplete (($CopiedFiles / $TotalFiles) * 100)
}
}
Write-Progress -Activity "Copying deployment package" -Completed
Write-Log "Copied $CopiedFiles files from network share" "Green"
$LocalPackageDir = $PackagesDir
}
catch {
Write-Log "Failed to copy from network share: $_" "Red"
Write-Log "Trying to list top-level directory..." "Yellow"
try {
$TopItems = Get-ChildItem -Path $NetworkShare -ErrorAction Stop
Write-Log "Found items in network share:" "Gray"
foreach ($Item in $TopItems) {
Write-Log " - $($Item.Name) ($($Item.Length) bytes)" "Gray"
}
}
catch {
Write-Log "Cannot access network share" "Red"
}
exit 1
}
# Step 2: Create deploy directory on server
Write-Log "`nStep 2: Creating deploy directory on server..." "Yellow"
Invoke-SSHCommand -Command "mkdir -p /home/deploy"
Write-Log "Deploy directory created" "Green"
# Step 3: Upload deployment package
Write-Log "`nStep 3: Uploading deployment package to server..." "Yellow"
$UploadFiles = Get-ChildItem -Path $LocalPackageDir -Recurse -File
$TotalUpload = $UploadFiles.Count
$UploadedCount = 0
$FailedUploads = @()
foreach ($File in $UploadFiles) {
$RelativePath = $File.FullName.Substring($LocalPackageDir.Length + 1)
$RemotePath = "/home/deploy/$RelativePath"
$RemoteDir = "/home/deploy/" + (Split-Path $RelativePath -Parent)
# Create remote directory
Invoke-SSHCommand -Command "mkdir -p '$RemoteDir'"
# Upload file
$Success = Upload-File -LocalPath $File.FullName -RemotePath $RemotePath
if ($Success) {
$UploadedCount++
} else {
$FailedUploads += $RelativePath
}
if ($UploadedCount % 10 -eq 0) {
Write-Progress -Activity "Uploading to server" -Status "$UploadedCount / $TotalUpload files" -PercentComplete (($UploadedCount / $TotalUpload) * 100)
}
}
Write-Progress -Activity "Uploading to server" -Completed
Write-Log "Uploaded $UploadedCount files to server" "Green"
if ($FailedUploads.Count -gt 0) {
Write-Log "Failed to upload $($FailedUploads.Count) files:" "Yellow"
foreach ($Failed in $FailedUploads) {
Write-Log " - $Failed" "Gray"
}
}
# Step 4: Check uploaded files
Write-Log "`nStep 4: Verifying uploaded files..." "Yellow"
$ServerFiles = Invoke-SSHCommand -Command "find /home/deploy -type f | wc -l"
Write-Log "Files on server: $ServerFiles" "Green"
# Step 5: Find deployment script
Write-Log "`nStep 5: Looking for deployment script..." "Yellow"
$DeployScripts = Invoke-SSHCommand -Command "find /home/deploy -name '*.sh' -type f 2>/dev/null | head -10"
Write-Log "Found deployment scripts:" "Gray"
Write-Host $DeployScripts.Output
Write-Log "`n========================================" "Green"
Write-Log "Upload completed!" "Green"
Write-Log "========================================" "Green"
Write-Log "Next steps:" "Yellow"
Write-Log "1. SSH to server: ssh root@${ServerIP}" "Gray"
Write-Log "2. Go to deploy directory: cd /home/deploy" "Gray"
Write-Log "3. Run deployment script" "Gray"
Write-Log "========================================" "Green"
@echo off
setlocal enabledelayedexpansion
REM ========================================
REM Upload and Deploy Script
REM ========================================
set SCRIPT_DIR=%~dp0
set PACKAGES_DIR=%SCRIPT_DIR%packages
set REPORTS_DIR=%SCRIPT_DIR%reports
set SERVER_IP=192.168.5.52
set USERNAME=root
set PASSWORD=Ubains@123
set SSH_PORT=22
set NETWORK_SHARE=\\192.168.9.9\发布版本\03服务器部署\临时使用-新统一平台\X86部署包\全量版
echo ========================================
echo Upload and Deploy Script
echo ========================================
echo.
REM Create directories
if not exist "%PACKAGES_DIR%" mkdir "%PACKAGES_DIR%"
if not exist "%REPORTS_DIR%" mkdir "%REPORTS_DIR%"
REM Step 1: Check network share
echo Step 1: Checking network share...
echo Source: %NETWORK_SHARE%
if not exist "%NETWORK_SHARE%" (
echo ERROR: Network share not accessible!
echo.
echo Possible reasons:
echo 1. Not connected to company network
echo 2. No permission to access share
echo 3. Network path is incorrect
pause
exit /b 1
)
echo OK: Network share is accessible
echo.
REM Step 2: List files
echo Step 2: Listing files in network share...
dir "%NETWORK_SHARE%" /b
echo.
REM Step 3: Copy files locally
echo Step 3: Copying files locally...
echo This may take a while...
robocopy "%NETWORK_SHARE%" "%PACKAGES_DIR%" /E /NFL /NDL /NJH /NJS
if %ERRORLEVEL% LSS 8 (
echo OK: Files copied locally
) else (
echo WARNING: Robocopy reported some issues
)
echo.
REM Step 4: Create deploy directory on server
echo Step 4: Creating deploy directory on server...
plink.exe -pw %PASSWORD% -P %SSH_PORT% %USERNAME%@%SERVER_IP% "mkdir -p /home/deploy && echo 'OK'"
echo.
echo.
REM Step 5: Upload files to server
echo Step 5: Uploading files to server...
echo This may take a long time depending on file size...
echo.
echo Using pscp to upload files...
pscp.exe -pw %PASSWORD% -P %SSH_PORT% -batch -r "%PACKAGES_DIR%\*" %USERNAME%@%SERVER_IP%:/home/deploy/
echo.
echo Upload completed
echo.
REM Step 6: Verify upload
echo Step 6: Verifying upload...
plink.exe -pw %PASSWORD% -P %SSH_PORT% %USERNAME%@%SERVER_IP% "find /home/deploy -type f | wc -l"
echo.
REM Step 7: Find deployment scripts
echo Step 7: Looking for deployment scripts...
plink.exe -pw %PASSWORD% -P %SSH_PORT% %USERNAME%@%SERVER_IP% "find /home/deploy -name '*.sh' -type f 2>/dev/null | head -10"
echo.
echo ========================================
echo Upload completed!
echo ========================================
echo.
echo Next steps to complete deployment:
echo 1. SSH to server: ssh root@%SERVER_IP%
echo 2. Go to deploy directory: cd /home/deploy
echo 3. Find and run the deployment script
echo 4. Follow the deployment prompts
echo.
echo After deployment completes:
echo 1. Access maintenance platform: https://%SERVER_IP%/#/LoginConfig
echo 2. Enter verification code: csba
echo 3. Upload license file from network share
echo ========================================
echo.
pause
# Upload and Deploy Script - Simplified
# Author: Automation Team
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$PackagesDir = Join-Path $ScriptDir "packages"
$ReportsDir = Join-Path $ScriptDir "reports"
if (-not (Test-Path $PackagesDir)) { New-Item -ItemType Directory -Path $PackagesDir -Force | Out-Null }
if (-not (Test-Path $ReportsDir)) { New-Item -ItemType Directory -Path $ReportsDir -Force | Out-Null }
function Write-Log {
param([string]$Message, [string]$Color = "White")
$Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
Write-Host "[$Timestamp] $Message" -ForegroundColor $Color
}
function Invoke-SSHCommand {
param([string]$Command)
$PlinkPath = Join-Path $ScriptDir "plink.exe"
$Password = "Ubains@123"
$SSHPort = 22
$ServerIP = "192.168.5.52"
$Username = "root"
$psi = New-Object System.Diagnostics.ProcessStartInfo
$psi.FileName = $PlinkPath
$psi.Arguments = "-pw $Password -P $SSHPort ${Username}@${ServerIP} $Command"
$psi.UseShellExecute = $false
$psi.RedirectStandardOutput = $true
$psi.RedirectStandardError = $true
$psi.CreateNoWindow = $true
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $psi
$p.Start() | Out-Null
$p.WaitForExit(60000)
return $p.StandardOutput.ReadToEnd()
}
function Upload-File {
param([string]$LocalPath, [string]$RemotePath)
$PscpPath = Join-Path $ScriptDir "pscp.exe"
$Password = "Ubains@123"
$SSHPort = 22
$ServerIP = "192.168.5.52"
$Username = "root"
$psi = New-Object System.Diagnostics.ProcessStartInfo
$psi.FileName = $PscpPath
$psi.Arguments = "-pw $Password -P $SSHPort -batch '$LocalPath' '${Username}@${ServerIP}:${RemotePath}'"
$psi.UseShellExecute = $false
$psi.RedirectStandardOutput = $true
$psi.RedirectStandardError = $true
$psi.CreateNoWindow = $true
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $psi
$p.Start() | Out-Null
$p.WaitForExit(300000)
return $p.ExitCode -eq 0
}
# Network share path (using single quotes to avoid encoding issues)
$NetworkShare = '\\192.168.9.9\发布版本\03服务器部署\临时使用-新统一平台\X86部署包\全量版'
Write-Log "========================================" "Cyan"
Write-Log "Upload and Deploy Script" "Cyan"
Write-Log "========================================" "Cyan"
# Step 1: Check network share
Write-Log "Step 1: Checking network share..." "Yellow"
Write-Log "Source: $NetworkShare" "Gray"
if (-not (Test-Path $NetworkShare)) {
Write-Log "ERROR: Network share not accessible!" "Red"
Write-Log "" "Yellow"
Write-Log "Possible reasons:" "Yellow"
Write-Log "1. Not connected to company network" "Gray"
Write-Log "2. No permission to access share" "Gray"
Write-Log "3. Network path is incorrect" "Gray"
Write-Log "" "Yellow"
Write-Log "Please check the path and try again." "Yellow"
Read-Host "Press Enter to exit"
exit 1
}
Write-Log "Network share is accessible" "Green"
# Step 2: List files in network share
Write-Log "" "Yellow"
Write-Log "Step 2: Listing files in network share..." "Yellow"
try {
$Items = Get-ChildItem -Path $NetworkShare -ErrorAction Stop
Write-Log "Found $($Items.Count) items:" "Gray"
foreach ($Item in $Items) {
if ($Item.PSIsContainer) {
Write-Log " [DIR] $($Item.Name)" "Gray"
} else {
$Size = [math]::Round($Item.Length / 1MB, 2)
Write-Log " [FILE] $($Item.Name) ($Size MB)" "Gray"
}
}
}
catch {
Write-Log "ERROR: Failed to list files: $_" "Red"
Read-Host "Press Enter to exit"
exit 1
}
# Step 3: Create deploy directory on server
Write-Log "" "Yellow"
Write-Log "Step 3: Creating deploy directory on server..." "Yellow"
$Result = Invoke-SSHCommand -Command "mkdir -p /home/deploy && echo 'OK'"
if ($Result -match "OK") {
Write-Log "Deploy directory created successfully" "Green"
} else {
Write-Log "ERROR: Failed to create deploy directory" "Red"
Read-Host "Press Enter to exit"
exit 1
}
# Step 4: Upload deployment package
Write-Log "" "Yellow"
Write-Log "Step 4: Uploading deployment package..." "Yellow"
Write-Log "This may take a while depending on file size..." "Gray"
# Clean local packages directory
if (Test-Path $PackagesDir) {
Remove-Item -Path "$PackagesDir\*" -Recurse -Force -ErrorAction SilentlyContinue
}
# Copy files locally first (for faster processing)
Write-Log "Copying files locally first..." "Gray"
try {
robocopy $NetworkShare $PackagesDir /E /NFL /NDL /NJH /NJS | Out-Null
Write-Log "Files copied locally" "Green"
}
catch {
Write-Log "Warning: Robocopy had issues, trying alternative..." "Yellow"
Copy-Item -Path "$NetworkShare\*" -Destination $PackagesDir -Recurse -Force -ErrorAction SilentlyContinue
}
# Get files to upload
$UploadFiles = Get-ChildItem -Path $PackagesDir -Recurse -File
$TotalFiles = $UploadFiles.Count
$UploadedCount = 0
Write-Log "Total files to upload: $TotalFiles" "Gray"
# Upload files
foreach ($File in $UploadFiles) {
$RelativePath = $File.FullName.Substring($PackagesDir.Length + 1)
$RemotePath = "/home/deploy/$RelativePath"
$RemoteDir = Split-Path $RemotePath -Parent
# Create remote directory
Invoke-SSHCommand -Command "mkdir -p '$RemoteDir'" | Out-Null
# Upload file
$Success = Upload-File -LocalPath $File.FullName -RemotePath $RemotePath
if ($Success) {
$UploadedCount++
}
if ($UploadedCount % 50 -eq 0) {
$Percent = [math]::Round(($UploadedCount / $TotalFiles) * 100)
Write-Log "Progress: $UploadedCount / $TotalFiles ($Percent%)" "Gray"
}
}
Write-Log "Uploaded $UploadedCount files to server" "Green"
# Step 5: Verify upload
Write-Log "" "Yellow"
Write-Log "Step 5: Verifying upload..." "Yellow"
$ServerFiles = Invoke-SSHCommand -Command "find /home/deploy -type f | wc -l"
Write-Log "Files on server: $ServerFiles" "Green"
# Step 6: Find deployment scripts
Write-Log "" "Yellow"
Write-Log "Step 6: Looking for deployment scripts..." "Yellow"
$DeployScripts = Invoke-SSHCommand -Command "find /home/deploy -name '*.sh' -type f 2>/dev/null | head -10"
if ($DeployScripts) {
Write-Log "Found deployment scripts:" "Gray"
$DeployScripts -split "`n" | Where-Object { $_ -ne "" } | ForEach-Object {
Write-Log " $_" "Gray"
}
} else {
Write-Log "No deployment scripts found" "Yellow"
}
Write-Log "" "Green"
Write-Log "========================================" "Green"
Write-Log "Upload completed successfully!" "Green"
Write-Log "========================================" "Green"
Write-Log "" "Yellow"
Write-Log "Next steps to complete deployment:" "Yellow"
Write-Log "1. SSH to server: ssh root@192.168.5.52" "Gray"
Write-Log "2. Go to deploy directory: cd /home/deploy" "Gray"
Write-Log "3. Find and run the deployment script" "Gray"
Write-Log "4. Follow the deployment prompts" "Gray"
Write-Log "" "Gray"
Write-Log "After deployment completes:" "Yellow"
Write-Log "1. Access maintenance platform: https://192.168.5.52/#/LoginConfig" "Gray"
Write-Log "2. Enter verification code: csba" "Gray"
Write-Log "3. Upload license file from network share" "Gray"
Write-Log "========================================" "Green"
Read-Host "Press Enter to exit"
...@@ -3,12 +3,13 @@ ...@@ -3,12 +3,13 @@
""" """
X86服务器远程自动化部署脚本 X86服务器远程自动化部署脚本
严格按照PRD文档和部署操作指导执行 严格按照PRD文档和部署操作指导执行
禁止中断解压缩操作
""" """
import sys import sys
import os import os
import time import time
import subprocess import socket
import paramiko import paramiko
import requests import requests
from datetime import datetime from datetime import datetime
...@@ -17,6 +18,14 @@ from urllib3.exceptions import InsecureRequestWarning ...@@ -17,6 +18,14 @@ from urllib3.exceptions import InsecureRequestWarning
# 禁用SSL警告 # 禁用SSL警告
requests.packages.urllib3.disable_warnings(InsecureRequestWarning) requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
# 修复Windows控制台编码问题
if sys.platform == 'win32':
try:
sys.stdout.reconfigure(encoding='utf-8', errors='replace')
sys.stderr.reconfigure(encoding='utf-8', errors='replace')
except Exception:
pass
class X86AutoDeploy: class X86AutoDeploy:
def __init__(self): def __init__(self):
...@@ -24,31 +33,68 @@ class X86AutoDeploy: ...@@ -24,31 +33,68 @@ class X86AutoDeploy:
self.username = 'root' self.username = 'root'
self.password = 'Ubains@123' self.password = 'Ubains@123'
self.deploy_dir = '/data/offline_auto_unifiedPlatform' self.deploy_dir = '/data/offline_auto_unifiedPlatform'
self.deploy_log = '/data/offline_auto_unifiedPlatform/deploy_output.log'
self.ssh_client = None self.ssh_client = None
self.deploy_start_time = None
self.total_start_time = None self.total_start_time = None
self.deploy_start_time = None
self.log_file = None self.log_file = None
self.license_path = r'E:\自动化部署\X86-5.52\license.zip'
self.admin_user = 'superadmin'
self.admin_pass = 'Ubains@1357'
def log(self, message, level="INFO", print_only=False): def log(self, message, level="INFO"):
"""输出日志""" """输出日志到控制台和文件"""
timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S') timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
log_msg = f"[{timestamp}] [{level}] {message}" log_msg = f"[{timestamp}] [{level}] {message}"
try:
print(log_msg) print(log_msg)
except UnicodeEncodeError:
if self.log_file and not print_only: safe_msg = log_msg.encode('gbk', errors='replace').decode('gbk')
print(safe_msg)
if self.log_file:
try: try:
with open(self.log_file, 'a', encoding='utf-8') as f: with open(self.log_file, 'a', encoding='utf-8') as f:
f.write(log_msg + '\n') f.write(log_msg + '\n')
except: except Exception:
pass pass
def init_log_file(self): def init_log_file(self):
"""初始化日志文件""" """初始化日志文件"""
reports_dir = os.path.join(os.path.dirname(__file__), 'reports') reports_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'reports')
os.makedirs(reports_dir, exist_ok=True) os.makedirs(reports_dir, exist_ok=True)
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S') timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
self.log_file = os.path.join(reports_dir, f'{self.host}_deploy_{timestamp}.log') self.log_file = os.path.join(reports_dir, f'{self.host}_deploy_{timestamp}.log')
self.log(f"日志文件: {self.log_file}", print_only=True) self.log(f"日志文件: {self.log_file}")
def exec_cmd(self, cmd, timeout=300):
"""执行SSH命令并等待返回"""
try:
stdin, stdout, stderr = self.ssh_client.exec_command(cmd, timeout=timeout)
out = stdout.read().decode('utf-8', errors='replace')
err = stderr.read().decode('utf-8', errors='replace')
exit_code = stdout.channel.recv_exit_status()
return exit_code, out, err
except Exception as e:
self.log(f"命令执行异常: {cmd[:80]}... -> {str(e)}", "ERROR")
return -1, '', str(e)
def exec_background(self, cmd):
"""执行后台命令,用独立通道避免阻塞,立即返回输出"""
transport = self.ssh_client.get_transport()
channel = transport.open_session()
channel.settimeout(15)
channel.exec_command(cmd)
output = ''
# 等待命令输出
time.sleep(3)
try:
if channel.recv_ready():
output = channel.recv(8192).decode('utf-8', errors='replace')
except socket.timeout:
pass
channel.close()
return output.strip()
def connect_ssh(self): def connect_ssh(self):
"""连接SSH""" """连接SSH"""
...@@ -70,332 +116,339 @@ class X86AutoDeploy: ...@@ -70,332 +116,339 @@ class X86AutoDeploy:
self.log(f"SSH连接失败: {str(e)}", "ERROR") self.log(f"SSH连接失败: {str(e)}", "ERROR")
return False return False
def cleanup_existing_processes(self): def step1_check_disk(self):
"""清理现有部署进程""" """步骤1:服务器硬盘检查"""
self.log("检查并清理现有部署进程...") self.log("=" * 60)
try: self.log("【步骤1】服务器硬盘检查")
commands = [ self.log("=" * 60)
"pkill -9 -f new_auto.sh",
"sleep 2" code, out, err = self.exec_cmd("df -h /data")
] self.log(f"磁盘状态:\n{out}")
for cmd in commands:
stdin, stdout, stderr = self.ssh_client.exec_command(cmd) if '/data' in out:
stdout.read() self.log("[OK] /data 分区存在")
self.log("现有进程清理完成")
time.sleep(2)
return True
except Exception as e:
self.log(f"清理进程时出错: {str(e)}", "WARN")
return True return True
self.log("[FAIL] /data 分区不存在", "ERROR")
return False
def check_prerequisites(self): def step2_verify_package(self):
"""检查前置条件""" """步骤2:校验部署包完整性"""
self.log("=" * 60) self.log("=" * 60)
self.log("检查前置条件") self.log("【步骤2】校验部署包完整性")
self.log("=" * 60) self.log("=" * 60)
checks = [] code, out, err = self.exec_cmd(
"ls -la /data/offline_auto_unifiedPlatform.tar.gz "
# 1. 检查部署目录 "/data/offline_auto_unifiedPlatform.tar.gz.md5 2>&1"
self.log("1. 检查部署目录...")
try:
stdin, stdout, stderr = self.ssh_client.exec_command(
f"ls -la {self.deploy_dir} | head -20"
) )
output = stdout.read().decode('utf-8', errors='ignore') self.log(f"文件列表:\n{out}")
self.log(f"部署目录内容:\n{output}")
if 'new_auto.sh' in output:
self.log("[OK] 部署脚本存在")
checks.append(True)
else:
self.log("[FAIL] 部署脚本不存在", "ERROR")
checks.append(False)
except Exception as e:
self.log(f"[FAIL] 无法访问部署目录: {str(e)}", "ERROR")
checks.append(False)
# 2. 检查脚本权限 if 'No such file' in out or '无法访问' in out:
self.log("\n2. 检查脚本权限...") self.log("[FAIL] 部署包文件不存在", "ERROR")
try: return False
stdin, stdout, stderr = self.ssh_client.exec_command(
f"ls -l {self.deploy_dir}/new_auto.sh"
)
output = stdout.read().decode('utf-8', errors='ignore')
self.log(f"脚本权限: {output.strip()}")
if 'x' in output:
self.log("[OK] 脚本有执行权限")
checks.append(True)
else:
self.log("[WARN] 脚本无执行权限,正在添加...")
stdin, stdout, stderr = self.ssh_client.exec_command(
f"chmod 755 {self.deploy_dir}/new_auto.sh"
)
stdout.read()
self.log("[OK] 已添加执行权限")
checks.append(True)
except Exception as e:
self.log(f"[FAIL] 检查权限失败: {str(e)}", "ERROR")
checks.append(False)
# 3. 检查磁盘空间 code, out, err = self.exec_cmd("cd /data && md5sum -c offline_auto_unifiedPlatform.tar.gz.md5")
self.log("\n3. 检查磁盘空间...") self.log(f"MD5校验结果: {out.strip()}")
try:
stdin, stdout, stderr = self.ssh_client.exec_command("df -h /data")
output = stdout.read().decode('utf-8', errors='ignore')
self.log(f"磁盘状态:\n{output}")
checks.append(True)
except Exception as e:
self.log(f"[WARN] 检查磁盘失败: {str(e)}", "WARN")
checks.append(True)
return all(checks) if 'OK' in out or '成功' in out:
self.log("[OK] 部署包完整性校验通过")
return True
self.log("[WARN] MD5校验结果不确定,继续执行", "WARN")
return True
def execute_deployment(self): def step3_extract_and_chmod(self):
"""执行部署脚本 new_auto.sh --all""" """步骤3:解压并赋权(禁止中断)"""
self.log("=" * 60) self.log("=" * 60)
self.log("开始执行部署脚本: new_auto.sh --all") self.log("【步骤3】解压并赋权脚本")
self.log("【重要】解压过程禁止中断!")
self.log("=" * 60) self.log("=" * 60)
self.deploy_start_time = time.time()
try: # 检查是否已解压
cmd = f"cd {self.deploy_dir} && ./new_auto.sh --all" code, out, err = self.exec_cmd(f"ls {self.deploy_dir}/new_auto.sh 2>&1")
self.log(f"执行命令: {cmd}") if code == 0 and 'new_auto.sh' in out:
self.log("预计部署时间: 40分钟") self.log("[OK] 部署目录已存在,跳过解压")
else:
# 使用exec_command执行 self.log("开始解压部署包(后台执行,不会中断)...")
stdin, stdout, stderr = self.ssh_client.exec_command(cmd, get_pty=True, timeout=2700) # 写一个解压脚本到服务器
extract_script = f"""#!/bin/bash
# 监控部署过程 cd /data
output_buffer = "" tar -zxvf offline_auto_unifiedPlatform.tar.gz
last_log_time = time.time() echo "EXTRACT_DONE"
last_progress_time = time.time() """
self.exec_cmd(f"cat > /tmp/extract.sh << 'EXTRACT_EOF'\n{extract_script}\nEXTRACT_EOF")
self.log("开始监控部署过程...") self.exec_cmd("chmod +x /tmp/extract.sh")
while True: # 后台执行解压
# 检查进程状态 output = self.exec_background(
if stdout.channel.exit_status_ready(): f"nohup /tmp/extract.sh </dev/null > /data/extract_output.log 2>&1 & echo $!"
exit_code = stdout.channel.exit_status )
self.log(f"部署脚本进程已结束,退出码: {exit_code}") pid = output.strip().split('\n')[-1].strip()
self.log(f"解压进程PID: {pid}")
if not pid or not pid.isdigit():
# 可能解压已经完成了,检查文件
code, out, err = self.exec_cmd(f"ls {self.deploy_dir}/new_auto.sh 2>&1")
if 'new_auto.sh' in out:
self.log("[OK] 解压已完成")
else:
# 等一下再试
time.sleep(10)
code, out, err = self.exec_cmd(f"pgrep -f 'tar -zxvf' | head -1")
pid = out.strip()
# 等待解压完成(最多20分钟)
max_wait = 1200
waited = 0
while waited < max_wait:
time.sleep(10)
waited += 10
# 检查extract_output.log是否包含完成标志
code, out, err = self.exec_cmd("grep 'EXTRACT_DONE' /data/extract_output.log 2>/dev/null && echo 'done' || echo 'running'")
if waited % 60 == 0:
self.log(f"解压进行中... 已等待 {waited}秒")
if 'done' in out:
self.log("[OK] 解压完成")
break break
# 读取输出 # 也检查进程
try: if pid and pid.isdigit():
if stdout.channel.recv_ready(): code, out, err = self.exec_cmd(f"ps -p {pid} > /dev/null 2>&1 && echo 'running' || echo 'done'")
chunk = stdout.channel.recv(8192).decode('utf-8', errors='ignore') if 'done' in out and 'EXTRACT_DONE' not in out:
output_buffer += chunk # 进程结束但没看到完成标志,可能解压完了
time.sleep(5)
# 打印重要输出 code, out2, err = self.exec_cmd(f"ls {self.deploy_dir}/new_auto.sh 2>&1")
current_time = time.time() if 'new_auto.sh' in out2:
if current_time - last_log_time >= 5: # 每5秒打印一次日志 self.log("[OK] 解压完成(通过文件检查确认)")
for line in chunk.split('\n'):
line = line.strip()
if line:
# 过滤关键信息
if any(kw in line for kw in [
'部署', '安装', '启动', '完成', '成功',
'失败', '错误', '容器', 'Docker', '服务',
'ERROR', 'WARN', 'INFO', '系统'
]):
self.log(f"[部署] {line}")
last_log_time = current_time
except Exception as e:
pass
# 每60秒输出进度
elapsed = int(time.time() - self.deploy_start_time)
if elapsed > 0 and elapsed % 60 == 0:
progress_time = time.time()
if progress_time - last_progress_time >= 55:
self.log(f"[进度] 部署进行中... 已用时: {int(elapsed/60)}分钟/{40}分钟")
last_progress_time = progress_time
self.check_container_status()
# 检查超时
if elapsed > 2700: # 45分钟超时
self.log("部署超时,终止监控", "WARN")
break break
time.sleep(2) if waited >= max_wait:
self.log("[FAIL] 解压超时(20分钟)", "ERROR")
# 获取最终输出 return False
try:
remaining_output = stdout.read().decode('utf-8', errors='ignore')
output_buffer += remaining_output
except:
pass
deploy_time = int((time.time() - self.deploy_start_time) / 60)
self.log("=" * 60)
self.log(f"部署脚本执行完成,用时: {deploy_time}分钟")
self.log("=" * 60)
return True
except Exception as e: # 确认解压结果
self.log(f"执行部署脚本时出错: {str(e)}", "ERROR") code, out, err = self.exec_cmd(f"ls {self.deploy_dir}/new_auto.sh 2>&1")
import traceback if 'new_auto.sh' not in out:
traceback.print_exc() self.log("[FAIL] 解压后未找到部署脚本", "ERROR")
return False return False
self.log("[OK] 解压成功,部署脚本已就位")
def check_container_status(self): # 赋权
"""检查容器状态""" self.log("赋予脚本可执行权限...")
try: code, out, err = self.exec_cmd(f"cd {self.deploy_dir} && chmod 755 *.sh && ls -l *.sh | head -5")
stdin, stdout, stderr = self.ssh_client.exec_command( self.log(f"脚本权限:\n{out}")
"docker ps --format 'table {{.Names}}\t{{.Status}}' 2>/dev/null | head -20" self.log("[OK] 脚本赋权完成")
)
output = stdout.read().decode('utf-8', errors='ignore')
if output.strip():
lines = output.strip().split('\n')
count = len(lines) - 1 if len(lines) > 1 else 0
if count > 0:
self.log(f"[容器] 运行中: {count}个")
return True return True
except Exception as e:
return False
def wait_for_services(self): def step4_run_deployment(self):
"""等待服务启动""" """步骤4:运行 new_auto.sh --all(禁止中断)"""
self.log("=" * 60) self.log("=" * 60)
self.log("等待服务启动...") self.log("【步骤4】运行部署脚本 new_auto.sh --all")
self.log("【重要】部署过程禁止中断!预计40分钟")
self.log("=" * 60) self.log("=" * 60)
max_wait = 600 # 10分钟 self.deploy_start_time = time.time()
check_interval = 30
for i in range(0, max_wait, check_interval):
elapsed = i + check_interval
self.log(f"等待中... {elapsed}秒/{max_wait}秒")
# 检查预定对外服务日志
try:
log_path = "/data/services/api/java-meeting/java-meeting-extapi/logs/ubains-INFO-AND-ERROR.log"
stdin, stdout, stderr = self.ssh_client.exec_command(
f"tail -50 {log_path} 2>/dev/null | grep -i 'SYSTEMVERSION\\|target_api' || echo 'waiting'"
)
output = stdout.read().decode('utf-8', errors='ignore')
if 'SYSTEMVERSION' in output and 'target_api' in output: # 清理旧的部署日志
self.log("[OK] 预定对外服务已启动") self.exec_cmd(f"rm -f {self.deploy_log}")
return True
except:
pass
time.sleep(check_interval) # 写部署启动脚本到服务器,使用 yes y 自动确认可能的提示
launcher_script = f"""#!/bin/bash
cd {self.deploy_dir}
yes y | ./new_auto.sh --all
echo "DEPLOY_SCRIPT_FINISHED"
"""
self.exec_cmd(f"cat > /tmp/run_deploy.sh << 'DEPLOY_EOF'\n{launcher_script}\nDEPLOY_EOF")
self.exec_cmd("chmod +x /tmp/run_deploy.sh")
self.log("[WARN] 服务启动等待超时", "WARN") # 使用独立通道后台启动,避免阻塞
self.log("启动部署脚本(后台运行)...")
output = self.exec_background(
f"nohup /tmp/run_deploy.sh </dev/null >{self.deploy_log} 2>&1 & echo $!"
)
pid = output.strip().split('\n')[-1].strip()
self.log(f"部署进程PID: {pid}")
# 等几秒确认进程已启动
time.sleep(5)
if pid and pid.isdigit():
code, out, err = self.exec_cmd(f"ps -p {pid} > /dev/null 2>&1 && echo 'running' || echo 'not_found'")
if 'not_found' in out:
self.log("[WARN] 进程PID已不存在,检查日志...", "WARN")
# 可能是 nohup 命令本身的PID,不是脚本的PID
# 查找实际的 new_auto.sh 进程
code, out, err = self.exec_cmd("pgrep -f 'new_auto.sh' | head -1")
actual_pid = out.strip()
if actual_pid and actual_pid.isdigit():
pid = actual_pid
self.log(f"找到实际部署进程PID: {pid}")
else:
# 检查日志文件
code, out, err = self.exec_cmd(f"cat {self.deploy_log} 2>/dev/null | head -20")
self.log(f"部署日志:\n{out}")
if not out.strip():
self.log("[FAIL] 部署进程未启动且无日志输出", "ERROR")
return False return False
def test_api_with_retry(self, url, expected_keyword, api_name, max_retries=5): if not pid or not pid.isdigit():
"""使用重试机制测试API""" # 尝试用 pgrep 查找
self.log(f"\n测试 {api_name}") code, out, err = self.exec_cmd("pgrep -f 'new_auto.sh' | head -1")
self.log(f"URL: {url}") pid = out.strip()
if pid and pid.isdigit():
for retry in range(max_retries): self.log(f"通过pgrep找到部署进程: {pid}")
try: else:
response = requests.get(url, verify=False, timeout=30) # 检查日志是否有内容(可能脚本已经快速完成了或失败了)
response_text = response.text time.sleep(10)
code, out, err = self.exec_cmd(f"wc -l {self.deploy_log} 2>/dev/null || echo '0'")
if '0' in out or not out.strip():
self.log("[FAIL] 无法找到部署进程且无日志", "ERROR")
return False
# 有日志输出,说明脚本已运行或正在运行
self.log("[WARN] 无法获取PID,但有日志输出,继续监控...", "WARN")
pid = None
# 监控部署进度
max_wait = 3600 # 60分钟超时
waited = 0
last_progress_minute = -1
while waited < max_wait:
time.sleep(15)
waited += 15
current_minute = int(waited / 60)
# 每分钟输出一次进度
if current_minute > last_progress_minute:
last_progress_minute = current_minute
# 读取日志大小
code, size_out, _ = self.exec_cmd(f"wc -l {self.deploy_log} 2>/dev/null || echo '0'")
log_lines = size_out.strip().split()[0] if size_out.strip() else '0'
# 读取最后几行关键信息
code, tail_out, _ = self.exec_cmd(
f"tail -30 {self.deploy_log} 2>/dev/null | grep -E "
f"'部署|安装|启动|完成|成功|失败|错误|ERROR|容器|Docker|服务|"
f"系统|middleware|database|redis|nginx|解压|loading|pull|image' | tail -5"
)
self.log(f"[进度] {current_minute}分钟/40分钟 | 日志行数: {log_lines}")
if tail_out.strip():
for line in tail_out.strip().split('\n')[-3:]:
if line.strip():
self.log(f" > {line.strip()}")
# 检查是否完成
code, out, err = self.exec_cmd(
f"grep 'DEPLOY_SCRIPT_FINISHED' {self.deploy_log} 2>/dev/null && echo 'FINISHED' || echo 'RUNNING'"
)
if 'FINISHED' in out:
self.log("[OK] 部署脚本执行完成")
break
# 检查是否包含预期关键词 # 也检查进程是否还在运行
if expected_keyword in response_text: if pid and pid.isdigit():
self.log(f"[OK] {api_name} 响应正常 (第{retry + 1}次尝试)") code, out, err = self.exec_cmd(f"ps -p {pid} > /dev/null 2>&1 && echo 'running' || echo 'done'")
return True if 'done' in out:
elif '<!DOCTYPE html>' in response_text and 'Error' in response_text: # 进程结束,再检查日志
self.log(f"[FAIL] {api_name} 返回错误页面 (第{retry + 1}次尝试)", "WARN") time.sleep(5)
code, out, err = self.exec_cmd(
f"grep 'DEPLOY_SCRIPT_FINISHED' {self.deploy_log} 2>/dev/null && echo 'FINISHED' || echo 'NOT_FINISHED'"
)
if 'FINISHED' in out:
self.log("[OK] 部署脚本执行完成")
else:
# 进程结束但没有完成标志,检查日志尾部
code, out, err = self.exec_cmd(f"tail -30 {self.deploy_log}")
self.log(f"部署日志末尾:\n{out}")
if 'source /etc/profile' in out:
self.log("[OK] 检测到完成标志")
else: else:
self.log(f"[WARN] {api_name} 响应不符合预期 (第{retry + 1}次尝试)", "WARN") self.log("[WARN] 进程已结束,但未检测到明确的完成标志", "WARN")
break
except Exception as e: else:
self.log(f"[WARN] {api_name} 请求失败 (第{retry + 1}次尝试): {str(e)}", "WARN") self.log("[FAIL] 部署超时(60分钟)", "ERROR")
return False
if retry < max_retries - 1: # 执行 source /etc/profile
self.log("等待30秒后重试...") self.exec_cmd("source /etc/profile")
time.sleep(30)
self.log(f"[FAIL] {api_name} 经过{max_retries}次尝试后仍然失败", "ERROR") deploy_time = int((time.time() - self.deploy_start_time) / 60)
return False self.log(f"部署脚本执行完成,用时: {deploy_time}分钟")
return True
def perform_acceptance_check(self): def step5_acceptance_check(self):
"""执行验收检查""" """步骤5:验收检查"""
self.log("=" * 60) self.log("=" * 60)
self.log("开始验收检查") self.log("【步骤5】验收检查")
self.log("=" * 60) self.log("=" * 60)
results = {} results = {}
# 1. 检查容器状态 # 5.1 检查容器状态
self.log("\n1. 检查容器状态...") self.log("\n--- 5.1 检查容器状态 ---")
try: code, out, err = self.exec_cmd("docker ps --format 'table {{.Names}}\t{{.Status}}'")
stdin, stdout, stderr = self.ssh_client.exec_command( self.log(f"容器状态:\n{out}")
"docker ps --format 'table {{.Names}}\t{{.Status}}'" container_lines = [l for l in out.split('\n') if l.strip() and 'NAMES' not in l]
) container_count = len(container_lines)
docker_output = stdout.read().decode('utf-8', errors='ignore')
self.log(f"\n容器状态:\n{docker_output}")
container_count = len([l for l in docker_output.split('\n') if l.strip() and 'NAMES' not in l])
results['容器状态'] = container_count >= 5 results['容器状态'] = container_count >= 5
self.log(f"运行中的容器: {container_count}个") self.log(f"运行中的容器: {container_count}个 -> {'通过' if results['容器状态'] else '不足'}")
except Exception as e:
self.log(f"检查容器失败: {str(e)}", "ERROR")
results['容器状态'] = False
# 2. 检查服务日志 # 5.2 等待服务启动并检查日志
self.log("\n2. 检查服务日志...") self.log("\n--- 5.2 等待服务启动 ---")
log_checks = { results['服务日志'] = self._wait_for_service_log()
"预定对外服务": "/data/services/api/java-meeting/java-meeting-extapi/logs/ubains-INFO-AND-ERROR.log"
}
for service_name, log_path in log_checks.items(): # 5.3 检查服务日志异常
try: self.log("\n--- 5.3 检查服务日志异常 ---")
stdin, stdout, stderr = self.ssh_client.exec_command( error_summary = self._check_service_errors()
f"tail -100 {log_path} 2>/dev/null | grep 'SYSTEMVERSION' || echo 'not found'"
)
output = stdout.read().decode('utf-8', errors='ignore')
if 'SYSTEMVERSION' in output and 'target_api' in output:
self.log(f"[OK] {service_name} 日志正常")
results[f'{service_name}_日志'] = True
else:
self.log(f"[WARN] {service_name} 日志未找到版本信息", "WARN")
results[f'{service_name}_日志'] = False
except Exception as e:
self.log(f"[WARN] 检查{service_name}日志失败: {str(e)}", "WARN")
results[f'{service_name}_日志'] = False
# 3. 检查接口状态 # 5.4 接口测试
self.log("\n3. 检查接口状态...") self.log("\n--- 5.4 接口测试(重试:5次,间隔30秒) ---")
base_url = f"https://{self.host}" base_url = f"https://{self.host}"
results['预定对外接口'] = self.test_api_with_retry( results['预定对外接口'] = self._test_api_with_retry(
f"{base_url}/exapi/message/getMsgPageList", f"{base_url}/exapi/message/getMsgPageList",
"无效token", "无效token", "预定对外服务接口"
"预定对外服务接口"
) )
results['预定系统接口'] = self._test_api_with_retry(
results['预定系统接口'] = self.test_api_with_retry(
f"{base_url}/meetingV3/api/systemConfiguration/globalConfig?companyNumber=CN-SZ-00-0201", f"{base_url}/meetingV3/api/systemConfiguration/globalConfig?companyNumber=CN-SZ-00-0201",
"accessToken", "accessToken", "预定系统接口"
"预定系统接口"
) )
results['运维集控接口'] = self._test_api_with_retry(
results['运维集控接口'] = self.test_api_with_retry(
f"{base_url}/monitor/api2/api/servermonitor/", f"{base_url}/monitor/api2/api/servermonitor/",
"用户不存在", "用户不存在", "运维集控系统接口"
"运维集控系统接口"
) )
results['讯飞转录接口'] = self._test_api_with_retry(
results['讯飞转录接口'] = self.test_api_with_retry(
f"{base_url}/voice/api/iflytek/roommaster?company_id=1&user_id=8&company_secret=57d00f9f-020f-5f1f-b788-55fae843bceb&getall=1", f"{base_url}/voice/api/iflytek/roommaster?company_id=1&user_id=8&company_secret=57d00f9f-020f-5f1f-b788-55fae843bceb&getall=1",
"缺少关键参数", "缺少关键参数", "讯飞转录系统接口"
"讯飞转录系统接口"
) )
return results return results, error_summary
def _wait_for_service_log(self):
"""等待服务日志输出版本信息"""
log_path = "/data/services/api/java-meeting/java-meeting-extapi/logs/ubains-INFO-AND-ERROR.log"
for phase, max_wait in [("首次", 600), ("二次", 600)]:
self.log(f" {phase}等待(最多{max_wait // 60}分钟)...")
for waited in range(0, max_wait, 30):
self.log(f" 等待中... {waited + 30}秒/{max_wait}秒")
code, out, err = self.exec_cmd(
f"tail -50 {log_path} 2>/dev/null | grep -i 'SYSTEMVERSION\\|target_api' || echo 'waiting'"
)
if 'SYSTEMVERSION' in out and 'target_api' in out:
self.log(f"[OK] 预定对外服务已启动({phase}等待)")
return True
time.sleep(30)
def check_service_logs_for_errors(self): self.log("[FAIL] 服务启动等待超时", "ERROR")
"""检查服务日志是否有异常""" return False
self.log("\n检查服务日志中的异常...")
def _check_service_errors(self):
"""检查四个服务的日志异常"""
log_paths = { log_paths = {
"预定对外服务": "/data/services/api/java-meeting/java-meeting-extapi/logs/ubains-INFO-AND-ERROR.log", "预定对外服务": "/data/services/api/java-meeting/java-meeting-extapi/logs/ubains-INFO-AND-ERROR.log",
"预定对内服务": "/data/services/api/java-meeting/java-meeting2.0/logs/ubains-INFO-AND-ERROR.log", "预定对内服务": "/data/services/api/java-meeting/java-meeting2.0/logs/ubains-INFO-AND-ERROR.log",
...@@ -404,36 +457,67 @@ class X86AutoDeploy: ...@@ -404,36 +457,67 @@ class X86AutoDeploy:
} }
error_summary = {} error_summary = {}
for name, path in log_paths.items():
for service_name, log_path in log_paths.items(): code, out, err = self.exec_cmd(
try: f"tail -100 {path} 2>/dev/null | grep -i 'error\\|exception' || echo 'clean'"
stdin, stdout, stderr = self.ssh_client.exec_command(
f"tail -100 {log_path} 2>/dev/null | grep -i 'error\\|exception' || echo 'clean'"
) )
output = stdout.read().decode('utf-8', errors='ignore') if out.strip() and out.strip() != 'clean':
count = len([l for l in out.split('\n') if l.strip()])
if output.strip() and output.strip() != 'clean': error_summary[name] = count
error_count = len([l for l in output.split('\n') if l.strip()]) self.log(f"[WARN] {name}: 发现 {count} 条异常记录", "WARN")
error_summary[service_name] = error_count
self.log(f"[WARN] {service_name} 发现 {error_count} 条异常记录", "WARN")
else: else:
self.log(f"[OK] {service_name} 日志无明显异常") error_summary[name] = 0
error_summary[service_name] = 0 self.log(f"[OK] {name}: 无明显异常")
return error_summary
def _test_api_with_retry(self, url, keyword, name, max_retries=5):
"""接口测试:5次重试,间隔30秒,成功即停"""
self.log(f"\n 测试 {name}")
self.log(f" URL: {url}")
for retry in range(max_retries):
try:
resp = requests.get(url, verify=False, timeout=30)
if keyword in resp.text:
self.log(f" [OK] {name} 正常 (第{retry + 1}次)")
# 成功后等30秒再确认一次
if retry < max_retries - 1:
time.sleep(30)
resp2 = requests.get(url, verify=False, timeout=30)
if keyword in resp2.text:
self.log(f" [OK] {name} 二次确认正常")
return True
else:
self.log(f" [FAIL] {name} 响应异常 (第{retry + 1}次)", "WARN")
except Exception as e: except Exception as e:
self.log(f"[WARN] 无法读取 {service_name} 日志: {str(e)}", "WARN") self.log(f" [FAIL] {name} 请求失败 (第{retry + 1}次): {str(e)}", "WARN")
error_summary[service_name] = -1
return error_summary if retry < max_retries - 1:
self.log(" 等待30秒后重试...")
time.sleep(30)
def generate_report(self, results, error_summary): self.log(f" [FAIL] {name} 经{max_retries}次尝试后仍然失败", "ERROR")
"""生成部署报告""" return False
self.log("\n" + "=" * 60)
self.log("部署验收报告") def step6_authorization(self):
"""步骤6:系统授权指导"""
self.log("=" * 60)
self.log("【步骤6】系统授权")
self.log("需要通过浏览器Web界面操作")
self.log("=" * 60) self.log("=" * 60)
self.log("请手动执行以下步骤:")
self.log(f" 1. 访问: https://{self.host}/#/LoginConfig")
self.log(f" 2. 登录: {self.admin_user} / {self.admin_pass}")
self.log(" 3. 验证码: csba")
self.log(f" 4. 上传授权文件: {self.license_path}")
self.log(" 5. 勾选 运维系统、预定系统2.0、预定系统3.0 -> 重启已选服务")
self.log(" 6. 填写项目信息 -> 保存")
return True
def generate_report(self, results, error_summary):
"""生成部署验收报告"""
total_time = int((time.time() - self.total_start_time) / 60) total_time = int((time.time() - self.total_start_time) / 60)
deploy_time = int((self.deploy_start_time - self.total_start_time) / 60) if self.deploy_start_time else 0 deploy_time = int((time.time() - self.deploy_start_time) / 60) if self.deploy_start_time else 0
report_lines = [ report_lines = [
"# 远程自动化部署报告", "# 远程自动化部署报告",
...@@ -446,13 +530,10 @@ class X86AutoDeploy: ...@@ -446,13 +530,10 @@ class X86AutoDeploy:
] ]
for key, value in results.items(): for key, value in results.items():
status = "✓ 通过" if value else "✗ 失败" status = "通过" if value else "失败"
report_lines.append(f"- {status}: {key}") report_lines.append(f"- [{status}] {key}")
report_lines.extend([
"\n### 2. 日志异常检查",
])
report_lines.append("\n### 2. 日志异常检查")
for service, count in error_summary.items(): for service, count in error_summary.items():
if count > 0: if count > 0:
report_lines.append(f"- [!] {service}: {count} 条异常记录") report_lines.append(f"- [!] {service}: {count} 条异常记录")
...@@ -461,7 +542,6 @@ class X86AutoDeploy: ...@@ -461,7 +542,6 @@ class X86AutoDeploy:
else: else:
report_lines.append(f"- [?] {service}: 无法检查") report_lines.append(f"- [?] {service}: 无法检查")
# 计算通过率
passed = sum(1 for v in results.values() if v) passed = sum(1 for v in results.values() if v)
total = len(results) total = len(results)
pass_rate = (passed / total * 100) if total > 0 else 0 pass_rate = (passed / total * 100) if total > 0 else 0
...@@ -473,31 +553,23 @@ class X86AutoDeploy: ...@@ -473,31 +553,23 @@ class X86AutoDeploy:
]) ])
if pass_rate >= 80: if pass_rate >= 80:
report_lines.extend([ report_lines.append("\n**结论**: 部署验收基本通过")
"\n**结论**: 部署验收基本通过",
"\n## 二、后续步骤",
"\n### 1. 系统授权",
f"- 访问: https://{self.host}/#/LoginConfig",
"- 账号: superadmin / Ubains@1357",
"- 验证码: csba",
"- 上传授权文件",
"\n### 2. 重启服务",
"- 勾选需要重启的服务",
"- 点击【重启已选服务】",
"\n### 3. 创建管理员(暂时跳过)",
"- 根据部署文档第四章操作",
])
else: else:
report_lines.append("\n**结论**: 部署存在问题,需要检查失败项")
report_lines.extend([ report_lines.extend([
"\n**结论**: 部署存在问题,需要检查失败项", "\n## 二、后续步骤",
"\n## 二、问题处理", f"1. 系统授权: https://{self.host}/#/LoginConfig",
"\n请检查上述失败项目,必要时联系技术支持。", f" - 账号: {self.admin_user} / {self.admin_pass}",
" - 验证码: csba",
f" - 授权文件: {self.license_path}",
"2. 重启服务后再次验证接口",
"3. 创建管理员(暂时跳过)",
]) ])
report = '\n'.join(report_lines) report = '\n'.join(report_lines)
# 保存报告 reports_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'reports')
reports_dir = os.path.join(os.path.dirname(__file__), 'reports')
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S') timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
report_file = os.path.join(reports_dir, f'{self.host}_deployment_report_{timestamp}.md') report_file = os.path.join(reports_dir, f'{self.host}_deployment_report_{timestamp}.md')
...@@ -508,63 +580,53 @@ class X86AutoDeploy: ...@@ -508,63 +580,53 @@ class X86AutoDeploy:
except Exception as e: except Exception as e:
self.log(f"保存报告失败: {str(e)}", "ERROR") self.log(f"保存报告失败: {str(e)}", "ERROR")
# 打印报告 self.log("\n" + report)
print("\n" + report)
return report_file return report_file
def close(self): def close(self):
"""关闭连接""" """关闭SSH连接"""
if self.ssh_client: if self.ssh_client:
self.ssh_client.close() self.ssh_client.close()
self.log("SSH连接已关闭") self.log("SSH连接已关闭")
def main(): def main():
print("=" * 80)
print("X86服务器远程自动化部署")
print("目标服务器: 192.168.5.52")
print("部署脚本: new_auto.sh --all")
print("=" * 80)
print()
deploy = X86AutoDeploy() deploy = X86AutoDeploy()
deploy.init_log_file() deploy.init_log_file()
deploy.total_start_time = time.time() deploy.total_start_time = time.time()
deploy.log("=" * 60)
deploy.log("X86服务器远程自动化部署")
deploy.log(f"目标服务器: 192.168.5.52")
deploy.log("部署脚本: new_auto.sh --all")
deploy.log("严格按照部署文档执行,禁止中断解压缩操作")
deploy.log("=" * 60)
try: try:
# 1. 连接SSH
if not deploy.connect_ssh(): if not deploy.connect_ssh():
return 1 return 1
# 2. 检查前置条件 if not deploy.step1_check_disk():
if not deploy.check_prerequisites(): deploy.log("硬盘检查失败", "WARN")
deploy.log("前置条件检查失败,但继续执行部署", "WARN")
# 3. 清理现有进程
deploy.cleanup_existing_processes()
# 4. 执行部署脚本 if not deploy.step2_verify_package():
if not deploy.execute_deployment(): deploy.log("部署包校验失败", "ERROR")
deploy.log("部署脚本执行失败", "ERROR")
deploy.close() deploy.close()
return 1 return 1
# 5. 等待服务启动 if not deploy.step3_extract_and_chmod():
deploy.wait_for_services() deploy.log("解压或赋权失败", "ERROR")
deploy.close()
# 6. 验收检查 return 1
results = deploy.perform_acceptance_check()
# 7. 检查日志异常 if not deploy.step4_run_deployment():
error_summary = deploy.check_service_logs_for_errors() deploy.log("部署脚本执行失败", "ERROR")
# 8. 生成报告 results, error_summary = deploy.step5_acceptance_check()
deploy.step6_authorization()
deploy.generate_report(results, error_summary) deploy.generate_report(results, error_summary)
deploy.close() deploy.close()
# 判断是否成功
if all(results.values()): if all(results.values()):
deploy.log("\n[SUCCESS] 部署验收通过!") deploy.log("\n[SUCCESS] 部署验收通过!")
return 0 return 0
...@@ -573,9 +635,12 @@ def main(): ...@@ -573,9 +635,12 @@ def main():
return 1 return 1
except Exception as e: except Exception as e:
deploy.log(f"部署过程出错: {str(e)}", "ERROR") deploy.log(f"部署过程异常: {str(e)}", "ERROR")
try:
import traceback import traceback
traceback.print_exc() traceback.print_exc()
except Exception:
pass
deploy.close() deploy.close()
return 1 return 1
......
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
X86服务器自动化部署脚本 - 使用 new_auto.sh --all 参数
严格按照需求文档执行部署操作
"""
import sys
import os
import time
import subprocess
import paramiko
import requests
from datetime import datetime
from urllib3.exceptions import InsecureRequestWarning
# 禁用SSL警告
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
class X86Deployment:
def __init__(self):
self.host = '192.168.5.52'
self.username = 'root'
self.password = 'Ubains@123'
self.deploy_dir = '/data/offline_auto_unifiedPlatform'
self.ssh_client = None
self.start_time = None
def log(self, message, level="INFO"):
"""输出日志"""
timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
print(f"[{timestamp}] [{level}] {message}")
def connect_ssh(self):
"""连接SSH"""
self.log("正在连接SSH服务器...")
try:
self.ssh_client = paramiko.SSHClient()
self.ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
self.ssh_client.connect(self.host, username=self.username, password=self.password, timeout=30)
self.log("SSH连接成功")
return True
except Exception as e:
self.log(f"SSH连接失败: {str(e)}", "ERROR")
return False
def check_and_cleanup(self):
"""检查并清理现有部署进程"""
self.log("检查并清理现有部署进程...")
try:
# 终止可能存在的new_auto.sh进程
stdin, stdout, stderr = self.ssh_client.exec_command(
"pkill -9 -f new_auto.sh; sleep 2; echo '清理完成'"
)
stdout.read()
self.log("现有进程清理完成")
time.sleep(2)
return True
except Exception as e:
self.log(f"清理进程时出错: {str(e)}", "WARN")
return True
def run_deployment_script(self):
"""执行部署脚本 new_auto.sh --all"""
self.log("=" * 60)
self.log("开始执行部署脚本: new_auto.sh --all")
self.log("=" * 60)
self.start_time = time.time()
try:
# 切换到部署目录并执行脚本
cmd = f"cd {self.deploy_dir} && ./new_auto.sh --all"
self.log(f"执行命令: {cmd}")
self.log("预计部署时间: 40分钟")
# 使用exec_command执行,设置超时
stdin, stdout, stderr = self.ssh_client.exec_command(cmd, get_pty=True)
# 监控部署过程
output_buffer = ""
last_progress_time = time.time()
while True:
# 检查进程状态
if stdout.channel.exit_status_ready():
# 进程已结束
exit_code = stdout.channel.exit_status
self.log(f"部署脚本进程已结束,退出码: {exit_code}")
break
# 读取输出
try:
if stdout.channel.recv_ready():
chunk = stdout.channel.recv(4096).decode('utf-8', errors='ignore')
output_buffer += chunk
# 打印重要输出
if any(keyword in chunk for keyword in ['部署', '安装', '启动', '完成', '成功', '失败', '错误', 'error']):
# 清理并打印
for line in chunk.split('\n'):
line = line.strip()
if line and any(kw in line for kw in ['部署', '安装', '启动', '完成', '成功', '失败', '错误']):
self.log(f"[部署输出] {line}")
except Exception as e:
pass
# 每60秒输出进度
elapsed = int(time.time() - self.start_time)
if elapsed % 60 == 0 and elapsed > 0:
progress_time = time.time()
if progress_time - last_progress_time >= 55: # 避免重复输出
self.log(f"[进度] 部署进行中... 已用时: {int(elapsed/60)}分钟")
last_progress_time = progress_time
# 检查容器状态
self.check_container_status()
# 检查是否超时
if elapsed > 2700: # 45分钟超时
self.log("部署超时", "WARN")
break
time.sleep(5)
# 获取最终输出
remaining_output = stdout.read().decode('utf-8', errors='ignore')
output_buffer += remaining_output
self.log("=" * 60)
self.log("部署脚本执行完成")
self.log("=" * 60)
return True
except Exception as e:
self.log(f"执行部署脚本时出错: {str(e)}", "ERROR")
return False
def check_container_status(self):
"""检查容器状态"""
try:
stdin, stdout, stderr = self.ssh_client.exec_command(
"docker ps --format '{{.Names}}' | wc -l"
)
count = int(stdout.read().decode().strip())
if count > 0:
self.log(f"[容器状态] 运行中的容器数量: {count}")
return count
except:
return 0
def check_deployment_result(self):
"""检查部署结果"""
self.log("=" * 60)
self.log("开始检查部署结果")
self.log("=" * 60)
results = {
'containers': False,
'logs': False,
'external_api': False,
'meeting_api': False,
'monitor_api': False,
'voice_api': False
}
# 1. 检查容器状态
self.log("1. 检查容器状态...")
try:
stdin, stdout, stderr = self.ssh_client.exec_command(
"docker ps --format 'table {{.Names}}\t{{.Status}}'"
)
docker_output = stdout.read().decode('utf-8', errors='ignore')
self.log(f"\n容器状态:\n{docker_output}")
container_count = docker_output.count('\n') - 1 # 减去表头
if container_count >= 5:
self.log(f"[OK] 运行中的容器数量: {container_count}")
results['containers'] = True
else:
self.log(f"[FAIL] 容器数量不足: {container_count}", "ERROR")
except Exception as e:
self.log(f"检查容器状态失败: {str(e)}", "ERROR")
# 2. 检查预定对外服务日志
self.log("\n2. 检查预定对外服务日志...")
log_path = "/data/services/api/java-meeting/java-meeting-extapi/logs/ubains-INFO-AND-ERROR.log"
# 等待日志输出
max_wait = 600 # 10分钟
wait_start = time.time()
while time.time() - wait_start < max_wait:
try:
stdin, stdout, stderr = self.ssh_client.exec_command(
f"tail -100 {log_path} | grep 'SYSTEMVERSION'"
)
log_output = stdout.read().decode('utf-8', errors='ignore')
if 'SYSTEMVERSION' in log_output and 'target_api_integration' in log_output:
self.log(f"[OK] 找到版本信息: {log_output.strip()}")
results['logs'] = True
break
else:
self.log("等待服务启动...")
time.sleep(30)
except Exception as e:
self.log(f"检查日志失败: {str(e)}", "WARN")
time.sleep(30)
else:
self.log("[FAIL] 10分钟后仍未检测到服务启动", "ERROR")
# 3. 使用重试机制检查接口状态
self.log("\n3. 检查接口状态(使用重试机制)...")
# 对外接口
results['external_api'] = self.test_api_with_retry(
"https://192.168.5.52/exapi/message/getMsgPageList",
"无效token",
"预定对外服务接口"
)
# 预定系统接口
results['meeting_api'] = self.test_api_with_retry(
"https://192.168.5.52/meetingV3/api/systemConfiguration/globalConfig?companyNumber=CN-SZ-00-0201",
"accessToken",
"预定系统接口"
)
# 运维集控系统接口
results['monitor_api'] = self.test_api_with_retry(
"https://192.168.5.52/monitor/api2/api/servermonitor/",
"用户不存在",
"运维集控系统接口"
)
# 讯飞转录系统接口
results['voice_api'] = self.test_api_with_retry(
"https://192.168.5.52/voice/api/iflytek/roommaster?company_id=1&user_id=8&company_secret=57d00f9f-020f-5f1f-b788-55fae843bceb&getall=1",
"缺少关键参数",
"讯飞转录系统接口"
)
# 输出结果摘要
self.log("=" * 60)
self.log("部署检查结果摘要")
self.log("=" * 60)
total_time = int((time.time() - self.start_time) / 60)
self.log(f"总用时: {total_time} 分钟")
for key, value in results.items():
status = "[OK]" if value else "[FAIL]"
self.log(f"{status} {key}")
all_ok = all(results.values())
if all_ok:
self.log("\n[SUCCESS] 部署验收通过!")
else:
self.log("\n[WARN] 部署存在问题,请检查上述失败项")
return all_ok
def test_api_with_retry(self, url, expected_keyword, api_name):
"""使用重试机制测试API"""
self.log(f"\n测试 {api_name}: {url}")
retry_count = 0
max_retries = 5
while retry_count < max_retries:
try:
response = requests.get(url, verify=False, timeout=30)
response_text = response.text
# 检查是否包含预期关键词
if expected_keyword in response_text:
self.log(f"[OK] {api_name} 响应正常 (尝试 {retry_count + 1}/{max_retries})")
return True
elif '<!DOCTYPE html>' in response_text and 'Error' in response_text:
self.log(f"[FAIL] {api_name} 返回错误页面 (尝试 {retry_count + 1}/{max_retries})")
else:
self.log(f"[WARN] {api_name} 响应不符合预期 (尝试 {retry_count + 1}/{max_retries})")
self.log(f"响应内容: {response_text[:200]}")
except Exception as e:
self.log(f"[WARN] {api_name} 请求失败 (尝试 {retry_count + 1}/{max_retries}): {str(e)}")
retry_count += 1
if retry_count < max_retries:
self.log("等待30秒后重试...")
time.sleep(30)
self.log(f"[FAIL] {api_name} 经过 {max_retries} 次尝试后仍然失败", "ERROR")
return False
def check_service_logs(self):
"""检查服务日志是否有异常"""
self.log("\n检查服务日志...")
log_paths = {
"预定对外服务": "/data/services/api/java-meeting/java-meeting-extapi/logs/ubains-INFO-AND-ERROR.log",
"预定对内服务": "/data/services/api/java-meeting/java-meeting2.0/logs/ubains-INFO-AND-ERROR.log",
"运维服务": "/data/services/api/python-cmdb/log/uinfo.log",
"讯飞服务": "/data/services/api/python-voice/log/uinfo.log"
}
for service_name, log_path in log_paths.items():
try:
stdin, stdout, stderr = self.ssh_client.exec_command(
f"tail -50 {log_path} 2>/dev/null || echo '日志文件不存在'"
)
log_output = stdout.read().decode('utf-8', errors='ignore')
if 'ERROR' in log_output.upper() or 'EXCEPTION' in log_output.upper():
self.log(f"[WARN] {service_name} 日志中发现异常:", "WARN")
else:
self.log(f"[OK] {service_name} 日志正常")
except Exception as e:
self.log(f"[WARN] 无法读取 {service_name} 日志: {str(e)}", "WARN")
def close(self):
"""关闭连接"""
if self.ssh_client:
self.ssh_client.close()
self.log("SSH连接已关闭")
def main():
print("=" * 80)
print("X86服务器远程自动化部署")
print("目标服务器: 192.168.5.52")
print("部署脚本: new_auto.sh --all")
print("=" * 80)
print()
deploy = X86Deployment()
try:
# 1. 连接SSH
if not deploy.connect_ssh():
return 1
# 2. 清理现有进程
deploy.check_and_cleanup()
# 3. 执行部署脚本
if not deploy.run_deployment_script():
return 1
# 4. 等待服务启动
deploy.log("\n等待服务启动...")
time.sleep(60)
# 5. 检查部署结果
success = deploy.check_deployment_result()
# 6. 检查服务日志
deploy.check_service_logs()
# 7. 输出后续步骤
print("\n" + "=" * 80)
print("部署脚本执行完成")
print("=" * 80)
print("\n后续步骤:")
print("1. 系统授权: https://192.168.5.52/#/LoginConfig")
print(" 账号: superadmin / Ubains@1357")
print(" 验证码: csba")
print(" 授权文件: \\\\192.168.9.9\\发布版本\\03服务器部署\\临时使用-新统一平台\\测试授权文件-请勿使用\\5.52授权文件\\license.zip")
print("\n2. 创建管理员: 为'自动化'公司创建admin用户")
print("\n3. 前台访问: https://192.168.5.52/")
print(" 后台访问: https://192.168.5.52/#/LoginAdmin")
deploy.close()
return 0 if success else 1
except Exception as e:
deploy.log(f"部署过程出错: {str(e)}", "ERROR")
import traceback
traceback.print_exc()
deploy.close()
return 1
if __name__ == '__main__':
sys.exit(main())
...@@ -60,7 +60,7 @@ ...@@ -60,7 +60,7 @@
## 验收要求 ## 验收要求
1. 自动化部署完成后检查容器状态是否正常,核查容器日志是否正确。 1. 自动化部署完成后检查容器状态是否正常,核查容器日志是否正确。
2. 检查对外服务状态: 2. 检查对外服务状态:
- 等待10分钟后执行接口调用: - 日志是否正确打印如下信息`SYSTEMVERSION :: target_api_integration2.0.2612.258 2026-03-17 10:59:54`,版本号不固定判断,只要有就行,如有则标识为服务启动正常,若无则再等待10分钟,再次检查,若10分钟后仍然未输出,则标识为启动异常,记录异常日志。
- 调用对外接口`curl -k https://服务器IP/exapi/message/getMsgPageList` - 调用对外接口`curl -k https://服务器IP/exapi/message/getMsgPageList`
- 成功:返回信息:`{"success":false,"code":"A0076","message":"无效token","result":"Full authentication is required to access this resource"}` - 成功:返回信息:`{"success":false,"code":"A0076","message":"无效token","result":"Full authentication is required to access this resource"}`
- 失败:返回信息: - 失败:返回信息:
...@@ -91,7 +91,6 @@ ...@@ -91,7 +91,6 @@
- 按照部署文档中第三章系统授权进行执行操作,如遇验证码输入则填入`csba` - 按照部署文档中第三章系统授权进行执行操作,如遇验证码输入则填入`csba`
- 需上传的授权文件路径根据服务器IP获取对应的授权文件,文档顶部有标注对应路径。 - 需上传的授权文件路径根据服务器IP获取对应的授权文件,文档顶部有标注对应路径。
- 继续根据文档执行第三章节的授权操作。 - 继续根据文档执行第三章节的授权操作。
4. 新统一平台服务检查 4. 新统一平台服务检查
- 检查服务启动状态: - 检查服务启动状态:
- 检查预定对内、对外服务日志是否正常,是否存在异常日志输出。 - 检查预定对内、对外服务日志是否正常,是否存在异常日志输出。
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论