From 8cb285866f1367b9ea3dae113779971d7e4de9f2 Mon Sep 17 00:00:00 2001 From: MasonLiu <2857911564@qq.com> Date: Tue, 30 Jun 2026 01:24:49 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=AF=B9=E9=98=BF=E9=87=8C?= =?UTF-8?q?=E4=BA=91=E7=9A=84=E6=94=AF=E6=8C=81=EF=BC=88ecs=E6=9C=AA?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- aliyun.php | 933 +++++++++++++++++++++++++++++++++++++++++++ config_add.php | 55 ++- diagnose_tencent.php | 108 ----- index.php | 53 ++- tencentcloud.php | 90 +++++ 5 files changed, 1114 insertions(+), 125 deletions(-) create mode 100644 aliyun.php delete mode 100644 diagnose_tencent.php diff --git a/aliyun.php b/aliyun.php new file mode 100644 index 0000000..7b64f7e --- /dev/null +++ b/aliyun.php @@ -0,0 +1,933 @@ + $value) { + if ($canonicalizedQueryString !== '') { + $canonicalizedQueryString .= '&'; + } + $canonicalizedQueryString .= aliyunEncode($key) . '=' . aliyunEncode($value); + } + + // 构造待签名字符串 + $stringToSign = $method . '&%2F&' . aliyunEncode($canonicalizedQueryString); + + // 计算HMAC-SHA1签名 + $signature = base64_encode(hash_hmac('sha1', $stringToSign, $secretKey . '&', true)); + + return $signature; +} + +/** + * 发送阿里云API请求 + * @param string $configId 配置ID + * @param string $action API动作 + * @param array $params 请求参数 + * @param string $region 区域 + * @param string $serviceType 服务类型: ecs 或 swas + * @return array|null + */ +function aliyunApiRequest($configId, $action, $params = [], $region = 'cn-hangzhou', $serviceType = 'ecs') { + $db = getVpsDB(); + $config = $db->queryOne('SELECT * FROM configs WHERE id = ?', [$configId]); + + if (!$config) { + Logger::error("配置ID {$configId} 不存在", 'aliyunApiRequest'); + return null; + } + + $accessKeyId = $config['account']; + $accessKeySecret = $config['api_key']; + + Logger::debug("[aliyunApiRequest] Config ID: {$configId}, AccessKeyId: " . substr($accessKeyId, 0, 8) . "***", 'aliyunApiRequest'); + + // 确定API域名 + if (!$region || empty($region)) { + Logger::error("Region参数为空,无法构建API域名", 'aliyunApiRequest'); + return ['status' => 400, 'error' => 'Region参数为空']; + } + + if ($serviceType === 'swas') { + $host = 'swas.' . $region . '.aliyuncs.com'; + } else { + $host = 'ecs.' . $region . '.aliyuncs.com'; + } + + // 公共参数 + $commonParams = [ + 'Action' => $action, + 'Version' => ($serviceType === 'swas') ? '2020-06-01' : '2014-05-26', + 'Format' => 'JSON', + 'AccessKeyId' => $accessKeyId, + 'SignatureMethod' => 'HMAC-SHA1', + 'SignatureVersion' => '1.0', + 'SignatureNonce' => uniqid(), + 'Timestamp' => gmdate('Y-m-d\TH:i:s\Z'), + 'RegionId' => $region, + ]; + + // 合并参数 + $allParams = array_merge($commonParams, $params); + + // 生成签名 + $signature = generateAliyunSignature( + 'GET', + $allParams, + $accessKeySecret + ); + + $allParams['Signature'] = $signature; + + // 构建URL + $url = 'https://' . $host . '/?' . http_build_query($allParams); + + Logger::debug("[aliyunApiRequest] URL: {$url}", 'aliyunApiRequest'); + Logger::debug("[aliyunApiRequest] Action: {$action}, Region: {$region}, ServiceType: {$serviceType}", 'aliyunApiRequest'); + + // 发送请求 + $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_TIMEOUT, 15); + + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + $curlError = curl_error($ch); + curl_close($ch); + + if ($curlError) { + Logger::error("cURL错误: {$curlError}", 'aliyunApiRequest'); + return ['status' => 0, 'error' => $curlError]; + } + + if ($httpCode !== 200) { + Logger::error("HTTP请求失败: {$httpCode}, 响应: {$response}", 'aliyunApiRequest'); + + // 尝试解析错误响应 + $errorResult = json_decode($response, true); + if ($errorResult && isset($errorResult['Message'])) { + return ['status' => $httpCode, 'error' => $errorResult['Message'], 'code' => $errorResult['Code'] ?? 'Unknown']; + } + + return ['status' => $httpCode, 'error' => 'HTTP请求失败 (' . $httpCode . ')']; + } + + $result = json_decode($response, true); + + if (!$result) { + Logger::error("JSON解析失败", 'aliyunApiRequest'); + return ['status' => 500, 'error' => '响应解析失败']; + } + + // 检查响应 + if (isset($result['Code'])) { + Logger::error("API错误: {$result['Code']} - {$result['Message']}", 'aliyunApiRequest'); + return ['status' => 400, 'error' => $result['Message'], 'code' => $result['Code']]; + } + + return ['status' => 200, 'data' => $result, 'region' => $region, 'service_type' => $serviceType]; +} + +/** + * 获取所有可用区域列表(ECS) + */ +function getAliyunRegions($configId) { + return [ + 'cn-qingdao', // 华北1(青岛) + 'cn-beijing', // 华北2(北京) + 'cn-zhangjiakou', // 华北3(张家口) + 'cn-huhehaote', // 华北5(呼和浩特) + 'cn-wulanchabu', // 华北6(乌兰察布) + 'cn-hangzhou', // 华东1(杭州) + 'cn-shanghai', // 华东2(上海) + 'cn-nanjing', // 华东5(南京) + 'cn-fuzhou', // 华东6(福州) + 'cn-shenzhen', // 华南1(深圳) + 'cn-heyuan', // 华南2(河源) + 'cn-guangzhou', // 华南3(广州) + 'cn-chengdu', // 西南1(成都) + 'cn-hongkong', // 中国香港 + 'ap-southeast-1', // 新加坡 + 'ap-southeast-5', // 印度尼西亚(雅加达) + 'ap-northeast-1', // 日本(东京) + 'ap-northeast-2', // 韩国(首尔) + 'ap-southeast-3', // 马来西亚(吉隆坡) + 'ap-southeast-6', // 菲律宾(马尼拉) + 'ap-southeast-7', // 泰国(曼谷) + 'us-west-1', // 美国(硅谷) + 'us-east-1', // 美国(弗吉尼亚) + 'eu-central-1', // 德国(法兰克福) + 'eu-west-1', // 英国(伦敦) + 'me-east-1', // 阿联酋(迪拜) + 'me-central-1', // 沙特(利雅得) + ]; +} + +/** + * 获取轻量应用服务器可用区域列表 + */ +function getAliyunSwasRegions($configId) { + return [ + 'cn-hangzhou', // 华东1(杭州) + 'cn-shanghai', // 华东2(上海) + 'cn-qingdao', // 华北1(青岛) + 'cn-beijing', // 华北2(北京) + 'cn-zhangjiakou', // 华北3(张家口) + 'cn-shenzhen', // 华南1(深圳) + 'cn-heyuan', // 华南2(河源) + 'cn-chengdu', // 西南1(成都) + 'cn-hongkong', // 中国香港 + 'ap-southeast-1', // 新加坡 + 'ap-northeast-1', // 日本(东京) + 'us-west-1', // 美国(硅谷) + 'eu-central-1', // 德国(法兰克福) + ]; +} + +/** + * 获取ECS实例列表(单个区域) + */ +function aliyunGetEcsList($configId, $region, $maxResults = 100, $nextToken = null) { + $params = [ + 'MaxResults' => $maxResults, + ]; + + if ($nextToken) { + $params['NextToken'] = $nextToken; + } + + return aliyunApiRequest($configId, 'DescribeInstances', $params, $region, 'ecs'); +} + +/** + * 获取轻量应用服务器实例列表(单个区域) + */ +function aliyunGetSwasList($configId, $region, $pageNumber = 1, $pageSize = 100) { + $params = [ + 'PageNumber' => $pageNumber, + 'PageSize' => $pageSize, + ]; + + return aliyunApiRequest($configId, 'ListInstances', $params, $region, 'swas'); +} + +/** + * 获取ECS实例详细信息 + */ +function aliyunGetEcsDetails($configId, $instanceId, $region = null, $updateDb = true) { + $params = [ + 'InstanceIds' => json_encode([$instanceId]), + ]; + + $result = aliyunApiRequest($configId, 'DescribeInstances', $params, $region, 'ecs'); + + // 如果获取成功且需要更新数据库 + if ($updateDb && $result && isset($result['status']) && $result['status'] === 200) { + $instances = $result['data']['Instances']['Instance'] ?? []; + + if (!empty($instances)) { + updateAliyunEcsToDatabase($configId, $instances[0]); + } + } + + return $result; +} + +/** + * 获取轻量应用服务器实例详细信息 + */ +function aliyunGetSwasDetails($configId, $instanceId, $region = null, $updateDb = true) { + $params = [ + 'InstanceIds' => json_encode([$instanceId]), + ]; + + $result = aliyunApiRequest($configId, 'ListInstances', $params, $region, 'swas'); + + // 如果获取成功且需要更新数据库 + if ($updateDb && $result && isset($result['status']) && $result['status'] === 200) { + $instances = $result['data']['Instances'] ?? []; + + if (!empty($instances)) { + updateAliyunSwasToDatabase($configId, $instances[0]); + } + } + + return $result; +} + +/** + * 获取ECS实例状态 + */ +function aliyunGetEcsStatus($configId, $instanceId, $region = null, $updateDb = true) { + $params = [ + 'InstanceId.1' => $instanceId, + ]; + + $result = aliyunApiRequest($configId, 'DescribeInstanceStatus', $params, $region, 'ecs'); + + // 如果获取成功且需要更新数据库 + if ($updateDb && $result && isset($result['status']) && $result['status'] === 200) { + $instanceStatusSet = $result['data']['InstanceStatuses']['InstanceStatus'] ?? []; + + if (!empty($instanceStatusSet)) { + $statusInfo = $instanceStatusSet[0]; + $rawStatus = $statusInfo['Status'] ?? 'UNKNOWN'; + + // 状态映射 + $statusMap = [ + 'Pending' => 'process', + 'Running' => 'on', + 'Starting' => 'process', + 'Stopping' => 'process', + 'Stopped' => 'off', + 'Rebooting' => 'process', + 'Unknown' => 'unknown' + ]; + + $status = $statusMap[$rawStatus] ?? 'unknown'; + + updateVpsStatusInDatabaseAliyun($configId, $instanceId, $status); + } + } + + return $result; +} + +/** + * 获取轻量应用服务器实例状态 + */ +function aliyunGetSwasStatus($configId, $instanceId, $region = null, $updateDb = true) { + $params = [ + 'InstanceIds' => json_encode([$instanceId]), + ]; + + $result = aliyunApiRequest($configId, 'ListInstanceStatus', $params, $region, 'swas'); + + // 如果获取成功且需要更新数据库 + if ($updateDb && $result && isset($result['status']) && $result['status'] === 200) { + $instanceStatusSet = $result['data']['InstanceStatuses'] ?? []; + + if (!empty($instanceStatusSet)) { + $statusInfo = $instanceStatusSet[0]; + $rawStatus = $statusInfo['Status'] ?? 'UNKNOWN'; + + // 状态映射 + $statusMap = [ + 'Pending' => 'process', + 'Starting' => 'process', + 'Running' => 'on', + 'Stopping' => 'process', + 'Stopped' => 'off', + 'Resetting' => 'process', + 'Upgrading' => 'process', + 'Disabled' => 'off', + 'Unknown' => 'unknown' + ]; + + $status = $statusMap[$rawStatus] ?? 'unknown'; + + updateVpsStatusInDatabaseAliyun($configId, $instanceId, $status); + } + } + + return $result; +} + +/** + * 启动ECS实例 + */ +function aliyunPowerOn($configId, $instanceId, $region = null) { + // 如果未提供region,从数据库获取 + if (!$region) { + $listDb = getVpsListDB(); + $vpsInfo = $listDb->queryOne( + 'SELECT domain FROM vps_list WHERE config_id = ? AND vps_id = ?', + [$configId, $instanceId] + ); + if ($vpsInfo && !empty($vpsInfo['domain'])) { + $region = $vpsInfo['domain']; + Logger::info("[aliyunPowerOn] 从数据库获取到 region: {$region}", 'aliyunPowerOn'); + } else { + Logger::error("[aliyunPowerOn] 无法从数据库获取 region,config_id: {$configId}, instance_id: {$instanceId}", 'aliyunPowerOn'); + return ['status' => 400, 'error' => '无法获取实例区域信息']; + } + } + + $params = [ + 'InstanceId' => $instanceId, + ]; + + $result = aliyunApiRequest($configId, 'StartInstance', $params, $region, 'ecs'); + + // 开机操作后立即获取状态并更新数据库 + if ($result && isset($result['status']) && $result['status'] === 200) { + sleep(2); + aliyunGetEcsStatus($configId, $instanceId, $region, true); + } + + return $result; +} + +/** + * 启动轻量应用服务器 + */ +function aliyunSwasPowerOn($configId, $instanceId, $region = null) { + // 如果未提供region,从数据库获取 + if (!$region) { + $listDb = getVpsListDB(); + $vpsInfo = $listDb->queryOne( + 'SELECT domain FROM vps_list WHERE config_id = ? AND vps_id = ?', + [$configId, $instanceId] + ); + if ($vpsInfo && !empty($vpsInfo['domain'])) { + $region = $vpsInfo['domain']; + Logger::info("[aliyunSwasPowerOn] 从数据库获取到 region: {$region}", 'aliyunSwasPowerOn'); + } else { + Logger::error("[aliyunSwasPowerOn] 无法从数据库获取 region,config_id: {$configId}, instance_id: {$instanceId}", 'aliyunSwasPowerOn'); + return ['status' => 400, 'error' => '无法获取实例区域信息']; + } + } + + $params = [ + 'InstanceId' => $instanceId, + ]; + + $result = aliyunApiRequest($configId, 'StartInstance', $params, $region, 'swas'); + + // 开机操作后立即获取状态并更新数据库 + if ($result && isset($result['status']) && $result['status'] === 200) { + sleep(2); + aliyunGetSwasStatus($configId, $instanceId, $region, true); + } + + return $result; +} + +/** + * 停止ECS实例 + */ +function aliyunPowerOff($configId, $instanceId, $region = null) { + // 如果未提供region,从数据库获取 + if (!$region) { + $listDb = getVpsListDB(); + $vpsInfo = $listDb->queryOne( + 'SELECT domain FROM vps_list WHERE config_id = ? AND vps_id = ?', + [$configId, $instanceId] + ); + if ($vpsInfo && !empty($vpsInfo['domain'])) { + $region = $vpsInfo['domain']; + } else { + Logger::error("[aliyunPowerOff] 无法从数据库获取 region", 'aliyunPowerOff'); + return ['status' => 400, 'error' => '无法获取实例区域信息']; + } + } + + $params = [ + 'InstanceId' => $instanceId, + ]; + + $result = aliyunApiRequest($configId, 'StopInstance', $params, $region, 'ecs'); + + // 关机操作后立即获取状态并更新数据库 + if ($result && isset($result['status']) && $result['status'] === 200) { + sleep(2); + aliyunGetEcsStatus($configId, $instanceId, $region, true); + } + + return $result; +} + +/** + * 停止轻量应用服务器 + */ +function aliyunSwasPowerOff($configId, $instanceId, $region = null) { + // 如果未提供region,从数据库获取 + if (!$region) { + $listDb = getVpsListDB(); + $vpsInfo = $listDb->queryOne( + 'SELECT domain FROM vps_list WHERE config_id = ? AND vps_id = ?', + [$configId, $instanceId] + ); + if ($vpsInfo && !empty($vpsInfo['domain'])) { + $region = $vpsInfo['domain']; + } else { + Logger::error("[aliyunSwasPowerOff] 无法从数据库获取 region", 'aliyunSwasPowerOff'); + return ['status' => 400, 'error' => '无法获取实例区域信息']; + } + } + + $params = [ + 'InstanceId' => $instanceId, + ]; + + $result = aliyunApiRequest($configId, 'StopInstance', $params, $region, 'swas'); + + // 关机操作后立即获取状态并更新数据库 + if ($result && isset($result['status']) && $result['status'] === 200) { + sleep(2); + aliyunGetSwasStatus($configId, $instanceId, $region, true); + } + + return $result; +} + +/** + * 重启ECS实例 + */ +function aliyunReboot($configId, $instanceId, $region = null) { + // 如果未提供region,从数据库获取 + if (!$region) { + $listDb = getVpsListDB(); + $vpsInfo = $listDb->queryOne( + 'SELECT domain FROM vps_list WHERE config_id = ? AND vps_id = ?', + [$configId, $instanceId] + ); + if ($vpsInfo && !empty($vpsInfo['domain'])) { + $region = $vpsInfo['domain']; + } else { + Logger::error("[aliyunReboot] 无法从数据库获取 region", 'aliyunReboot'); + return ['status' => 400, 'error' => '无法获取实例区域信息']; + } + } + + $params = [ + 'InstanceId' => $instanceId, + ]; + + $result = aliyunApiRequest($configId, 'RebootInstance', $params, $region, 'ecs'); + + // 重启操作后立即获取状态并更新数据库 + if ($result && isset($result['status']) && $result['status'] === 200) { + sleep(3); + aliyunGetEcsStatus($configId, $instanceId, $region, true); + } + + return $result; +} + +/** + * 重启轻量应用服务器 + */ +function aliyunSwasReboot($configId, $instanceId, $region = null) { + // 如果未提供region,从数据库获取 + if (!$region) { + $listDb = getVpsListDB(); + $vpsInfo = $listDb->queryOne( + 'SELECT domain FROM vps_list WHERE config_id = ? AND vps_id = ?', + [$configId, $instanceId] + ); + if ($vpsInfo && !empty($vpsInfo['domain'])) { + $region = $vpsInfo['domain']; + } else { + Logger::error("[aliyunSwasReboot] 无法从数据库获取 region", 'aliyunSwasReboot'); + return ['status' => 400, 'error' => '无法获取实例区域信息']; + } + } + + $params = [ + 'InstanceId' => $instanceId, + ]; + + $result = aliyunApiRequest($configId, 'RebootInstance', $params, $region, 'swas'); + + // 重启操作后立即获取状态并更新数据库 + if ($result && isset($result['status']) && $result['status'] === 200) { + sleep(3); + aliyunGetSwasStatus($configId, $instanceId, $region, true); + } + + return $result; +} + +/** + * 将ECS信息更新到数据库 + */ +function updateAliyunEcsToDatabase($configId, $instance) { + $listDb = getVpsListDB(); + + $vpsId = $instance['InstanceId']; + $region = $instance['RegionId'] ?? ''; + $zoneId = $instance['ZoneId'] ?? ''; + + // 提取CPU和内存信息 + $cpuCores = $instance['Cpu'] ?? null; + // 注意:阿里云API返回的Memory单位是MB,需要转换为GB + $memorySize = isset($instance['Memory']) ? round($instance['Memory'] / 1024, 2) . 'G' : null; + + // 提取系统盘信息 + $diskSize = null; + if (isset($instance['SystemDisk']) && isset($instance['SystemDisk']['Size'])) { + $diskSize = $instance['SystemDisk']['Size'] . 'G'; + } + + // 提取带宽信息 + $bandwidth = null; + if (isset($instance['InternetMaxBandwidthOut'])) { + $bandwidth = $instance['InternetMaxBandwidthOut'] . 'Mbps'; + } + + // 提取操作系统信息 + $osType = $instance['OSName'] ?? ($instance['ImageId'] ?? null); + + // 提取IP地址 + $ipAddress = null; + if (isset($instance['PublicIpAddress']) && !empty($instance['PublicIpAddress']['IpAddress'])) { + $ipAddress = $instance['PublicIpAddress']['IpAddress'][0]; + } elseif (isset($instance['EipAddress']) && isset($instance['EipAddress']['IpAddress'])) { + $ipAddress = $instance['EipAddress']['IpAddress']; + } + + // 提取实例名称 + $productName = $instance['InstanceName'] ?? null; + + // 提取到期时间 + $nextduedate = null; + if (isset($instance['ExpiredTime'])) { + $expiredTime = $instance['ExpiredTime']; + if ($expiredTime !== '' && $expiredTime !== null) { + $nextduedate = strtotime($expiredTime); + } + } + + // 检查记录是否存在 + $existing = $listDb->queryOne( + 'SELECT id FROM vps_list WHERE config_id = ? AND vps_id = ?', + [$configId, $vpsId] + ); + + if ($existing) { + // 更新现有记录 + $listDb->execute( + 'UPDATE vps_list SET domain = ?, ip_address = ?, product_name = ?, cpu_cores = ?, memory_size = ?, disk_size = ?, bandwidth = ?, os_type = ?, nextduedate = ?, last_check = CURRENT_TIMESTAMP WHERE id = ?', + [ + $zoneId, + $ipAddress, + $productName, + $cpuCores, + $memorySize, + $diskSize, + $bandwidth, + $osType, + $nextduedate, + $existing['id'] + ] + ); + Logger::info("[updateAliyunEcsToDatabase] ECS {$vpsId} 详细信息已更新", 'updateAliyunEcsToDatabase'); + } else { + // 插入新记录 + $listDb->execute( + 'INSERT INTO vps_list (config_id, vps_id, domain, ip_address, product_name, cpu_cores, memory_size, disk_size, bandwidth, os_type, status, nextduedate, last_check) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, CURRENT_TIMESTAMP)', + [ + $configId, + $vpsId, + $zoneId, + $ipAddress, + $productName, + $cpuCores, + $memorySize, + $diskSize, + $bandwidth, + $osType, + $nextduedate + ] + ); + Logger::info("[updateAliyunEcsToDatabase] ECS {$vpsId} 新记录已插入", 'updateAliyunEcsToDatabase'); + } +} + +/** + * 将轻量应用服务器信息更新到数据库 + */ +function updateAliyunSwasToDatabase($configId, $instance) { + $listDb = getVpsListDB(); + + $vpsId = $instance['InstanceId']; + $region = $instance['RegionId'] ?? ''; + + // 提取CPU和内存信息(从ResourceSpec中获取) + $cpuCores = isset($instance['ResourceSpec']) ? $instance['ResourceSpec']['Cpu'] : null; + $memorySize = isset($instance['ResourceSpec']) ? $instance['ResourceSpec']['Memory'] . 'G' : null; + + // 提取磁盘信息 + $diskSize = isset($instance['ResourceSpec']) ? $instance['ResourceSpec']['DiskSize'] . 'G' : null; + + // 提取带宽信息 + $bandwidth = isset($instance['ResourceSpec']) ? $instance['ResourceSpec']['Bandwidth'] . 'Mbps' : null; + + // 提取操作系统信息 + $osType = null; + if (isset($instance['Image'])) { + $osType = $instance['Image']['OsType'] ?? null; + } + + // 提取IP地址 + $ipAddress = $instance['PublicIpAddress'] ?? null; + + // 提取实例名称 + $productName = $instance['InstanceName'] ?? null; + + // 提取到期时间 + $nextduedate = null; + if (isset($instance['ExpiredTime'])) { + $expiredTime = $instance['ExpiredTime']; + if ($expiredTime !== '' && $expiredTime !== null) { + $nextduedate = strtotime($expiredTime); + } + } + + // 检查记录是否存在 + $existing = $listDb->queryOne( + 'SELECT id FROM vps_list WHERE config_id = ? AND vps_id = ?', + [$configId, $vpsId] + ); + + if ($existing) { + // 更新现有记录 + $listDb->execute( + 'UPDATE vps_list SET domain = ?, ip_address = ?, product_name = ?, cpu_cores = ?, memory_size = ?, disk_size = ?, bandwidth = ?, os_type = ?, nextduedate = ?, last_check = CURRENT_TIMESTAMP WHERE id = ?', + [ + $region, + $ipAddress, + $productName, + $cpuCores, + $memorySize, + $diskSize, + $bandwidth, + $osType, + $nextduedate, + $existing['id'] + ] + ); + Logger::info("[updateAliyunSwasToDatabase] SWAS {$vpsId} 详细信息已更新", 'updateAliyunSwasToDatabase'); + } else { + // 插入新记录 + $listDb->execute( + 'INSERT INTO vps_list (config_id, vps_id, domain, ip_address, product_name, cpu_cores, memory_size, disk_size, bandwidth, os_type, status, nextduedate, last_check) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, CURRENT_TIMESTAMP)', + [ + $configId, + $vpsId, + $region, + $ipAddress, + $productName, + $cpuCores, + $memorySize, + $diskSize, + $bandwidth, + $osType, + $nextduedate + ] + ); + Logger::info("[updateAliyunSwasToDatabase] SWAS {$vpsId} 新记录已插入", 'updateAliyunSwasToDatabase'); + } +} + +/** + * 更新VPS状态到数据库 + */ +function updateVpsStatusInDatabaseAliyun($configId, $vpsId, $status) { + $listDb = getVpsListDB(); + + $vpsInfo = $listDb->queryOne( + 'SELECT id FROM vps_list WHERE config_id = ? AND vps_id = ?', + [$configId, $vpsId] + ); + + if ($vpsInfo) { + $listDb->execute( + 'UPDATE vps_list SET status = ?, last_check = CURRENT_TIMESTAMP WHERE id = ?', + [$status, $vpsInfo['id']] + ); + Logger::info("[updateVpsStatusInDatabaseAliyun] VPS {$vpsId} 状态已更新为: {$status}", 'updateVpsStatusInDatabaseAliyun'); + } else { + $listDb->execute( + 'INSERT INTO vps_list (config_id, vps_id, status, last_check) VALUES (?, ?, ?, CURRENT_TIMESTAMP)', + [$configId, $vpsId, $status] + ); + Logger::info("[updateVpsStatusInDatabaseAliyun] VPS {$vpsId} 新记录已插入,状态: {$status}", 'updateVpsStatusInDatabaseAliyun'); + } +} + +/** + * 刷新指定配置的ECS列表(遍历所有区域) + */ +function refreshAliyunEcsListForConfig($configId) { + $db = getVpsDB(); + $config = $db->queryOne('SELECT * FROM configs WHERE id = ?', [$configId]); + + if (!$config || $config['site_type'] !== 'aliyun') { + return false; + } + + // 先获取区域列表 + $regions = getAliyunRegions($configId); + $totalInstances = 0; + + Logger::info("[refreshAliyunEcsListForConfig] 开始遍历所有区域获取ECS列表", 'refreshAliyunEcsListForConfig'); + + foreach ($regions as $region) { + try { + $nextToken = null; + do { + $result = aliyunGetEcsList($configId, $region, 100, $nextToken); + + if ($result && isset($result['status']) && $result['status'] === 200) { + $instances = $result['data']['Instances']['Instance'] ?? []; + + if (!empty($instances)) { + Logger::info("[refreshAliyunEcsListForConfig] 区域 {$region} 找到 " . count($instances) . " 台ECS", 'refreshAliyunEcsListForConfig'); + + foreach ($instances as $instance) { + updateAliyunEcsToDatabase($configId, $instance); + + // 获取状态 + aliyunGetEcsStatus($configId, $instance['InstanceId'], $region, true); + + $totalInstances++; + + // 避免频繁请求 + usleep(300000); // 300毫秒 + } + } + + // 检查是否有下一页 + $nextToken = $result['data']['NextToken'] ?? null; + } else { + Logger::warning("[refreshAliyunEcsListForConfig] 区域 {$region} 获取失败: " . ($result['msg'] ?? '未知错误'), 'refreshAliyunEcsListForConfig'); + break; + } + } while ($nextToken); + } catch (Exception $e) { + Logger::error("[refreshAliyunEcsListForConfig] 区域 {$region} 异常: " . $e->getMessage(), 'refreshAliyunEcsListForConfig'); + } + + // 区域之间稍作延迟 + usleep(500000); // 500毫秒 + } + + Logger::info("[refreshAliyunEcsListForConfig] ECS列表刷新完成,共获取 {$totalInstances} 台实例", 'refreshAliyunEcsListForConfig'); + + return true; +} + +/** + * 刷新指定配置的轻量应用服务器列表(遍历所有区域) + */ +function refreshAliyunSwasListForConfig($configId) { + $db = getVpsDB(); + $config = $db->queryOne('SELECT * FROM configs WHERE id = ?', [$configId]); + + if (!$config || $config['site_type'] !== 'aliyun_swas') { + return false; + } + + // 先获取区域列表 + $regions = getAliyunSwasRegions($configId); + $totalInstances = 0; + + Logger::info("[refreshAliyunSwasListForConfig] 开始遍历所有区域获取轻量应用服务器列表", 'refreshAliyunSwasListForConfig'); + + foreach ($regions as $region) { + try { + $pageNumber = 1; + do { + $result = aliyunGetSwasList($configId, $region, $pageNumber, 100); + + if ($result && isset($result['status']) && $result['status'] === 200) { + $instances = $result['data']['Instances'] ?? []; + $totalCount = $result['data']['TotalCount'] ?? 0; + $pageSize = $result['data']['PageSize'] ?? 10; + + if (!empty($instances)) { + Logger::info("[refreshAliyunSwasListForConfig] 区域 {$region} 找到 " . count($instances) . " 台轻量服务器", 'refreshAliyunSwasListForConfig'); + + foreach ($instances as $instance) { + updateAliyunSwasToDatabase($configId, $instance); + + // 获取状态 + aliyunGetSwasStatus($configId, $instance['InstanceId'], $region, true); + + $totalInstances++; + + // 避免频繁请求 + usleep(300000); // 300毫秒 + } + } + + // 检查是否有下一页 + $totalPages = ceil($totalCount / $pageSize); + $pageNumber++; + + if ($pageNumber > $totalPages) { + break; + } + } else { + Logger::warning("[refreshAliyunSwasListForConfig] 区域 {$region} 获取失败: " . ($result['msg'] ?? '未知错误'), 'refreshAliyunSwasListForConfig'); + break; + } + } while (true); + } catch (Exception $e) { + Logger::error("[refreshAliyunSwasListForConfig] 区域 {$region} 异常: " . $e->getMessage(), 'refreshAliyunSwasListForConfig'); + } + + // 区域之间稍作延迟 + usleep(500000); // 500毫秒 + } + + Logger::info("[refreshAliyunSwasListForConfig] 轻量应用服务器列表刷新完成,共获取 {$totalInstances} 台实例", 'refreshAliyunSwasListForConfig'); + + return true; +} + +/** + * 刷新所有阿里云配置的实例列表(ECS + SWAS) + */ +function refreshAllAliyunVpsLists() { + $db = getVpsDB(); + $configs = $db->query('SELECT * FROM configs WHERE site_type IN (?, ?)', ['aliyun', 'aliyun_swas']); + + $successCount = 0; + + foreach ($configs as $config) { + if ($config['site_type'] === 'aliyun') { + // 刷新ECS列表 + if (refreshAliyunEcsListForConfig($config['id'])) { + $successCount++; + } + } elseif ($config['site_type'] === 'aliyun_swas') { + // 刷新轻量应用服务器列表 + if (refreshAliyunSwasListForConfig($config['id'])) { + $successCount++; + } + } + } + + return $successCount; +} +?> diff --git a/config_add.php b/config_add.php index bf7087f..8a93777 100644 --- a/config_add.php +++ b/config_add.php @@ -138,13 +138,15 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $dbSiteType = $siteType; if ($siteType === 'tencent_cvm' || $siteType === 'tencent_lh') { $dbSiteType = 'tencent'; + } elseif ($siteType === 'aliyun_swas') { + $dbSiteType = 'aliyun_swas'; } - // 验证必填字段(腾讯云需要siteUrl) - if ($siteType === 'tencent_cvm' || $siteType === 'tencent_lh') { - // 腾讯云:siteUrl必填(API域名) + // 验证必填字段(腾讯云和阿里云需要siteUrl) + if ($siteType === 'tencent_cvm' || $siteType === 'tencent_lh' || $siteType === 'aliyun' || $siteType === 'aliyun_swas') { + // 腾讯云/阿里云:siteUrl必填(API域名) if (empty($apiLabel) || empty($siteType) || empty($siteUrl) || empty($account) || empty($apiKey)) { - $message = '
❌ API标识、网站类型、API地址、SecretId和SecretKey不能为空!
'; + $message = '
❌ API标识、网站类型、API地址、AccessKey ID和AccessKey Secret不能为空!
'; } else { $db = getVpsDB(); @@ -160,8 +162,14 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { ); if ($configId) { - $typeName = ($siteType === 'tencent_cvm') ? 'CVM云服务器' : '轻量应用服务器'; - $message = '
✅ 腾讯云' . $typeName . '配置添加成功!ID: ' . $configId . '
'; + if ($siteType === 'aliyun') { + $message = '
✅ 阿里云ECS配置添加成功!ID: ' . $configId . '
'; + } elseif ($siteType === 'aliyun_swas') { + $message = '
✅ 阿里云轻量应用服务器配置添加成功!ID: ' . $configId . '
'; + } else { + $typeName = ($siteType === 'tencent_cvm') ? 'CVM云服务器' : '轻量应用服务器'; + $message = '
✅ 腾讯云' . $typeName . '配置添加成功!ID: ' . $configId . '
'; + } // 如果是首次添加配置,提示运行install.sh $configCount = $db->queryOne('SELECT COUNT(*) as count FROM configs')['count']; @@ -209,6 +217,16 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { refreshTencentLighthouseListForConfig($configId); } $message .= '
✅ 已自动获取实例列表(遍历所有区域)
'; + } elseif ($dbSiteType === 'aliyun') { + // 阿里云ECS + require_once __DIR__ . '/aliyun.php'; + refreshAliyunEcsListForConfig($configId); + $message .= '
✅ 已自动获取ECS实例列表(遍历所有区域)
'; + } elseif ($dbSiteType === 'aliyun_swas') { + // 阿里云轻量应用服务器 + require_once __DIR__ . '/aliyun.php'; + refreshAliyunSwasListForConfig($configId); + $message .= '
✅ 已自动获取轻量应用服务器列表(遍历所有区域)
'; } } else { $message = '
❌ 配置添加失败,请重试
'; @@ -387,7 +405,8 @@ $configs = $db->query('SELECT * FROM configs ORDER BY id'); @@ -435,7 +454,6 @@ $configs = $db->query('SELECT * FROM configs ORDER BY id'); - @@ -448,13 +466,13 @@ $configs = $db->query('SELECT * FROM configs ORDER BY id'); -
序号 API标识 网站类型 网站链接
'魔方', - 'aliyun' => '阿里云', + 'aliyun' => '阿里云ECS', + 'aliyun_swas' => '阿里云轻量', 'tencent' => '腾讯云' ]; echo $typeMap[$config['site_type']] ?? $config['site_type']; @@ -504,12 +522,21 @@ $configs = $db->query('SELECT * FROM configs ORDER BY id'); accountLabel.innerHTML = '账户 * (邮箱或手机号)'; keyLabel.textContent = 'API密钥 *'; } else if (siteType === 'aliyun') { - // 阿里云 + // 阿里云ECS urlGroup.style.display = 'block'; - urlInput.placeholder = '例如: https://ecs.aliyuncs.com'; + urlInput.value = 'https://ecs.aliyuncs.com'; + urlInput.placeholder = 'https://ecs.aliyuncs.com'; urlInput.required = true; - accountLabel.innerHTML = '账户 * (AccessKey ID)'; - keyLabel.textContent = 'API密钥 *'; + accountLabel.innerHTML = 'AccessKey ID * (阿里云访问密钥ID)'; + keyLabel.textContent = 'AccessKey Secret *'; + } else if (siteType === 'aliyun_swas') { + // 阿里云轻量应用服务器 + urlGroup.style.display = 'block'; + urlInput.value = 'https://swas.aliyuncs.com'; + urlInput.placeholder = 'https://swas.aliyuncs.com'; + urlInput.required = true; + accountLabel.innerHTML = 'AccessKey ID * (阿里云访问密钥ID)'; + keyLabel.textContent = 'AccessKey Secret *'; } else if (siteType === 'tencent_cvm') { // CVM云服务器 urlGroup.style.display = 'block'; diff --git a/diagnose_tencent.php b/diagnose_tencent.php deleted file mode 100644 index 595d1ff..0000000 --- a/diagnose_tencent.php +++ /dev/null @@ -1,108 +0,0 @@ -query('SELECT * FROM configs WHERE site_type = ?', ['tencent']); - -if (empty($configs)) { - echo "❌ 未找到腾讯云配置\n"; - exit; -} - -echo "✅ 找到 " . count($configs) . " 个腾讯云配置\n\n"; - -foreach ($configs as $configIndex => $config) { - echo "--- 配置 #" . ($configIndex + 1) . " ---\n"; - echo "ID: {$config['id']}\n"; - echo "API标识: {$config['api_label']}\n"; - echo "API域名: {$config['site_url']}\n"; - echo "SecretId: " . substr($config['account'], 0, 15) . "...\n"; - echo "\n"; - - // 2. 测试区域获取 - echo "【步骤2】测试区域获取...\n"; - try { - $regions = getTencentRegions($config['id'], 'lighthouse'); - echo "✅ 获取到 " . count($regions) . " 个区域\n"; - echo "前3个区域: " . implode(', ', array_slice($regions, 0, 3)) . "\n\n"; - } catch (Exception $e) { - echo "❌ 区域获取失败: " . $e->getMessage() . "\n\n"; - continue; - } - - // 3. 测试实例列表获取 - echo "【步骤3】测试实例列表获取...\n"; - if (!empty($regions)) { - $testRegion = $regions[0]; - echo "测试区域: {$testRegion}\n"; - - $result = tencentGetLighthouseList($config['id'], $testRegion, 0, 10); - - if (!$result) { - echo "❌ API返回null\n\n"; - continue; - } - - echo "HTTP状态码: {$result['status']}\n"; - - if (isset($result['error'])) { - echo "❌ API错误: {$result['error']}\n"; - if (isset($result['code'])) { - echo "错误代码: {$result['code']}\n"; - } - if (isset($result['request_id'])) { - echo "Request ID: {$result['request_id']}\n"; - } - echo "\n"; - continue; - } - - if ($result['status'] !== 200) { - echo "❌ HTTP状态码异常: {$result['status']}\n\n"; - continue; - } - - $instances = $result['data']['InstanceSet'] ?? []; - $totalCount = $result['data']['TotalCount'] ?? 0; - - echo "✅ API调用成功\n"; - echo "总实例数: {$totalCount}\n"; - echo "当前页实例数: " . count($instances) . "\n\n"; - - if (!empty($instances)) { - echo "【步骤4】检查第一个实例数据...\n"; - $instance = $instances[0]; - echo "实例ID: " . ($instance['InstanceId'] ?? 'N/A') . "\n"; - echo "实例名称: " . ($instance['InstanceName'] ?? 'N/A') . "\n"; - echo "状态: " . ($instance['InstanceState'] ?? 'N/A') . "\n"; - echo "CPU: " . ($instance['CPU'] ?? 'N/A') . "核\n"; - echo "内存: " . ($instance['Memory'] ?? 'N/A') . "GB\n"; - - // 检查带宽 - if (isset($instance['InternetAccessible'])) { - echo "InternetAccessible: 存在\n"; - if (isset($instance['InternetAccessible']['InternetMaxBandwidthOut'])) { - echo "带宽: " . $instance['InternetAccessible']['InternetMaxBandwidthOut'] . "Mbps\n"; - } else { - echo "带宽字段: 不存在\n"; - } - } else { - echo "InternetAccessible: 不存在\n"; - } - - echo "\n完整数据结构:\n"; - echo json_encode($instance, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . "\n"; - } else { - echo "⚠️ 该区域没有实例\n"; - } - } - - echo "\n" . str_repeat("=", 60) . "\n\n"; -} - -echo "诊断完成!\n"; -?> diff --git a/index.php b/index.php index 7c9ab0f..13aed5f 100644 --- a/index.php +++ b/index.php @@ -3,6 +3,7 @@ require_once __DIR__ . '/app/db_helper.php'; require_once __DIR__ . '/app/logger.php'; require_once __DIR__ . '/mofangidc.php'; require_once __DIR__ . '/tencentcloud.php'; +require_once __DIR__ . '/aliyun.php'; // 存储API_PASS $tokenFile = __DIR__ . '/app/pass.php'; @@ -29,12 +30,14 @@ if (!defined('API_PASS') || $pass !== API_PASS) { $message = ''; if ($_SERVER['REQUEST_METHOD'] === 'POST') { $action = $_POST['action'] ?? ''; - $hostId = intval($_POST['host_id'] ?? 0); + $hostId = $_POST['host_id'] ?? ''; $configId = intval($_POST['config_id'] ?? 0); - if ($action && $hostId > 0 && $configId > 0) { + if ($action && !empty($hostId) && $configId > 0) { $result = null; + Logger::info("[操作请求] action={$action}, host_id={$hostId}, config_id={$configId}", 'index.php'); + // 获取配置信息以确定平台类型 $db = getVpsDB(); $config = $db->queryOne('SELECT * FROM configs WHERE id = ?', [$configId]); @@ -57,6 +60,24 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { } elseif ($action === 'off') { $result = tencentSmartPowerOff($configId, $hostId); } + } elseif ($config['site_type'] === 'aliyun') { + // 阿里云ECS操作 + if ($action === 'reboot') { + $result = aliyunReboot($configId, $hostId); + } elseif ($action === 'on') { + $result = aliyunPowerOn($configId, $hostId); + } elseif ($action === 'off') { + $result = aliyunPowerOff($configId, $hostId); + } + } elseif ($config['site_type'] === 'aliyun_swas') { + // 阿里云轻量应用服务器操作 + if ($action === 'reboot') { + $result = aliyunSwasReboot($configId, $hostId); + } elseif ($action === 'on') { + $result = aliyunSwasPowerOn($configId, $hostId); + } elseif ($action === 'off') { + $result = aliyunSwasPowerOff($configId, $hostId); + } } } @@ -78,6 +99,10 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $tencentCount = refreshAllTencentVpsLists(); $count += $tencentCount; + // 刷新阿里云的ECS列表 + $aliyunCount = refreshAllAliyunVpsLists(); + $count += $aliyunCount; + $message = '

✅ 刷新完成

已成功刷新 ' . $count . ' 个配置的VPS列表

'; // 获取每个VPS的详细信息并更新数据库 @@ -127,6 +152,12 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { } elseif ($config['site_type'] === 'tencent') { // 腾讯云实例已在refreshAllTencentVpsLists中更新了详细信息,这里不需要额外处理 Logger::info("[refresh_vps_list] 腾讯云配置 {$config['id']} 已刷新", 'index.php'); + } elseif ($config['site_type'] === 'aliyun') { + // 阿里云ECS实例已在refreshAllAliyunVpsLists中更新了详细信息,这里不需要额外处理 + Logger::info("[refresh_vps_list] 阿里云配置 {$config['id']} 已刷新", 'index.php'); + } elseif ($config['site_type'] === 'aliyun_swas') { + // 阿里云轻量应用服务器实例已在refreshAllAliyunVpsLists中更新了详细信息,这里不需要额外处理 + Logger::info("[refresh_vps_list] 阿里云轻量配置 {$config['id']} 已刷新", 'index.php'); } } @@ -262,6 +293,7 @@ foreach ($vpsList as $vps) { font-size: 18px; font-weight: bold; color: #333; + cursor: help; } .status-badge { padding: 4px 12px; @@ -450,10 +482,19 @@ foreach ($vpsList as $vps) { $statusText = '处理中'; $statusColor = '#ffc107'; } + + // 处理长ID显示 + $vpsId = $vps['vps_id']; + $displayId = $vpsId; + $showTooltip = false; + if (strlen($vpsId) > 12) { + $displayId = substr($vpsId, 0, 10) . '...'; + $showTooltip = true; + } ?>
-
#
+
title="">#
@@ -540,6 +581,12 @@ foreach ($vpsList as $vps) { + + diff --git a/tencentcloud.php b/tencentcloud.php index 272a32f..df56d65 100644 --- a/tencentcloud.php +++ b/tencentcloud.php @@ -300,6 +300,21 @@ function tencentGetLighthouseStatus($configId, $instanceId, $region = null, $upd * 启动CVM实例 */ function tencentPowerOn($configId, $instanceId, $region = null) { + // 如果未提供region,从数据库获取 + if (!$region) { + $listDb = getVpsListDB(); + $vpsInfo = $listDb->queryOne( + 'SELECT domain FROM vps_list WHERE config_id = ? AND vps_id = ?', + [$configId, $instanceId] + ); + if ($vpsInfo && !empty($vpsInfo['domain'])) { + $region = $vpsInfo['domain']; + } else { + Logger::error("[tencentPowerOn] 无法从数据库获取 region", 'tencentPowerOn'); + return ['status' => 400, 'error' => '无法获取实例区域信息']; + } + } + $params = [ 'InstanceIds.0' => $instanceId, ]; @@ -319,6 +334,21 @@ function tencentPowerOn($configId, $instanceId, $region = null) { * 启动轻量应用服务器 */ function tencentLighthousePowerOn($configId, $instanceId, $region = null) { + // 如果未提供region,从数据库获取 + if (!$region) { + $listDb = getVpsListDB(); + $vpsInfo = $listDb->queryOne( + 'SELECT domain FROM vps_list WHERE config_id = ? AND vps_id = ?', + [$configId, $instanceId] + ); + if ($vpsInfo && !empty($vpsInfo['domain'])) { + $region = $vpsInfo['domain']; + } else { + Logger::error("[tencentLighthousePowerOn] 无法从数据库获取 region", 'tencentLighthousePowerOn'); + return ['status' => 400, 'error' => '无法获取实例区域信息']; + } + } + $params = [ 'InstanceIds.0' => $instanceId, ]; @@ -338,6 +368,21 @@ function tencentLighthousePowerOn($configId, $instanceId, $region = null) { * 停止CVM实例 */ function tencentPowerOff($configId, $instanceId, $region = null) { + // 如果未提供region,从数据库获取 + if (!$region) { + $listDb = getVpsListDB(); + $vpsInfo = $listDb->queryOne( + 'SELECT domain FROM vps_list WHERE config_id = ? AND vps_id = ?', + [$configId, $instanceId] + ); + if ($vpsInfo && !empty($vpsInfo['domain'])) { + $region = $vpsInfo['domain']; + } else { + Logger::error("[tencentPowerOff] 无法从数据库获取 region", 'tencentPowerOff'); + return ['status' => 400, 'error' => '无法获取实例区域信息']; + } + } + $params = [ 'InstanceIds.0' => $instanceId, ]; @@ -357,6 +402,21 @@ function tencentPowerOff($configId, $instanceId, $region = null) { * 停止轻量应用服务器 */ function tencentLighthousePowerOff($configId, $instanceId, $region = null) { + // 如果未提供region,从数据库获取 + if (!$region) { + $listDb = getVpsListDB(); + $vpsInfo = $listDb->queryOne( + 'SELECT domain FROM vps_list WHERE config_id = ? AND vps_id = ?', + [$configId, $instanceId] + ); + if ($vpsInfo && !empty($vpsInfo['domain'])) { + $region = $vpsInfo['domain']; + } else { + Logger::error("[tencentLighthousePowerOff] 无法从数据库获取 region", 'tencentLighthousePowerOff'); + return ['status' => 400, 'error' => '无法获取实例区域信息']; + } + } + $params = [ 'InstanceIds.0' => $instanceId, ]; @@ -376,6 +436,21 @@ function tencentLighthousePowerOff($configId, $instanceId, $region = null) { * 重启CVM实例 */ function tencentReboot($configId, $instanceId, $region = null) { + // 如果未提供region,从数据库获取 + if (!$region) { + $listDb = getVpsListDB(); + $vpsInfo = $listDb->queryOne( + 'SELECT domain FROM vps_list WHERE config_id = ? AND vps_id = ?', + [$configId, $instanceId] + ); + if ($vpsInfo && !empty($vpsInfo['domain'])) { + $region = $vpsInfo['domain']; + } else { + Logger::error("[tencentReboot] 无法从数据库获取 region", 'tencentReboot'); + return ['status' => 400, 'error' => '无法获取实例区域信息']; + } + } + $params = [ 'InstanceIds.0' => $instanceId, ]; @@ -395,6 +470,21 @@ function tencentReboot($configId, $instanceId, $region = null) { * 重启轻量应用服务器 */ function tencentLighthouseReboot($configId, $instanceId, $region = null) { + // 如果未提供region,从数据库获取 + if (!$region) { + $listDb = getVpsListDB(); + $vpsInfo = $listDb->queryOne( + 'SELECT domain FROM vps_list WHERE config_id = ? AND vps_id = ?', + [$configId, $instanceId] + ); + if ($vpsInfo && !empty($vpsInfo['domain'])) { + $region = $vpsInfo['domain']; + } else { + Logger::error("[tencentLighthouseReboot] 无法从数据库获取 region", 'tencentLighthouseReboot'); + return ['status' => 400, 'error' => '无法获取实例区域信息']; + } + } + $params = [ 'InstanceIds.0' => $instanceId, ];