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

213 lines
8.3 KiB
PHP
Executable File

<?php
/**
* COST TRACKER
* Real-time cloud spending monitoring
*/
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.cost_tracking (
id SERIAL PRIMARY KEY,
provider VARCHAR(50),
resource_type VARCHAR(50),
resource_id VARCHAR(255),
cost_per_hour FLOAT,
hours_running FLOAT DEFAULT 0,
total_cost FLOAT DEFAULT 0,
status VARCHAR(50) DEFAULT 'running',
started_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
stopped_at TIMESTAMP
);
CREATE TABLE IF NOT EXISTS admin.cost_daily (
id SERIAL PRIMARY KEY,
date DATE UNIQUE,
huawei_cost FLOAT DEFAULT 0,
scaleway_cost FLOAT DEFAULT 0,
other_cost FLOAT DEFAULT 0,
total_cost FLOAT DEFAULT 0,
servers_used INTEGER DEFAULT 0,
emails_sent INTEGER DEFAULT 0,
cost_per_email FLOAT DEFAULT 0
);
CREATE TABLE IF NOT EXISTS admin.cost_alerts (
id SERIAL PRIMARY KEY,
alert_type VARCHAR(50),
threshold FLOAT,
current_value FLOAT,
triggered BOOLEAN DEFAULT false,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS admin.budget_limits (
id SERIAL PRIMARY KEY,
period VARCHAR(20) DEFAULT 'daily',
provider VARCHAR(50) DEFAULT 'all',
limit_amount FLOAT,
current_spend FLOAT DEFAULT 0,
is_active BOOLEAN DEFAULT true
);
");
class CostTracker {
private $pdo;
// Huawei T6 pricing (approximate)
private $pricing = [
'huawei' => [
't6.small.1' => 0.02,
't6.medium.2' => 0.05,
't6.large.4' => 0.10,
'eip' => 0.01
],
'scaleway' => [
'DEV1-S' => 0.01,
'DEV1-M' => 0.02,
'DEV1-L' => 0.04,
'GP1-S' => 0.05
]
];
public function __construct($pdo) {
$this->pdo = $pdo;
$this->initBudgets();
}
private function initBudgets() {
$budgets = [
['daily', 'all', 100],
['daily', 'huawei', 75],
['daily', 'scaleway', 25],
['monthly', 'all', 2000]
];
foreach ($budgets as $b) {
$this->pdo->prepare("INSERT INTO admin.budget_limits (period, provider, limit_amount) VALUES (?, ?, ?) ON CONFLICT DO NOTHING")
->execute($b);
}
}
public function trackResource($provider, $resourceType, $resourceId, $flavor = 't6.medium.2') {
$costPerHour = $this->pricing[$provider][$flavor] ?? 0.05;
$this->pdo->prepare("INSERT INTO admin.cost_tracking (provider, resource_type, resource_id, cost_per_hour) VALUES (?, ?, ?, ?)")
->execute([$provider, $resourceType, $resourceId, $costPerHour]);
return ['success' => true, 'cost_per_hour' => $costPerHour];
}
public function stopTracking($resourceId) {
$this->pdo->exec("UPDATE admin.cost_tracking SET status = 'stopped', stopped_at = NOW(),
hours_running = EXTRACT(EPOCH FROM (NOW() - started_at)) / 3600,
total_cost = cost_per_hour * EXTRACT(EPOCH FROM (NOW() - started_at)) / 3600
WHERE resource_id = '$resourceId' AND status = 'running'");
return ['success' => true];
}
public function updateDailyCosts() {
$today = date('Y-m-d');
// Calculate today's costs
$huawei = $this->pdo->query("SELECT COALESCE(SUM(
cost_per_hour * EXTRACT(EPOCH FROM (COALESCE(stopped_at, NOW()) - started_at)) / 3600
), 0) FROM admin.cost_tracking WHERE provider = 'huawei' AND DATE(started_at) = '$today'")->fetchColumn();
$scaleway = $this->pdo->query("SELECT COALESCE(SUM(
cost_per_hour * EXTRACT(EPOCH FROM (COALESCE(stopped_at, NOW()) - started_at)) / 3600
), 0) FROM admin.cost_tracking WHERE provider = 'scaleway' AND DATE(started_at) = '$today'")->fetchColumn();
$servers = $this->pdo->query("SELECT COUNT(DISTINCT resource_id) FROM admin.cost_tracking WHERE DATE(started_at) = '$today'")->fetchColumn();
$emails = $this->pdo->query("SELECT COALESCE(SUM(total_sent), 0) FROM admin.campaigns WHERE DATE(started_at) = '$today'")->fetchColumn();
$total = $huawei + $scaleway;
$costPerEmail = $emails > 0 ? $total / $emails : 0;
$this->pdo->prepare("INSERT INTO admin.cost_daily (date, huawei_cost, scaleway_cost, total_cost, servers_used, emails_sent, cost_per_email)
VALUES (?, ?, ?, ?, ?, ?, ?)
ON CONFLICT (date) DO UPDATE SET huawei_cost = ?, scaleway_cost = ?, total_cost = ?, servers_used = ?, emails_sent = ?, cost_per_email = ?")
->execute([$today, $huawei, $scaleway, $total, $servers, $emails, $costPerEmail, $huawei, $scaleway, $total, $servers, $emails, $costPerEmail]);
// Check budgets
$this->checkBudgets($total);
return [
'date' => $today,
'huawei' => round($huawei, 2),
'scaleway' => round($scaleway, 2),
'total' => round($total, 2),
'servers' => $servers,
'emails' => $emails,
'cost_per_email' => round($costPerEmail, 6)
];
}
private function checkBudgets($dailySpend) {
$budgets = $this->pdo->query("SELECT * FROM admin.budget_limits WHERE is_active = true AND period = 'daily'")->fetchAll(PDO::FETCH_ASSOC);
foreach ($budgets as $budget) {
if ($dailySpend >= $budget['limit_amount'] * 0.8) {
// 80% warning
$this->createAlert('budget_warning', $budget['limit_amount'], $dailySpend);
}
if ($dailySpend >= $budget['limit_amount']) {
// Over budget - could trigger server shutdowns
$this->createAlert('budget_exceeded', $budget['limit_amount'], $dailySpend);
}
}
}
private function createAlert($type, $threshold, $value) {
$this->pdo->prepare("INSERT INTO admin.cost_alerts (alert_type, threshold, current_value, triggered) VALUES (?, ?, ?, true)")
->execute([$type, $threshold, $value]);
}
public function getStats() {
$today = date('Y-m-d');
$month = date('Y-m');
return [
'today' => $this->pdo->query("SELECT * FROM admin.cost_daily WHERE date = '$today'")->fetch(PDO::FETCH_ASSOC) ?: ['total_cost' => 0],
'this_month' => $this->pdo->query("SELECT SUM(total_cost) as total, SUM(emails_sent) as emails FROM admin.cost_daily WHERE date >= '$month-01'")->fetch(PDO::FETCH_ASSOC),
'running_resources' => $this->pdo->query("SELECT provider, COUNT(*) as count FROM admin.cost_tracking WHERE status = 'running' GROUP BY provider")->fetchAll(PDO::FETCH_ASSOC),
'budgets' => $this->pdo->query("SELECT * FROM admin.budget_limits WHERE is_active = true")->fetchAll(PDO::FETCH_ASSOC),
'recent_alerts' => $this->pdo->query("SELECT * FROM admin.cost_alerts ORDER BY created_at DESC LIMIT 10")->fetchAll(PDO::FETCH_ASSOC)
];
}
public function getHistory($days = 30) {
return $this->pdo->query("SELECT * FROM admin.cost_daily ORDER BY date DESC LIMIT $days")->fetchAll(PDO::FETCH_ASSOC);
}
}
$tracker = new CostTracker($pdo);
$action = $_POST['action'] ?? $_GET['action'] ?? '';
switch ($action) {
case 'track':
echo json_encode($tracker->trackResource($_POST['provider'], $_POST['resource_type'], $_POST['resource_id'], $_POST['flavor'] ?? 't6.medium.2'));
break;
case 'stop':
echo json_encode($tracker->stopTracking($_POST['resource_id']));
break;
case 'update':
echo json_encode($tracker->updateDailyCosts());
break;
case 'history':
echo json_encode(['history' => $tracker->getHistory($_GET['days'] ?? 30)]);
break;
case 'stats':
echo json_encode($tracker->getStats());
break;
case 'set_budget':
$pdo->prepare("UPDATE admin.budget_limits SET limit_amount = ? WHERE period = ? AND provider = ?")
->execute([$_POST['limit'], $_POST['period'], $_POST['provider']]);
echo json_encode(['success' => true]);
break;
default:
echo json_encode(['name' => 'Cost Tracker', 'actions' => ['track','stop','update','history','stats','set_budget']]);
}