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(); } }