Get to the point where we can start notifying the other daemon, remove TransferJob.php, add DaemonTransferRepository.php

This commit is contained in:
Matthew Penner 2020-04-04 00:50:06 -06:00
parent a2eab3ca43
commit 5007ce0b1c
8 changed files with 172 additions and 115 deletions

View file

@ -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 {

View file

@ -0,0 +1,85 @@
<?php
namespace Pterodactyl\Http\Controllers\Api\Remote\Servers;
use Cake\Chronos\Chronos;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use Lcobucci\JWT\Signer\Key;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Models\Server;
use Pterodactyl\Repositories\Eloquent\ServerRepository;
use Pterodactyl\Repositories\Eloquent\NodeRepository;
use Pterodactyl\Repositories\Wings\DaemonTransferRepository;
class ServerTransferController extends Controller
{
/**
* @var \Pterodactyl\Repositories\Eloquent\ServerRepository
*/
private $repository;
/**
* @var \Pterodactyl\Repositories\Eloquent\NodeRepository
*/
private $nodeRepository;
/**
* @var \Pterodactyl\Repositories\Wings\DaemonTransferRepository
*/
private $daemonTransferRepository;
/**
* ServerTransferController constructor.
*
* @param \Pterodactyl\Repositories\Eloquent\ServerRepository $repository
* @param \Pterodactyl\Repositories\Eloquent\NodeRepository $nodeRepository
* @param DaemonTransferRepository $daemonTransferRepository
*/
public function __construct(
ServerRepository $repository,
NodeRepository $nodeRepository,
DaemonTransferRepository $daemonTransferRepository
) {
$this->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);
}
}

View file

@ -1,91 +0,0 @@
<?php
namespace Pterodactyl\Jobs\Server;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Pterodactyl\Models\Node;
use Pterodactyl\Models\Server;
use Pterodactyl\Services\Servers\ServerCreationService;
use Pterodactyl\Services\Servers\ServerDeletionService;
use Pterodactyl\Services\Servers\SuspensionService;
use Pterodactyl\Services\Servers\TransferService;
class TransferJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
private $server, $node, $allocation_id, $additional_allocations;
/**
* Create a new job instance.
*
* @param Server $serverToTransfer
* @param Node $newNode
*/
public function __construct(Server $serverToTransfer, Node $newNode, int $allocation_id, array $additional_allocations)
{
$this->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');
}
}

View file

@ -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,

View file

@ -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);
}
}
}

View file

@ -0,0 +1,31 @@
<?php
namespace Pterodactyl\Repositories\Wings;
use Pterodactyl\Models\Server;
use GuzzleHttp\Exception\TransferException;
use Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException;
class DaemonTransferRepository extends DaemonRepository
{
/**
* @param Server $server
* @param string $token
*
* @throws DaemonConnectionException
*/
public function notify(Server $server, string $token): void
{
try {
$this->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);
}
}
}

View file

@ -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();
}
}

View file

@ -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');
});