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