Files
Sentri/pub/api/classes/API_inserve.php
2026-01-01 10:54:18 +01:00

478 lines
18 KiB
PHP

<?php
namespace api\classes;
use api\classes\API;
require_once 'API.php';
class API_inserve extends API
{
private $inserve_url;
private $inserve_token;
public $inserve_source_uuid;
private $ch;
public $httpCode = false;
public $response = false;
private $cloudDistrubutor = 'digistate-servers';
public function setupConnection()
{
$query = "SELECT * FROM system_sources WHERE source_name = 'inserve'";
$result = $this->conn->query($query)->fetch_assoc();
$this->inserve_url = $result['source_url'];
$this->inserve_token = $result['source_auth_token'];
$this->inserve_source_uuid = $result['source_uuid'];
}
public function execCurl()
{
$this->response = curl_exec($this->ch);
$this->httpCode = curl_getinfo($this->ch, CURLINFO_HTTP_CODE);
curl_close($this->ch);
}
public function returnResponse()
{
$this->apiOutput($this->httpCode, json_decode($this->response, true));
}
public function authMe()
{
$this->ch = curl_init($this->inserve_url . 'auth/me');
curl_setopt_array($this->ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"X-Api-Key: $this->inserve_token",
"Accept: application/json"
]
]);
$this->execCurl();
}
public function getLinkedCompanies()
{
$this->ch = curl_init($this->inserve_url . 'cloud-distributors/digistate-servers/companies');
curl_setopt_array($this->ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"X-Api-Key: $this->inserve_token",
"Accept: application/json"
]
]);
$this->execCurl();
}
public function companies($page)
{
// Build array the way the API expects
$params = [
'b' => [
['orderBy' => ['name', 'ASC']],
['orderBy' => ['id', 'DESC']],
['with' => ['operator', 'country']],
['paginate' => 300],
],
'page' => $page
];
$query = http_build_query($params);
$this->ch = curl_init($this->inserve_url . 'companies?' . $query);
curl_setopt_array($this->ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"X-Api-Key: $this->inserve_token",
"Accept: application/json"
]
]);
$this->execCurl();
return json_decode($this->response, true);
}
public function syncCompaniesFromSentri()
{
# First retrieve all the active companies to sync to the Inserver cloud distributor
$companies = [];
$sql = "SELECT company_source_id FROM companies WHERE company_state = 'active'";
$stmt = $this->conn->query($sql);
while ($row = $stmt->fetch_assoc()) {
$id = (int)$row['company_source_id'];
$companies[] = [
'cloud_distribution_id' => (string)$id,
'company_id' => $id
];
}
$url = $this->inserve_url . 'cloud-distributors/digistate-servers/companies';
$this->ch = curl_init($url);
curl_setopt_array($this->ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($companies),
CURLOPT_HTTPHEADER => [
"X-Api-Key: $this->inserve_token",
"Accept: application/json",
"Content-Type: application/json"
],
]);
$this->execCurl();
}
public function getCloudSubscriptions()
{
$this->ch = curl_init($this->inserve_url . 'cloud-distribution-subscriptions/');
curl_setopt_array($this->ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"X-Api-Key: $this->inserve_token",
"Accept: application/json"
]
]);
$this->execCurl();
}
public function updateSubscription($subscriptionId = false, $payload = false)
{
$url = $this->inserve_url . 'cloud-distribution-subscriptions/' . $subscriptionId;
$this->ch = curl_init($url);
curl_setopt_array($this->ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'PUT',
CURLOPT_POSTFIELDS => json_encode($payload),
CURLOPT_HTTPHEADER => [
"X-Api-Key: $this->inserve_token",
"Accept: application/json",
"Content-Type: application/json"
],
]);
$this->execCurl();
}
private function getAllTypes($type)
{
$allowedColumns = [
'server_licenses',
'server_backup'
];
if (!in_array($type, $allowedColumns, true)) {
throw new Exception('Invalid column name');
}
$query = "SELECT `$type` FROM servers";
$stmt = $this->prepareStatement($query);
$this->executeStatement($stmt);
$result = $stmt->get_result();
$servers = [];
while ($row = $result->fetch_assoc()) {
array_push($servers, $row);
}
$allTypes = [];
foreach ($servers as $server) {
if (!empty($server[$type])) {
$types = json_decode($server[$type], true);
if (is_array($types)) {
foreach ($types as $item) {
foreach ($item as $key => $value) {
$allTypes[$key . '.' . $value] = 0;
}
}
}
}
}
return $allTypes;
}
private function calculateTotalDiskUsage($diskJson)
{
$disks = json_decode($diskJson, true);
$server_disks_count = 0;
if (is_array($disks)) {
foreach ($disks as $disk) {
$server_disks_count += $disk['disk_space'];
}
}
if (is_array($disks) && count($disks) > 0) {
$sizes = array_column($disks, 'disk_space');
$server_disks_count = array_sum($sizes);
}
return $server_disks_count;
}
private function buildCountObject(string $serverUuid, string $key): array
{
return [
'countSentri' => 0,
'countInserve' => 0,
'sentriCompanyId' => 0,
'SentriStatus' => 0,
'subscriptionInserveExists' => false,
'subscriptionInserveId' => false,
'subscriptionInserveCompanyId' => false,
'subscriptionInserveName' => false,
'subscriptionInserveStatus' => 0,
'md5' => md5($serverUuid . ':' . $key),
];
}
private function transformTypes(array $types, string $serverUuid): array
{
$result = [];
foreach ($types as $key => $value) {
$result[$key] = $this->buildCountObject($serverUuid, $key);
}
return $result;
}
private function buildCountArray($serverUuid)
{
$allBackupTypes = $this->getAllTypes('server_backup');
$allLicenseTypes = $this->getAllTypes('server_licenses');
$backupCounts = $this->transformTypes($allBackupTypes, $serverUuid);
$licenseCounts = $this->transformTypes($allLicenseTypes, $serverUuid);
return array_merge(
[
"server_CPU_count" => $this->buildCountObject($serverUuid, 'server_cpu_count'),
"server_Memory_count" => $this->buildCountObject($serverUuid, 'server_memory_count'),
"server_Disk_space_count" => $this->buildCountObject($serverUuid, 'server_disks_count'),
],
$licenseCounts,
$backupCounts
);
}
public function syncServerLicencesToInserve()
{
# Get all the linked companies
$this->getLinkedCompanies();
$allCompanies = json_decode($this->response, true);
$allCompaniesIds = array_column($allCompanies['matched'], 'id', 'company_id');
# first get the current subscriptions
$this->getCloudSubscriptions();
$allInserveSubscriptions = json_decode($this->response, true);
# Filter out all the none Sentri posted subscriptions based on the name for performance
$allInserveSubscriptions = array_filter($allInserveSubscriptions, function ($subscription) {
return isset($subscription['cloud_subscription_id']) && $subscription['cloud_subscription_id'] === 'sentri-servers';
});
# Build lookup of existing Inserve subscriptions by cloud_distribution_id
# this will be used later to lookup
$inserveLookup = [];
foreach ($allInserveSubscriptions as $subscription) {
if (!empty($subscription['cloud_distribution_id'])) {
$inserveLookup[$subscription['cloud_distribution_id']] = [
'id' => (int)$subscription['id'],
'quantity' => (int)$subscription['quantity'],
'status' => (int)$subscription['status'],
'cloud_distribution_company_id' => (int)$subscription['cloud_distribution_company_id'],
];
}
}
# get all the servers from Sentri
$sql = "SELECT * FROM servers INNER JOIN companies ON servers.company_uuid = companies.company_uuid WHERE company_state = 'active' AND server_state != 'new' AND server_state != 'disabled' ";
$stmt = $this->conn->query($sql);
while ($row = $stmt->fetch_assoc()) {
# Create a count of all the Subscriptions possible with every count on 0
$subscriptionCounts = $this->buildCountArray($row['server_uuid']);
$totalDiskSpace = $this->calculateTotalDiskUsage($row['server_disks']);
# Inserve status codes are:
# 0 = active, 1 = cancelled, 2 = pending, 3 = trial, 4 = on hold, 5 = removed
$statusMap = [
'active' => 0,
'trial' => 3,
'deleted' => 5,
];
// if no states matched there is something terrifying wrong, call the ambulance!
if (!isset($statusMap[$row['server_state']])) {
exit;
}
$sentriStatus = $statusMap[$row['server_state']];
# Set all the server resource counts from Sentri into the $subscriptionCounts
$subscriptionCounts['server_CPU_count']['countSentri'] = $row['server_cpu'];
$subscriptionCounts['server_Memory_count']['countSentri'] = (int)ceil($row['server_memory'] / 1024);
$subscriptionCounts['server_Disk_space_count']['countSentri'] = $totalDiskSpace;
$licenses = json_decode($row['server_licenses'], true);
foreach ($licenses as $license) {
foreach ($license as $key => $LicenseType) {
$subscriptionCounts[$key . '.' . $LicenseType]['countSentri']++;
}
}
$backups = json_decode($row['server_backup'], true);
foreach ($backups as $backup) {
foreach ($backup as $key => $BackupType) {
$subscriptionCounts[$key . '.' . $BackupType]['countSentri'] = $totalDiskSpace;
}
}
# Mark subscriptions that already exist in Inserve
foreach ($subscriptionCounts as $key => &$item) {
if (!is_array($item) || !isset($item['md5'])) {
continue;
}
$md5 = (string)$item['md5'];
if (isset($inserveLookup[$md5])) { # Subscription already exists in Inserve
$item['SentriStatus'] = $sentriStatus;
$item['sentriCompanyId'] = (int)$allCompaniesIds[$row['company_source_id']] ?? 0;
$item['subscriptionInserveExists'] = true;
$item['subscriptionInserveId'] = $inserveLookup[$item['md5']]['id'];
$item['countInserve'] = $inserveLookup[$item['md5']]['quantity'];
$item['subscriptionInserveCompanyId'] = $inserveLookup[$item['md5']]['cloud_distribution_company_id'];
$item['subscriptionInserveStatus'] = $inserveLookup[$item['md5']]['status'];
} else { # Subscription does not exists in Inserve
$item['sentriCompanyId'] = (int)$allCompaniesIds[$row['company_source_id']] ?? 0;
$item['subscriptionInserveExists'] = false;
$item['subscriptionInserveId'] = false;
$item['countInserve'] = 0;
$item['subscriptionInserveCompanyId'] = false;
}
}
unset($item);
// Make the subscriptions names look nice and dandy.
foreach ($subscriptionCounts as $key => &$item) {
// Set server name
$serverName = $row['server_hostname'] ?? $row['server_vm_host_name'] ?? 'Unknown';
// remove server_ prefix and _count suffix
$namePart = $key;
if (str_starts_with($key, 'server_') && str_ends_with($key, '_count')) {
$namePart = substr($key, 7, -6);
$namePart = ucfirst($namePart);
} // Handle keys with "."
elseif (strpos($key, '.') !== false) {
[$first, $second] = explode('.', $key, 2);
if ($first === $second || strtolower($second) === 'yes') {
$namePart = ucfirst($first);
} else {
$namePart = ucfirst($first) . ' - ' . $second;
}
} //Handle keys without . but with a space (expmale directadmin.Standard Discounted)
elseif (strpos($key, ' ') !== false) {
// explode on first .
$parts = explode('.', $key, 2);
if (count($parts) === 2) {
$namePart = ucfirst($parts[0]) . ' - ' . $parts[1];
} else {
// Cap first word before first space
$spacePos = strpos($key, ' ');
$first = ucfirst(substr($key, 0, $spacePos));
$rest = substr($key, $spacePos + 1);
$namePart = $first . ' - ' . $rest;
}
}
$item['subscriptionInserveName'] = $serverName . ' - ' . $namePart;
}
unset($item);
foreach ($subscriptionCounts as $key => $item) {
// if subscriptionInserveExists but the countInserve is null skip creation
if ($item['subscriptionInserveExists'] === false && (int)$item['countSentri'] === 0) {
continue;
}
// if subscriptionInserveExists is false create a new subscription
if ($item['subscriptionInserveExists'] === false) {
$payload = [
"cloud_distribution_id" => $item['md5'], #md5 hash based on the server_uuid from sentri and the subscription name (eg. server_cpu_count)
"cloud_subscription_id" => "sentri-servers", # Mark all the sentri-servers subscriptions so we can filter the subscriptions better
"name" => $item['subscriptionInserveName'],
"quantity" => $item['countSentri'],
"cloud_distribution_company_id" => $item['sentriCompanyId'], # this is generated by inserve (306 = digistate)
"status" => $item['SentriStatus'],
"period_type" => 0, # 0 = monthly, 1 = anual, 2 = one time cost
"start_date" => date('Y-m-d')
];
$this->createSubscription($payload);
continue;
}
// update the subscription if the countInserve and countSentri dont match
// Or when sentriCompanyId and subscriptionInserveCompanyId dont match
if ((
(int)$item['countInserve'] !== (int)$item['countSentri'] ||
(int)$item['sentriCompanyId'] !== (int)$item['subscriptionInserveCompanyId'] ||
(int)$item['SentriStatus'] !== (int)$item['subscriptionInserveStatus']
)
&& $item['subscriptionInserveExists'] !== false
) {
$payload = [
"quantity" => (int)$item['countSentri'],
"cloud_distribution_company_id" => (int)$item['sentriCompanyId'],
"name" => $item['subscriptionInserveName'],
"status" => $item['SentriStatus'],
"quantity" => $item['countSentri']
];
$this->updateSubscription($item['subscriptionInserveId'], $payload);
continue;
}
}
}
}
public function createSubscription($payload)
{
$url = $this->inserve_url . 'cloud-distribution-subscriptions';
$this->ch = curl_init($url);
# I need to make this pay load:
curl_setopt_array($this->ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($payload),
CURLOPT_HTTPHEADER => [
"X-Api-Key: $this->inserve_token",
"Accept: application/json",
"Content-Type: application/json"
],
]);
$this->execCurl();
}
}