diff --git a/app/Services/Servers/BuildModificationService.php b/app/Services/Servers/BuildModificationService.php index 6a96075c5..9a8c1c3c4 100644 --- a/app/Services/Servers/BuildModificationService.php +++ b/app/Services/Servers/BuildModificationService.php @@ -5,10 +5,12 @@ namespace Pterodactyl\Services\Servers; use Illuminate\Support\Arr; use Pterodactyl\Models\Server; use Pterodactyl\Models\Allocation; +use Illuminate\Support\Facades\Log; use Illuminate\Database\ConnectionInterface; use Pterodactyl\Exceptions\DisplayException; use Illuminate\Database\Eloquent\ModelNotFoundException; use Pterodactyl\Repositories\Wings\DaemonServerRepository; +use Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException; class BuildModificationService { @@ -78,10 +80,18 @@ class BuildModificationService $updateData = $this->structureService->handle($server); + // Because Wings always fetches an updated configuration from the Panel when booting + // a server this type of exception can be safely "ignored" and just written to the logs. + // Ideally this request succeedes so we can apply resource modifications on the fly + // but if it fails it isn't the end of the world. if (!empty($updateData['build'])) { - $this->daemonServerRepository->setServer($server)->update([ - 'build' => $updateData['build'], - ]); + try { + $this->daemonServerRepository->setServer($server)->update([ + 'build' => $updateData['build'], + ]); + } catch (DaemonConnectionException $exception) { + Log::warning($exception, ['server_id' => $server->id]); + } } $this->connection->commit(); diff --git a/tests/Integration/Services/Servers/BuildModificationServiceTest.php b/tests/Integration/Services/Servers/BuildModificationServiceTest.php index 359dff67e..9a61caa34 100644 --- a/tests/Integration/Services/Servers/BuildModificationServiceTest.php +++ b/tests/Integration/Services/Servers/BuildModificationServiceTest.php @@ -3,12 +3,17 @@ namespace Pterodactyl\Tests\Integration\Services\Servers; use Mockery; +use GuzzleHttp\Psr7\Request; +use GuzzleHttp\Psr7\Response; use Pterodactyl\Models\Server; use Pterodactyl\Models\Allocation; +use GuzzleHttp\Exception\RequestException; +use GuzzleHttp\Exception\TransferException; use Pterodactyl\Exceptions\DisplayException; use Pterodactyl\Tests\Integration\IntegrationTestCase; use Pterodactyl\Repositories\Wings\DaemonServerRepository; use Pterodactyl\Services\Servers\BuildModificationService; +use Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException; class BuildModificationServiceTest extends IntegrationTestCase { @@ -149,6 +154,30 @@ class BuildModificationServiceTest extends IntegrationTestCase $this->assertSame(20, $response->allocation_limit); } + /** + * Test that an exception when connecting to the Wings instance is properly ignored + * when making updates. This allows for a server to be modified even when the Wings + * node is offline. + */ + public function testConnectionExceptionIsIgnoredWhenUpdatingServerSettings() + { + $server = $this->createServerModel(); + + $this->daemonServerRepository->expects('setServer->update')->andThrows( + new DaemonConnectionException( + new RequestException('Bad request', new Request('GET', '/test'), new Response()) + ) + ); + + $response = $this->getService()->handle($server, ['memory' => 256, 'disk' => 10240]); + + $this->assertInstanceOf(Server::class, $response); + $this->assertSame(256, $response->memory); + $this->assertSame(10240, $response->disk); + + $this->assertDatabaseHas('servers', ['id' => $response->id, 'memory' => 256, 'disk' => 10240]); + } + /** * Test that no exception is thrown if we are only removing an allocation. */ @@ -215,7 +244,9 @@ class BuildModificationServiceTest extends IntegrationTestCase /** * Test that any changes we made to the server or allocations are rolled back if there is an - * exception while performing any action. + * exception while performing any action. This is different than the connection exception + * test which should properly ignore connection issues. We want any other type of exception + * to properly be thrown back to the caller. */ public function testThatUpdatesAreRolledBackIfExceptionIsEncountered() {