Skip to content

Commit a2eab3c

Browse files
committed
Add ui elements for handling server transfers, add TransferJob.php and TransferService.php
1 parent 49f0421 commit a2eab3c

File tree

11 files changed

+512
-57
lines changed

11 files changed

+512
-57
lines changed
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
<?php
2+
3+
namespace Pterodactyl\Http\Controllers\Admin\Servers;
4+
5+
use Illuminate\Bus\Dispatcher;
6+
use Illuminate\Http\Request;
7+
use Prologue\Alerts\AlertsMessageBag;
8+
use Pterodactyl\Http\Controllers\Controller;
9+
use Pterodactyl\Jobs\Server\TransferJob;
10+
use Pterodactyl\Models\Server;
11+
use Pterodactyl\Repositories\Eloquent\ServerRepository;
12+
use Pterodactyl\Repositories\Eloquent\LocationRepository;
13+
use Pterodactyl\Repositories\Eloquent\NodeRepository;
14+
15+
class ServerTransferController extends Controller
16+
{
17+
/**
18+
* @var \Prologue\Alerts\AlertsMessageBag
19+
*/
20+
private $alert;
21+
22+
/**
23+
* @var \Illuminate\Bus\Dispatcher
24+
*/
25+
private $dispatcher;
26+
27+
/**
28+
* @var \Pterodactyl\Repositories\Eloquent\ServerRepository
29+
*/
30+
private $repository;
31+
32+
/**
33+
* @var \Pterodactyl\Repositories\Eloquent\LocationRepository
34+
*/
35+
private $locationRepository;
36+
37+
/**
38+
* @var \Pterodactyl\Repositories\Eloquent\NodeRepository
39+
*/
40+
private $nodeRepository;
41+
42+
/**
43+
* ServerTransferController constructor.
44+
*
45+
* @param \Prologue\Alerts\AlertsMessageBag $alert
46+
* @param \Illuminate\Bus\Dispatcher $dispatcher
47+
* @param \Pterodactyl\Repositories\Eloquent\ServerRepository $repository
48+
* @param \Pterodactyl\Repositories\Eloquent\LocationRepository $locationRepository
49+
* @param \Pterodactyl\Repositories\Eloquent\NodeRepository $nodeRepository
50+
*/
51+
public function __construct(
52+
AlertsMessageBag $alert,
53+
Dispatcher $dispatcher,
54+
ServerRepository $repository,
55+
LocationRepository $locationRepository,
56+
NodeRepository $nodeRepository
57+
) {
58+
$this->alert = $alert;
59+
$this->dispatcher = $dispatcher;
60+
$this->repository = $repository;
61+
$this->locationRepository = $locationRepository;
62+
$this->nodeRepository = $nodeRepository;
63+
}
64+
65+
/**
66+
* Starts a transfer of a server to a new node.
67+
*
68+
* @param \Illuminate\Http\Request $request
69+
* @param \Pterodactyl\Models\Server $server
70+
* @return \Illuminate\Http\RedirectResponse
71+
*/
72+
public function transfer(Request $request, Server $server)
73+
{
74+
$validatedData = $request->validate([
75+
'node_id' => 'required|exists:nodes,id',
76+
'allocation_id' => 'required|bail|unique:servers|exists:allocations,id',
77+
'allocation_additional' => 'nullable',
78+
]);
79+
80+
$node_id = $validatedData['node_id'];
81+
$allocation_id = $validatedData['allocation_id'];
82+
$additional_allocations = $validatedData['allocation_additional'] ?? [];
83+
84+
// Check if the node is viable for the transfer.
85+
$node = $this->nodeRepository->getNodeWithResourceUsage($node_id);
86+
if ($node->isViable($server->memory, $server->disk)) {
87+
// TODO: Run TransferJob.
88+
$this->dispatcher->dispatch(new TransferJob($server, $node, $allocation_id, $additional_allocations));
89+
90+
$this->alert->success(trans('admin/server.alerts.transfer_started'))->flash();
91+
} else {
92+
$this->alert->danger(trans('admin/server.alerts.transfer_not_viable'))->flash();
93+
}
94+
95+
return redirect()->route('admin.servers.view.manage', $server->id);
96+
}
97+
}

app/Http/Controllers/Admin/Servers/ServerViewController.php

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@
22

33
namespace Pterodactyl\Http\Controllers\Admin\Servers;
44

5+
use JavaScript;
56
use Illuminate\Http\Request;
67
use Pterodactyl\Models\Nest;
78
use Pterodactyl\Models\Server;
89
use Illuminate\Contracts\View\Factory;
910
use Pterodactyl\Exceptions\DisplayException;
1011
use Pterodactyl\Http\Controllers\Controller;
1112
use Pterodactyl\Repositories\Eloquent\NestRepository;
13+
use Pterodactyl\Repositories\Eloquent\LocationRepository;
14+
use Pterodactyl\Repositories\Eloquent\NodeRepository;
1215
use Pterodactyl\Repositories\Eloquent\ServerRepository;
1316
use Pterodactyl\Traits\Controllers\JavascriptInjection;
1417
use Pterodactyl\Repositories\Eloquent\DatabaseHostRepository;
@@ -37,24 +40,40 @@ class ServerViewController extends Controller
3740
*/
3841
private $nestRepository;
3942

