Path: blob/1.0-develop/app/Services/Servers/BuildModificationService.php
10276 views
<?php12namespace Pterodactyl\Services\Servers;34use Illuminate\Support\Arr;5use Pterodactyl\Models\Server;6use Pterodactyl\Models\Allocation;7use Illuminate\Support\Facades\Log;8use Illuminate\Database\ConnectionInterface;9use Pterodactyl\Exceptions\DisplayException;10use Illuminate\Database\Eloquent\ModelNotFoundException;11use Pterodactyl\Repositories\Wings\DaemonServerRepository;12use Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException;1314class BuildModificationService15{16/**17* BuildModificationService constructor.18*/19public function __construct(20private ConnectionInterface $connection,21private DaemonServerRepository $daemonServerRepository,22private ServerConfigurationStructureService $structureService,23) {24}2526/**27* Change the build details for a specified server.28*29* @throws \Throwable30* @throws DisplayException31*/32public function handle(Server $server, array $data): Server33{34/** @var Server $server */35$server = $this->connection->transaction(function () use ($server, $data) {36$this->processAllocations($server, $data);3738if (isset($data['allocation_id']) && $data['allocation_id'] != $server->allocation_id) {39try {40Allocation::query()->where('id', $data['allocation_id'])->where('server_id', $server->id)->firstOrFail();41} catch (ModelNotFoundException) {42throw new DisplayException('The requested default allocation is not currently assigned to this server.');43}44}4546// If any of these values are passed through in the data array go ahead and set47// them correctly on the server model.48$merge = Arr::only($data, ['oom_disabled', 'memory', 'swap', 'io', 'cpu', 'threads', 'disk', 'allocation_id']);4950$server->forceFill(array_merge($merge, [51'database_limit' => Arr::get($data, 'database_limit', 0) ?? null,52'allocation_limit' => Arr::get($data, 'allocation_limit', 0) ?? null,53'backup_limit' => Arr::get($data, 'backup_limit', 0) ?? 0,54]))->saveOrFail();5556return $server->refresh();57});5859$updateData = $this->structureService->handle($server);6061// Because Wings always fetches an updated configuration from the Panel when booting62// a server this type of exception can be safely "ignored" and just written to the logs.63// Ideally this request succeeds, so we can apply resource modifications on the fly, but64// if it fails we can just continue on as normal.65if (!empty($updateData['build'])) {66try {67$this->daemonServerRepository->setServer($server)->sync();68} catch (DaemonConnectionException $exception) {69Log::warning($exception, ['server_id' => $server->id]);70}71}7273return $server;74}7576/**77* Process the allocations being assigned in the data and ensure they are available for a server.78*79* @throws DisplayException80*/81private function processAllocations(Server $server, array &$data): void82{83if (empty($data['add_allocations']) && empty($data['remove_allocations'])) {84return;85}8687// Handle the addition of allocations to this server. Only assign allocations that are not currently88// assigned to a different server, and only allocations on the same node as the server.89if (!empty($data['add_allocations'])) {90$query = Allocation::query()91->where('node_id', $server->node_id)92->whereIn('id', $data['add_allocations'])93->whereNull('server_id');9495// Keep track of all the allocations we're just now adding so that we can use the first96// one to reset the default allocation to.97$freshlyAllocated = $query->pluck('id')->first(); // @phpstan-ignore larastan.noUnnecessaryCollectionCall9899$query->update(['server_id' => $server->id, 'notes' => null]);100}101102if (!empty($data['remove_allocations'])) {103foreach ($data['remove_allocations'] as $allocation) {104// If we are attempting to remove the default allocation for the server, see if we can reassign105// to the first provided value in add_allocations. If there is no new first allocation then we106// will throw an exception back.107if ($allocation === ($data['allocation_id'] ?? $server->allocation_id)) {108if (empty($freshlyAllocated)) {109throw new DisplayException('You are attempting to delete the default allocation for this server but there is no fallback allocation to use.');110}111112// Update the default allocation to be the first allocation that we are creating.113$data['allocation_id'] = $freshlyAllocated;114}115}116117// Remove any of the allocations we got that are currently assigned to this server on118// this node. Also set the notes to null, otherwise when re-allocated to a new server those119// notes will be carried over.120Allocation::query()->where('node_id', $server->node_id)121->where('server_id', $server->id)122// Only remove the allocations that we didn't also attempt to add to the server...123->whereIn('id', array_diff($data['remove_allocations'], $data['add_allocations'] ?? []))124->update([125'notes' => null,126'server_id' => null,127]);128}129}130}131132133