390 lines
16 KiB
PHP
Executable File
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']]);
|
|
}
|
|
|