| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469 |
- <?php
- /* * ********************************************************************
- * ProxmoxVPS product developed. (Jan 16, 2019)
- * *
- *
- * CREATED BY MODULESGARDEN -> http://modulesgarden.com
- * CONTACT -> contact@modulesgarden.com
- *
- *
- * This software is furnished under a license and may be used and copied
- * only in accordance with the terms of such license and with the
- * inclusion of the above copyright notice. This software or any other
- * copies thereof may not be provided or otherwise made available to any
- * other person. No title to and ownership of the software is hereby
- * transferred.
- *
- *
- * ******************************************************************** */
- namespace ModulesGarden\ProxmoxAddon\App\Services;
- use MGProvision\Proxmox\v2\models\Kvm;
- use MGProvision\Proxmox\v2\models\Lxc;
- use ModulesGarden\ProxmoxAddon\App\Models\NodeSetting;
- use ModulesGarden\ProxmoxAddon\App\Models\Whmcs\Hosting;
- use ModulesGarden\ProxmoxAddon\Core\Models\ModuleSettings\Model as Settings;
- /**
- * Description of LoadBalancerService
- *
- * @author Pawel Kopec <pawelk@modulesgardne.com>
- */
- class LoadBalancerService
- {
- protected $nodesResurces = [];
- private $serverId;
- /**
- *
- * @var \MGProvision\Proxmox\v2\Api
- */
- private $api;
- private $usage = false;
- private $filter = [];
- private $excludeVmid;
- private $vmsWeight;
- private $ramWeight;
- private $diskWeight;
- private $cpuWeight;
- function __construct($serverId)
- {
- $this->serverId = $serverId;
- }
- public function getExcludeVmid()
- {
- return $this->excludeVmid;
- }
- public function setExcludeVmid($excludeVmid)
- {
- $this->excludeVmid = $excludeVmid;
- return $this;
- }
- public function findByNodes(array $nodes){
- $this->filter['nodes'] = $nodes;
- return $this;
- }
- /**
- * @return LoadBalancerService
- */
- public function findByVmCreate()
- {
- //Node settings
- $this->nodesResurces = [];
- $query = NodeSetting::ofServer($this->serverId);
- if($this->filter['nodes']){
- $query->ofNodes($this->filter['nodes']);
- }
- $query->ofSetting('vmCreate')->ofValue(1);
- foreach ($query->get() as $entity)
- {
- $this->nodesResurces[] = $this->format($entity);
- }
- return clone $this;
- }
- private function format(NodeSetting $entity)
- {
- $nodesResurce = [
- 'node' => $entity->node,
- 'vmCreate' => NodeSetting::ofServer($this->serverId)->ofNode($entity->node)->ofSetting('vmCreate')->value('value'),
- 'vmsMax' => NodeSetting::ofServer($this->serverId)->ofNode($entity->node)->ofSetting('vmsMax')->value('value'),
- 'vmsWeight' => NodeSetting::ofServer($this->serverId)->ofNode($entity->node)->ofSetting('vmsWeight')->value('value'),
- 'vmsUsed' => 0,
- 'vmsFree' => null,
- 'cpuMax' => NodeSetting::ofServer($this->serverId)->ofNode($entity->node)->ofSetting('cpuMax')->value('value'),
- 'cpuWeight' => NodeSetting::ofServer($this->serverId)->ofNode($entity->node)->ofSetting('cpuWeight')->value('value'),
- 'cpuUsed' => 0,
- 'cpuFree' => null,
- 'diskUsed' => 0,
- 'diskMax' => NodeSetting::ofServer($this->serverId)->ofNode($entity->node)->ofSetting('diskMax')->value('value'),
- 'diskWeight' => NodeSetting::ofServer($this->serverId)->ofNode($entity->node)->ofSetting('diskWeight')->value('value'),
- 'diskFree' => null,
- 'ramMax' => NodeSetting::ofServer($this->serverId)->ofNode($entity->node)->ofSetting('ramMax')->value('value'),
- 'ramWeight' => NodeSetting::ofServer($this->serverId)->ofNode($entity->node)->ofSetting('ramWeight')->value('value'),
- 'ramUsed' => 0,
- 'ramFree' => 0,
- ];
- if ($nodesResurce['diskMax'])
- {
- $nodesResurce['diskMax'] = $nodesResurce['diskMax'] * pow(1024, 3);
- }
- if ($nodesResurce['ramMax'])
- {
- $nodesResurce['ramMax'] = $nodesResurce['ramMax'] * pow(1024, 3);
- }
- return $nodesResurce;
- }
- /**
- * @return LoadBalancerService
- */
- public function findByNode($node, $vmCreate = true)
- {
- $this->filter['node'] = $node;
- $this->usage = false;
- //Node settings
- $this->nodesResurces = [];
- $query = NodeSetting::ofServer($this->serverId)
- ->ofNode($node)
- ->ofSetting('vmCreate');
- if ($vmCreate)
- {
- $query->ofValue(1);
- }
- if(!$query->count()){
- $entity = new NodeSetting();
- $entity->node = $node;
- $entity->server_id = $this->serverId;
- $entity->setting = 'vmsMax';
- $entity->value = "";
- $this->nodesResurces[] = $this->format($entity);
- }
- foreach ($query->get() as $entity)
- {
- $this->nodesResurces[] = $this->format($entity);
- }
- return clone $this;
- }
- /**
- * @return LoadBalancerService
- */
- public function findNotUser($userId)
- {
- $this->filter['notUserId'] = $userId;
- foreach ($this->nodesResurces as $k => $nodeResurce)
- {
- if ($this->hasNode($userId, $nodeResurce['node']))
- {
- unset($this->nodesResurces[$k]);
- }
- }
- return clone $this;
- }
- private function hasNode($userId, $node)
- {
- $total = Hosting::ofUserId($userId)
- ->ofServerId($this->serverId)
- ->active()
- ->ofCustomFieldNode($node)
- ->count();
- try
- {
- $total += Hosting::ofUserId($userId)
- ->ofServerId($this->serverId)
- ->active()
- ->ofvServerNode($node)
- ->count();
- }
- catch (\Exception $ex)
- {//Table does not exist
- }
- return $total > 0;
- }
- /**
- * @return LoadBalancerService
- */
- public function findByRam($bytes)
- {
- $this->filter['ram'] = $bytes;
- $this->usage();
- foreach ($this->nodesResurces as $k => $nodeResurce)
- {
- if (!is_null($nodeResurce['ramFree']) && $nodeResurce['ramFree'] < $bytes)
- {
- unset($this->nodesResurces[$k]);
- }
- }
- return clone $this;
- }
- private function usage()
- {
- if ($this->usage)
- {
- return true;
- }
- if (!$this->api instanceof \MGProvision\Proxmox\v2\Api)
- {
- throw new \Exception("API instance is not initialized");
- }
- $nodes = [];
- foreach ($this->api->get("/nodes") as $node)
- {
- if ($node['status'] != "online")
- {
- continue;
- }
- $nodes[] = $node['node'];
- }
- foreach ($this->nodesResurces as $k => &$nodeResurce)
- {
- if (!in_array($nodeResurce['node'], $nodes))
- {
- continue;
- }
- //kvm
- $qemu = $this->api->get("/nodes/{$nodeResurce['node']}/qemu");
- foreach ($qemu as $record)
- {
- if ($record['template'] || ($this->excludeVmid && $this->excludeVmid == $record['vmid']) || !$this->hasVmid($record['vmid']))
- {
- continue;
- }
- $vm = new Kvm($nodeResurce['node'], $record['vmid']);
- $vm->setApi($this->api);
- foreach ($vm->getHardDisks() as $hardDisk)
- {
- $nodeResurce['diskUsed'] += $hardDisk->getBytes();
- }
- $nodeResurce['ramUsed'] += $record['maxmem'];
- $nodeResurce['vmsUsed']++;
- $nodeResurce['cpuUsed'] += $record['cpus'];
- }
- unset($qemu, $record, $vm);
- //lxc
- $lxc = $this->api->get("/nodes/{$nodeResurce['node']}/lxc");
- foreach ($lxc as $record)
- {
- if ($record['template'] || ($this->excludeVmid && $this->excludeVmid == $record['vmid']) || !$this->hasVmid($record['vmid']))
- {
- continue;
- }
- $vm = new Lxc($nodeResurce['node'], $record['vmid']);
- $vm->setApi($this->api);
- foreach ($vm->getMounPoints()->fetch() as $mounPoint)
- {
- /*@var $mounPoint MountPoint */
- $nodeResurce['diskUsed'] += $mounPoint->getBytes();
- }
- $nodeResurce['ramUsed'] += $record['maxmem'];
- $nodeResurce['vmsUsed']++;
- $nodeResurce['cpuUsed'] += $record['cpus'];
- }
- unset($lxc, $record, $vm);
- }
- //calculate free resurces
- foreach ($this->nodesResurces as $k => &$nodeResurce)
- {
- $nodeResurce['ramFree'] = $nodeResurce['ramMax'] - $nodeResurce['ramUsed'];
- $nodeResurce['vmsFree'] = $nodeResurce['vmsMax'] - $nodeResurce['vmsUsed'];
- $nodeResurce['cpuFree'] = $nodeResurce['cpuMax'] - $nodeResurce['cpuUsed'];
- $nodeResurce['diskFree'] = $nodeResurce['diskMax'] - $nodeResurce['diskUsed'];
- }
- $this->usage = true;
- }
- private function hasVmid($vmid)
- {
- $total = Hosting::ofServerId($this->serverId)
- ->ofStatus(['Active', 'Suspended'])
- ->ofCustomFielVmid($vmid)
- ->count();
- try
- {
- $total += Hosting::ofServerId($this->serverId)
- ->active()
- ->ofvServerVmid($vmid)
- ->count();
- }
- catch (\Exception $ex)
- {//Table does not exist
- }
- return $total > 0;
- }
- /**
- * @return LoadBalancerService
- */
- public function findByDisk($bytes)
- {
- $this->filter['disk'] = $bytes;
- $this->usage();
- foreach ($this->nodesResurces as $k => $nodeResurce)
- {
- if (!is_null($nodeResurce['diskFree']) && $nodeResurce['diskFree'] < $bytes)
- {
- unset($this->nodesResurces[$k]);
- }
- }
- return clone $this;
- }
- /**
- * @return LoadBalancerService
- */
- public function findByCpu($cpu)
- {
- $this->filter['cpu'] = $cpu;
- $this->usage();
- foreach ($this->nodesResurces as $k => $nodeResurce)
- {
- if (!is_null($nodeResurce['cpuFree']) && $nodeResurce['cpuFree'] < $cpu)
- {
- unset($this->nodesResurces[$k]);
- }
- }
- return clone $this;
- }
- /**
- * @return LoadBalancerService
- */
- public function findByVms($number)
- {
- $this->filter['vms'] = $number;
- $this->usage();
- foreach ($this->nodesResurces as $k => $nodeResurce)
- {
- if (!is_null($nodeResurce['vmsFree']) && $nodeResurce['vmsFree'] < $number)
- {
- unset($this->nodesResurces[$k]);
- }
- }
- return clone $this;
- }
- public function getApi()
- {
- return $this->api;
- }
- public function setApi(\MGProvision\Proxmox\v2\Api $api)
- {
- $this->api = $api;
- return $this;
- }
- public function getNodesResurces()
- {
- $this->usage();
- return $this->nodesResurces;
- }
- public function count()
- {
- return count($this->nodesResurces);
- }
- public function isEmpty()
- {
- return empty($this->nodesResurces);
- }
- public function nodeLowLoad()
- {
- $this->usage();
- $weight = Settings::where("setting", 'vmsWeight')->value("value");
- $this->vmsWeight = $weight ? $weight : 1;
- $weight = Settings::where("setting", 'cpuWeight')->value("value");
- $this->cpuWeight = $weight ? $weight : 1;
- $weight = Settings::where("setting", 'ramWeight')->value("value");
- $this->ramWeight = $weight ? $weight : 1;
- $weight = Settings::where("setting", 'diskWeight')->value("value");
- $this->diskWeight = $weight ? $weight : 1;
- $nodes = [];
- //By ram
- $nodes = $this->nodesUsage($nodes, $this->orderByRamUsage(), $this->ramWeight);
- //By cpu
- $nodes = $this->nodesUsage($nodes, $this->orderByCpuUsage(), $this->cpuWeight);
- //By Disk
- $nodes = $this->nodesUsage($nodes, $this->orderByDiskUsage(), $this->diskWeight);
- //By Vms
- $nodes = $this->nodesUsage($nodes, $this->orderByVmsUsage(), $this->vmsWeight);
- if (empty($nodes))
- {
- throw new \Exception("Load Balancer: Cannot find node with free resources");
- }
- asort($nodes);
- $nodes = array_reverse($nodes);
- return key($nodes);
- }
- private function nodesUsage($nodes, $values, $weight = 1)
- {
- foreach (array_reverse($values) as $index => $nodeName)
- {
- if (!array_key_exists($nodeName, $nodes))
- {
- $nodes[$nodeName] = 0;
- }
- $nodes[$nodeName] += ($index + 1) * $weight; // we don't want zero value so we add "1"
- }
- return $nodes;
- }
- /**
- * @return LoadBalancerService
- */
- public function orderByRamUsage()
- {
- return $this->orderBy('ramUsed');
- }
- private function orderBy($column)
- {
- $this->usage();
- $column = array_column($this->nodesResurces, $column);
- array_multisort($column, SORT_ASC, $this->nodesResurces);
- $nodes = [];
- foreach ($column as $k => $v)
- {
- $nodes[] = $this->nodesResurces[$k]['node'];
- }
- return $nodes;
- }
- public function orderByCpuUsage()
- {
- return $this->orderBy('ramUsed');
- }
- public function orderByDiskUsage()
- {
- return $this->orderBy('vmsUsed');
- }
- public function orderByVmsUsage()
- {
- return $this->orderBy('vmsUsed');
- }
- }
|