Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
pterodactyl
GitHub Repository: pterodactyl/panel
Path: blob/1.0-develop/app/Services/Deployment/FindViableNodesService.php
10261 views
1
<?php
2
3
namespace Pterodactyl\Services\Deployment;
4
5
use Pterodactyl\Models\Node;
6
use Webmozart\Assert\Assert;
7
use Illuminate\Support\Collection;
8
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
9
use Pterodactyl\Exceptions\Service\Deployment\NoViableNodeException;
10
11
class FindViableNodesService
12
{
13
protected array $locations = [];
14
protected ?int $disk = null;
15
protected ?int $memory = null;
16
17
/**
18
* Set the locations that should be searched through to locate available nodes.
19
*/
20
public function setLocations(array $locations): self
21
{
22
Assert::allIntegerish($locations, 'An array of location IDs should be provided when calling setLocations.');
23
24
$this->locations = $locations;
25
26
return $this;
27
}
28
29
/**
30
* Set the amount of disk that will be used by the server being created. Nodes will be
31
* filtered out if they do not have enough available free disk space for this server
32
* to be placed on.
33
*/
34
public function setDisk(int $disk): self
35
{
36
$this->disk = $disk;
37
38
return $this;
39
}
40
41
/**
42
* Set the amount of memory that this server will be using. As with disk space, nodes that
43
* do not have enough free memory will be filtered out.
44
*/
45
public function setMemory(int $memory): self
46
{
47
$this->memory = $memory;
48
49
return $this;
50
}
51
52
/**
53
* Returns an array of nodes that meet the provided requirements and can then
54
* be passed to the AllocationSelectionService to return a single allocation.
55
*
56
* This functionality is used for automatic deployments of servers and will
57
* attempt to find all nodes in the defined locations that meet the disk and
58
* memory availability requirements. Any nodes not meeting those requirements
59
* are tossed out, as are any nodes marked as non-public, meaning automatic
60
* deployments should not be done against them.
61
*
62
* @param int|null $page If provided the results will be paginated by returning
63
* up to 50 nodes at a time starting at the provided page.
64
* If "null" is provided as the value no pagination will
65
* be used.
66
*
67
* @throws NoViableNodeException
68
*/
69
public function handle(?int $perPage = null, ?int $page = null): LengthAwarePaginator|Collection
70
{
71
Assert::integer($this->disk, 'Disk space must be an int, got %s');
72
Assert::integer($this->memory, 'Memory usage must be an int, got %s');
73
74
$query = Node::query()->select('nodes.*')
75
->selectRaw('IFNULL(SUM(servers.memory), 0) as sum_memory')
76
->selectRaw('IFNULL(SUM(servers.disk), 0) as sum_disk')
77
->leftJoin('servers', 'servers.node_id', '=', 'nodes.id')
78
->where('nodes.public', 1);
79
80
if (!empty($this->locations)) {
81
$query = $query->whereIn('nodes.location_id', $this->locations);
82
}
83
84
$results = $query->groupBy('nodes.id')
85
->havingRaw('(IFNULL(SUM(servers.memory), 0) + ?) <= (nodes.memory * (1 + (nodes.memory_overallocate / 100)))', [$this->memory])
86
->havingRaw('(IFNULL(SUM(servers.disk), 0) + ?) <= (nodes.disk * (1 + (nodes.disk_overallocate / 100)))', [$this->disk]);
87
88
if (!is_null($page)) {
89
$results = $results->paginate($perPage ?? 50, ['*'], 'page', $page);
90
} else {
91
$results = $results->get()->toBase();
92
}
93
94
if ($results->isEmpty()) {
95
throw new NoViableNodeException(trans('exceptions.deployment.no_viable_nodes'));
96
}
97
98
return $results;
99
}
100
}
101
102