813 lines
27 KiB
PHP
813 lines
27 KiB
PHP
<?php
|
||
require_once __DIR__ . '/app/db_helper.php';
|
||
require_once __DIR__ . '/app/logger.php';
|
||
|
||
define('TOKEN_CACHE_FILE', __DIR__ . '/app/token.php');
|
||
define('TOKEN_EXPIRE_TIME', 7200);
|
||
|
||
/**
|
||
* 获取缓存的Token
|
||
*/
|
||
function getCachedToken($configId) {
|
||
if (!file_exists(TOKEN_CACHE_FILE)) {
|
||
return null;
|
||
}
|
||
|
||
include TOKEN_CACHE_FILE;
|
||
|
||
if (!isset($cached_tokens[$configId])) {
|
||
return null;
|
||
}
|
||
|
||
$cache = $cached_tokens[$configId];
|
||
$currentTime = time();
|
||
$tokenAge = $currentTime - $cache['timestamp'];
|
||
|
||
if ($tokenAge < TOKEN_EXPIRE_TIME) {
|
||
return $cache['token'];
|
||
}
|
||
|
||
// Token已过期,清除该配置的缓存
|
||
unset($cached_tokens[$configId]);
|
||
saveTokensFile($cached_tokens);
|
||
|
||
return null;
|
||
}
|
||
|
||
/**
|
||
* 保存Token到缓存文件
|
||
*/
|
||
function saveToken($configId, $token) {
|
||
$cached_tokens = [];
|
||
if (file_exists(TOKEN_CACHE_FILE)) {
|
||
include TOKEN_CACHE_FILE;
|
||
}
|
||
|
||
$cached_tokens[$configId] = [
|
||
'token' => $token,
|
||
'timestamp' => time()
|
||
];
|
||
|
||
saveTokensFile($cached_tokens);
|
||
}
|
||
|
||
/**
|
||
* 保存tokens数组到文件
|
||
* @param array $cached_tokens tokens数组
|
||
*/
|
||
function saveTokensFile($cached_tokens) {
|
||
$content = "<?php\n";
|
||
$content .= "// Token缓存文件 - 自动生成\n";
|
||
$content .= "// 警告: 不要手动修改此文件\n\n";
|
||
$content .= '$cached_tokens = ' . var_export($cached_tokens, true) . ";\n";
|
||
$content .= "?>\n";
|
||
|
||
file_put_contents(TOKEN_CACHE_FILE, $content);
|
||
chmod(TOKEN_CACHE_FILE, 0600);
|
||
}
|
||
|
||
/**
|
||
* 魔方平台登录获取JWT Token
|
||
*/
|
||
function mofangLogin($siteUrl, $account, $apiKey) {
|
||
try {
|
||
$url = rtrim($siteUrl, '/') . '/v1/login_api';
|
||
$data = [
|
||
'account' => $account,
|
||
'password' => $apiKey
|
||
];
|
||
|
||
$ch = curl_init();
|
||
curl_setopt($ch, CURLOPT_URL, $url);
|
||
curl_setopt($ch, CURLOPT_POST, true);
|
||
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
|
||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
|
||
|
||
$response = curl_exec($ch);
|
||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||
curl_close($ch);
|
||
|
||
if ($httpCode !== 200) {
|
||
Logger::error("魔方登录请求失败,HTTP状态码: {$httpCode}", 'mofangLogin');
|
||
return null;
|
||
}
|
||
|
||
$result = json_decode($response, true);
|
||
|
||
if (isset($result['status']) && $result['status'] === 200 && isset($result['jwt'])) {
|
||
return $result['jwt'];
|
||
} else {
|
||
Logger::error("魔方登录失败: " . ($result['msg'] ?? '未知错误'), 'mofangLogin');
|
||
return null;
|
||
}
|
||
|
||
} catch (Exception $e) {
|
||
Logger::error("魔方登录异常: " . $e->getMessage(), 'mofangLogin');
|
||
return null;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取有效的Token(先查缓存,没有则重新登录)
|
||
*/
|
||
function getValidToken($configId) {
|
||
// 先尝试从缓存获取
|
||
$token = getCachedToken($configId);
|
||
if ($token) {
|
||
return $token;
|
||
}
|
||
|
||
// 缓存不存在或已过期,重新获取
|
||
$db = getVpsDB();
|
||
$config = $db->queryOne('SELECT * FROM configs WHERE id = ?', [$configId]);
|
||
|
||
if (!$config) {
|
||
Logger::error("配置ID {$configId} 不存在", 'getValidToken');
|
||
return null;
|
||
}
|
||
|
||
$token = mofangLogin($config['site_url'], $config['account'], $config['api_key']);
|
||
|
||
if ($token) {
|
||
saveToken($configId, $token);
|
||
}
|
||
|
||
return $token;
|
||
}
|
||
|
||
/**
|
||
* 发送魔方API请求
|
||
*/
|
||
function mofangApiRequest($siteUrl, $endpoint, $method = 'GET', $data = [], $configId = null) {
|
||
// 获取Token
|
||
if ($configId) {
|
||
$token = getValidToken($configId);
|
||
} else {
|
||
// 如果没有configId,尝试从第一个配置获取
|
||
$db = getVpsDB();
|
||
$configs = $db->query('SELECT * FROM configs LIMIT 1');
|
||
if (!$configs) {
|
||
return null;
|
||
}
|
||
$config = $configs[0];
|
||
$token = getValidToken($config['id']);
|
||
$siteUrl = $config['site_url'];
|
||
}
|
||
|
||
if (!$token) {
|
||
return ['status' => 400, 'msg' => '获取Token失败'];
|
||
}
|
||
|
||
$url = rtrim($siteUrl, '/') . $endpoint;
|
||
$headers = [
|
||
'Authorization: JWT ' . $token,
|
||
'Content-Type: application/json'
|
||
];
|
||
|
||
$ch = curl_init();
|
||
curl_setopt($ch, CURLOPT_URL, $url);
|
||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
||
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
|
||
|
||
if ($method === 'POST') {
|
||
curl_setopt($ch, CURLOPT_POST, true);
|
||
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
|
||
} elseif ($method === 'PUT') {
|
||
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
|
||
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
|
||
}
|
||
|
||
$response = curl_exec($ch);
|
||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||
curl_close($ch);
|
||
|
||
if ($httpCode !== 200) {
|
||
return ['status' => $httpCode, 'msg' => 'HTTP请求失败'];
|
||
}
|
||
|
||
$result = json_decode($response, true);
|
||
|
||
// 如果Token失效(405),清除缓存并重试
|
||
if (isset($result['status']) && $result['status'] === 405 && $configId) {
|
||
// 清除缓存
|
||
$cached_tokens = [];
|
||
if (file_exists(TOKEN_CACHE_FILE)) {
|
||
include TOKEN_CACHE_FILE;
|
||
}
|
||
unset($cached_tokens[$configId]);
|
||
saveTokensFile($cached_tokens);
|
||
|
||
// 重试一次
|
||
return mofangApiRequest($siteUrl, $endpoint, $method, $data, $configId);
|
||
}
|
||
|
||
return $result;
|
||
}
|
||
|
||
/**
|
||
* 获取VPS列表
|
||
*/
|
||
function mofangGetVpsList($configId, $page = 1, $limit = 100) {
|
||
$db = getVpsDB();
|
||
$config = $db->queryOne('SELECT * FROM configs WHERE id = ?', [$configId]);
|
||
|
||
if (!$config) {
|
||
return null;
|
||
}
|
||
|
||
$endpoint = "/v1/hosts?page={$page}&limit={$limit}";
|
||
return mofangApiRequest($config['site_url'], $endpoint, 'GET', [], $configId);
|
||
}
|
||
|
||
/**
|
||
* 获取VPS状态
|
||
*/
|
||
function mofangGetVpsStatus($configId, $vpsId, $updateDb = true) {
|
||
$db = getVpsDB();
|
||
$config = $db->queryOne('SELECT * FROM configs WHERE id = ?', [$configId]);
|
||
|
||
if (!$config) {
|
||
return null;
|
||
}
|
||
|
||
$endpoint = "/v1/hosts/{$vpsId}/module/status?type=host";
|
||
$result = mofangApiRequest($config['site_url'], $endpoint, 'GET', [], $configId);
|
||
|
||
// 如果获取成功且需要更新数据库
|
||
if ($updateDb && $result && isset($result['status']) && $result['status'] === 200 && isset($result['data'])) {
|
||
$statusData = $result['data'];
|
||
$rawStatus = $statusData['status'] ?? 'unknown';
|
||
|
||
// 状态映射:将魔方平台的原始状态转换为标准状态
|
||
$statusMap = [
|
||
'on' => 'on', // 开机
|
||
'off' => 'off', // 关机
|
||
'running' => 'on', // 运行中
|
||
'stopped' => 'off', // 已停止
|
||
'process' => 'process', // 处理中(开机/关机/重启过程中)
|
||
'pending' => 'process', // 等待中
|
||
'installing' => 'process', // 安装中
|
||
'rebooting' => 'process', // 重启中
|
||
'unknown' => 'unknown' // 未知
|
||
];
|
||
|
||
$status = $statusMap[$rawStatus] ?? $rawStatus;
|
||
|
||
$listDb = getVpsListDB();
|
||
|
||
// 先获取该VPS的IP地址,用于精确匹配
|
||
$vpsInfo = $listDb->queryOne(
|
||
'SELECT id, ip_address FROM vps_list WHERE config_id = ? AND vps_id = ?',
|
||
[$configId, $vpsId]
|
||
);
|
||
|
||
if ($vpsInfo) {
|
||
// 记录存在,执行UPDATE
|
||
$success = $listDb->execute(
|
||
'UPDATE vps_list SET status = ?, last_check = CURRENT_TIMESTAMP WHERE id = ?',
|
||
[$status, $vpsInfo['id']]
|
||
);
|
||
if ($success) {
|
||
Logger::info("[mofangGetVpsStatus] VPS {$vpsId} (IP: {$vpsInfo['ip_address']}) 状态已更新为: {$status}", 'mofangGetVpsStatus');
|
||
} else {
|
||
Logger::error("[mofangGetVpsStatus] VPS {$vpsId} 状态更新失败", 'mofangGetVpsStatus');
|
||
}
|
||
} else {
|
||
// 记录不存在,插入新记录
|
||
$success = $listDb->execute(
|
||
'INSERT INTO vps_list (config_id, vps_id, status, last_check) VALUES (?, ?, ?, CURRENT_TIMESTAMP)',
|
||
[$configId, $vpsId, $status]
|
||
);
|
||
if ($success) {
|
||
Logger::info("[mofangGetVpsStatus] VPS {$vpsId} 新记录已插入,状态: {$status}", 'mofangGetVpsStatus');
|
||
} else {
|
||
Logger::error("[mofangGetVpsStatus] VPS {$vpsId} 新记录插入失败", 'mofangGetVpsStatus');
|
||
}
|
||
}
|
||
} elseif ($updateDb && (!$result || !isset($result['status']) || $result['status'] !== 200)) {
|
||
// API调用失败,不更新数据库,保留原有状态
|
||
Logger::warning("[mofangGetVpsStatus] VPS {$vpsId} API调用失败,保留原有状态", 'mofangGetVpsStatus');
|
||
}
|
||
|
||
return $result;
|
||
}
|
||
|
||
/**
|
||
* 获取VPS详细信息
|
||
*/
|
||
function mofangGetVpsDetails($configId, $vpsId, $updateDb = true) {
|
||
$db = getVpsDB();
|
||
$config = $db->queryOne('SELECT * FROM configs WHERE id = ?', [$configId]);
|
||
|
||
if (!$config) {
|
||
return null;
|
||
}
|
||
|
||
$endpoint = "/v1/hosts/{$vpsId}";
|
||
$result = mofangApiRequest($config['site_url'], $endpoint, 'GET', [], $configId);
|
||
|
||
// 如果获取成功且需要更新数据库
|
||
if ($updateDb && $result && isset($result['status']) && $result['status'] === 200 && isset($result['data']['host'])) {
|
||
$host = $result['data']['host'];
|
||
|
||
// 解析详细信息
|
||
$updates = []; // 存储要更新的字段
|
||
$values = [];
|
||
|
||
// 提取开关机状态(如果有)
|
||
if (isset($host['status'])) {
|
||
$rawStatus = $host['status'];
|
||
|
||
// 状态映射:将魔方平台的原始状态转换为标准状态
|
||
$statusMap = [
|
||
'on' => 'on', // 开机
|
||
'off' => 'off', // 关机
|
||
'running' => 'on', // 运行中
|
||
'stopped' => 'off', // 已停止
|
||
'process' => 'process', // 处理中(开机/关机/重启过程中)
|
||
'pending' => 'process', // 等待中
|
||
'installing' => 'process', // 安装中
|
||
'rebooting' => 'process', // 重启中
|
||
'unknown' => 'unknown' // 未知
|
||
];
|
||
|
||
$status = $statusMap[$rawStatus] ?? $rawStatus;
|
||
$updates[] = 'status = ?';
|
||
$values[] = $status;
|
||
}
|
||
|
||
if (isset($host['config_option']) && is_array($host['config_option'])) {
|
||
foreach ($host['config_option'] as $option) {
|
||
switch ($option['key']) {
|
||
case 'cpu':
|
||
if (isset($option['value'])) {
|
||
preg_match('/(\d+)/', $option['value'], $matches);
|
||
if (!empty($matches)) {
|
||
$updates[] = 'cpu_cores = ?';
|
||
$values[] = intval($matches[1]);
|
||
}
|
||
}
|
||
break;
|
||
case 'memory':
|
||
if (isset($option['value'])) {
|
||
$updates[] = 'memory_size = ?';
|
||
$values[] = $option['value'];
|
||
}
|
||
break;
|
||
case 'system_disk_size':
|
||
if (isset($option['value'])) {
|
||
$updates[] = 'disk_size = ?';
|
||
$values[] = $option['value'];
|
||
}
|
||
break;
|
||
case 'bw':
|
||
if (isset($option['value'])) {
|
||
$updates[] = 'bandwidth = ?';
|
||
$values[] = $option['value'];
|
||
}
|
||
break;
|
||
case 'os':
|
||
if (isset($option['value'])) {
|
||
$updates[] = 'os_type = ?';
|
||
$values[] = $option['value'];
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 只有当有字段需要更新时才执行UPDATE
|
||
if (!empty($updates)) {
|
||
// 添加last_check更新
|
||
$updates[] = 'last_check = CURRENT_TIMESTAMP';
|
||
|
||
// 构建动态UPDATE语句
|
||
$setClause = implode(', ', $updates);
|
||
$values[] = $configId;
|
||
$values[] = $vpsId;
|
||
|
||
$listDb = getVpsListDB();
|
||
|
||
// 先检查记录是否存在
|
||
$existing = $listDb->queryOne(
|
||
'SELECT id FROM vps_list WHERE config_id = ? AND vps_id = ?',
|
||
[$configId, $vpsId]
|
||
);
|
||
|
||
if ($existing) {
|
||
// 记录存在,执行UPDATE
|
||
$listDb->execute(
|
||
"UPDATE vps_list SET {$setClause} WHERE config_id = ? AND vps_id = ?",
|
||
$values
|
||
);
|
||
Logger::info("[mofangGetVpsDetails] VPS {$vpsId} 详细信息已更新" . (isset($status) ? ",状态: {$status}" : ""), 'mofangGetVpsDetails');
|
||
} else {
|
||
// 记录不存在,插入新记录(只插入获取到的字段)
|
||
$columns = [];
|
||
$insertValues = [];
|
||
$placeholders = [];
|
||
|
||
// 解析SET子句中的字段
|
||
foreach ($updates as $update) {
|
||
if (strpos($update, 'last_check') === false) {
|
||
list($column, $value) = explode(' = ', $update);
|
||
$columns[] = $column;
|
||
$insertValues[] = array_shift($values); // 从$values中取出对应的值
|
||
$placeholders[] = '?';
|
||
}
|
||
}
|
||
|
||
// 添加config_id和vps_id
|
||
$columns[] = 'config_id';
|
||
$columns[] = 'vps_id';
|
||
$insertValues[] = $configId;
|
||
$insertValues[] = $vpsId;
|
||
|
||
if (!empty($columns)) {
|
||
$columnStr = implode(', ', $columns);
|
||
$placeholderStr = implode(', ', $placeholders);
|
||
$listDb->execute(
|
||
"INSERT INTO vps_list ({$columnStr}) VALUES ({$placeholderStr})",
|
||
$insertValues
|
||
);
|
||
Logger::info("[mofangGetVpsDetails] VPS {$vpsId} 新记录已插入", 'mofangGetVpsDetails');
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return $result;
|
||
}
|
||
|
||
/**
|
||
* VPS开机
|
||
*/
|
||
function mofangPowerOn($configId, $vpsId) {
|
||
$db = getVpsDB();
|
||
$config = $db->queryOne('SELECT * FROM configs WHERE id = ?', [$configId]);
|
||
|
||
if (!$config) {
|
||
return null;
|
||
}
|
||
|
||
$endpoint = "/v1/hosts/{$vpsId}/module/on";
|
||
$result = mofangApiRequest($config['site_url'], $endpoint, 'PUT', [], $configId);
|
||
|
||
// 开机操作后立即获取状态并更新数据库
|
||
if ($result && isset($result['status']) && $result['status'] === 200) {
|
||
sleep(2); // 等待2秒让状态生效
|
||
mofangGetVpsStatus($configId, $vpsId, true);
|
||
}
|
||
|
||
return $result;
|
||
}
|
||
|
||
/**
|
||
* VPS关机
|
||
*/
|
||
function mofangPowerOff($configId, $vpsId) {
|
||
$db = getVpsDB();
|
||
$config = $db->queryOne('SELECT * FROM configs WHERE id = ?', [$configId]);
|
||
|
||
if (!$config) {
|
||
return null;
|
||
}
|
||
|
||
$endpoint = "/v1/hosts/{$vpsId}/module/off";
|
||
$result = mofangApiRequest($config['site_url'], $endpoint, 'PUT', [], $configId);
|
||
|
||
// 关机操作后立即获取状态并更新数据库
|
||
if ($result && isset($result['status']) && $result['status'] === 200) {
|
||
sleep(2); // 等待2秒让状态生效
|
||
mofangGetVpsStatus($configId, $vpsId, true);
|
||
}
|
||
|
||
return $result;
|
||
}
|
||
|
||
/**
|
||
* VPS硬重启
|
||
*/
|
||
function mofangHardReboot($configId, $vpsId) {
|
||
$db = getVpsDB();
|
||
$config = $db->queryOne('SELECT * FROM configs WHERE id = ?', [$configId]);
|
||
|
||
if (!$config) {
|
||
return null;
|
||
}
|
||
|
||
$endpoint = "/v1/hosts/{$vpsId}/module/hard_reboot";
|
||
$result = mofangApiRequest($config['site_url'], $endpoint, 'PUT', [], $configId);
|
||
|
||
// 硬重启操作后立即获取状态并更新数据库
|
||
if ($result && isset($result['status']) && $result['status'] === 200) {
|
||
sleep(3); // 等待3秒让重启生效
|
||
mofangGetVpsStatus($configId, $vpsId, true);
|
||
}
|
||
|
||
return $result;
|
||
}
|
||
|
||
/**
|
||
* 刷新指定配置的VPS列表并保存到数据库
|
||
*/
|
||
function refreshVpsListForConfig($configId) {
|
||
$db = getVpsDB();
|
||
$config = $db->queryOne('SELECT * FROM configs WHERE id = ?', [$configId]);
|
||
|
||
if (!$config) {
|
||
return false;
|
||
}
|
||
|
||
// 获取VPS列表
|
||
$result = mofangGetVpsList($configId);
|
||
|
||
if (!$result || !isset($result['status']) || $result['status'] !== 200) {
|
||
Logger::error("获取VPS列表失败: " . ($result['msg'] ?? '未知错误'), 'refreshVpsListForConfig');
|
||
return false;
|
||
}
|
||
|
||
$hosts = $result['data']['host'] ?? [];
|
||
|
||
if (empty($hosts)) {
|
||
return true; // 没有VPS也算成功
|
||
}
|
||
|
||
// 批量保存到数据库
|
||
$listDb = getVpsListDB();
|
||
|
||
foreach ($hosts as $host) {
|
||
// 解析详细信息
|
||
$cpuCores = null;
|
||
$memorySize = null;
|
||
$diskSize = null;
|
||
$bandwidth = null;
|
||
$osType = null;
|
||
|
||
if (isset($host['config_option']) && is_array($host['config_option'])) {
|
||
foreach ($host['config_option'] as $option) {
|
||
switch ($option['key']) {
|
||
case 'cpu':
|
||
if (isset($option['value'])) {
|
||
// 提取数字,例如 "16核" -> 16
|
||
preg_match('/(\d+)/', $option['value'], $matches);
|
||
if (!empty($matches)) {
|
||
$cpuCores = intval($matches[1]);
|
||
}
|
||
}
|
||
break;
|
||
case 'memory':
|
||
if (isset($option['value'])) {
|
||
$memorySize = $option['value']; // 例如 "16G"
|
||
}
|
||
break;
|
||
case 'system_disk_size':
|
||
if (isset($option['value'])) {
|
||
$diskSize = $option['value']; // 例如 "Lin50G,Win50G"
|
||
}
|
||
break;
|
||
case 'bw':
|
||
if (isset($option['value'])) {
|
||
$bandwidth = $option['value']; // 例如 "70Mbps"
|
||
}
|
||
break;
|
||
case 'os':
|
||
if (isset($option['value'])) {
|
||
$osType = $option['value']; // 例如 "Debian-12.0_x64"
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 基于vps_id和ip_address去重
|
||
$existing = $listDb->queryOne(
|
||
'SELECT id, status FROM vps_list WHERE vps_id = ? AND ip_address = ?',
|
||
[$host['id'], $host['dedicatedip'] ?? null]
|
||
);
|
||
|
||
if ($existing) {
|
||
// 记录已存在,只更新非status字段,保留原有status
|
||
$listDb->execute(
|
||
'UPDATE vps_list SET domain = ?, product_name = ?, cpu_cores = ?, memory_size = ?, disk_size = ?, bandwidth = ?, os_type = ?, amount = ?, nextduedate = ?, section = ?, last_check = CURRENT_TIMESTAMP WHERE id = ?',
|
||
[
|
||
$host['domain'] ?? null,
|
||
$host['product_name'] ?? null,
|
||
$cpuCores,
|
||
$memorySize,
|
||
$diskSize,
|
||
$bandwidth,
|
||
$osType,
|
||
$host['amount'] ?? null,
|
||
$host['nextduedate'] ?? null,
|
||
$config['auto_monitor'] ? 1 : 0,
|
||
$existing['id']
|
||
]
|
||
);
|
||
} else {
|
||
// 新记录,插入所有字段(status设为null,稍后通过状态接口获取)
|
||
$listDb->execute(
|
||
'INSERT INTO vps_list (config_id, vps_id, domain, ip_address, product_name, cpu_cores, memory_size, disk_size, bandwidth, os_type, amount, nextduedate, status, section, last_check) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, CURRENT_TIMESTAMP)',
|
||
[
|
||
$configId,
|
||
$host['id'],
|
||
$host['domain'] ?? null,
|
||
$host['dedicatedip'] ?? null,
|
||
$host['product_name'] ?? null,
|
||
$cpuCores,
|
||
$memorySize,
|
||
$diskSize,
|
||
$bandwidth,
|
||
$osType,
|
||
$host['amount'] ?? null,
|
||
$host['nextduedate'] ?? null,
|
||
$config['auto_monitor'] ? 1 : 0
|
||
]
|
||
);
|
||
}
|
||
}
|
||
|
||
// 刷新列表后,批量获取每个VPS的状态
|
||
Logger::info("[refreshVpsListForConfig] 开始批量获取 {$configId} 配置下 " . count($hosts) . " 台VPS的状态", 'refreshVpsListForConfig');
|
||
|
||
foreach ($hosts as $host) {
|
||
// 调用专门的状态接口获取开关机状态
|
||
mofangGetVpsStatus($configId, $host['id'], true);
|
||
|
||
// 避免频繁请求,每次请求间隔0.5秒
|
||
usleep(500000); // 500毫秒
|
||
}
|
||
|
||
Logger::info("[refreshVpsListForConfig] 配置 {$configId} 的VPS列表和状态刷新完成", 'refreshVpsListForConfig');
|
||
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* 刷新所有配置的VPS列表
|
||
*/
|
||
function refreshAllVpsLists() {
|
||
$db = getVpsDB();
|
||
$configs = $db->query('SELECT * FROM configs');
|
||
|
||
$successCount = 0;
|
||
|
||
foreach ($configs as $config) {
|
||
if (refreshVpsListForConfig($config['id'])) {
|
||
$successCount++;
|
||
}
|
||
}
|
||
|
||
return $successCount;
|
||
}
|
||
|
||
/**
|
||
* 获取单个VPS的状态并更新到数据库
|
||
*/
|
||
function updateVpsStatusToDb($configId, $vpsId) {
|
||
$db = getVpsDB();
|
||
$config = $db->queryOne('SELECT * FROM configs WHERE id = ?', [$configId]);
|
||
|
||
if (!$config) {
|
||
Logger::error("配置ID {$configId} 不存在", 'updateVpsStatusToDb');
|
||
return null;
|
||
}
|
||
|
||
// 调用API获取VPS状态(不自动更新数据库,由本函数统一处理)
|
||
$result = mofangGetVpsStatus($configId, $vpsId, false);
|
||
|
||
if (!$result || !isset($result['status']) || $result['status'] !== 200) {
|
||
Logger::error("获取VPS {$vpsId} 状态失败,保留原有状态: " . ($result['msg'] ?? '未知错误'), 'updateVpsStatusToDb');
|
||
return null;
|
||
}
|
||
|
||
$statusData = $result['data'];
|
||
$rawStatus = $statusData['status'] ?? 'unknown';
|
||
$des = $statusData['des'] ?? '未知';
|
||
|
||
// 状态映射:将魔方平台的原始状态转换为标准状态
|
||
$statusMap = [
|
||
'on' => 'on', // 开机
|
||
'off' => 'off', // 关机
|
||
'running' => 'on', // 运行中
|
||
'stopped' => 'off', // 已停止
|
||
'process' => 'process', // 处理中(开机/关机/重启过程中)
|
||
'pending' => 'process', // 等待中
|
||
'installing' => 'process', // 安装中
|
||
'rebooting' => 'process', // 重启中
|
||
'unknown' => 'unknown' // 未知
|
||
];
|
||
|
||
$status = $statusMap[$rawStatus] ?? $rawStatus;
|
||
|
||
// 检查记录是否存在
|
||
$listDb = getVpsListDB();
|
||
$vpsInfo = $listDb->queryOne(
|
||
'SELECT id, ip_address FROM vps_list WHERE config_id = ? AND vps_id = ?',
|
||
[$configId, $vpsId]
|
||
);
|
||
|
||
if ($vpsInfo) {
|
||
// 记录存在,执行UPDATE
|
||
$success = $listDb->execute(
|
||
'UPDATE vps_list SET status = ?, last_check = CURRENT_TIMESTAMP WHERE id = ?',
|
||
[$status, $vpsInfo['id']]
|
||
);
|
||
if ($success) {
|
||
Logger::info("[updateVpsStatusToDb] VPS {$vpsId} (IP: {$vpsInfo['ip_address']}) 状态已更新为: {$status}", 'updateVpsStatusToDb');
|
||
} else {
|
||
Logger::error("[updateVpsStatusToDb] VPS {$vpsId} 状态更新失败,保留原有状态", 'updateVpsStatusToDb');
|
||
return null;
|
||
}
|
||
} else {
|
||
// 记录不存在,插入新记录
|
||
$success = $listDb->execute(
|
||
'INSERT INTO vps_list (config_id, vps_id, status, last_check) VALUES (?, ?, ?, CURRENT_TIMESTAMP)',
|
||
[$configId, $vpsId, $status]
|
||
);
|
||
if ($success) {
|
||
Logger::info("[updateVpsStatusToDb] VPS {$vpsId} 新记录已插入,状态: {$status}", 'updateVpsStatusToDb');
|
||
} else {
|
||
Logger::error("[updateVpsStatusToDb] VPS {$vpsId} 新记录插入失败", 'updateVpsStatusToDb');
|
||
return null;
|
||
}
|
||
}
|
||
|
||
return [
|
||
'vps_id' => $vpsId,
|
||
'status' => $status,
|
||
'des' => $des,
|
||
'updated' => true
|
||
];
|
||
}
|
||
|
||
/**
|
||
* 批量获取VPS状态并更新到数据库
|
||
*/
|
||
function batchUpdateVpsStatus($configId, $vpsIds = []) {
|
||
$db = getVpsDB();
|
||
$config = $db->queryOne('SELECT * FROM configs WHERE id = ?', [$configId]);
|
||
|
||
if (!$config) {
|
||
return ['success' => 0, 'failed' => 0, 'error' => '配置不存在'];
|
||
}
|
||
|
||
// 如果未指定VPS IDs,获取该配置下的所有VPS
|
||
if (empty($vpsIds)) {
|
||
$listDb = getVpsListDB();
|
||
$vpsList = $listDb->query('SELECT vps_id FROM vps_list WHERE config_id = ?', [$configId]);
|
||
$vpsIds = array_column($vpsList, 'vps_id');
|
||
}
|
||
|
||
if (empty($vpsIds)) {
|
||
return ['success' => 0, 'failed' => 0, 'error' => '没有VPS需要更新'];
|
||
}
|
||
|
||
$successCount = 0;
|
||
$failedCount = 0;
|
||
$results = [];
|
||
|
||
$listDb = getVpsListDB();
|
||
$listDb->getConnection()->beginTransaction();
|
||
|
||
try {
|
||
foreach ($vpsIds as $vpsId) {
|
||
$result = updateVpsStatusToDb($configId, $vpsId);
|
||
|
||
if ($result) {
|
||
$successCount++;
|
||
$results[] = $result;
|
||
} else {
|
||
$failedCount++;
|
||
$results[] = [
|
||
'vps_id' => $vpsId,
|
||
'status' => 'error',
|
||
'des' => '获取状态失败',
|
||
'updated' => false
|
||
];
|
||
}
|
||
}
|
||
|
||
$listDb->getConnection()->commit();
|
||
Logger::info("[batchUpdateVpsStatus] 批量更新完成: 成功{$successCount}, 失败{$failedCount}", 'batchUpdateVpsStatus');
|
||
} catch (Exception $e) {
|
||
$listDb->getConnection()->rollBack();
|
||
Logger::error("[batchUpdateVpsStatus] 批量更新失败,已回滚: " . $e->getMessage(), 'batchUpdateVpsStatus');
|
||
return ['success' => 0, 'failed' => count($vpsIds), 'error' => '批量更新失败: ' . $e->getMessage()];
|
||
}
|
||
|
||
return [
|
||
'success' => $successCount,
|
||
'failed' => $failedCount,
|
||
'total' => count($vpsIds),
|
||
'results' => $results
|
||
];
|
||
}
|
||
?>
|