2019-09-22 15:30:53 -07:00
|
|
|
<?php
|
|
|
|
|
|
2024-03-12 22:39:16 -04:00
|
|
|
namespace App\Http\Controllers\Api\Remote\Servers;
|
2019-09-22 15:30:53 -07:00
|
|
|
|
2024-04-18 03:50:20 -04:00
|
|
|
use App\Enums\ServerState;
|
2026-04-20 17:25:54 +02:00
|
|
|
use App\Exceptions\Http\HttpForbiddenException;
|
2025-09-24 13:34:19 +02:00
|
|
|
use App\Facades\Activity;
|
|
|
|
|
use App\Http\Controllers\Controller;
|
|
|
|
|
use App\Http\Resources\Daemon\ServerConfigurationCollection;
|
|
|
|
|
use App\Models\ActivityLog;
|
2024-03-17 12:52:22 -04:00
|
|
|
use App\Models\Backup;
|
2025-09-24 13:34:19 +02:00
|
|
|
use App\Models\Node;
|
2024-03-12 22:39:16 -04:00
|
|
|
use App\Models\Server;
|
|
|
|
|
use App\Services\Eggs\EggConfigurationService;
|
|
|
|
|
use App\Services\Servers\ServerConfigurationStructureService;
|
2025-09-24 13:34:19 +02:00
|
|
|
use Illuminate\Database\ConnectionInterface;
|
|
|
|
|
use Illuminate\Http\JsonResponse;
|
|
|
|
|
use Illuminate\Http\Request;
|
|
|
|
|
use Throwable;
|
2026-04-20 17:25:54 +02:00
|
|
|
use Webmozart\Assert\Assert;
|
2019-09-22 15:30:53 -07:00
|
|
|
|
2019-12-22 13:28:51 -08:00
|
|
|
class ServerDetailsController extends Controller
|
2019-09-22 15:30:53 -07:00
|
|
|
{
|
|
|
|
|
/**
|
|
|
|
|
* ServerConfigurationController constructor.
|
|
|
|
|
*/
|
2019-12-22 13:28:51 -08:00
|
|
|
public function __construct(
|
2022-10-14 10:59:20 -06:00
|
|
|
protected ConnectionInterface $connection,
|
|
|
|
|
private ServerConfigurationStructureService $configurationStructureService,
|
|
|
|
|
private EggConfigurationService $eggConfigurationService
|
2024-11-22 09:27:57 +01:00
|
|
|
) {}
|
2019-09-22 15:30:53 -07:00
|
|
|
|
|
|
|
|
/**
|
2024-03-12 22:39:16 -04:00
|
|
|
* Returns details about the server that allows daemon to self-recover and ensure
|
2019-12-22 13:28:51 -08:00
|
|
|
* that the state of the server matches the Panel at all times.
|
2019-09-22 15:30:53 -07:00
|
|
|
*/
|
2026-04-20 17:25:54 +02:00
|
|
|
public function __invoke(Request $request, Server $server): JsonResponse
|
2019-09-22 15:30:53 -07:00
|
|
|
{
|
2026-04-20 17:25:54 +02:00
|
|
|
Assert::isInstanceOf($node = $request->attributes->get('node'), Node::class);
|
|
|
|
|
|
|
|
|
|
$transfer = $server->transfer;
|
|
|
|
|
|
|
|
|
|
// If the server is being transferred allow either node to request information about
|
|
|
|
|
// the server. If the server is not being transferred only the target node is allowed
|
|
|
|
|
// to fetch these details.
|
|
|
|
|
$valid = $transfer ? $node->id === $transfer->old_node || $node->id === $transfer->new_node : $node->id === $server->node_id;
|
|
|
|
|
|
|
|
|
|
if (!$valid) {
|
|
|
|
|
throw new HttpForbiddenException('Requesting node does not have permission to access this server.');
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-31 11:14:28 -07:00
|
|
|
return new JsonResponse([
|
2019-12-22 13:28:51 -08:00
|
|
|
'settings' => $this->configurationStructureService->handle($server),
|
|
|
|
|
'process_configuration' => $this->eggConfigurationService->handle($server),
|
|
|
|
|
]);
|
2019-09-22 15:30:53 -07:00
|
|
|
}
|
2020-04-10 13:04:11 -06:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Lists all servers with their configurations that are assigned to the requesting node.
|
|
|
|
|
*/
|
2022-10-14 10:59:20 -06:00
|
|
|
public function list(Request $request): ServerConfigurationCollection
|
2020-04-10 13:04:11 -06:00
|
|
|
{
|
2025-08-09 23:53:45 +02:00
|
|
|
/** @var Node $node */
|
2020-04-10 17:54:50 -06:00
|
|
|
$node = $request->attributes->get('node');
|
2020-04-10 13:04:11 -06:00
|
|
|
|
2022-10-14 10:59:20 -06:00
|
|
|
// Avoid run-away N+1 SQL queries by preloading the relationships that are used
|
2020-10-31 11:14:28 -07:00
|
|
|
// within each of the services called below.
|
2024-03-17 12:52:22 -04:00
|
|
|
$servers = Server::query()->with('allocations', 'egg', 'mounts', 'variables')
|
2020-10-31 11:14:28 -07:00
|
|
|
->where('node_id', $node->id)
|
2020-11-01 14:27:14 -08:00
|
|
|
// If you don't cast this to a string you'll end up with a stringified per_page returned in
|
2024-03-12 22:39:16 -04:00
|
|
|
// the metadata, and then daemon will panic crash as a result.
|
2021-01-23 12:09:16 -08:00
|
|
|
->paginate((int) $request->input('per_page', 50));
|
2020-04-10 13:04:11 -06:00
|
|
|
|
2020-10-31 11:14:28 -07:00
|
|
|
return new ServerConfigurationCollection($servers);
|
2020-04-10 13:04:11 -06:00
|
|
|
}
|
2021-02-23 21:20:02 -08:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Resets the state of all servers on the node to be normal. This is triggered
|
2024-03-12 22:39:16 -04:00
|
|
|
* when daemon restarts and is useful for ensuring that any servers on the node
|
2021-02-23 21:20:02 -08:00
|
|
|
* do not get incorrectly stuck in installing/restoring from backup states since
|
2024-03-12 22:39:16 -04:00
|
|
|
* a daemon reboot would completely stop those processes.
|
2021-02-23 21:20:02 -08:00
|
|
|
*
|
2025-09-08 13:12:33 -04:00
|
|
|
* @throws Throwable
|
2021-02-23 21:20:02 -08:00
|
|
|
*/
|
2022-10-14 10:59:20 -06:00
|
|
|
public function resetState(Request $request): JsonResponse
|
2021-02-23 21:20:02 -08:00
|
|
|
{
|
|
|
|
|
$node = $request->attributes->get('node');
|
|
|
|
|
|
2022-10-14 10:59:20 -06:00
|
|
|
// Get all the servers that are currently marked as restoring from a backup
|
2021-02-23 21:20:02 -08:00
|
|
|
// on this node that do not have a failed backup tracked in the audit logs table
|
|
|
|
|
// as well.
|
|
|
|
|
//
|
|
|
|
|
// For each of those servers we'll track a new audit log entry to mark them as
|
|
|
|
|
// failed and then update them all to be in a valid state.
|
|
|
|
|
$servers = Server::query()
|
2022-05-29 18:20:54 -04:00
|
|
|
->with([
|
|
|
|
|
'activity' => fn ($builder) => $builder
|
|
|
|
|
->where('activity_logs.event', 'server:backup.restore-started')
|
|
|
|
|
->latest('timestamp'),
|
|
|
|
|
])
|
|
|
|
|
->where('node_id', $node->id)
|
2024-04-18 03:50:20 -04:00
|
|
|
->where('status', ServerState::RestoringBackup)
|
2021-02-23 21:20:02 -08:00
|
|
|
->get();
|
|
|
|
|
|
2022-05-29 18:20:54 -04:00
|
|
|
$this->connection->transaction(function () use ($node, $servers) {
|
2025-08-09 23:53:45 +02:00
|
|
|
/** @var Server $server */
|
2022-05-29 18:20:54 -04:00
|
|
|
foreach ($servers as $server) {
|
2025-08-09 23:53:45 +02:00
|
|
|
/** @var ActivityLog|null $activity */
|
2022-05-29 18:20:54 -04:00
|
|
|
$activity = $server->activity->first();
|
2024-03-17 12:52:22 -04:00
|
|
|
if (!$activity) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($subject = $activity->subjects()->where('subject_type', 'backup')->first()) {
|
|
|
|
|
/** @var Backup $backup */
|
|
|
|
|
$backup = $subject->subject;
|
|
|
|
|
// Just create a new audit entry for this event and update the server state
|
|
|
|
|
// so that power actions, file management, and backups can resume as normal.
|
|
|
|
|
Activity::event('server:backup.restore-failed')
|
|
|
|
|
->subject($server, $backup)
|
|
|
|
|
->property('name', $backup->name)
|
|
|
|
|
->log();
|
2022-05-29 18:20:54 -04:00
|
|
|
}
|
2022-05-29 16:19:04 -04:00
|
|
|
}
|
2021-02-23 21:20:02 -08:00
|
|
|
|
2022-05-29 18:20:54 -04:00
|
|
|
// Update any server marked as installing or restoring as being in a normal state
|
|
|
|
|
// at this point in the process.
|
|
|
|
|
Server::query()->where('node_id', $node->id)
|
2024-04-18 03:50:20 -04:00
|
|
|
->whereIn('status', [ServerState::Installing, ServerState::RestoringBackup])
|
2022-05-29 18:20:54 -04:00
|
|
|
->update(['status' => null]);
|
|
|
|
|
});
|
2021-02-23 21:20:02 -08:00
|
|
|
|
|
|
|
|
return new JsonResponse([], JsonResponse::HTTP_NO_CONTENT);
|
|
|
|
|
}
|
2019-09-22 15:30:53 -07:00
|
|
|
}
|