Skip to content

Commit 536f056

Browse files
authored
Merge pull request pterodactyl#1889 from matthewpi/feature/server-transfers-actually
Server Transfers (pterodactyl#18)
2 parents 7b69b4b + e7784bf commit 536f056

File tree

19 files changed

+958
-59
lines changed

19 files changed

+958
-59
lines changed
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
<?php
2+
3+
namespace Pterodactyl\Http\Controllers\Admin\Servers;
4+
5+
use Illuminate\Http\Request;
6+
use Pterodactyl\Models\Server;
7+
use Prologue\Alerts\AlertsMessageBag;
8+
use Pterodactyl\Models\ServerTransfer;
9+
use Pterodactyl\Http\Controllers\Controller;
10+
use Pterodactyl\Services\Servers\TransferService;
11+
use Pterodactyl\Services\Servers\SuspensionService;
12+
use Pterodactyl\Repositories\Eloquent\NodeRepository;
13+
use Pterodactyl\Repositories\Eloquent\ServerRepository;
14+
use Pterodactyl\Repositories\Eloquent\LocationRepository;
15+
use Pterodactyl\Repositories\Wings\DaemonConfigurationRepository;
16+
use Pterodactyl\Contracts\Repository\AllocationRepositoryInterface;
17+
18+
class ServerTransferController extends Controller
19+
{
20+
/**
21+
* @var \Prologue\Alerts\AlertsMessageBag
22+
*/
23+
private $alert;
24+
25+
/**
26+
* @var \Pterodactyl\Contracts\Repository\AllocationRepositoryInterface
27+
*/
28+
private $allocationRepository;
29+
30+
/**
31+
* @var \Pterodactyl\Repositories\Eloquent\ServerRepository
32+
*/
33+
private $repository;
34+
35+
/**
36+
* @var \Pterodactyl\Repositories\Eloquent\LocationRepository
37+
*/
38+
private $locationRepository;
39+
40+
/**
41+
* @var \Pterodactyl\Repositories\Eloquent\NodeRepository
42+
*/
43+
private $nodeRepository;
44+
45+
/**
46+
* @var \Pterodactyl\Services\Servers\SuspensionService
47+
*/
48+
private $suspensionService;
49+
50+
/**
51+
* @var \Pterodactyl\Services\Servers\TransferService
52+
*/
53+
private $transferService;
54+
55+
/**
56+
* @var \Pterodactyl\Repositories\Wings\DaemonConfigurationRepository
57+
*/
58+
private $daemonConfigurationRepository;
59+
60+
/**
61+
* ServerTransferController constructor.
62+
*
63+
* @param \Prologue\Alerts\AlertsMessageBag $alert
64+
* @param \Pterodactyl\Contracts\Repository\AllocationRepositoryInterface $allocationRepository
65+
* @param \Pterodactyl\Repositories\Eloquent\ServerRepository $repository
66+
* @param \Pterodactyl\Repositories\Eloquent\LocationRepository $locationRepository
67+
* @param \Pterodactyl\Repositories\Eloquent\NodeRepository $nodeRepository
68+
* @param \Pterodactyl\Services\Servers\SuspensionService $suspensionService
69+
* @param \Pterodactyl\Services\Servers\TransferService $transferService
70+
* @param \Pterodactyl\Repositories\Wings\DaemonConfigurationRepository $daemonConfigurationRepository
71+
*/
72+
public function __construct(
73+
AlertsMessageBag $alert,
74+
AllocationRepositoryInterface $allocationRepository,
75+
ServerRepository $repository,
76+
LocationRepository $locationRepository,
77+
NodeRepository $nodeRepository,
78+
SuspensionService $suspensionService,
79+
TransferService $transferService,
80+
DaemonConfigurationRepository $daemonConfigurationRepository
81+
) {
82+
$this->alert = $alert;
83+
$this->allocationRepository = $allocationRepository;
84+
$this->repository = $repository;
85+
$this->locationRepository = $locationRepository;
86+
$this->nodeRepository = $nodeRepository;
87+
$this->suspensionService = $suspensionService;
88+
$this->transferService = $transferService;
89+
$this->daemonConfigurationRepository = $daemonConfigurationRepository;
90+
}
91+
92+
/**
93+
* Starts a transfer of a server to a new node.
94+
*
95+
* @param \Illuminate\Http\Request $request
96+
* @param \Pterodactyl\Models\Server $server
97+
* @return \Illuminate\Http\RedirectResponse
98+
*
99+
* @throws \Throwable
100+
*/
101+
public function transfer(Request $request, Server $server)
102+
{
103+
$validatedData = $request->validate([
104+
'node_id' => 'required|exists:nodes,id',
105+
'allocation_id' => 'required|bail|unique:servers|exists:allocations,id',
106+
'allocation_additional' => 'nullable',
107+
]);
108+
109+
$node_id = $validatedData['node_id'];
110+
$allocation_id = intval($validatedData['allocation_id']);
111+
$additional_allocations = array_map('intval', $validatedData['allocation_additional'] ?? []);
112+
113+
// Check if the node is viable for the transfer.
114+
$node = $this->nodeRepository->getNodeWithResourceUsage($node_id);
115+
if ($node->isViable($server->memory, $server->disk)) {
116+
// Check if the selected daemon is online.
117+
$this->daemonConfigurationRepository->setNode($node)->getSystemInformation();
118+
119+
// Suspend the server and request an archive to be created.
120+
$this->suspensionService->toggle($server, 'suspend');
121+
122+
// Create a new ServerTransfer entry.
123+
$transfer = new ServerTransfer;
124+
125+
$transfer->server_id = $server->id;
126+
$transfer->old_node = $server->node_id;
127+
$transfer->new_node = $node_id;
128+
$transfer->old_allocation = $server->allocation_id;
129+
$transfer->new_allocation = $allocation_id;
130+
$transfer->old_additional_allocations = json_encode($server->allocations->where('id', '!=', $server->allocation_id)->pluck('id'));
131+
$transfer->new_additional_allocations = json_encode($additional_allocations);
132+
133+
$transfer->save();
134+
135+
// Add the allocations to the server so they cannot be automatically assigned while the transfer is in progress.
136+
$this->assignAllocationsToServer($server, $node_id, $allocation_id, $additional_allocations);
137+
138+
// Request an archive from the server's current daemon. (this also checks if the daemon is online)
139+
$this->transferService->requestArchive($server);
140+
141+
$this->alert->success(trans('admin/server.alerts.transfer_started'))->flash();
142+
} else {
143+
$this->alert->danger(trans('admin/server.alerts.transfer_not_viable'))->flash();
144+
}
145+
146+
return redirect()->route('admin.servers.view.manage', $server->id);
147+
}
148+
149+
/**
150+
* Assigns the specified allocations to the specified server.
151+
*
152+
* @param Server $server
153+
* @param int $node_id
154+
* @param int $allocation_id
155+
* @param array $additional_allocations
156+
*/
157+
private function assignAllocationsToServer(Server $server, int $node_id, int $allocation_id, array $additional_allocations)
158+
{
159+
$allocations = $additional_allocations;
160+
array_push($allocations, $allocation_id);
161+
162+
$unassigned = $this->allocationRepository->getUnassignedAllocationIds($node_id);
163+
164+
$updateIds = [];
165+
foreach ($allocations as $allocation) {
166+
if (! in_array($allocation, $unassigned)) {
167+
continue;
168+
}
169+
170+
$updateIds[] = $allocation;
171+
}
172+
173+
if (! empty($updateIds)) {
174+
$this->allocationRepository->updateWhereIn('id', $updateIds, ['server_id' => $server->id]);
175+
}
176+
}
177+
}

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

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,18 @@
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\NodeRepository;
1214
use Pterodactyl\Repositories\Eloquent\ServerRepository;
1315
use Pterodactyl\Traits\Controllers\JavascriptInjection;
16+
use Pterodactyl\Repositories\Eloquent\LocationRepository;
1417
use Pterodactyl\Repositories\Eloquent\DatabaseHostRepository;
1518

1619
class ServerViewController extends Controller
@@ -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
/**

0 commit comments

Comments
 (0)