diff --git a/app/Exceptions/Service/Allocation/ServerUsingAllocationException.php b/app/Exceptions/Service/Allocation/ServerUsingAllocationException.php deleted file mode 100644 index 60fac561e..000000000 --- a/app/Exceptions/Service/Allocation/ServerUsingAllocationException.php +++ /dev/null @@ -1,9 +0,0 @@ -columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2]), Forms\Components\Toggle::make('force_outgoing_ip') ->hintIcon('tabler-question-mark') - ->hintIconTooltip("Forces all outgoing network traffic to have its Source IP NATed to the IP of the server's primary allocation IP. + ->hintIconTooltip("Forces all outgoing network traffic to have its Source IP NATed to the IP of the server's primary endpoint. Required for certain games to work properly when the Node has multiple public IP addresses. Enabling this option will disable internal networking for any servers using this egg, causing them to be unable to internally access other servers on the same node."), Forms\Components\Hidden::make('script_is_privileged') diff --git a/app/Filament/Resources/EggResource/Pages/EditEgg.php b/app/Filament/Resources/EggResource/Pages/EditEgg.php index f0ff69ce1..dd33919c5 100644 --- a/app/Filament/Resources/EggResource/Pages/EditEgg.php +++ b/app/Filament/Resources/EggResource/Pages/EditEgg.php @@ -62,7 +62,7 @@ class EditEgg extends EditRecord ->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2]), Forms\Components\Toggle::make('force_outgoing_ip') ->hintIcon('tabler-question-mark') - ->hintIconTooltip("Forces all outgoing network traffic to have its Source IP NATed to the IP of the server's primary allocation IP. + ->hintIconTooltip("Forces all outgoing network traffic to have its Source IP NATed to the IP of the server's endpoint. Required for certain games to work properly when the Node has multiple public IP addresses. Enabling this option will disable internal networking for any servers using this egg, causing them to be unable to internally access other servers on the same node."), Forms\Components\Hidden::make('script_is_privileged') diff --git a/app/Filament/Resources/EggResource/RelationManagers/ServersRelationManager.php b/app/Filament/Resources/EggResource/RelationManagers/ServersRelationManager.php index 3e72e4236..5f94523a0 100644 --- a/app/Filament/Resources/EggResource/RelationManagers/ServersRelationManager.php +++ b/app/Filament/Resources/EggResource/RelationManagers/ServersRelationManager.php @@ -32,11 +32,6 @@ class ServersRelationManager extends RelationManager ->url(fn (Server $server): string => route('filament.admin.resources.nodes.edit', ['record' => $server->node])), Tables\Columns\TextColumn::make('image') ->label('Docker Image'), - Tables\Columns\SelectColumn::make('allocation.id') - ->label('Primary Allocation') - ->options(fn ($state, Server $server) => [$server->allocation->id => $server->allocation->address]) - ->selectablePlaceholder(false) - ->sortable(), ]); } } diff --git a/app/Filament/Resources/NodeResource/RelationManagers/NodesRelationManager.php b/app/Filament/Resources/NodeResource/RelationManagers/NodesRelationManager.php index b9775b4c2..8fe609428 100644 --- a/app/Filament/Resources/NodeResource/RelationManagers/NodesRelationManager.php +++ b/app/Filament/Resources/NodeResource/RelationManagers/NodesRelationManager.php @@ -32,11 +32,6 @@ class NodesRelationManager extends RelationManager ->icon('tabler-egg') ->url(fn (Server $server): string => route('filament.admin.resources.eggs.edit', ['record' => $server->user])) ->sortable(), - Tables\Columns\SelectColumn::make('allocation.id') - ->label('Primary Allocation') - ->options(fn ($state, Server $server) => [$server->allocation->id => $server->allocation->address]) - ->selectablePlaceholder(false) - ->sortable(), Tables\Columns\TextColumn::make('memory')->icon('tabler-device-desktop-analytics'), Tables\Columns\TextColumn::make('cpu')->icon('tabler-cpu'), Tables\Columns\TextColumn::make('databases_count') diff --git a/app/Filament/Resources/UserResource/RelationManagers/ServersRelationManager.php b/app/Filament/Resources/UserResource/RelationManagers/ServersRelationManager.php index 7be484b60..705eb92af 100644 --- a/app/Filament/Resources/UserResource/RelationManagers/ServersRelationManager.php +++ b/app/Filament/Resources/UserResource/RelationManagers/ServersRelationManager.php @@ -66,11 +66,6 @@ class ServersRelationManager extends RelationManager ->icon('tabler-egg') ->url(fn (Server $server): string => route('filament.admin.resources.eggs.edit', ['record' => $server->egg])) ->sortable(), - Tables\Columns\SelectColumn::make('allocation.id') - ->label('Primary Allocation') - ->options(fn ($state, Server $server) => [$server->allocation->id => $server->allocation->address]) - ->selectablePlaceholder(false) - ->sortable(), Tables\Columns\TextColumn::make('image')->hidden(), Tables\Columns\TextColumn::make('databases_count') ->counts('databases') diff --git a/app/Http/Controllers/Admin/Nodes/NodeViewController.php b/app/Http/Controllers/Admin/Nodes/NodeViewController.php index 95dc7ede0..b3e9f2621 100644 --- a/app/Http/Controllers/Admin/Nodes/NodeViewController.php +++ b/app/Http/Controllers/Admin/Nodes/NodeViewController.php @@ -5,7 +5,6 @@ namespace App\Http\Controllers\Admin\Nodes; use Illuminate\View\View; use App\Models\Node; use Illuminate\Support\Collection; -use App\Models\Allocation; use App\Http\Controllers\Controller; use App\Traits\Controllers\JavascriptInjection; use App\Services\Helpers\SoftwareVersionService; @@ -56,32 +55,6 @@ class NodeViewController extends Controller return view('admin.nodes.view.configuration', compact('node')); } - /** - * Return the node allocation management page. - */ - public function allocations(Node $node): View - { - $node->setRelation( - 'allocations', - $node->allocations() - ->orderByRaw('server_id IS NOT NULL DESC, server_id IS NULL') - ->orderByRaw('INET_ATON(ip) ASC') - ->orderBy('port') - ->with('server:id,name') - ->paginate(50) - ); - - $this->plainInject(['node' => Collection::wrap($node)->only(['id'])]); - - return view('admin.nodes.view.allocation', [ - 'node' => $node, - 'allocations' => Allocation::query()->where('node_id', $node->id) - ->groupBy('ip') - ->orderByRaw('INET_ATON(ip) ASC') - ->get(['ip']), - ]); - } - /** * Return a listing of servers that exist for this specific node. */ diff --git a/app/Http/Controllers/Admin/NodesController.php b/app/Http/Controllers/Admin/NodesController.php index 66ba487f6..ebb1f56c3 100644 --- a/app/Http/Controllers/Admin/NodesController.php +++ b/app/Http/Controllers/Admin/NodesController.php @@ -3,10 +3,7 @@ namespace App\Http\Controllers\Admin; use Illuminate\View\View; -use Illuminate\Http\Request; use App\Models\Node; -use Illuminate\Http\Response; -use App\Models\Allocation; use Illuminate\Http\RedirectResponse; use Prologue\Alerts\AlertsMessageBag; use Illuminate\View\Factory as ViewFactory; @@ -15,11 +12,8 @@ use App\Services\Nodes\NodeUpdateService; use Illuminate\Cache\Repository as CacheRepository; use App\Services\Nodes\NodeCreationService; use App\Services\Nodes\NodeDeletionService; -use App\Services\Allocations\AssignmentService; use App\Services\Helpers\SoftwareVersionService; use App\Http\Requests\Admin\Node\NodeFormRequest; -use App\Http\Requests\Admin\Node\AllocationFormRequest; -use App\Http\Requests\Admin\Node\AllocationAliasFormRequest; class NodesController extends Controller { @@ -28,7 +22,6 @@ class NodesController extends Controller */ public function __construct( protected AlertsMessageBag $alert, - protected AssignmentService $assignmentService, protected CacheRepository $cache, protected NodeCreationService $creationService, protected NodeDeletionService $deletionService, @@ -46,19 +39,6 @@ class NodesController extends Controller return view('admin.nodes.new'); } - /** - * Post controller to create a new node on the system. - * - * @throws \App\Exceptions\Model\DataValidationException - */ - public function store(NodeFormRequest $request): RedirectResponse - { - $node = $this->creationService->handle($request->normalize()); - $this->alert->info(trans('admin/node.notices.node_created'))->flash(); - - return redirect()->route('admin.nodes.view.allocation', $node->id); - } - /** * Updates settings for a node. * @@ -73,83 +53,6 @@ class NodesController extends Controller return redirect()->route('admin.nodes.view.settings', $node->id)->withInput(); } - /** - * Removes a single allocation from a node. - * - * @throws \App\Exceptions\Service\Allocation\ServerUsingAllocationException - */ - public function allocationRemoveSingle(int $node, Allocation $allocation): Response - { - $allocation->delete(); - - return response('', 204); - } - - /** - * Removes multiple individual allocations from a node. - * - * @throws \App\Exceptions\Service\Allocation\ServerUsingAllocationException - */ - public function allocationRemoveMultiple(Request $request, int $node): Response - { - $allocations = $request->input('allocations'); - foreach ($allocations as $rawAllocation) { - $allocation = new Allocation(); - $allocation->id = $rawAllocation['id']; - $this->allocationRemoveSingle($node, $allocation); - } - - return response('', 204); - } - - /** - * Remove all allocations for a specific IP at once on a node. - */ - public function allocationRemoveBlock(Request $request, int $node): RedirectResponse - { - /** @var Node $node */ - $node = Node::query()->findOrFail($node); - $node->allocations() - ->where('ip', $request->input('ip')) - ->whereNull('server_id') - ->delete(); - - $this->alert->success(trans('admin/node.notices.unallocated_deleted', ['ip' => $request->input('ip')])) - ->flash(); - - return redirect()->route('admin.nodes.view.allocation', $node); - } - - /** - * Sets an alias for a specific allocation on a node. - * - * @throws \App\Exceptions\Model\DataValidationException - */ - public function allocationSetAlias(AllocationAliasFormRequest $request): \Symfony\Component\HttpFoundation\Response - { - $allocation = Allocation::query()->findOrFail($request->input('allocation_id')); - $alias = (empty($request->input('alias'))) ? null : $request->input('alias'); - $allocation->update(['ip_alias' => $alias]); - - return response('', 204); - } - - /** - * Creates new allocations on a node. - * - * @throws \App\Exceptions\Service\Allocation\CidrOutOfRangeException - * @throws \App\Exceptions\Service\Allocation\InvalidPortMappingException - * @throws \App\Exceptions\Service\Allocation\PortOutOfRangeException - * @throws \App\Exceptions\Service\Allocation\TooManyPortsInRangeException - */ - public function createAllocation(AllocationFormRequest $request, Node $node): RedirectResponse - { - $this->assignmentService->handle($node, $request->normalize()); - $this->alert->success(trans('admin/node.notices.allocations_added'))->flash(); - - return redirect()->route('admin.nodes.view.allocation', $node->id); - } - /** * Deletes a node from the system. * diff --git a/app/Http/Controllers/Admin/Servers/CreateServerController.php b/app/Http/Controllers/Admin/Servers/CreateServerController.php index c59e22fbe..c06ed6e5d 100644 --- a/app/Http/Controllers/Admin/Servers/CreateServerController.php +++ b/app/Http/Controllers/Admin/Servers/CreateServerController.php @@ -36,11 +36,6 @@ class CreateServerController extends Controller $eggs = Egg::with('variables')->get(); - \JavaScript::put([ - 'nodeData' => Node::getForServerCreation(), - 'eggs' => $eggs->keyBy('id'), - ]); - return view('admin.servers.new', [ 'eggs' => $eggs, 'nodes' => Node::all(), diff --git a/app/Http/Controllers/Admin/Servers/ServerTransferController.php b/app/Http/Controllers/Admin/Servers/ServerTransferController.php index 9fdaa7bf8..7421c3f82 100644 --- a/app/Http/Controllers/Admin/Servers/ServerTransferController.php +++ b/app/Http/Controllers/Admin/Servers/ServerTransferController.php @@ -29,8 +29,6 @@ class ServerTransferController extends Controller { $validatedData = $request->validate([ 'node_id' => 'required|exists:nodes,id', - 'allocation_id' => 'required|bail|unique:servers|exists:allocations,id', - 'allocation_additional' => 'nullable', ]); if ($this->transferServerService->handle($server, $validatedData)) { diff --git a/app/Http/Controllers/Admin/Servers/ServerViewController.php b/app/Http/Controllers/Admin/Servers/ServerViewController.php index 594022a97..43e1a2ae8 100644 --- a/app/Http/Controllers/Admin/Servers/ServerViewController.php +++ b/app/Http/Controllers/Admin/Servers/ServerViewController.php @@ -121,10 +121,6 @@ class ServerViewController extends Controller $canTransfer = true; } - \JavaScript::put([ - 'nodeData' => Node::getForServerCreation(), - ]); - return view('admin.servers.view.manage', [ 'nodes' => Node::all(), 'server' => $server, diff --git a/app/Http/Controllers/Api/Application/Nodes/AllocationController.php b/app/Http/Controllers/Api/Application/Nodes/AllocationController.php deleted file mode 100644 index 18e2f5cfc..000000000 --- a/app/Http/Controllers/Api/Application/Nodes/AllocationController.php +++ /dev/null @@ -1,79 +0,0 @@ -allocations()) - ->allowedFilters([ - AllowedFilter::exact('ip'), - AllowedFilter::exact('port'), - 'ip_alias', - AllowedFilter::callback('server_id', function (Builder $builder, $value) { - if (empty($value) || is_bool($value) || !ctype_digit((string) $value)) { - return $builder->whereNull('server_id'); - } - - return $builder->where('server_id', $value); - }), - ]) - ->paginate($request->query('per_page') ?? 50); - - return $this->fractal->collection($allocations) - ->transformWith($this->getTransformer(AllocationTransformer::class)) - ->toArray(); - } - - /** - * Store new allocations for a given node. - * - * @throws \App\Exceptions\DisplayException - * @throws \App\Exceptions\Service\Allocation\CidrOutOfRangeException - * @throws \App\Exceptions\Service\Allocation\InvalidPortMappingException - * @throws \App\Exceptions\Service\Allocation\PortOutOfRangeException - * @throws \App\Exceptions\Service\Allocation\TooManyPortsInRangeException - */ - public function store(StoreAllocationRequest $request, Node $node): JsonResponse - { - $this->assignmentService->handle($node, $request->validated()); - - return new JsonResponse([], JsonResponse::HTTP_NO_CONTENT); - } - - /** - * Delete a specific allocation from the Panel. - */ - public function delete(DeleteAllocationRequest $request, Node $node, Allocation $allocation): JsonResponse - { - $allocation->delete(); - - return new JsonResponse([], JsonResponse::HTTP_NO_CONTENT); - } -} diff --git a/app/Http/Controllers/Api/Application/Servers/ServerManagementController.php b/app/Http/Controllers/Api/Application/Servers/ServerManagementController.php index d728ea83c..dcb6ad795 100644 --- a/app/Http/Controllers/Api/Application/Servers/ServerManagementController.php +++ b/app/Http/Controllers/Api/Application/Servers/ServerManagementController.php @@ -69,8 +69,6 @@ class ServerManagementController extends ApplicationApiController { $validatedData = $request->validate([ 'node_id' => 'required|exists:nodes,id', - 'allocation_id' => 'required|bail|unique:servers|exists:allocations,id', - 'allocation_additional' => 'nullable', ]); if ($this->transferServerService->handle($server, $validatedData)) { diff --git a/app/Http/Controllers/Api/Client/Servers/NetworkAllocationController.php b/app/Http/Controllers/Api/Client/Servers/NetworkAllocationController.php deleted file mode 100644 index 948fbbace..000000000 --- a/app/Http/Controllers/Api/Client/Servers/NetworkAllocationController.php +++ /dev/null @@ -1,137 +0,0 @@ -fractal->collection($server->allocations) - ->transformWith($this->getTransformer(AllocationTransformer::class)) - ->toArray(); - } - - /** - * Set the primary allocation for a server. - * - * @throws \App\Exceptions\Model\DataValidationException - */ - public function update(UpdateAllocationRequest $request, Server $server, Allocation $allocation): array - { - $original = $allocation->notes; - - $allocation->forceFill(['notes' => $request->input('notes')])->save(); - - if ($original !== $allocation->notes) { - Activity::event('server:allocation.notes') - ->subject($allocation) - ->property(['allocation' => $allocation->toString(), 'old' => $original, 'new' => $allocation->notes]) - ->log(); - } - - return $this->fractal->item($allocation) - ->transformWith($this->getTransformer(AllocationTransformer::class)) - ->toArray(); - } - - /** - * Set the primary allocation for a server. - * - * @throws \App\Exceptions\Model\DataValidationException - */ - public function setPrimary(SetPrimaryAllocationRequest $request, Server $server, Allocation $allocation): array - { - $server->allocation()->associate($allocation); - $server->save(); - - Activity::event('server:allocation.primary') - ->subject($allocation) - ->property('allocation', $allocation->toString()) - ->log(); - - return $this->fractal->item($allocation) - ->transformWith($this->getTransformer(AllocationTransformer::class)) - ->toArray(); - } - - /** - * Set the notes for the allocation for a server. - *s. - * - * @throws \App\Exceptions\DisplayException - */ - public function store(NewAllocationRequest $request, Server $server): array - { - if ($server->allocations()->count() >= $server->allocation_limit) { - throw new DisplayException('Cannot assign additional allocations to this server: limit has been reached.'); - } - - $allocation = $this->assignableAllocationService->handle($server); - - Activity::event('server:allocation.create') - ->subject($allocation) - ->property('allocation', $allocation->toString()) - ->log(); - - return $this->fractal->item($allocation) - ->transformWith($this->getTransformer(AllocationTransformer::class)) - ->toArray(); - } - - /** - * Delete an allocation from a server. - * - * @throws \App\Exceptions\DisplayException - */ - public function delete(DeleteAllocationRequest $request, Server $server, Allocation $allocation): JsonResponse - { - // Don't allow the deletion of allocations if the server does not have an - // allocation limit set. - if (empty($server->allocation_limit)) { - throw new DisplayException('You cannot delete allocations for this server: no allocation limit is set.'); - } - - if ($allocation->id === $server->allocation_id) { - throw new DisplayException('You cannot delete the primary allocation for this server.'); - } - - Allocation::query()->where('id', $allocation->id)->update([ - 'notes' => null, - 'server_id' => null, - ]); - - Activity::event('server:allocation.delete') - ->subject($allocation) - ->property('allocation', $allocation->toString()) - ->log(); - - return new JsonResponse([], JsonResponse::HTTP_NO_CONTENT); - } -} diff --git a/app/Http/Controllers/Api/Remote/Servers/ServerDetailsController.php b/app/Http/Controllers/Api/Remote/Servers/ServerDetailsController.php index 824453045..88ad0ed91 100644 --- a/app/Http/Controllers/Api/Remote/Servers/ServerDetailsController.php +++ b/app/Http/Controllers/Api/Remote/Servers/ServerDetailsController.php @@ -48,7 +48,7 @@ class ServerDetailsController extends Controller // Avoid run-away N+1 SQL queries by preloading the relationships that are used // within each of the services called below. - $servers = Server::query()->with('allocations', 'egg', 'mounts', 'variables') + $servers = Server::query()->with('egg', 'mounts', 'variables') ->where('node_id', $node->id) // If you don't cast this to a string you'll end up with a stringified per_page returned in // the metadata, and then daemon will panic crash as a result. diff --git a/app/Http/Controllers/Api/Remote/Servers/ServerTransferController.php b/app/Http/Controllers/Api/Remote/Servers/ServerTransferController.php index 6a74521f9..95026b5d7 100644 --- a/app/Http/Controllers/Api/Remote/Servers/ServerTransferController.php +++ b/app/Http/Controllers/Api/Remote/Servers/ServerTransferController.php @@ -6,7 +6,6 @@ use App\Models\Server; use App\Repositories\Daemon\DaemonServerRepository; use Illuminate\Http\Response; use Illuminate\Http\JsonResponse; -use App\Models\Allocation; use App\Models\ServerTransfer; use Illuminate\Database\ConnectionInterface; use App\Http\Controllers\Controller; @@ -53,13 +52,7 @@ class ServerTransferController extends Controller /** @var \App\Models\Server $server */ $server = $this->connection->transaction(function () use ($server, $transfer) { - $allocations = array_merge([$transfer->old_allocation], $transfer->old_additional_allocations); - - // Remove the old allocations for the server and re-assign the server to the new - // primary allocation and node. - Allocation::query()->whereIn('id', $allocations)->update(['server_id' => null]); $server->update([ - 'allocation_id' => $transfer->new_allocation, 'node_id' => $transfer->new_node, ]); @@ -93,9 +86,6 @@ class ServerTransferController extends Controller { $this->connection->transaction(function () use (&$transfer) { $transfer->forceFill(['successful' => false])->saveOrFail(); - - $allocations = array_merge([$transfer->new_allocation], $transfer->new_additional_allocations); - Allocation::query()->whereIn('id', $allocations)->update(['server_id' => null]); }); return new JsonResponse([], Response::HTTP_NO_CONTENT); diff --git a/app/Http/Middleware/Api/Client/Server/ResourceBelongsToServer.php b/app/Http/Middleware/Api/Client/Server/ResourceBelongsToServer.php index 0ead01f1d..c6f971992 100644 --- a/app/Http/Middleware/Api/Client/Server/ResourceBelongsToServer.php +++ b/app/Http/Middleware/Api/Client/Server/ResourceBelongsToServer.php @@ -10,7 +10,6 @@ use App\Models\Server; use App\Models\Subuser; use App\Models\Database; use App\Models\Schedule; -use App\Models\Allocation; use Illuminate\Database\Eloquent\Model; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; @@ -48,7 +47,6 @@ class ResourceBelongsToServer switch (get_class($model)) { // All of these models use "server_id" as the field key for the server // they are assigned to, so the logic is identical for them all. - case Allocation::class: case Backup::class: case Database::class: case Schedule::class: diff --git a/app/Http/Requests/Admin/Node/AllocationAliasFormRequest.php b/app/Http/Requests/Admin/Node/AllocationAliasFormRequest.php deleted file mode 100644 index 3da9f1896..000000000 --- a/app/Http/Requests/Admin/Node/AllocationAliasFormRequest.php +++ /dev/null @@ -1,16 +0,0 @@ - 'present|nullable|string', - 'allocation_id' => 'required|numeric|exists:allocations,id', - ]; - } -} diff --git a/app/Http/Requests/Admin/Node/AllocationFormRequest.php b/app/Http/Requests/Admin/Node/AllocationFormRequest.php deleted file mode 100644 index 1bd39c405..000000000 --- a/app/Http/Requests/Admin/Node/AllocationFormRequest.php +++ /dev/null @@ -1,17 +0,0 @@ - 'required|string', - 'allocation_alias' => 'sometimes|nullable|string|max:191', - 'allocation_ports' => 'required|array', - ]; - } -} diff --git a/app/Http/Requests/Admin/ServerFormRequest.php b/app/Http/Requests/Admin/ServerFormRequest.php index d3f978128..aa5931731 100644 --- a/app/Http/Requests/Admin/ServerFormRequest.php +++ b/app/Http/Requests/Admin/ServerFormRequest.php @@ -3,7 +3,6 @@ namespace App\Http\Requests\Admin; use App\Models\Server; -use Illuminate\Validation\Rule; use Illuminate\Validation\Validator; class ServerFormRequest extends AdminFormRequest @@ -25,34 +24,10 @@ class ServerFormRequest extends AdminFormRequest */ public function withValidator(Validator $validator): void { - $validator->after(function ($validator) { + $validator->after(function (Validator $validator) { $validator->sometimes('node_id', 'required|numeric|bail|exists:nodes,id', function ($input) { return !$input->auto_deploy; }); - - $validator->sometimes('allocation_id', [ - 'required', - 'numeric', - 'bail', - Rule::exists('allocations', 'id')->where(function ($query) { - $query->where('node_id', $this->input('node_id')); - $query->whereNull('server_id'); - }), - ], function ($input) { - return !$input->auto_deploy; - }); - - $validator->sometimes('allocation_additional.*', [ - 'sometimes', - 'required', - 'numeric', - Rule::exists('allocations', 'id')->where(function ($query) { - $query->where('node_id', $this->input('node_id')); - $query->whereNull('server_id'); - }), - ], function ($input) { - return !$input->auto_deploy; - }); }); } } diff --git a/app/Http/Requests/Api/Application/Allocations/DeleteAllocationRequest.php b/app/Http/Requests/Api/Application/Allocations/DeleteAllocationRequest.php deleted file mode 100644 index 74077965e..000000000 --- a/app/Http/Requests/Api/Application/Allocations/DeleteAllocationRequest.php +++ /dev/null @@ -1,13 +0,0 @@ - 'required|string', - 'alias' => 'sometimes|nullable|string|max:191', - 'ports' => 'required|array', - 'ports.*' => 'string', - ]; - } - - public function validated($key = null, $default = null): array - { - $data = parent::validated(); - - return [ - 'allocation_ip' => $data['ip'], - 'allocation_ports' => $data['ports'], - 'allocation_alias' => $data['alias'] ?? null, - ]; - } -} diff --git a/app/Http/Requests/Api/Application/Servers/StoreServerRequest.php b/app/Http/Requests/Api/Application/Servers/StoreServerRequest.php index 263b7c540..de729ff12 100644 --- a/app/Http/Requests/Api/Application/Servers/StoreServerRequest.php +++ b/app/Http/Requests/Api/Application/Servers/StoreServerRequest.php @@ -3,7 +3,6 @@ namespace App\Http\Requests\Api\Application\Servers; use App\Models\Server; -use Illuminate\Validation\Rule; use Illuminate\Validation\Validator; use App\Services\Acl\Api\AdminAcl; use App\Models\Objects\DeploymentObject; @@ -49,10 +48,6 @@ class StoreServerRequest extends ApplicationApiRequest 'feature_limits.allocations' => $rules['allocation_limit'], 'feature_limits.backups' => $rules['backup_limit'], - // Placeholders for rules added in withValidator() function. - 'allocation.default' => '', - 'allocation.additional.*' => '', - // Automatic deployment rules 'deploy' => 'sometimes|required|array', 'deploy.locations' => 'array', @@ -87,8 +82,7 @@ class StoreServerRequest extends ApplicationApiRequest 'cpu' => array_get($data, 'limits.cpu'), 'threads' => array_get($data, 'limits.threads'), 'skip_scripts' => array_get($data, 'skip_scripts', false), - 'allocation_id' => array_get($data, 'allocation.default'), - 'allocation_additional' => array_get($data, 'allocation.additional'), + 'ports' => array_get($data, 'ports'), 'start_on_completion' => array_get($data, 'start_on_completion', false), 'database_limit' => array_get($data, 'feature_limits.databases'), 'allocation_limit' => array_get($data, 'feature_limits.allocations'), @@ -104,24 +98,6 @@ class StoreServerRequest extends ApplicationApiRequest */ public function withValidator(Validator $validator): void { - $validator->sometimes('allocation.default', [ - 'required', 'integer', 'bail', - Rule::exists('allocations', 'id')->where(function ($query) { - $query->whereNull('server_id'); - }), - ], function ($input) { - return !$input->deploy; - }); - - $validator->sometimes('allocation.additional.*', [ - 'integer', - Rule::exists('allocations', 'id')->where(function ($query) { - $query->whereNull('server_id'); - }), - ], function ($input) { - return !$input->deploy; - }); - /** @deprecated use tags instead */ $validator->sometimes('deploy.locations', 'present', function ($input) { return $input->deploy; diff --git a/app/Http/Requests/Api/Application/Servers/UpdateServerBuildConfigurationRequest.php b/app/Http/Requests/Api/Application/Servers/UpdateServerBuildConfigurationRequest.php index 7b0fcad10..f30e4d049 100644 --- a/app/Http/Requests/Api/Application/Servers/UpdateServerBuildConfigurationRequest.php +++ b/app/Http/Requests/Api/Application/Servers/UpdateServerBuildConfigurationRequest.php @@ -15,7 +15,6 @@ class UpdateServerBuildConfigurationRequest extends ServerWriteRequest $rules = Server::getRulesForUpdate($this->parameter('server', Server::class)); return [ - 'allocation' => $rules['allocation_id'], 'oom_killer' => $rules['oom_killer'], 'limits' => 'sometimes|array', @@ -54,7 +53,6 @@ class UpdateServerBuildConfigurationRequest extends ServerWriteRequest { $data = parent::validated(); - $data['allocation_id'] = $data['allocation']; $data['database_limit'] = $data['feature_limits']['databases'] ?? null; $data['allocation_limit'] = $data['feature_limits']['allocations'] ?? null; $data['backup_limit'] = $data['feature_limits']['backups'] ?? null; diff --git a/app/Http/Requests/Api/Client/Servers/Network/DeleteAllocationRequest.php b/app/Http/Requests/Api/Client/Servers/Network/DeleteAllocationRequest.php deleted file mode 100644 index a5d76472d..000000000 --- a/app/Http/Requests/Api/Client/Servers/Network/DeleteAllocationRequest.php +++ /dev/null @@ -1,14 +0,0 @@ - array_merge($rules['notes'], ['present']), - ]; - } -} diff --git a/app/Models/Allocation.php b/app/Models/Allocation.php deleted file mode 100644 index c58514b84..000000000 --- a/app/Models/Allocation.php +++ /dev/null @@ -1,100 +0,0 @@ - 'required|exists:nodes,id', - 'ip' => 'required|ip', - 'port' => 'required|numeric|between:1024,65535', - 'ip_alias' => 'nullable|string', - 'server_id' => 'nullable|exists:servers,id', - 'notes' => 'nullable|string|max:256', - ]; - - protected static function booted(): void - { - static::deleting(function (self $allocation) { - throw_if($allocation->server_id, new ServerUsingAllocationException(trans('exceptions.allocations.server_using'))); - }); - } - - protected function casts(): array - { - return [ - 'node_id' => 'integer', - 'port' => 'integer', - 'server_id' => 'integer', - ]; - } - - public function getRouteKeyName(): string - { - return $this->getKeyName(); - } - - /** - * Accessor to automatically provide the IP alias if defined. - */ - public function getAliasAttribute(?string $value): string - { - return (is_null($this->ip_alias)) ? $this->ip : $this->ip_alias; - } - - /** - * Accessor to quickly determine if this allocation has an alias. - */ - public function getHasAliasAttribute(?string $value): bool - { - return !is_null($this->ip_alias); - } - - public function address(): Attribute - { - return Attribute::make( - get: fn () => "$this->ip:$this->port", - ); - } - - public function toString(): string - { - return $this->address; - } - - /** - * Gets information for the server associated with this allocation. - */ - public function server(): BelongsTo - { - return $this->belongsTo(Server::class); - } - - /** - * Return the Node model associated with this allocation. - */ - public function node(): BelongsTo - { - return $this->belongsTo(Node::class); - } -} diff --git a/app/Models/Filters/MultiFieldServerFilter.php b/app/Models/Filters/MultiFieldServerFilter.php index da3f91f6d..92495af47 100644 --- a/app/Models/Filters/MultiFieldServerFilter.php +++ b/app/Models/Filters/MultiFieldServerFilter.php @@ -2,7 +2,6 @@ namespace App\Models\Filters; -use Illuminate\Support\Str; use Spatie\QueryBuilder\Filters\Filter; use Illuminate\Database\Eloquent\Builder; @@ -32,26 +31,6 @@ class MultiFieldServerFilter implements Filter // Only select the server values, otherwise you'll end up merging the allocation and // server objects together, resulting in incorrect behavior and returned values. ->select('servers.*') - ->join('allocations', 'allocations.server_id', '=', 'servers.id') - ->where(function (Builder $builder) use ($value) { - $parts = explode(':', $value); - - $builder->when( - !Str::startsWith($value, ':'), - // When the string does not start with a ":" it means we're looking for an IP or IP:Port - // combo, so use a query to handle that. - function (Builder $builder) use ($parts) { - $builder->orWhere('allocations.ip', $parts[0]); - if (!is_null($parts[1] ?? null)) { - $builder->where('allocations.port', 'LIKE', "{$parts[1]}%"); - } - }, - // Otherwise, just try to search for that specific port in the allocations. - function (Builder $builder) use ($value) { - $builder->orWhere('allocations.port', 'LIKE', substr($value, 1) . '%'); - } - ); - }) ->groupBy('servers.id'); return; diff --git a/app/Models/Node.php b/app/Models/Node.php index d0b9bb5a1..a933d16fe 100644 --- a/app/Models/Node.php +++ b/app/Models/Node.php @@ -201,14 +201,6 @@ class Node extends Model return $this->hasMany(Server::class); } - /** - * Gets the allocations associated with a node. - */ - public function allocations(): HasMany - { - return $this->hasMany(Allocation::class); - } - /** * Returns a boolean if the node is viable for an additional server to be placed on it. */ @@ -238,28 +230,6 @@ class Node extends Model return true; } - public static function getForServerCreation() - { - return self::with('allocations')->get()->map(function (Node $item) { - $filtered = $item->getRelation('allocations')->where('server_id', null)->map(function ($map) { - return collect($map)->only(['id', 'ip', 'port']); - }); - - $ports = $filtered->map(function ($map) { - return [ - 'id' => $map['id'], - 'text' => sprintf('%s:%s', $map['ip'], $map['port']), - ]; - })->values(); - - return [ - 'id' => $item->id, - 'text' => $item->name, - 'allocations' => $ports, - ]; - })->values(); - } - public function systemInformation(): array { return once(function () { diff --git a/app/Models/Objects/Endpoint.php b/app/Models/Objects/Endpoint.php new file mode 100644 index 000000000..cc8de189d --- /dev/null +++ b/app/Models/Objects/Endpoint.php @@ -0,0 +1,39 @@ +ip = $ip; + $this->port = $port; + } +} diff --git a/app/Models/Server.php b/app/Models/Server.php index 491b64b2b..076c62ff7 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -41,11 +41,6 @@ class Server extends Model 'installed_at' => null, ]; - /** - * The default relationships to load for all server models. - */ - protected $with = ['allocation']; - /** * Fields that are not mass assignable. */ @@ -65,7 +60,6 @@ class Server extends Model 'threads' => 'nullable|regex:/^[0-9-,]+$/', 'oom_killer' => 'sometimes|boolean', 'disk' => 'required|numeric|min:0', - 'allocation_id' => 'required|bail|unique:servers|exists:allocations,id', 'egg_id' => 'required|exists:eggs,id', 'startup' => 'required|string', 'skip_scripts' => 'sometimes|boolean', @@ -73,6 +67,7 @@ class Server extends Model 'database_limit' => 'present|nullable|integer|min:0', 'allocation_limit' => 'sometimes|nullable|integer|min:0', 'backup_limit' => 'present|nullable|integer|min:0', + 'ports' => 'array', ]; protected function casts(): array @@ -88,27 +83,33 @@ class Server extends Model 'io' => 'integer', 'cpu' => 'integer', 'oom_killer' => 'boolean', - 'allocation_id' => 'integer', 'egg_id' => 'integer', 'database_limit' => 'integer', 'allocation_limit' => 'integer', 'backup_limit' => 'integer', - self::CREATED_AT => 'datetime', - self::UPDATED_AT => 'datetime', 'deleted_at' => 'datetime', 'installed_at' => 'datetime', 'docker_labels' => 'array', + 'ports' => 'array', ]; } /** * Returns the format for server allocations when communicating with the Daemon. */ - public function getAllocationMappings(): array + public function getPortMappings(): array { - return $this->allocations->where('node_id', $this->node_id)->groupBy('ip')->map(function ($item) { - return $item->pluck('port'); - })->toArray(); + $defaultIp = '0.0.0.0'; + + $ports = collect($this->ports) + ->map(fn ($port) => str_contains($port, ':') ? $port : "$defaultIp:$port") + ->mapToGroups(function ($port) { + [$ip, $port] = explode(':', $port); + + return [$ip => (int) $port]; + }); + + return $ports->all(); } public function isInstalled(): bool @@ -137,22 +138,6 @@ class Server extends Model return $this->hasMany(Subuser::class, 'server_id', 'id'); } - /** - * Gets the default allocation for a server. - */ - public function allocation(): BelongsTo - { - return $this->belongsTo(Allocation::class); - } - - /** - * Gets all allocations associated with this server. - */ - public function allocations(): HasMany - { - return $this->hasMany(Allocation::class); - } - /** * Gets information for the egg associated with this server. */ diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 5817890b1..c0dcc1a64 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -45,7 +45,6 @@ class AppServiceProvider extends ServiceProvider } Relation::enforceMorphMap([ - 'allocation' => Models\Allocation::class, 'api_key' => Models\ApiKey::class, 'backup' => Models\Backup::class, 'database' => Models\Database::class, diff --git a/app/Rules/Port.php b/app/Rules/Port.php index 7225509c0..f2a598c12 100644 --- a/app/Rules/Port.php +++ b/app/Rules/Port.php @@ -23,12 +23,12 @@ class Port implements ValidationRule $fail('The :attribute must be an integer.'); } - if ($value < 0) { - $fail('The :attribute must be greater or equal to 0.'); + if ($value <= 1024) { + $fail('The :attribute must be greater than 1024.'); } if ($value > 65535) { - $fail('The :attribute must be less or equal to 65535.'); + $fail('The :attribute must be less than 65535.'); } } } diff --git a/app/Services/Allocations/AssignmentService.php b/app/Services/Allocations/AssignmentService.php deleted file mode 100644 index 3788d6bf8..000000000 --- a/app/Services/Allocations/AssignmentService.php +++ /dev/null @@ -1,115 +0,0 @@ - self::CIDR_MIN_BITS || $explode[1] < self::CIDR_MAX_BITS)) { - throw new CidrOutOfRangeException(); - } - } - - try { - // TODO: how should we approach supporting IPv6 with this? - // gethostbyname only supports IPv4, but the alternative (dns_get_record) returns - // an array of records, which is not ideal for this use case, we need a SINGLE - // IP to use, not multiple. - $underlying = gethostbyname($data['allocation_ip']); - $parsed = Network::parse($underlying); - } catch (\Exception $exception) { - throw new DisplayException("Could not parse provided allocation IP address ({$data['allocation_ip']}): {$exception->getMessage()}", $exception); - } - - $this->connection->beginTransaction(); - - $ids = []; - foreach ($parsed as $ip) { - foreach ($data['allocation_ports'] as $port) { - if (!is_digit($port) && !preg_match(self::PORT_RANGE_REGEX, $port)) { - throw new InvalidPortMappingException($port); - } - - $insertData = []; - if (preg_match(self::PORT_RANGE_REGEX, $port, $matches)) { - $block = range($matches[1], $matches[2]); - - if (count($block) > self::PORT_RANGE_LIMIT) { - throw new TooManyPortsInRangeException(); - } - - if ((int) $matches[1] <= self::PORT_FLOOR || (int) $matches[2] > self::PORT_CEIL) { - throw new PortOutOfRangeException(); - } - - foreach ($block as $unit) { - $insertData[] = [ - 'node_id' => $node->id, - 'ip' => $ip->__toString(), - 'port' => (int) $unit, - 'ip_alias' => array_get($data, 'allocation_alias'), - 'server_id' => null, - ]; - } - } else { - if ((int) $port <= self::PORT_FLOOR || (int) $port > self::PORT_CEIL) { - throw new PortOutOfRangeException(); - } - - $insertData[] = [ - 'node_id' => $node->id, - 'ip' => $ip->__toString(), - 'port' => (int) $port, - 'ip_alias' => array_get($data, 'allocation_alias'), - 'server_id' => null, - ]; - } - - foreach ($insertData as $insert) { - $allocation = Allocation::query()->create($insert); - $ids[] = $allocation->id; - } - } - } - - $this->connection->commit(); - - return $ids; - } -} diff --git a/app/Services/Allocations/FindAssignableAllocationService.php b/app/Services/Allocations/FindAssignableAllocationService.php index 5c62b7539..6f9958a6a 100644 --- a/app/Services/Allocations/FindAssignableAllocationService.php +++ b/app/Services/Allocations/FindAssignableAllocationService.php @@ -4,51 +4,26 @@ namespace App\Services\Allocations; use Webmozart\Assert\Assert; use App\Models\Server; -use App\Models\Allocation; use App\Exceptions\Service\Allocation\AutoAllocationNotEnabledException; use App\Exceptions\Service\Allocation\NoAutoAllocationSpaceAvailableException; class FindAssignableAllocationService { - /** - * FindAssignableAllocationService constructor. - */ - public function __construct(private AssignmentService $service) + public function __construct() { } /** - * Finds an existing unassigned allocation and attempts to assign it to the given server. If - * no allocation can be found, a new one will be created with a random port between the defined - * range from the configuration. - * - * @throws \App\Exceptions\DisplayException - * @throws \App\Exceptions\Service\Allocation\CidrOutOfRangeException - * @throws \App\Exceptions\Service\Allocation\InvalidPortMappingException - * @throws \App\Exceptions\Service\Allocation\PortOutOfRangeException - * @throws \App\Exceptions\Service\Allocation\TooManyPortsInRangeException + * @throws AutoAllocationNotEnabledException + * @throws NoAutoAllocationSpaceAvailableException */ - public function handle(Server $server): Allocation + public function handle(Server $server): int { if (!config('panel.client_features.allocations.enabled')) { throw new AutoAllocationNotEnabledException(); } - // Attempt to find a given available allocation for a server. If one cannot be found - // we will fall back to attempting to create a new allocation that can be used for the - // server. - /** @var \App\Models\Allocation|null $allocation */ - $allocation = $server->node->allocations() - ->where('ip', $server->allocation->ip) - ->whereNull('server_id') - ->inRandomOrder() - ->first(); - - $allocation = $allocation ?? $this->createNewAllocation($server); - - $allocation->update(['server_id' => $server->id]); - - return $allocation->refresh(); + return $this->createNewAllocation($server); } /** @@ -56,16 +31,12 @@ class FindAssignableAllocationService * in the settings. If there are no matches in that range, or something is wrong with the * range information provided an exception will be raised. * - * @throws \App\Exceptions\DisplayException - * @throws \App\Exceptions\Service\Allocation\CidrOutOfRangeException - * @throws \App\Exceptions\Service\Allocation\InvalidPortMappingException - * @throws \App\Exceptions\Service\Allocation\PortOutOfRangeException - * @throws \App\Exceptions\Service\Allocation\TooManyPortsInRangeException + * @throws NoAutoAllocationSpaceAvailableException */ - protected function createNewAllocation(Server $server): Allocation + protected function createNewAllocation(Server $server): int { - $start = config('panel.client_features.allocations.range_start', null); - $end = config('panel.client_features.allocations.range_end', null); + $start = config('panel.client_features.allocations.range_start'); + $end = config('panel.client_features.allocations.range_end'); if (!$start || !$end) { throw new NoAutoAllocationSpaceAvailableException(); @@ -74,8 +45,7 @@ class FindAssignableAllocationService Assert::integerish($start); Assert::integerish($end); - // Get all of the currently allocated ports for the node so that we can figure out - // which port might be available. + // Get all the currently allocated ports for the node so that we can figure out which port might be available. $ports = $server->node->allocations() ->where('ip', $server->allocation->ip) ->whereBetween('port', [$start, $end]) @@ -86,26 +56,8 @@ class FindAssignableAllocationService // array of ports to create a new allocation to assign to the server. $available = array_diff(range($start, $end), $ports->toArray()); - // If we've already allocated all of the ports, just abort. - if (empty($available)) { - throw new NoAutoAllocationSpaceAvailableException(); - } - // Pick a random port out of the remaining available ports. /** @var int $port */ - $port = $available[array_rand($available)]; - - $this->service->handle($server->node, [ - 'allocation_ip' => $server->allocation->ip, - 'allocation_ports' => [$port], - ]); - - /** @var \App\Models\Allocation $allocation */ - $allocation = $server->node->allocations() - ->where('ip', $server->allocation->ip) - ->where('port', $port) - ->firstOrFail(); - - return $allocation; + return $available[array_rand($available)]; } } diff --git a/app/Services/Deployment/AllocationSelectionService.php b/app/Services/Deployment/AllocationSelectionService.php deleted file mode 100644 index 3868d0b38..000000000 --- a/app/Services/Deployment/AllocationSelectionService.php +++ /dev/null @@ -1,150 +0,0 @@ -dedicated = $dedicated; - - return $this; - } - - /** - * A list of node IDs that should be used when selecting an allocation. If empty, all - * nodes will be used to filter with. - */ - public function setNodes(array $nodes): self - { - $this->nodes = $nodes; - - return $this; - } - - /** - * An array of individual ports or port ranges to use when selecting an allocation. If - * empty, all ports will be considered when finding an allocation. If set, only ports appearing - * in the array or range will be used. - * - * @throws \App\Exceptions\DisplayException - */ - public function setPorts(array $ports): self - { - $stored = []; - foreach ($ports as $port) { - if (is_digit($port)) { - $stored[] = $port; - } - - // Ranges are stored in the ports array as an array which can be - // better processed in the repository. - if (preg_match(AssignmentService::PORT_RANGE_REGEX, $port, $matches)) { - if (abs((int) $matches[2] - (int) $matches[1]) > AssignmentService::PORT_RANGE_LIMIT) { - throw new DisplayException(trans('exceptions.allocations.too_many_ports')); - } - - $stored[] = [$matches[1], $matches[2]]; - } - } - - $this->ports = $stored; - - return $this; - } - - /** - * Return a single allocation that should be used as the default allocation for a server. - * - * @throws \App\Exceptions\Service\Deployment\NoViableAllocationException - */ - public function handle(): Allocation - { - $allocation = $this->getRandomAllocation($this->nodes, $this->ports, $this->dedicated); - - if (is_null($allocation)) { - throw new NoViableAllocationException(trans('exceptions.deployment.no_viable_allocations')); - } - - return $allocation; - } - - /** - * Return a single allocation from those meeting the requirements. - */ - private function getRandomAllocation(array $nodes = [], array $ports = [], bool $dedicated = false): ?Allocation - { - $query = Allocation::query() - ->whereNull('server_id') - ->whereIn('node_id', $nodes); - - if (!empty($ports)) { - $query->where(function ($inner) use ($ports) { - $whereIn = []; - foreach ($ports as $port) { - if (is_array($port)) { - $inner->orWhereBetween('port', $port); - - continue; - } - - $whereIn[] = $port; - } - - if (!empty($whereIn)) { - $inner->orWhereIn('port', $whereIn); - } - }); - } - - // If this allocation should not be shared with any other servers get - // the data and modify the query as necessary, - if ($dedicated) { - $discard = $this->getDiscardableDedicatedAllocations($nodes); - - if (!empty($discard)) { - $query->whereNotIn('ip', $discard); - } - } - - return $query->inRandomOrder()->first(); - } - - /** - * Return a result set of node ips that already have at least one - * server assigned to that IP. This allows for filtering out sets for - * dedicated allocation IPs. - * - * If an array of nodes is passed the results will be limited to allocations - * in those nodes. - */ - private function getDiscardableDedicatedAllocations(array $nodes = []): array - { - $query = Allocation::query()->whereNotNull('server_id'); - - if (!empty($nodes)) { - $query->whereIn('node_id', $nodes); - } - - return $query->groupBy('ip') - ->get() - ->pluck('ip') - ->toArray(); - } -} diff --git a/app/Services/Servers/BuildModificationService.php b/app/Services/Servers/BuildModificationService.php index f7c740324..3b74af065 100644 --- a/app/Services/Servers/BuildModificationService.php +++ b/app/Services/Servers/BuildModificationService.php @@ -4,9 +4,7 @@ namespace App\Services\Servers; use Illuminate\Support\Arr; use App\Models\Server; -use App\Models\Allocation; use Illuminate\Database\ConnectionInterface; -use App\Exceptions\DisplayException; use App\Repositories\Daemon\DaemonServerRepository; use App\Exceptions\Http\Connection\DaemonConnectionException; @@ -32,20 +30,12 @@ class BuildModificationService { /** @var \App\Models\Server $server */ $server = $this->connection->transaction(function () use ($server, $data) { - $this->processAllocations($server, $data); - - if (isset($data['allocation_id']) && $data['allocation_id'] != $server->allocation_id) { - $existingAllocation = $server->allocations()->findOrFail($data['allocation_id']); - - throw_unless($existingAllocation, new DisplayException('The requested default allocation is not currently assigned to this server.')); - } - if (!isset($data['oom_killer']) && isset($data['oom_disabled'])) { $data['oom_killer'] = !$data['oom_disabled']; } // 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_killer', 'memory', 'swap', 'io', 'cpu', 'threads', 'disk', 'allocation_id']); + $merge = Arr::only($data, ['oom_killer', 'memory', 'swap', 'io', 'cpu', 'threads', 'disk', 'ports']); $server->forceFill(array_merge($merge, [ 'database_limit' => Arr::get($data, 'database_limit', 0) ?? null, @@ -72,59 +62,4 @@ class BuildModificationService return $server; } - - /** - * Process the allocations being assigned in the data and ensure they are available for a server. - * - * @throws \App\Exceptions\DisplayException - */ - private function processAllocations(Server $server, array &$data): void - { - 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->first()?->id; - - $query->update(['server_id' => $server->id, 'notes' => null]); - } - - 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, - ]); - } - } } diff --git a/app/Services/Servers/ServerConfigurationStructureService.php b/app/Services/Servers/ServerConfigurationStructureService.php index 43fd9f76c..b71d6995d 100644 --- a/app/Services/Servers/ServerConfigurationStructureService.php +++ b/app/Services/Servers/ServerConfigurationStructureService.php @@ -69,7 +69,7 @@ class ServerConfigurationStructureService 'ip' => $server->allocation->ip, 'port' => $server->allocation->port, ], - 'mappings' => $server->getAllocationMappings(), + 'mappings' => $server->getPortMappings(), ], 'egg' => [ 'id' => $server->egg->uuid, diff --git a/app/Services/Servers/ServerCreationService.php b/app/Services/Servers/ServerCreationService.php index d555f7876..fe39b8501 100644 --- a/app/Services/Servers/ServerCreationService.php +++ b/app/Services/Servers/ServerCreationService.php @@ -10,12 +10,9 @@ use App\Models\User; use Webmozart\Assert\Assert; use App\Models\Server; use Illuminate\Support\Collection; -use App\Models\Allocation; use Illuminate\Database\ConnectionInterface; 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; class ServerCreationService @@ -24,27 +21,23 @@ class ServerCreationService * ServerCreationService constructor. */ public function __construct( - private AllocationSelectionService $allocationSelectionService, private ConnectionInterface $connection, private DaemonServerRepository $daemonServerRepository, - private FindViableNodesService $findViableNodesService, private ServerDeletionService $serverDeletionService, private VariableValidatorService $validatorService ) { } /** - * Create a server on the Panel and trigger a request to the Daemon to begin the server - * creation process. This function will attempt to set as many additional values - * as possible given the input data. For example, if an allocation_id is passed with - * no node_id the node_is will be picked from the allocation. + * Create a server on the Panel and trigger a request to the Daemon to begin the server creation process. + * This function will attempt to set as many additional values as possible given the input data. * * @throws \Throwable * @throws \App\Exceptions\DisplayException * @throws \Illuminate\Validation\ValidationException * @throws \App\Exceptions\Service\Deployment\NoViableAllocationException */ - public function handle(array $data, DeploymentObject $deployment = null): Server + public function handle(array $data, DeploymentObject $deployment = null, $validateVariables = true): Server { if (!isset($data['oom_killer']) && isset($data['oom_disabled'])) { $data['oom_killer'] = !$data['oom_disabled']; @@ -53,22 +46,15 @@ class ServerCreationService // If a deployment object has been passed we need to get the allocation // that the server should use, and assign the node from that allocation. if ($deployment instanceof DeploymentObject) { - $allocation = $this->configureDeployment($data, $deployment); - $data['allocation_id'] = $allocation->id; - $data['node_id'] = $allocation->node_id; + // Todo: Refactor + // $allocation = $this->configureDeployment($data, $deployment); } - // Auto-configure the node based on the selected allocation - // if no node was defined. - if (empty($data['node_id'])) { - Assert::false(empty($data['allocation_id']), 'Expected a non-empty allocation_id in server creation data.'); - - $data['node_id'] = Allocation::query()->findOrFail($data['allocation_id'])->node_id; - } + Assert::false(empty($data['node_id'])); $eggVariableData = $this->validatorService ->setUserLevel(User::USER_LEVEL_ADMIN) - ->handle(Arr::get($data, 'egg_id'), Arr::get($data, 'environment', [])); + ->handle(Arr::get($data, 'egg_id'), Arr::get($data, 'environment', []), $validateVariables); // Due to the design of the Daemon, we need to persist this server to the disk // before we can actually create it on the Daemon. @@ -80,7 +66,6 @@ class ServerCreationService // Create the server and assign any additional allocations to it. $server = $this->createModel($data); - $this->storeAssignedAllocations($server, $data); $this->storeEggVariables($server, $eggVariableData); return $server; @@ -99,28 +84,6 @@ class ServerCreationService return $server; } - /** - * Gets an allocation to use for automatic deployment. - * - * @throws \App\Exceptions\DisplayException - * @throws \App\Exceptions\Service\Deployment\NoViableAllocationException - */ - private function configureDeployment(array $data, DeploymentObject $deployment): Allocation - { - /** @var Collection<\App\Models\Node> $nodes */ - $nodes = $this->findViableNodesService->handle( - Arr::get($data, 'memory', 0), - Arr::get($data, 'disk', 0), - Arr::get($data, 'cpu', 0), - Arr::get($data, 'tags', []), - ); - - return $this->allocationSelectionService->setDedicated($deployment->isDedicated()) - ->setNodes($nodes->pluck('id')->toArray()) - ->setPorts($deployment->getPorts()) - ->handle(); - } - /** * Store the server in the database and return the model. * @@ -158,21 +121,6 @@ class ServerCreationService ]); } - /** - * Configure the allocations assigned to this server. - */ - private function storeAssignedAllocations(Server $server, array $data): void - { - $records = [$data['allocation_id']]; - if (isset($data['allocation_additional']) && is_array($data['allocation_additional'])) { - $records = array_merge($records, $data['allocation_additional']); - } - - Allocation::query()->whereIn('id', $records)->update([ - 'server_id' => $server->id, - ]); - } - /** * Process environment variables passed for this server and store them in the database. */ diff --git a/app/Services/Servers/TransferServerService.php b/app/Services/Servers/TransferServerService.php index 4312369dd..c948f3b9c 100644 --- a/app/Services/Servers/TransferServerService.php +++ b/app/Services/Servers/TransferServerService.php @@ -3,7 +3,6 @@ namespace App\Services\Servers; use App\Exceptions\Http\Connection\DaemonConnectionException; -use App\Models\Allocation; use App\Models\Node; use App\Models\Server; use App\Models\ServerTransfer; @@ -52,8 +51,6 @@ class TransferServerService public function handle(Server $server, array $data): bool { $node_id = $data['node_id']; - $allocation_id = intval($data['allocation_id']); - $additional_allocations = array_map(intval(...), $data['allocation_additional'] ?? []); // Check if the node is viable for the transfer. $node = Node::query() @@ -71,23 +68,15 @@ class TransferServerService $server->validateTransferState(); - $this->connection->transaction(function () use ($server, $node_id, $allocation_id, $additional_allocations) { - // Create a new ServerTransfer entry. + $this->connection->transaction(function () use ($server, $node_id) { $transfer = new ServerTransfer(); $transfer->server_id = $server->id; $transfer->old_node = $server->node_id; $transfer->new_node = $node_id; - $transfer->old_allocation = $server->allocation_id; - $transfer->new_allocation = $allocation_id; - $transfer->old_additional_allocations = $server->allocations->where('id', '!=', $server->allocation_id)->pluck('id')->all(); - $transfer->new_additional_allocations = $additional_allocations; $transfer->save(); - // Add the allocations to the server, so they cannot be automatically assigned while the transfer is in progress. - $this->assignAllocationsToServer($server, $node_id, $allocation_id, $additional_allocations); - // Generate a token for the destination node that the source node can use to authenticate with. $token = $this->nodeJWTService ->setExpiresAt(CarbonImmutable::now()->addMinutes(15)) @@ -102,32 +91,4 @@ class TransferServerService return true; } - - /** - * Assigns the specified allocations to the specified server. - */ - private function assignAllocationsToServer(Server $server, int $node_id, int $allocation_id, array $additional_allocations) - { - $allocations = $additional_allocations; - $allocations[] = $allocation_id; - - $node = Node::query()->findOrFail($node_id); - $unassigned = $node->allocations() - ->whereNull('server_id') - ->pluck('id') - ->toArray(); - - $updateIds = []; - foreach ($allocations as $allocation) { - if (!in_array($allocation, $unassigned)) { - continue; - } - - $updateIds[] = $allocation; - } - - if (!empty($updateIds)) { - Allocation::query()->whereIn('id', $updateIds)->update(['server_id' => $server->id]); - } - } } diff --git a/app/Services/Servers/VariableValidatorService.php b/app/Services/Servers/VariableValidatorService.php index 75f4a59b1..a55e27bf6 100644 --- a/app/Services/Servers/VariableValidatorService.php +++ b/app/Services/Servers/VariableValidatorService.php @@ -25,7 +25,7 @@ class VariableValidatorService * * @throws \Illuminate\Validation\ValidationException */ - public function handle(int $egg, array $fields = []): Collection + public function handle(int $egg, array $fields = [], $validate = false): Collection { $query = EggVariable::query()->where('egg_id', $egg); if (!$this->isUserLevel(User::USER_LEVEL_ADMIN)) { @@ -44,9 +44,11 @@ class VariableValidatorService $customAttributes['environment.' . $variable->env_variable] = trans('validation.internal.variable_value', ['env' => $variable->name]); } - $validator = $this->validator->make($data, $rules, [], $customAttributes); - if ($validator->fails()) { - throw new ValidationException($validator); + if ($validate) { + $validator = $this->validator->make($data, $rules, [], $customAttributes); + if ($validator->fails()) { + throw new ValidationException($validator); + } } return Collection::make($variables)->map(function ($item) use ($fields) { diff --git a/app/Transformers/Api/Application/AllocationTransformer.php b/app/Transformers/Api/Application/AllocationTransformer.php deleted file mode 100644 index 7f5bf8827..000000000 --- a/app/Transformers/Api/Application/AllocationTransformer.php +++ /dev/null @@ -1,77 +0,0 @@ - $allocation->id, - 'ip' => $allocation->ip, - 'alias' => $allocation->ip_alias, - 'port' => $allocation->port, - 'notes' => $allocation->notes, - 'assigned' => !is_null($allocation->server_id), - ]; - } - - /** - * Load the node relationship onto a given transformation. - * - * @throws \App\Exceptions\Transformer\InvalidTransformerLevelException - */ - public function includeNode(Allocation $allocation): Item|NullResource - { - if (!$this->authorize(AdminAcl::RESOURCE_NODES)) { - return $this->null(); - } - - return $this->item( - $allocation->node, - $this->makeTransformer(NodeTransformer::class), - Node::RESOURCE_NAME - ); - } - - /** - * Load the server relationship onto a given transformation. - * - * @throws \App\Exceptions\Transformer\InvalidTransformerLevelException - */ - public function includeServer(Allocation $allocation): Item|NullResource - { - if (!$this->authorize(AdminAcl::RESOURCE_SERVERS) || !$allocation->server) { - return $this->null(); - } - - return $this->item( - $allocation->server, - $this->makeTransformer(ServerTransformer::class), - Server::RESOURCE_NAME - ); - } -} diff --git a/app/Transformers/Api/Application/NodeTransformer.php b/app/Transformers/Api/Application/NodeTransformer.php index 670e4bcac..dabf8c40d 100644 --- a/app/Transformers/Api/Application/NodeTransformer.php +++ b/app/Transformers/Api/Application/NodeTransformer.php @@ -12,7 +12,7 @@ class NodeTransformer extends BaseTransformer /** * List of resources that can be included. */ - protected array $availableIncludes = ['allocations', 'servers']; + protected array $availableIncludes = ['servers']; /** * Return the resource name for the JSONAPI output. @@ -45,26 +45,6 @@ class NodeTransformer extends BaseTransformer return $response; } - /** - * Return the nodes associated with this location. - * - * @throws \App\Exceptions\Transformer\InvalidTransformerLevelException - */ - public function includeAllocations(Node $node): Collection|NullResource - { - if (!$this->authorize(AdminAcl::RESOURCE_ALLOCATIONS)) { - return $this->null(); - } - - $node->loadMissing('allocations'); - - return $this->collection( - $node->getRelation('allocations'), - $this->makeTransformer(AllocationTransformer::class), - 'allocation' - ); - } - /** * Return the nodes associated with this location. * diff --git a/app/Transformers/Api/Application/ServerTransformer.php b/app/Transformers/Api/Application/ServerTransformer.php index 90836cc24..e754b9452 100644 --- a/app/Transformers/Api/Application/ServerTransformer.php +++ b/app/Transformers/Api/Application/ServerTransformer.php @@ -17,7 +17,6 @@ class ServerTransformer extends BaseTransformer * List of resources that can be included. */ protected array $availableIncludes = [ - 'allocations', 'user', 'subusers', 'egg', @@ -76,7 +75,6 @@ class ServerTransformer extends BaseTransformer ], 'user' => $server->owner_id, 'node' => $server->node_id, - 'allocation' => $server->allocation_id, 'egg' => $server->egg_id, 'container' => [ 'startup_command' => $server->startup, @@ -87,25 +85,25 @@ class ServerTransformer extends BaseTransformer ], $server->getUpdatedAtColumn() => $this->formatTimestamp($server->updated_at), $server->getCreatedAtColumn() => $this->formatTimestamp($server->created_at), + + 'allocations' => collect($server->ports)->map(function ($port) { + $ip = '0.0.0.0'; + if (str_contains($port, ':')) { + [$ip, $port] = explode(':', $port); + } + + return [ + 'id' => random_int(1, PHP_INT_MAX), + 'ip' => $ip, + 'alias' => null, + 'port' => (int) $port, + 'notes' => null, + 'assigned' => false, + ]; + })->all(), ]; } - /** - * Return a generic array of allocations for this server. - * - * @throws \App\Exceptions\Transformer\InvalidTransformerLevelException - */ - public function includeAllocations(Server $server): Collection|NullResource - { - if (!$this->authorize(AdminAcl::RESOURCE_ALLOCATIONS)) { - return $this->null(); - } - - $server->loadMissing('allocations'); - - return $this->collection($server->getRelation('allocations'), $this->makeTransformer(AllocationTransformer::class), 'allocation'); - } - /** * Return a generic array of data about subusers for this server. * diff --git a/app/Transformers/Api/Client/AllocationTransformer.php b/app/Transformers/Api/Client/AllocationTransformer.php deleted file mode 100644 index 4fd84ed61..000000000 --- a/app/Transformers/Api/Client/AllocationTransformer.php +++ /dev/null @@ -1,28 +0,0 @@ - $model->id, - 'ip' => $model->ip, - 'ip_alias' => $model->ip_alias, - 'port' => $model->port, - 'notes' => $model->notes, - 'is_default' => $model->server->allocation_id === $model->id, - ]; - } -} diff --git a/app/Transformers/Api/Client/ServerTransformer.php b/app/Transformers/Api/Client/ServerTransformer.php index 07cd64dbd..b5c410f4a 100644 --- a/app/Transformers/Api/Client/ServerTransformer.php +++ b/app/Transformers/Api/Client/ServerTransformer.php @@ -6,7 +6,6 @@ use App\Models\Egg; use App\Models\Server; use App\Models\Subuser; use League\Fractal\Resource\Item; -use App\Models\Allocation; use App\Models\Permission; use Illuminate\Container\Container; use App\Models\EggVariable; @@ -16,7 +15,7 @@ use App\Services\Servers\StartupCommandService; class ServerTransformer extends BaseClientTransformer { - protected array $defaultIncludes = ['allocations', 'variables']; + protected array $defaultIncludes = ['variables']; protected array $availableIncludes = ['egg', 'subusers']; @@ -78,33 +77,6 @@ class ServerTransformer extends BaseClientTransformer ]; } - /** - * Returns the allocations associated with this server. - * - * @throws \App\Exceptions\Transformer\InvalidTransformerLevelException - */ - public function includeAllocations(Server $server): Collection - { - $transformer = $this->makeTransformer(AllocationTransformer::class); - - $user = $this->request->user(); - // While we include this permission, we do need to actually handle it slightly different here - // for the purpose of keeping things functionally working. If the user doesn't have read permissions - // for the allocations we'll only return the primary server allocation, and any notes associated - // with it will be hidden. - // - // This allows us to avoid too much permission regression, without also hiding information that - // is generally needed for the frontend to make sense when browsing or searching results. - if (!$user->can(Permission::ACTION_ALLOCATION_READ, $server)) { - $primary = clone $server->allocation; - $primary->notes = null; - - return $this->collection([$primary], $transformer, Allocation::RESOURCE_NAME); - } - - return $this->collection($server->allocations, $transformer, Allocation::RESOURCE_NAME); - } - /** * @throws \App\Exceptions\Transformer\InvalidTransformerLevelException */ diff --git a/database/Factories/AllocationFactory.php b/database/Factories/AllocationFactory.php deleted file mode 100644 index 19405b702..000000000 --- a/database/Factories/AllocationFactory.php +++ /dev/null @@ -1,36 +0,0 @@ - $this->faker->unique()->ipv4(), - 'port' => $this->faker->unique()->numberBetween(1024, 65535), - ]; - } - - /** - * Attaches the allocation to a specific server model. - */ - public function forServer(Server $server): self - { - return $this->for($server)->for($server->node); - } -} diff --git a/database/migrations/2024_06_06_043350_modify_allocations.php b/database/migrations/2024_06_06_043350_modify_allocations.php index 308e1adea..42c07b1aa 100644 --- a/database/migrations/2024_06_06_043350_modify_allocations.php +++ b/database/migrations/2024_06_06_043350_modify_allocations.php @@ -11,14 +11,37 @@ return new class extends Migration */ public function up(): void { - Schema::table('servers', function (Blueprint $table) { - $table->json('ports'); + Schema::table('server_transfers', function (Blueprint $table) { + $table->dropColumn(['old_allocation', 'new_allocation', 'old_additional_allocations', 'new_additional_allocations']); }); + Schema::table('servers', function (Blueprint $table) { + $table->json('ports')->nullable(); + }); + + DB::table('servers')->update(['ports' => '[]']); + + Schema::table('servers', function (Blueprint $table) { + $table->json('ports')->change(); + }); + + dd('works?'); + + $portMappings = []; + foreach (DB::table('allocations')->get() as $allocation) { + $portMappings[$allocation->server_id][] = "$allocation->ip:$allocation->port"; + } + + foreach ($portMappings as $serverId => $ports) { + DB::table('servers') + ->where('id', $serverId) + ->update(['ports' => json_encode($ports)]); + } + Schema::dropIfExists('allocations'); Schema::table('servers', function (Blueprint $table) { - $table->dropColumn(['allocation_id', 'allocation_limit']); + $table->dropColumn(['allocation_id']); }); Schema::table('nodes', function (Blueprint $table) { @@ -47,5 +70,12 @@ return new class extends Migration $table->unique(['node_id', 'ip', 'port']); }); + + Schema::table('server_transfers', function (Blueprint $table) { + $table->integer('old_node'); + $table->integer('new_node'); + $table->json('old_additional_allocations')->nullable(); + $table->json('new_additional_allocations')->nullable(); + }); } }; diff --git a/resources/views/admin/servers/new.blade.php b/resources/views/admin/servers/new.blade.php deleted file mode 100644 index 4aac49d39..000000000 --- a/resources/views/admin/servers/new.blade.php +++ /dev/null @@ -1,375 +0,0 @@ -@extends('layouts.admin') - -@section('title') - New Server -@endsection - -@section('content-header') -
This will reinstall the server with the assigned egg scripts. Danger! This could overwrite server data.
-If you need to change the install status from uninstalled to installed, or vice versa, you may do so with the button below.
-This will suspend the server, stop any running processes, and immediately block the user from being able to access their files or otherwise manage the server through the panel or API.
-This will unsuspend the server and restore normal user access.
-- Transfer this server to another node connected to this panel. - Warning! This feature has not been fully tested and may have bugs. -
-- This server is currently being transferred to another node. - Transfer was initiated at {{ $server->transfer->created_at }} -
-