From 5007ce0b1ce1f43bf0eaf18a679673dbf6feffb3 Mon Sep 17 00:00:00 2001 From: Matthew Penner Date: Sat, 4 Apr 2020 00:50:06 -0600 Subject: [PATCH] Get to the point where we can start notifying the other daemon, remove TransferJob.php, add DaemonTransferRepository.php --- .../Servers/ServerTransferController.php | 28 +++++- .../Servers/ServerTransferController.php | 85 +++++++++++++++++ app/Jobs/Server/TransferJob.php | 91 ------------------- app/Models/Node.php | 1 + .../Wings/DaemonServerRepository.php | 20 ++++ .../Wings/DaemonTransferRepository.php | 31 +++++++ app/Services/Servers/TransferService.php | 30 ++---- routes/api-remote.php | 1 + 8 files changed, 172 insertions(+), 115 deletions(-) create mode 100644 app/Http/Controllers/Api/Remote/Servers/ServerTransferController.php delete mode 100644 app/Jobs/Server/TransferJob.php create mode 100644 app/Repositories/Wings/DaemonTransferRepository.php diff --git a/app/Http/Controllers/Admin/Servers/ServerTransferController.php b/app/Http/Controllers/Admin/Servers/ServerTransferController.php index fc1b04e33..7cc5c5ec6 100644 --- a/app/Http/Controllers/Admin/Servers/ServerTransferController.php +++ b/app/Http/Controllers/Admin/Servers/ServerTransferController.php @@ -6,11 +6,12 @@ use Illuminate\Bus\Dispatcher; use Illuminate\Http\Request; use Prologue\Alerts\AlertsMessageBag; use Pterodactyl\Http\Controllers\Controller; -use Pterodactyl\Jobs\Server\TransferJob; use Pterodactyl\Models\Server; use Pterodactyl\Repositories\Eloquent\ServerRepository; use Pterodactyl\Repositories\Eloquent\LocationRepository; use Pterodactyl\Repositories\Eloquent\NodeRepository; +use Pterodactyl\Services\Servers\SuspensionService; +use Pterodactyl\Services\Servers\TransferService; class ServerTransferController extends Controller { @@ -39,6 +40,16 @@ class ServerTransferController extends Controller */ private $nodeRepository; + /** + * @var \Pterodactyl\Services\Servers\SuspensionService + */ + private $suspensionService; + + /** + * @var \Pterodactyl\Services\Servers\TransferService + */ + private $transferService; + /** * ServerTransferController constructor. * @@ -47,19 +58,25 @@ class ServerTransferController extends Controller * @param \Pterodactyl\Repositories\Eloquent\ServerRepository $repository * @param \Pterodactyl\Repositories\Eloquent\LocationRepository $locationRepository * @param \Pterodactyl\Repositories\Eloquent\NodeRepository $nodeRepository + * @param \Pterodactyl\Services\Servers\SuspensionService $suspensionService + * @param \Pterodactyl\Services\Servers\TransferService $transferService */ public function __construct( AlertsMessageBag $alert, Dispatcher $dispatcher, ServerRepository $repository, LocationRepository $locationRepository, - NodeRepository $nodeRepository + NodeRepository $nodeRepository, + SuspensionService $suspensionService, + TransferService $transferService ) { $this->alert = $alert; $this->dispatcher = $dispatcher; $this->repository = $repository; $this->locationRepository = $locationRepository; $this->nodeRepository = $nodeRepository; + $this->suspensionService = $suspensionService; + $this->transferService = $transferService; } /** @@ -68,6 +85,8 @@ class ServerTransferController extends Controller * @param \Illuminate\Http\Request $request * @param \Pterodactyl\Models\Server $server * @return \Illuminate\Http\RedirectResponse + * + * @throws \Throwable */ public function transfer(Request $request, Server $server) { @@ -84,8 +103,9 @@ class ServerTransferController extends Controller // Check if the node is viable for the transfer. $node = $this->nodeRepository->getNodeWithResourceUsage($node_id); if ($node->isViable($server->memory, $server->disk)) { - // TODO: Run TransferJob. - $this->dispatcher->dispatch(new TransferJob($server, $node, $allocation_id, $additional_allocations)); + // Suspend the server and request an archive to be created. + // $this->suspensionService->toggle($server, 'suspend'); + $this->transferService->requestArchive($server); $this->alert->success(trans('admin/server.alerts.transfer_started'))->flash(); } else { diff --git a/app/Http/Controllers/Api/Remote/Servers/ServerTransferController.php b/app/Http/Controllers/Api/Remote/Servers/ServerTransferController.php new file mode 100644 index 000000000..cff59b3d2 --- /dev/null +++ b/app/Http/Controllers/Api/Remote/Servers/ServerTransferController.php @@ -0,0 +1,85 @@ +repository = $repository; + $this->nodeRepository = $nodeRepository; + $this->daemonTransferRepository = $daemonTransferRepository; + } + + /** + * The daemon notifies us about the archive status. + * + * @param \Illuminate\Http\Request $request + * @param \Pterodactyl\Models\Server $server + * @return \Illuminate\Http\JsonResponse + * + * @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException + */ + public function archive(Request $request, Server $server) + { + // Unsuspend the server and don't continue the transfer. + if (!$request->input('successful')) { + // $this->suspensionService->toggle($server, 'unsuspend'); + return JsonResponse::create([], Response::HTTP_NO_CONTENT); + } + + $now = Chronos::now(); + $signer = new Sha256; + + $token = (new Builder)->issuedBy(config('app.url')) + ->permittedFor($server->node->getConnectionAddress()) + ->identifiedBy(hash('sha256', $server->uuid), true) + ->issuedAt($now->getTimestamp()) + ->canOnlyBeUsedAfter($now->getTimestamp()) + ->expiresAt($now->addMinutes(15)->getTimestamp()) + ->relatedTo($server->id, true) + ->getToken($signer, new Key($server->node->daemonSecret)); + + $this->daemonTransferRepository->notify($server, $token->__toString()); + + return JsonResponse::create([], Response::HTTP_NO_CONTENT); + } +} diff --git a/app/Jobs/Server/TransferJob.php b/app/Jobs/Server/TransferJob.php deleted file mode 100644 index 24b38b3bd..000000000 --- a/app/Jobs/Server/TransferJob.php +++ /dev/null @@ -1,91 +0,0 @@ -server = $serverToTransfer; - $this->node = $newNode; - $this->allocation_id = $allocation_id; - $this->additional_allocations = $additional_allocations; - } - - /** - * Execute the job. - * - * @param ServerCreationService $creationService - * @param ServerDeletionService $deletionService - * @param SuspensionService $suspensionService - * @param TransferService $transferService - * @return void - * - * @throws \Pterodactyl\Exceptions\DisplayException - * @throws \Throwable - */ - public function handle( - ServerCreationService $creationService, - ServerDeletionService $deletionService, - SuspensionService $suspensionService, - TransferService $transferService - ) { - //$server = $this->server; - //$newNode = $this->node; - - // 1. Suspend Old Server - //$suspensionService->toggle($server, 'suspend'); - - // 2. Zip Folder - //$backup = $server->generateBackup(); - - // 3. Transfer Zip File - //$archive = $newNode->transfer($backup); - - // 4. Verify File Hash - /*if ($backup->hash !== $archive->hash) { - $archive->delete(); - abort(500, 'File transfer corrupted, please try again.'); - }*/ - - // 5. Unzip File - //$archive->extract(); - - // 6. Update Settings on New Node - //$newServerDetails = $server->toArray(); - //$newServerDetails['node_id'] = $newNode->id; - //$newServer = $creationService->create($newServerDetails); - - // 7. Verify Server Status - /*if (!$newServer->isWorking()) { - $deletionService->withForce()->handle($newServer); - abort(500, 'Server failed to startup, please try again.'); - }*/ - - // 8. Unsuspend Old Server - //$deletionService->withForce()->handle($server); - //$suspensionService->toggle($server, 'unsuspend'); - } -} diff --git a/app/Models/Node.php b/app/Models/Node.php index dc789e64d..01335448e 100644 --- a/app/Models/Node.php +++ b/app/Models/Node.php @@ -170,6 +170,7 @@ class Node extends Validable ], 'system' => [ 'data' => $this->daemonBase, + 'archive_directory' => $this->daemonBase . '/.archives', 'username' => 'pterodactyl', 'timezone_path' => '/etc/timezone', 'set_permissions_on_boot' => true, diff --git a/app/Repositories/Wings/DaemonServerRepository.php b/app/Repositories/Wings/DaemonServerRepository.php index 3461e4cc9..b41c75483 100644 --- a/app/Repositories/Wings/DaemonServerRepository.php +++ b/app/Repositories/Wings/DaemonServerRepository.php @@ -124,4 +124,24 @@ class DaemonServerRepository extends DaemonRepository throw new DaemonConnectionException($exception); } } + + /** + * Requests the daemon to create a full archive of the server. + * Once the daemon is finished they will send a POST request to + * "/api/remote/servers/{uuid}/archive" with a boolean. + * + * @throws DaemonConnectionException + */ + public function requestArchive(): void + { + Assert::isInstanceOf($this->server, Server::class); + + try { + $this->getHttpClient()->post(sprintf( + '/api/servers/%s/archive', $this->server->uuid + )); + } catch (TransferException $exception) { + throw new DaemonConnectionException($exception); + } + } } diff --git a/app/Repositories/Wings/DaemonTransferRepository.php b/app/Repositories/Wings/DaemonTransferRepository.php new file mode 100644 index 000000000..9e82ff3c6 --- /dev/null +++ b/app/Repositories/Wings/DaemonTransferRepository.php @@ -0,0 +1,31 @@ +getHttpClient()->post('/api/transfer', [ + 'json' => [ + 'url' => $server->node->getConnectionAddress() . sprintf('/api/servers/%s/archive', $server->uuid), + 'token' => $token, + ], + ]); + } catch (TransferException $exception) { + throw new DaemonConnectionException($exception); + } + } +} diff --git a/app/Services/Servers/TransferService.php b/app/Services/Servers/TransferService.php index 762487e4f..924ad5d03 100644 --- a/app/Services/Servers/TransferService.php +++ b/app/Services/Servers/TransferService.php @@ -10,12 +10,6 @@ use Pterodactyl\Repositories\Wings\DaemonServerRepository; class TransferService { - - /** - * @var \Illuminate\Database\ConnectionInterface - */ - private $connection; - /** * @var \Pterodactyl\Contracts\Repository\ServerRepositoryInterface */ @@ -26,33 +20,29 @@ class TransferService */ private $daemonServerRepository; - /** - * @var \Psr\Log\LoggerInterface - */ - private $writer; - /** * TransferService constructor. * - * @param \Illuminate\Database\ConnectionInterface $connection * @param \Pterodactyl\Repositories\Wings\DaemonServerRepository $daemonServerRepository * @param \Pterodactyl\Contracts\Repository\ServerRepositoryInterface $repository - * @param \Psr\Log\LoggerInterface $writer */ public function __construct( - ConnectionInterface $connection, DaemonServerRepository $daemonServerRepository, - ServerRepositoryInterface $repository, - LoggerInterface $writer + ServerRepositoryInterface $repository ) { - $this->connection = $connection; $this->repository = $repository; $this->daemonServerRepository = $daemonServerRepository; - $this->writer = $writer; } - public function handle(Server $server) + /** + * Requests an archive from the daemon. + * + * @param int|\Pterodactyl\Models\Server $server + * + * @throws \Throwable + */ + public function requestArchive(Server $server) { - + $this->daemonServerRepository->setServer($server)->requestArchive(); } } diff --git a/routes/api-remote.php b/routes/api-remote.php index 4fb77b291..0893454d0 100644 --- a/routes/api-remote.php +++ b/routes/api-remote.php @@ -11,4 +11,5 @@ Route::group(['prefix' => '/servers/{uuid}'], function () { Route::get('/', 'Servers\ServerDetailsController'); Route::get('/install', 'Servers\ServerInstallController@index'); Route::post('/install', 'Servers\ServerInstallController@store'); + Route::post('/archive', 'Servers\ServerTransferController@archive'); });