43+
/**
44+
* @var \Pterodactyl\Repositories\Eloquent\LocationRepository
45+
*/
46+
private $locationRepository;
47+
48+
/**
49+
* @var \Pterodactyl\Repositories\Eloquent\NodeRepository
50+
*/
51+
private $nodeRepository;
52+
4053
/**
4154
* ServerViewController constructor.
4255
*
4356
* @param \Pterodactyl\Repositories\Eloquent\DatabaseHostRepository $databaseHostRepository
4457
* @param \Pterodactyl\Repositories\Eloquent\NestRepository $nestRepository
58+
* @param \Pterodactyl\Repositories\Eloquent\LocationRepository $locationRepository
59+
* @param \Pterodactyl\Repositories\Eloquent\NodeRepository $nodeRepository
4560
* @param \Pterodactyl\Repositories\Eloquent\ServerRepository $repository
4661
* @param \Illuminate\Contracts\View\Factory $view
4762
*/
4863
public function __construct(
4964
DatabaseHostRepository $databaseHostRepository,
5065
NestRepository $nestRepository,
66+
LocationRepository $locationRepository,
67+
NodeRepository $nodeRepository,
5168
ServerRepository $repository,
5269
Factory $view
5370
) {
5471
$this->view = $view;
5572
$this->databaseHostRepository = $databaseHostRepository;
5673
$this->repository = $repository;
5774
$this->nestRepository = $nestRepository;
75+
$this->nodeRepository = $nodeRepository;
76+
$this->locationRepository = $locationRepository;
5877
}
5978

6079
/**
@@ -150,6 +169,7 @@ public function database(Request $request, Server $server)
150169
* @return \Illuminate\Contracts\View\View
151170
*
152171
* @throws \Pterodactyl\Exceptions\DisplayException
172+
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
153173
*/
154174
public function manage(Request $request, Server $server)
155175
{
@@ -159,7 +179,22 @@ public function manage(Request $request, Server $server)
159179
);
160180
}
161181

162-
return $this->view->make('admin.servers.view.manage', compact('server'));
182+
// Check if the panel doesn't have at least 2 nodes configured.
183+
$nodes = $this->nodeRepository->all();
184+
$canTransfer = false;
185+
if (count($nodes) >= 2) {
186+
$canTransfer = true;
187+
}
188+
189+
Javascript::put([
190+
'nodeData' => $this->nodeRepository->getNodesForServerCreation(),
191+
]);
192+
193+
return $this->view->make('admin.servers.view.manage', [
194+
'server' => $server,
195+
'locations' => $this->locationRepository->all(),
196+
'canTransfer' => $canTransfer,
197+
]);
163198
}
164199

165200
/**

app/Jobs/Server/TransferJob.php

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<?php
2+
3+
namespace Pterodactyl\Jobs\Server;
4+
5+
use Illuminate\Bus\Queueable;
6+
use Illuminate\Queue\SerializesModels;
7+
use Illuminate\Queue\InteractsWithQueue;
8+
use Illuminate\Contracts\Queue\ShouldQueue;
9+
use Illuminate\Foundation\Bus\Dispatchable;
10+
use Pterodactyl\Models\Node;
11+
use Pterodactyl\Models\Server;
12+
use Pterodactyl\Services\Servers\ServerCreationService;
13+
use Pterodactyl\Services\Servers\ServerDeletionService;
14+
use Pterodactyl\Services\Servers\SuspensionService;
15+
use Pterodactyl\Services\Servers\TransferService;
16+
17+
class TransferJob implements ShouldQueue
18+
{
19+
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
20+
21+
private $server, $node, $allocation_id, $additional_allocations;
22+
23+
/**
24+
* Create a new job instance.
25+
*
26+
* @param Server $serverToTransfer
27+
* @param Node $newNode
28+
*/
29+
public function __construct(Server $serverToTransfer, Node $newNode, int $allocation_id, array $additional_allocations)
30+
{
31+
$this->server = $serverToTransfer;
32+
$this->node = $newNode;
33+
$this->allocation_id = $allocation_id;
34+
$this->additional_allocations = $additional_allocations;
35+
}
36+
37+
/**
38+
* Execute the job.
39+
*
40+
* @param ServerCreationService $creationService
41+
* @param ServerDeletionService $deletionService
42+
* @param SuspensionService $suspensionService
43+
* @param TransferService $transferService
44+
* @return void
45+
*
46+
* @throws \Pterodactyl\Exceptions\DisplayException
47+
* @throws \Throwable
48+
*/
49+
public function handle(
50+
ServerCreationService $creationService,
51+
ServerDeletionService $deletionService,
52+
SuspensionService $suspensionService,
53+
TransferService $transferService
54+
) {
55+
//$server = $this->server;
56+
//$newNode = $this->node;
57+
58+
// 1. Suspend Old Server
59+
//$suspensionService->toggle($server, 'suspend');
60+
61+
// 2. Zip Folder
62+
//$backup = $server->generateBackup();
63+
64+
// 3. Transfer Zip File
65+
//$archive = $newNode->transfer($backup);
66+
67+
// 4. Verify File Hash
68+
/*if ($backup->hash !== $archive->hash) {
69+
$archive->delete();
70+
abort(500, 'File transfer corrupted, please try again.');
71+
}*/
72+
73+
// 5. Unzip File
74+
//$archive->extract();
75+
76+
// 6. Update Settings on New Node
77+
//$newServerDetails = $server->toArray();
78+
//$newServerDetails['node_id'] = $newNode->id;
79+
//$newServer = $creationService->create($newServerDetails);
80+
81+
// 7. Verify Server Status
82+
/*if (!$newServer->isWorking()) {
83+
$deletionService->withForce()->handle($newServer);
84+
abort(500, 'Server failed to startup, please try again.');
85+
}*/
86+
87+
// 8. Unsuspend Old Server
88+
//$deletionService->withForce()->handle($server);
89+
//$suspensionService->toggle($server, 'unsuspend');
90+
}
91+
}

