Skip to content

Commit ff21d83

Browse files
committed
Add endpoint to get all nodes meeting memory & disk requirements for a server; closes pterodactyl#1012
1 parent ef3f858 commit ff21d83

File tree

5 files changed

+87
-5
lines changed

5 files changed

+87
-5
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
namespace Pterodactyl\Http\Controllers\Api\Application\Nodes;
4+
5+
use Pterodactyl\Services\Deployment\FindViableNodesService;
6+
use Pterodactyl\Transformers\Api\Application\NodeTransformer;
7+
use Pterodactyl\Http\Controllers\Api\Application\ApplicationApiController;
8+
use Pterodactyl\Http\Requests\Api\Application\Nodes\GetDeployableNodesRequest;
9+
10+
class NodeDeploymentController extends ApplicationApiController
11+
{
12+
/**
13+
* @var \Pterodactyl\Services\Deployment\FindViableNodesService
14+
*/
15+
private $viableNodesService;
16+
17+
/**
18+
* NodeDeploymentController constructor.
19+
*
20+
* @param \Pterodactyl\Services\Deployment\FindViableNodesService $viableNodesService
21+
*/
22+
public function __construct(FindViableNodesService $viableNodesService)
23+
{
24+
parent::__construct();
25+
26+
$this->viableNodesService = $viableNodesService;
27+
}
28+
29+
/**
30+
* Finds any nodes that are available using the given deployment criteria. This works
31+
* similarly to the server creation process, but allows you to pass the deployment object
32+
* to this endpoint and get back a list of all Nodes satisfying the requirements.
33+
*
34+
* @param \Pterodactyl\Http\Requests\Api\Application\Nodes\GetDeployableNodesRequest $request
35+
* @return array
36+
*
37+
* @throws \Pterodactyl\Exceptions\Service\Deployment\NoViableNodeException
38+
*/
39+
public function __invoke(GetDeployableNodesRequest $request): array
40+
{
41+
$data = $request->validated();
42+
$nodes = $this->viableNodesService->setLocations($data['location_ids'] ?? [])
43+
->setMemory($data['memory'])
44+
->setDisk($data['disk'])
45+
->handle($request->input('page') ?? 0);
46+
47+
return $this->fractal->collection($nodes)
48+
->transformWith($this->getTransformer(NodeTransformer::class))
49+
->toArray();
50+
}
51+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
namespace Pterodactyl\Http\Requests\Api\Application\Nodes;
4+
5+
class GetDeployableNodesRequest extends GetNodesRequest
6+
{
7+
/**
8+
* @return string[]
9+
*/
10+
public function rules(): array
11+
{
12+
return [
13+
'page' => 'integer',
14+
'memory' => 'required|integer|min:0',
15+
'disk' => 'required|integer|min:0',
16+
'location_ids' => 'array',
17+
'location_ids.*' => 'integer',
18+
];
19+
}
20+
}

app/Services/Deployment/FindViableNodesService.php

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,15 @@ public function setMemory(int $memory): self
7777
* are tossed out, as are any nodes marked as non-public, meaning automatic
7878
* deployments should not be done against them.
7979
*
80-
* @return \Pterodactyl\Models\Node[]|\Illuminate\Support\Collection
80+
* @param int|null $page If provided the results will be paginated by returning
81+
* up to 50 nodes at a time starting at the provided page.
82+
* If "null" is provided as the value no pagination will
83+
* be used.
84+
* @return \Illuminate\Support\Collection|\Illuminate\Contracts\Pagination\LengthAwarePaginator
85+
*
8186
* @throws \Pterodactyl\Exceptions\Service\Deployment\NoViableNodeException
8287
*/
83-
public function handle()
88+
public function handle(int $page = null)
8489
{
8590
Assert::integer($this->disk, 'Disk space must be an int, got %s');
8691
Assert::integer($this->memory, 'Memory usage must be an int, got %s');
@@ -97,9 +102,13 @@ public function handle()
97102

98103
$results = $query->groupBy('nodes.id')
99104
->havingRaw('(IFNULL(SUM(servers.memory), 0) + ?) <= (nodes.memory * (1 + (nodes.memory_overallocate / 100)))', [$this->memory])
100-
->havingRaw('(IFNULL(SUM(servers.disk), 0) + ?) <= (nodes.disk * (1 + (nodes.disk_overallocate / 100)))', [$this->disk])
101-
->get()
102-
->toBase();
105+
->havingRaw('(IFNULL(SUM(servers.disk), 0) + ?) <= (nodes.disk * (1 + (nodes.disk_overallocate / 100)))', [$this->disk]);
106+
107+
if (! is_null($page)) {
108+
$results = $results->paginate(50, ['*'], 'page', $page);
109+
} else {
110+
$results = $results->get()->toBase();
111+
}
103112

104113
if ($results->isEmpty()) {
105114
throw new NoViableNodeException(trans('exceptions.deployment.no_viable_nodes'));

app/Services/Servers/ServerCreationService.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ public function handle(array $data, DeploymentObject $deployment = null): Server
197197
*/
198198
private function configureDeployment(array $data, DeploymentObject $deployment): Allocation
199199
{
200+
/** @var \Illuminate\Support\Collection $nodes */
200201
$nodes = $this->findViableNodesService->setLocations($deployment->getLocations())
201202
->setDisk(Arr::get($data, 'disk'))
202203
->setMemory(Arr::get($data, 'memory'))

routes/api-application.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
*/
3333
Route::group(['prefix' => '/nodes'], function () {
3434
Route::get('/', 'Nodes\NodeController@index')->name('api.application.nodes');
35+
Route::get('/deployable', 'Nodes\NodeDeploymentController');
3536
Route::get('/{node}', 'Nodes\NodeController@view')->name('api.application.nodes.view');
3637
Route::get('/{node}/configuration', 'Nodes\NodeConfigurationController');
3738

0 commit comments

Comments
 (0)