PDO::ERRMODE_EXCEPTION]); $pdo->exec(" CREATE TABLE IF NOT EXISTS admin.huawei_regions ( id SERIAL PRIMARY KEY, region_code VARCHAR(50) UNIQUE, region_name VARCHAR(255), endpoint TEXT, eip_quota INTEGER DEFAULT 20, eip_used INTEGER DEFAULT 0, ecs_quota INTEGER DEFAULT 50, ecs_used INTEGER DEFAULT 0, is_active BOOLEAN DEFAULT true, priority INTEGER DEFAULT 5, last_check TIMESTAMP, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE IF NOT EXISTS admin.huawei_projects ( id SERIAL PRIMARY KEY, account_id INTEGER, region_code VARCHAR(50), project_id VARCHAR(255), project_name VARCHAR(255), ak TEXT, sk TEXT, eip_quota INTEGER DEFAULT 20, eip_used INTEGER DEFAULT 0, ecs_quota INTEGER DEFAULT 50, ecs_used INTEGER DEFAULT 0, is_active BOOLEAN DEFAULT true, priority INTEGER DEFAULT 5, last_sync TIMESTAMP, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, UNIQUE(region_code, project_id) ); CREATE TABLE IF NOT EXISTS admin.huawei_eips ( id SERIAL PRIMARY KEY, project_id INTEGER, region_code VARCHAR(50), eip_id VARCHAR(255), ip_address VARCHAR(50), bandwidth INTEGER DEFAULT 300, status VARCHAR(50) DEFAULT 'available', assigned_to VARCHAR(255), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE IF NOT EXISTS admin.huawei_rotation_log ( id SERIAL PRIMARY KEY, action VARCHAR(100), from_region VARCHAR(50), to_region VARCHAR(50), reason TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); "); class HuaweiRotation { private $pdo; // All Huawei regions with T6 support private $regions = [ 'af-south-1' => ['name' => 'Africa (Johannesburg)', 'priority' => 1], 'eu-west-0' => ['name' => 'Europe (Paris)', 'priority' => 2], 'eu-west-101' => ['name' => 'Europe (Dublin)', 'priority' => 3], 'ap-southeast-1' => ['name' => 'Asia Pacific (Singapore)', 'priority' => 4], 'ap-southeast-2' => ['name' => 'Asia Pacific (Bangkok)', 'priority' => 5], 'ap-southeast-3' => ['name' => 'Asia Pacific (Hong Kong)', 'priority' => 6], 'na-mexico-1' => ['name' => 'North America (Mexico)', 'priority' => 7], 'sa-brazil-1' => ['name' => 'South America (Sao Paulo)', 'priority' => 8], 'me-east-1' => ['name' => 'Middle East (Riyadh)', 'priority' => 9], 'tr-west-1' => ['name' => 'Turkey (Istanbul)', 'priority' => 10], 'ru-moscow-1' => ['name' => 'Russia (Moscow)', 'priority' => 11], 'cn-north-1' => ['name' => 'China (Beijing)', 'priority' => 12], 'cn-south-1' => ['name' => 'China (Guangzhou)', 'priority' => 13], 'cn-east-2' => ['name' => 'China (Shanghai)', 'priority' => 14], 'la-south-2' => ['name' => 'Latin America (Santiago)', 'priority' => 15], 'la-north-2' => ['name' => 'Latin America (Mexico City)', 'priority' => 16], 'ap-southeast-4' => ['name' => 'Asia Pacific (Jakarta)', 'priority' => 17], 'my-kualalumpur-1' => ['name' => 'Malaysia (Kuala Lumpur)', 'priority' => 18], 'ae-ad-1' => ['name' => 'UAE (Abu Dhabi)', 'priority' => 19] ]; public function __construct($pdo) { $this->pdo = $pdo; $this->initRegions(); } private function initRegions() { foreach ($this->regions as $code => $info) { $endpoint = "https://ecs.$code.myhuaweicloud.com"; $this->pdo->prepare("INSERT INTO admin.huawei_regions (region_code, region_name, endpoint, priority) VALUES (?, ?, ?, ?) ON CONFLICT (region_code) DO UPDATE SET region_name = ?, priority = ?") ->execute([$code, $info['name'], $endpoint, $info['priority'], $info['name'], $info['priority']]); } } // ============================================ // SMART REGION SELECTION // ============================================ public function getBestRegion() { // Get region with most available EIP quota $region = $this->pdo->query(" SELECT * FROM admin.huawei_regions WHERE is_active = true AND eip_used < eip_quota ORDER BY (eip_quota - eip_used) DESC, priority ASC LIMIT 1 ")->fetch(PDO::FETCH_ASSOC); if (!$region) { // All regions exhausted - try projects return $this->getBestProject(); } return ['type' => 'region', 'data' => $region]; } public function getBestProject() { // Get project with available EIP quota $project = $this->pdo->query(" SELECT p.*, r.region_name FROM admin.huawei_projects p JOIN admin.huawei_regions r ON p.region_code = r.region_code WHERE p.is_active = true AND p.eip_used < p.eip_quota ORDER BY (p.eip_quota - p.eip_used) DESC, p.priority ASC LIMIT 1 ")->fetch(PDO::FETCH_ASSOC); return $project ? ['type' => 'project', 'data' => $project] : null; } public function getNextAvailable($currentRegion = null) { $exclude = $currentRegion ? "AND region_code != '$currentRegion'" : ""; // First try regions $region = $this->pdo->query(" SELECT * FROM admin.huawei_regions WHERE is_active = true AND eip_used < eip_quota $exclude ORDER BY priority ASC LIMIT 1 ")->fetch(PDO::FETCH_ASSOC); if ($region) { $this->logRotation('region_switch', $currentRegion, $region['region_code'], 'Quota exhausted'); return ['type' => 'region', 'data' => $region]; } // Then try projects $projectExclude = $currentRegion ? "AND p.region_code != '$currentRegion'" : ""; $project = $this->pdo->query(" SELECT p.*, r.region_name FROM admin.huawei_projects p JOIN admin.huawei_regions r ON p.region_code = r.region_code WHERE p.is_active = true AND p.eip_used < p.eip_quota $projectExclude ORDER BY p.priority ASC LIMIT 1 ")->fetch(PDO::FETCH_ASSOC); if ($project) { $this->logRotation('project_switch', $currentRegion, $project['region_code'] . '/' . $project['project_name'], 'Region exhausted'); return ['type' => 'project', 'data' => $project]; } return null; } // ============================================ // PROJECT MANAGEMENT (Multiply EIP Quota) // ============================================ public function addProject($regionCode, $projectId, $projectName, $ak, $sk) { $this->pdo->prepare("INSERT INTO admin.huawei_projects (region_code, project_id, project_name, ak, sk) VALUES (?, ?, ?, ?, ?) ON CONFLICT (region_code, project_id) DO UPDATE SET project_name = ?, ak = ?, sk = ?") ->execute([$regionCode, $projectId, $projectName, $ak, $sk, $projectName, $ak, $sk]); return ['success' => true, 'message' => "Project added: $projectName in $regionCode (+20 EIP quota)"]; } public function createProjectsForRegion($regionCode, $count = 5) { // This would use IAM API to create new projects // Each project gets its own EIP quota (typically 20) $created = []; for ($i = 1; $i <= $count; $i++) { $projectName = "deliverads-$regionCode-$i"; // Simulated - in real implementation would call IAM API $created[] = $projectName; } return [ 'success' => true, 'region' => $regionCode, 'projects_created' => $created, 'additional_eip_capacity' => $count * 20 ]; } // ============================================ // EIP MANAGEMENT // ============================================ public function allocateEIP($preferredRegion = null) { $target = $preferredRegion ? $this->getRegionOrProject($preferredRegion) : $this->getBestRegion(); if (!$target) { return ['success' => false, 'error' => 'No available regions/projects with EIP quota']; } // Would call Huawei API to allocate EIP $eipId = 'eip-' . uniqid(); $ipAddress = $this->generateFakeIP(); // Simulated // Record EIP $projectId = $target['type'] === 'project' ? $target['data']['id'] : null; $regionCode = $target['data']['region_code']; $this->pdo->prepare("INSERT INTO admin.huawei_eips (project_id, region_code, eip_id, ip_address, status) VALUES (?, ?, ?, ?, 'available')") ->execute([$projectId, $regionCode, $eipId, $ipAddress]); // Update quota usage if ($target['type'] === 'project') { $this->pdo->exec("UPDATE admin.huawei_projects SET eip_used = eip_used + 1 WHERE id = " . $target['data']['id']); } else { $this->pdo->exec("UPDATE admin.huawei_regions SET eip_used = eip_used + 1 WHERE region_code = '$regionCode'"); } return [ 'success' => true, 'eip_id' => $eipId, 'ip_address' => $ipAddress, 'region' => $regionCode, 'source' => $target['type'] ]; } public function releaseEIP($eipId) { $eip = $this->pdo->query("SELECT * FROM admin.huawei_eips WHERE eip_id = '$eipId'")->fetch(PDO::FETCH_ASSOC); if (!$eip) return ['success' => false, 'error' => 'EIP not found']; // Would call Huawei API to release $this->pdo->exec("DELETE FROM admin.huawei_eips WHERE eip_id = '$eipId'"); // Update quota if ($eip['project_id']) { $this->pdo->exec("UPDATE admin.huawei_projects SET eip_used = GREATEST(0, eip_used - 1) WHERE id = " . $eip['project_id']); } else { $this->pdo->exec("UPDATE admin.huawei_regions SET eip_used = GREATEST(0, eip_used - 1) WHERE region_code = '" . $eip['region_code'] . "'"); } return ['success' => true]; } private function generateFakeIP() { return rand(1,255) . '.' . rand(1,255) . '.' . rand(1,255) . '.' . rand(1,255); } private function getRegionOrProject($regionCode) { $region = $this->pdo->query("SELECT * FROM admin.huawei_regions WHERE region_code = '$regionCode' AND eip_used < eip_quota")->fetch(PDO::FETCH_ASSOC); if ($region) return ['type' => 'region', 'data' => $region]; $project = $this->pdo->query("SELECT * FROM admin.huawei_projects WHERE region_code = '$regionCode' AND eip_used < eip_quota ORDER BY eip_used ASC LIMIT 1")->fetch(PDO::FETCH_ASSOC); if ($project) return ['type' => 'project', 'data' => $project]; return null; } // ============================================ // QUOTA SYNC & MONITORING // ============================================ public function syncQuotas() { // Would call Huawei API to get real quota usage // For now, count from our database $this->pdo->exec(" UPDATE admin.huawei_regions r SET eip_used = ( SELECT COUNT(*) FROM admin.huawei_eips e WHERE e.region_code = r.region_code AND e.project_id IS NULL ) "); $this->pdo->exec(" UPDATE admin.huawei_projects p SET eip_used = ( SELECT COUNT(*) FROM admin.huawei_eips e WHERE e.project_id = p.id ) "); return ['success' => true, 'message' => 'Quotas synchronized']; } private function logRotation($action, $from, $to, $reason) { $this->pdo->prepare("INSERT INTO admin.huawei_rotation_log (action, from_region, to_region, reason) VALUES (?, ?, ?, ?)") ->execute([$action, $from, $to, $reason]); } public function getCapacityOverview() { return [ 'regions' => $this->pdo->query(" SELECT region_code, region_name, eip_quota, eip_used, (eip_quota - eip_used) as available, is_active, priority FROM admin.huawei_regions ORDER BY priority ")->fetchAll(PDO::FETCH_ASSOC), 'projects' => $this->pdo->query(" SELECT p.region_code, p.project_name, p.eip_quota, p.eip_used, (p.eip_quota - p.eip_used) as available FROM admin.huawei_projects p WHERE p.is_active = true ORDER BY p.region_code, p.priority ")->fetchAll(PDO::FETCH_ASSOC), 'total_capacity' => $this->pdo->query(" SELECT (SELECT SUM(eip_quota) FROM admin.huawei_regions WHERE is_active = true) + (SELECT COALESCE(SUM(eip_quota), 0) FROM admin.huawei_projects WHERE is_active = true) as total_quota, (SELECT SUM(eip_used) FROM admin.huawei_regions) + (SELECT COALESCE(SUM(eip_used), 0) FROM admin.huawei_projects) as total_used ")->fetch(PDO::FETCH_ASSOC), 'recent_rotations' => $this->pdo->query("SELECT * FROM admin.huawei_rotation_log ORDER BY created_at DESC LIMIT 10")->fetchAll(PDO::FETCH_ASSOC) ]; } public function getStats() { $capacity = $this->getCapacityOverview(); return [ 'total_regions' => count($capacity['regions']), 'active_regions' => count(array_filter($capacity['regions'], fn($r) => $r['is_active'])), 'total_projects' => count($capacity['projects']), 'total_eip_capacity' => $capacity['total_capacity']['total_quota'], 'total_eip_used' => $capacity['total_capacity']['total_used'], 'available_eips' => $capacity['total_capacity']['total_quota'] - $capacity['total_capacity']['total_used'] ]; } } $rotation = new HuaweiRotation($pdo); $action = $_POST['action'] ?? $_GET['action'] ?? ''; switch ($action) { case 'best_region': echo json_encode($rotation->getBestRegion()); break; case 'next': echo json_encode($rotation->getNextAvailable($_GET['current'] ?? null)); break; case 'add_project': echo json_encode($rotation->addProject($_POST['region'], $_POST['project_id'], $_POST['project_name'], $_POST['ak'], $_POST['sk'])); break; case 'create_projects': echo json_encode($rotation->createProjectsForRegion($_POST['region'], $_POST['count'] ?? 5)); break; case 'allocate_eip': echo json_encode($rotation->allocateEIP($_POST['region'] ?? null)); break; case 'release_eip': echo json_encode($rotation->releaseEIP($_POST['eip_id'])); break; case 'sync': echo json_encode($rotation->syncQuotas()); break; case 'capacity': echo json_encode($rotation->getCapacityOverview()); break; case 'stats': echo json_encode($rotation->getStats()); break; default: echo json_encode(['name' => 'Huawei Rotation Engine', 'actions' => ['best_region','next','add_project','create_projects','allocate_eip','release_eip','sync','capacity','stats']]); }