Files
wevads-platform/scripts/api_huawei-rotation.php
2026-02-26 04:53:11 +01:00

390 lines
16 KiB
PHP
Executable File

<?php
/**
* HUAWEI REGION/PROJECT ROTATION
* Multi-region + Multi-project EIP quota management
*/
header('Content-Type: application/json');
$pdo = new PDO("pgsql:host=localhost;dbname=adx_system", "admin", "admin123", [PDO::ATTR_ERRMODE => 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']]);
}