mirror of
https://github.com/pelican-dev/panel.git
synced 2025-05-19 23:24:46 +02:00
Replace some guzzle exceptions and fix server creation failures (#848)
* Replace guzzle exceptions * Pint fixes * Fix test * Remove unused imports * Catch & Notify the user instead of 500 * Update app/Filament/Admin/Resources/ServerResource/Pages/CreateServer.php Co-authored-by: Boy132 <Boy132@users.noreply.github.com> --------- Co-authored-by: RMartinOscar <40749467+RMartinOscar@users.noreply.github.com> Co-authored-by: Boy132 <Boy132@users.noreply.github.com>
This commit is contained in:
parent
3a7ddfca5e
commit
133c1a511f
@ -2,8 +2,8 @@
|
||||
|
||||
namespace App\Exceptions\Http\Connection;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Http\Response;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use App\Exceptions\DisplayException;
|
||||
use Illuminate\Support\Facades\Context;
|
||||
|
||||
@ -22,7 +22,7 @@ class DaemonConnectionException extends DisplayException
|
||||
/**
|
||||
* Throw a displayable exception caused by a daemon connection error.
|
||||
*/
|
||||
public function __construct(GuzzleException $previous, bool $useStatusCode = true)
|
||||
public function __construct(?Exception $previous, bool $useStatusCode = true)
|
||||
{
|
||||
/** @var \GuzzleHttp\Psr7\Response|null $response */
|
||||
$response = method_exists($previous, 'getResponse') ? $previous->getResponse() : null;
|
||||
|
@ -26,8 +26,7 @@ use Filament\Notifications\Notification;
|
||||
use Filament\Pages\Concerns\InteractsWithHeaderActions;
|
||||
use Filament\Pages\Page;
|
||||
use Filament\Support\Enums\MaxWidth;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use Illuminate\Http\Client\Factory;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
use Illuminate\Support\Facades\Notification as MailNotification;
|
||||
use Illuminate\Support\HtmlString;
|
||||
@ -164,22 +163,23 @@ class Settings extends Page implements HasForms
|
||||
->label('Set to Cloudflare IPs')
|
||||
->icon('tabler-brand-cloudflare')
|
||||
->authorize(fn () => auth()->user()->can('update settings'))
|
||||
->action(function (Client $client, Set $set) {
|
||||
->action(function (Factory $client, Set $set) {
|
||||
$ips = collect();
|
||||
|
||||
try {
|
||||
$response = $client->request(
|
||||
'GET',
|
||||
'https://api.cloudflare.com/client/v4/ips',
|
||||
config('panel.guzzle')
|
||||
);
|
||||
$response = $client
|
||||
->timeout(3)
|
||||
->connectTimeout(3)
|
||||
->get('https://api.cloudflare.com/client/v4/ips');
|
||||
|
||||
if ($response->getStatusCode() === 200) {
|
||||
$result = json_decode($response->getBody(), true)['result'];
|
||||
$result = $response->json('result');
|
||||
foreach (['ipv4_cidrs', 'ipv6_cidrs'] as $value) {
|
||||
$ips->push(...data_get($result, $value));
|
||||
}
|
||||
$ips->unique();
|
||||
}
|
||||
} catch (GuzzleException $e) {
|
||||
} catch (Exception) {
|
||||
}
|
||||
|
||||
$set('TRUSTED_PROXIES', $ips->values()->all());
|
||||
@ -245,12 +245,12 @@ class Settings extends Page implements HasForms
|
||||
->columnSpanFull()
|
||||
->inline()
|
||||
->options([
|
||||
'log' => 'Print mails to Log',
|
||||
'log' => '/storage/logs Directory',
|
||||
'smtp' => 'SMTP Server',
|
||||
'sendmail' => 'sendmail Binary',
|
||||
'mailgun' => 'Mailgun',
|
||||
'mandrill' => 'Mandrill',
|
||||
'postmark' => 'Postmark',
|
||||
'sendmail' => 'sendmail (PHP)',
|
||||
])
|
||||
->live()
|
||||
->default(env('MAIL_MAILER', config('mail.default')))
|
||||
|
@ -34,7 +34,9 @@ use Filament\Forms\Components\Wizard\Step;
|
||||
use Filament\Forms\Form;
|
||||
use Filament\Forms\Get;
|
||||
use Filament\Forms\Set;
|
||||
use Filament\Notifications\Notification;
|
||||
use Filament\Resources\Pages\CreateRecord;
|
||||
use Filament\Support\Exceptions\Halt;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Blade;
|
||||
@ -873,7 +875,18 @@ class CreateServer extends CreateRecord
|
||||
{
|
||||
$data['allocation_additional'] = collect($data['allocation_additional'])->filter()->all();
|
||||
|
||||
return $this->serverCreationService->handle($data);
|
||||
try {
|
||||
return $this->serverCreationService->handle($data);
|
||||
} catch (Exception $exception) {
|
||||
Notification::make()
|
||||
->title('Could not create server')
|
||||
->body($exception->getMessage())
|
||||
->color('danger')
|
||||
->danger()
|
||||
->send();
|
||||
|
||||
throw new Halt();
|
||||
}
|
||||
}
|
||||
|
||||
private function shouldHideComponent(Get $get, Component $component): bool
|
||||
|
@ -5,12 +5,11 @@ namespace App\Models;
|
||||
use App\Enums\ContainerStatus;
|
||||
use App\Enums\ServerResourceType;
|
||||
use App\Enums\ServerState;
|
||||
use App\Exceptions\Http\Connection\DaemonConnectionException;
|
||||
use App\Repositories\Daemon\DaemonServerRepository;
|
||||
use Carbon\CarbonInterface;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Http\Client\ConnectionException;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Illuminate\Database\Query\JoinClause;
|
||||
use Illuminate\Support\Arr;
|
||||
@ -421,17 +420,13 @@ class Server extends Model
|
||||
/**
|
||||
* Sends a command or multiple commands to a running server instance.
|
||||
*
|
||||
* @throws DaemonConnectionException|GuzzleException
|
||||
* @throws ConnectionException
|
||||
*/
|
||||
public function send(array|string $command): ResponseInterface
|
||||
{
|
||||
try {
|
||||
return Http::daemon($this->node)->post("/api/servers/{$this->uuid}/commands", [
|
||||
'commands' => is_array($command) ? $command : [$command],
|
||||
])->toPsrResponse();
|
||||
} catch (GuzzleException $exception) {
|
||||
throw new DaemonConnectionException($exception);
|
||||
}
|
||||
return Http::daemon($this->node)->post("/api/servers/{$this->uuid}/commands", [
|
||||
'commands' => is_array($command) ? $command : [$command],
|
||||
])->toPsrResponse();
|
||||
}
|
||||
|
||||
public function retrieveStatus(): string
|
||||
|
@ -6,23 +6,16 @@ use App\Enums\ContainerStatus;
|
||||
use App\Enums\HttpStatusCode;
|
||||
use Exception;
|
||||
use Filament\Notifications\Notification;
|
||||
use Illuminate\Http\Client\ConnectionException;
|
||||
use Illuminate\Http\Client\RequestException;
|
||||
use Webmozart\Assert\Assert;
|
||||
use App\Models\Server;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use App\Exceptions\Http\Connection\DaemonConnectionException;
|
||||
|
||||
class DaemonServerRepository extends DaemonRepository
|
||||
{
|
||||
/**
|
||||
* Returns details about a server from the Daemon instance.
|
||||
*
|
||||
* @throws \App\Exceptions\Http\Connection\DaemonConnectionException
|
||||
*/
|
||||
public function getDetails(): array
|
||||
{
|
||||
Assert::isInstanceOf($this->server, Server::class);
|
||||
|
||||
try {
|
||||
return $this->getHttpClient()->get(
|
||||
sprintf('/api/servers/%s', $this->server->uuid)
|
||||
@ -53,131 +46,85 @@ class DaemonServerRepository extends DaemonRepository
|
||||
/**
|
||||
* Creates a new server on the daemon.
|
||||
*
|
||||
* @throws \App\Exceptions\Http\Connection\DaemonConnectionException
|
||||
* @throws ConnectionException
|
||||
*/
|
||||
public function create(bool $startOnCompletion = true): void
|
||||
{
|
||||
Assert::isInstanceOf($this->server, Server::class);
|
||||
|
||||
try {
|
||||
$response = $this->getHttpClient()->post('/api/servers', [
|
||||
'uuid' => $this->server->uuid,
|
||||
'start_on_completion' => $startOnCompletion,
|
||||
]);
|
||||
} catch (GuzzleException $exception) {
|
||||
throw new DaemonConnectionException($exception);
|
||||
}
|
||||
$this->getHttpClient()->post('/api/servers', [
|
||||
'uuid' => $this->server->uuid,
|
||||
'start_on_completion' => $startOnCompletion,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers a server sync on daemon.
|
||||
*
|
||||
* @throws \App\Exceptions\Http\Connection\DaemonConnectionException
|
||||
* @throws ConnectionException
|
||||
*/
|
||||
public function sync(): void
|
||||
{
|
||||
Assert::isInstanceOf($this->server, Server::class);
|
||||
|
||||
try {
|
||||
$this->getHttpClient()->post("/api/servers/{$this->server->uuid}/sync");
|
||||
} catch (GuzzleException $exception) {
|
||||
throw new DaemonConnectionException($exception);
|
||||
}
|
||||
$this->getHttpClient()->post("/api/servers/{$this->server->uuid}/sync");
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a server from the daemon, forcibly if passed.
|
||||
*
|
||||
* @throws \App\Exceptions\Http\Connection\DaemonConnectionException
|
||||
* @throws ConnectionException
|
||||
*/
|
||||
public function delete(): void
|
||||
{
|
||||
Assert::isInstanceOf($this->server, Server::class);
|
||||
|
||||
try {
|
||||
$this->getHttpClient()->delete('/api/servers/' . $this->server->uuid);
|
||||
} catch (GuzzleException $exception) {
|
||||
throw new DaemonConnectionException($exception);
|
||||
}
|
||||
$this->getHttpClient()->delete("/api/servers/{$this->server->uuid}");
|
||||
}
|
||||
|
||||
/**
|
||||
* Reinstall a server on the daemon.
|
||||
*
|
||||
* @throws \App\Exceptions\Http\Connection\DaemonConnectionException
|
||||
* @throws ConnectionException
|
||||
*/
|
||||
public function reinstall(): void
|
||||
{
|
||||
Assert::isInstanceOf($this->server, Server::class);
|
||||
|
||||
try {
|
||||
$this->getHttpClient()->post(sprintf(
|
||||
'/api/servers/%s/reinstall',
|
||||
$this->server->uuid
|
||||
));
|
||||
} catch (GuzzleException $exception) {
|
||||
throw new DaemonConnectionException($exception);
|
||||
}
|
||||
$this->getHttpClient()->post("/api/servers/{$this->server->uuid}/reinstall");
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 \App\Exceptions\Http\Connection\DaemonConnectionException
|
||||
* @throws ConnectionException
|
||||
*/
|
||||
public function requestArchive(): void
|
||||
{
|
||||
Assert::isInstanceOf($this->server, Server::class);
|
||||
|
||||
try {
|
||||
$this->getHttpClient()->post(sprintf(
|
||||
'/api/servers/%s/archive',
|
||||
$this->server->uuid
|
||||
));
|
||||
} catch (GuzzleException $exception) {
|
||||
throw new DaemonConnectionException($exception);
|
||||
}
|
||||
$this->getHttpClient()->post("/api/servers/{$this->server->uuid}/archive");
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels a server transfer.
|
||||
*
|
||||
* @throws \App\Exceptions\Http\Connection\DaemonConnectionException
|
||||
* @throws ConnectionException
|
||||
*/
|
||||
public function cancelTransfer(): void
|
||||
{
|
||||
Assert::isInstanceOf($this->server, Server::class);
|
||||
|
||||
if ($transfer = $this->server->transfer) {
|
||||
// Source node
|
||||
$this->setNode($transfer->oldNode);
|
||||
|
||||
try {
|
||||
$this->getHttpClient()->delete(sprintf(
|
||||
'/api/servers/%s/transfer',
|
||||
$this->server->uuid
|
||||
));
|
||||
} catch (GuzzleException $exception) {
|
||||
throw new DaemonConnectionException($exception);
|
||||
}
|
||||
|
||||
// Destination node
|
||||
$this->setNode($transfer->newNode);
|
||||
|
||||
try {
|
||||
$this->getHttpClient()->delete('/api/transfer', [
|
||||
'json' => [
|
||||
'server_id' => $this->server->uuid,
|
||||
'server' => [
|
||||
'uuid' => $this->server->uuid,
|
||||
],
|
||||
],
|
||||
]);
|
||||
} catch (GuzzleException $exception) {
|
||||
throw new DaemonConnectionException($exception);
|
||||
}
|
||||
$transfer = $this->server->transfer;
|
||||
if (!$transfer) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Source node
|
||||
$this->setNode($transfer->oldNode);
|
||||
|
||||
$this->getHttpClient()->delete("/api/servers/{$this->server->uuid}/transfer");
|
||||
|
||||
// Destination node
|
||||
$this->setNode($transfer->newNode);
|
||||
|
||||
$this->getHttpClient()->delete('/api/transfer', [
|
||||
'json' => [
|
||||
'server_id' => $this->server->uuid,
|
||||
'server' => [
|
||||
'uuid' => $this->server->uuid,
|
||||
],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -185,32 +132,13 @@ class DaemonServerRepository extends DaemonRepository
|
||||
* make it easier to revoke tokens on the fly. This ensures that the JTI key is formatted
|
||||
* correctly and avoids any costly mistakes in the codebase.
|
||||
*
|
||||
* @throws \App\Exceptions\Http\Connection\DaemonConnectionException
|
||||
* @throws ConnectionException
|
||||
*/
|
||||
public function revokeUserJTI(int $id): void
|
||||
{
|
||||
Assert::isInstanceOf($this->server, Server::class);
|
||||
|
||||
$this->revokeJTIs([md5($id . $this->server->uuid)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Revokes an array of JWT JTI's by marking any token generated before the current time on
|
||||
* the daemon instance as being invalid.
|
||||
*
|
||||
* @throws \App\Exceptions\Http\Connection\DaemonConnectionException
|
||||
*/
|
||||
protected function revokeJTIs(array $jtis): void
|
||||
{
|
||||
Assert::isInstanceOf($this->server, Server::class);
|
||||
|
||||
try {
|
||||
$this->getHttpClient()
|
||||
->post(sprintf('/api/servers/%s/ws/deny', $this->server->uuid), [
|
||||
'jtis' => $jtis,
|
||||
]);
|
||||
} catch (GuzzleException $exception) {
|
||||
throw new DaemonConnectionException($exception);
|
||||
}
|
||||
$this->getHttpClient()
|
||||
->post("/api/servers/{$this->server->uuid}/ws/deny", [
|
||||
'jtis' => [md5($id . $this->server->uuid)],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ namespace App\Services\Servers;
|
||||
|
||||
use App\Enums\ServerState;
|
||||
use App\Models\ServerVariable;
|
||||
use Illuminate\Http\Client\ConnectionException;
|
||||
use Ramsey\Uuid\Uuid;
|
||||
use Illuminate\Support\Arr;
|
||||
use App\Models\User;
|
||||
@ -16,7 +17,6 @@ use App\Models\Objects\DeploymentObject;
|
||||
use App\Repositories\Daemon\DaemonServerRepository;
|
||||
use App\Services\Deployment\FindViableNodesService;
|
||||
use App\Services\Deployment\AllocationSelectionService;
|
||||
use App\Exceptions\Http\Connection\DaemonConnectionException;
|
||||
use App\Models\Egg;
|
||||
|
||||
class ServerCreationService
|
||||
@ -94,10 +94,10 @@ class ServerCreationService
|
||||
}, 5);
|
||||
|
||||
try {
|
||||
$this->daemonServerRepository->setServer($server)->create(
|
||||
Arr::get($data, 'start_on_completion', false) ?? false
|
||||
);
|
||||
} catch (DaemonConnectionException $exception) {
|
||||
$this->daemonServerRepository
|
||||
->setServer($server)
|
||||
->create($data['start_on_completion'] ?? false);
|
||||
} catch (ConnectionException $exception) {
|
||||
$this->serverDeletionService->withForce()->handle($server);
|
||||
|
||||
throw $exception;
|
||||
|
@ -2,22 +2,19 @@
|
||||
|
||||
namespace App\Tests\Integration\Services\Servers;
|
||||
|
||||
use Illuminate\Http\Client\ConnectionException;
|
||||
use Mockery\MockInterface;
|
||||
use App\Models\Egg;
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
use App\Models\Node;
|
||||
use App\Models\User;
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
use App\Models\Server;
|
||||
use App\Models\Allocation;
|
||||
use Illuminate\Foundation\Testing\WithFaker;
|
||||
use GuzzleHttp\Exception\BadResponseException;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use App\Models\Objects\DeploymentObject;
|
||||
use App\Tests\Integration\IntegrationTestCase;
|
||||
use App\Services\Servers\ServerCreationService;
|
||||
use App\Repositories\Daemon\DaemonServerRepository;
|
||||
use App\Exceptions\Http\Connection\DaemonConnectionException;
|
||||
|
||||
class ServerCreationServiceTest extends IntegrationTestCase
|
||||
{
|
||||
@ -181,15 +178,11 @@ class ServerCreationServiceTest extends IntegrationTestCase
|
||||
],
|
||||
];
|
||||
|
||||
$this->daemonServerRepository->expects('setServer->create')->andThrows(
|
||||
new DaemonConnectionException(
|
||||
new BadResponseException('Bad request', new Request('POST', '/create'), new Response(500))
|
||||
)
|
||||
);
|
||||
$this->daemonServerRepository->expects('setServer->create')->andThrows(new ConnectionException());
|
||||
|
||||
$this->daemonServerRepository->expects('setServer->delete')->andReturnUndefined();
|
||||
|
||||
$this->expectException(DaemonConnectionException::class);
|
||||
$this->expectException(ConnectionException::class);
|
||||
|
||||
$this->getService()->handle($data);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user