app/Models/Node.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,4 +235,18 @@ public function allocations()
235235
{
236236
return $this->hasMany(Allocation::class);
237237
}
238+
239+
/**
240+
* Returns a boolean if the node is viable for an additional server to be placed on it.
241+
*
242+
* @param int $memory
243+
* @param int $disk
244+
* @return bool
245+
*/
246+
public function isViable(int $memory, int $disk): bool {
247+
$memoryLimit = $this->memory * (1 + ($this->memory_overallocate / 100));
248+
$diskLimit = $this->disk * (1 + ($this->disk_overallocate / 100));
249+
250+
return ($this->sum_memory + $memory) <= $memoryLimit && ($this->sum_disk + $disk) <= $diskLimit;
251+
}
238252
}

app/Repositories/Eloquent/NodeRepository.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,23 @@ public function getNodesForServerCreation(): Collection
174174
})->values();
175175
}
176176

177+
/**
178+
* Returns a node with the given id with the Node's resource usage.
179+
*
180+
* @param int $node_id
181+
* @return Node
182+
*/
183+
public function getNodeWithResourceUsage(int $node_id): Node
184+
{
185+
$instance = $this->getBuilder()
186+
->select(['nodes.id', 'nodes.memory', 'nodes.disk', 'nodes.memory_overallocate', 'nodes.disk_overallocate'])
187+
->selectRaw('IFNULL(SUM(servers.memory), 0) as sum_memory, IFNULL(SUM(servers.disk), 0) as sum_disk')
188+
->leftJoin('servers', 'servers.node_id', '=', 'nodes.id')
189+
->where('nodes.id', $node_id);
190+
191+
return $instance->first();
192+
}
193+
177194
/**
178195
* Return the IDs of all nodes that exist in the provided locations and have the space
179196
* available to support the additional disk and memory provided.

app/Services/Servers/ServerCreationService.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
use Ramsey\Uuid\Uuid;
66
use Illuminate\Support\Arr;
7-
use Pterodactyl\Models\Node;
87
use Pterodactyl\Models\User;
98
use Pterodactyl\Models\Server;
109
use Illuminate\Support\Collection;
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
3+
namespace Pterodactyl\Services\Servers;
4+
5+
use Illuminate\Database\ConnectionInterface;
6+
use Psr\Log\LoggerInterface;
7+
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
8+
use Pterodactyl\Models\Server;
9+
use Pterodactyl\Repositories\Wings\DaemonServerRepository;
10+
11+
class TransferService
12+
{
13+
14+
/**
15+
* @var \Illuminate\Database\ConnectionInterface
16+
*/
17+
private $connection;
18+
19+
/**
20+
* @var \Pterodactyl\Contracts\Repository\ServerRepositoryInterface
21+
*/
22+
private $repository;
23+
24+
/**
25+
* @var \Pterodactyl\Repositories\Wings\DaemonServerRepository
26+
*/
27+
private $daemonServerRepository;
28+
29+
/**
30+
* @var \Psr\Log\LoggerInterface
31+
*/
32+
private $writer;
33+
34+
/**
35+
* TransferService constructor.
36+
*
37+
* @param \Illuminate\Database\ConnectionInterface $connection
38+
* @param \Pterodactyl\Repositories\Wings\DaemonServerRepository $daemonServerRepository
39+
* @param \Pterodactyl\Contracts\Repository\ServerRepositoryInterface $repository
40+
* @param \Psr\Log\LoggerInterface $writer
41+
*/
42+
public function __construct(
43+
ConnectionInterface $connection,
44+
DaemonServerRepository $daemonServerRepository,
45+
ServerRepositoryInterface $repository,
46+
LoggerInterface $writer
47+
) {
48+
$this->connection = $connection;
49+
$this->repository = $repository;
50+
$this->daemonServerRepository = $daemonServerRepository;
51+
$this->writer = $writer;
52+
}
53+
54+
public function handle(Server $server)
55+
{
56+
57+
}
58+
}

0 commit comments

Comments
 (0)