Path: blob/1.0-develop/app/Services/Deployment/FindViableNodesService.php
10261 views
<?php12namespace Pterodactyl\Services\Deployment;34use Pterodactyl\Models\Node;5use Webmozart\Assert\Assert;6use Illuminate\Support\Collection;7use Illuminate\Contracts\Pagination\LengthAwarePaginator;8use Pterodactyl\Exceptions\Service\Deployment\NoViableNodeException;910class FindViableNodesService11{12protected array $locations = [];13protected ?int $disk = null;14protected ?int $memory = null;1516/**17* Set the locations that should be searched through to locate available nodes.18*/19public function setLocations(array $locations): self20{21Assert::allIntegerish($locations, 'An array of location IDs should be provided when calling setLocations.');2223$this->locations = $locations;2425return $this;26}2728/**29* Set the amount of disk that will be used by the server being created. Nodes will be30* filtered out if they do not have enough available free disk space for this server31* to be placed on.32*/33public function setDisk(int $disk): self34{35$this->disk = $disk;3637return $this;38}3940/**41* Set the amount of memory that this server will be using. As with disk space, nodes that42* do not have enough free memory will be filtered out.43*/44public function setMemory(int $memory): self45{46$this->memory = $memory;4748return $this;49}5051/**52* Returns an array of nodes that meet the provided requirements and can then53* be passed to the AllocationSelectionService to return a single allocation.54*55* This functionality is used for automatic deployments of servers and will56* attempt to find all nodes in the defined locations that meet the disk and57* memory availability requirements. Any nodes not meeting those requirements58* are tossed out, as are any nodes marked as non-public, meaning automatic59* deployments should not be done against them.60*61* @param int|null $page If provided the results will be paginated by returning62* up to 50 nodes at a time starting at the provided page.63* If "null" is provided as the value no pagination will64* be used.65*66* @throws NoViableNodeException67*/68public function handle(?int $perPage = null, ?int $page = null): LengthAwarePaginator|Collection69{70Assert::integer($this->disk, 'Disk space must be an int, got %s');71Assert::integer($this->memory, 'Memory usage must be an int, got %s');7273$query = Node::query()->select('nodes.*')74->selectRaw('IFNULL(SUM(servers.memory), 0) as sum_memory')75->selectRaw('IFNULL(SUM(servers.disk), 0) as sum_disk')76->leftJoin('servers', 'servers.node_id', '=', 'nodes.id')77->where('nodes.public', 1);7879if (!empty($this->locations)) {80$query = $query->whereIn('nodes.location_id', $this->locations);81}8283$results = $query->groupBy('nodes.id')84->havingRaw('(IFNULL(SUM(servers.memory), 0) + ?) <= (nodes.memory * (1 + (nodes.memory_overallocate / 100)))', [$this->memory])85->havingRaw('(IFNULL(SUM(servers.disk), 0) + ?) <= (nodes.disk * (1 + (nodes.disk_overallocate / 100)))', [$this->disk]);8687if (!is_null($page)) {88$results = $results->paginate($perPage ?? 50, ['*'], 'page', $page);89} else {90$results = $results->get()->toBase();91}9293if ($results->isEmpty()) {94throw new NoViableNodeException(trans('exceptions.deployment.no_viable_nodes'));95}9697return $results;98}99}100101102