1f5e0c0334
closes #2553
151 lines
5.9 KiB
PHP
151 lines
5.9 KiB
PHP
<?php
|
|
|
|
namespace Pterodactyl\Services\Servers;
|
|
|
|
use Illuminate\Support\Arr;
|
|
use Pterodactyl\Models\Server;
|
|
use Pterodactyl\Models\Allocation;
|
|
use Illuminate\Database\ConnectionInterface;
|
|
use Pterodactyl\Exceptions\DisplayException;
|
|
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
|
use Pterodactyl\Repositories\Wings\DaemonServerRepository;
|
|
|
|
class BuildModificationService
|
|
{
|
|
/**
|
|
* @var \Illuminate\Database\ConnectionInterface
|
|
*/
|
|
private $connection;
|
|
|
|
/**
|
|
* @var \Pterodactyl\Repositories\Wings\DaemonServerRepository
|
|
*/
|
|
private $daemonServerRepository;
|
|
|
|
/**
|
|
* @var \Pterodactyl\Services\Servers\ServerConfigurationStructureService
|
|
*/
|
|
private $structureService;
|
|
|
|
/**
|
|
* BuildModificationService constructor.
|
|
*
|
|
* @param \Pterodactyl\Services\Servers\ServerConfigurationStructureService $structureService
|
|
* @param \Illuminate\Database\ConnectionInterface $connection
|
|
* @param \Pterodactyl\Repositories\Wings\DaemonServerRepository $daemonServerRepository
|
|
*/
|
|
public function __construct(
|
|
ServerConfigurationStructureService $structureService,
|
|
ConnectionInterface $connection,
|
|
DaemonServerRepository $daemonServerRepository
|
|
) {
|
|
$this->daemonServerRepository = $daemonServerRepository;
|
|
$this->connection = $connection;
|
|
$this->structureService = $structureService;
|
|
}
|
|
|
|
/**
|
|
* Change the build details for a specified server.
|
|
*
|
|
* @param \Pterodactyl\Models\Server $server
|
|
* @param array $data
|
|
* @return \Pterodactyl\Models\Server
|
|
*
|
|
* @throws \Throwable
|
|
* @throws \Pterodactyl\Exceptions\DisplayException
|
|
*/
|
|
public function handle(Server $server, array $data)
|
|
{
|
|
$this->connection->beginTransaction();
|
|
|
|
$this->processAllocations($server, $data);
|
|
|
|
if (isset($data['allocation_id']) && $data['allocation_id'] != $server->allocation_id) {
|
|
try {
|
|
Allocation::query()->where('id', $data['allocation_id'])->where('server_id', $server->id)->firstOrFail();
|
|
} catch (ModelNotFoundException $ex) {
|
|
throw new DisplayException('The requested default allocation is not currently assigned to this server.');
|
|
}
|
|
}
|
|
|
|
// If any of these values are passed through in the data array go ahead and set
|
|
// them correctly on the server model.
|
|
$merge = Arr::only($data, ['oom_disabled', 'memory', 'swap', 'io', 'cpu', 'threads', 'disk', 'allocation_id']);
|
|
|
|
$server->forceFill(array_merge($merge, [
|
|
'database_limit' => Arr::get($data, 'database_limit', 0) ?? null,
|
|
'allocation_limit' => Arr::get($data, 'allocation_limit', 0) ?? null,
|
|
'backup_limit' => Arr::get($data, 'backup_limit', 0) ?? 0,
|
|
]))->saveOrFail();
|
|
|
|
$server = $server->fresh();
|
|
|
|
$updateData = $this->structureService->handle($server);
|
|
|
|
$this->daemonServerRepository->setServer($server)->update($updateData['build'] ?? []);
|
|
|
|
$this->connection->commit();
|
|
|
|
return $server;
|
|
}
|
|
|
|
/**
|
|
* Process the allocations being assigned in the data and ensure they are available for a server.
|
|
*
|
|
* @param \Pterodactyl\Models\Server $server
|
|
* @param array $data
|
|
*
|
|
* @throws \Pterodactyl\Exceptions\DisplayException
|
|
*/
|
|
private function processAllocations(Server $server, array &$data)
|
|
{
|
|
if (empty($data['add_allocations']) && empty($data['remove_allocations'])) {
|
|
return;
|
|
}
|
|
|
|
// Handle the addition of allocations to this server. Only assign allocations that are not currently
|
|
// assigned to a different server, and only allocations on the same node as the server.
|
|
if (! empty($data['add_allocations'])) {
|
|
$query = Allocation::query()
|
|
->where('node_id', $server->node_id)
|
|
->whereIn('id', $data['add_allocations'])
|
|
->whereNull('server_id');
|
|
|
|
// Keep track of all the allocations we're just now adding so that we can use the first
|
|
// one to reset the default allocation to.
|
|
$freshlyAllocated = $query->pluck('id')->first();
|
|
|
|
$query->update(['server_id' => $server->id]);
|
|
}
|
|
|
|
if (! empty($data['remove_allocations'])) {
|
|
foreach ($data['remove_allocations'] as $allocation) {
|
|
// If we are attempting to remove the default allocation for the server, see if we can reassign
|
|
// to the first provided value in add_allocations. If there is no new first allocation then we
|
|
// will throw an exception back.
|
|
if ($allocation === ($data['allocation_id'] ?? $server->allocation_id)) {
|
|
if (empty($freshlyAllocated)) {
|
|
throw new DisplayException(
|
|
'You are attempting to delete the default allocation for this server but there is no fallback allocation to use.'
|
|
);
|
|
}
|
|
|
|
// Update the default allocation to be the first allocation that we are creating.
|
|
$data['allocation_id'] = $freshlyAllocated;
|
|
}
|
|
}
|
|
|
|
// Remove any of the allocations we got that are currently assigned to this server on
|
|
// this node. Also set the notes to null, otherwise when re-allocated to a new server those
|
|
// notes will be carried over.
|
|
Allocation::query()->where('node_id', $server->node_id)
|
|
->where('server_id', $server->id)
|
|
// Only remove the allocations that we didn't also attempt to add to the server...
|
|
->whereIn('id', array_diff($data['remove_allocations'], $data['add_allocations'] ?? []))
|
|
->update([
|
|
'notes' => null,
|
|
'server_id' => null,
|
|
]);
|
|
}
|
|
}
|
|
}
|