diff --git a/app/Http/Controllers/Api/Application/Nodes/NodeDeploymentController.php b/app/Http/Controllers/Api/Application/Nodes/NodeDeploymentController.php index 1f79bf674..b5ba80cf1 100644 --- a/app/Http/Controllers/Api/Application/Nodes/NodeDeploymentController.php +++ b/app/Http/Controllers/Api/Application/Nodes/NodeDeploymentController.php @@ -9,9 +9,6 @@ use App\Http\Requests\Api\Application\Nodes\GetDeployableNodesRequest; class NodeDeploymentController extends ApplicationApiController { - /** - * NodeDeploymentController constructor. - */ public function __construct(private FindViableNodesService $viableNodesService) { parent::__construct(); @@ -25,10 +22,13 @@ class NodeDeploymentController extends ApplicationApiController public function __invoke(GetDeployableNodesRequest $request): array { $data = $request->validated(); - $nodes = $this->viableNodesService - ->setMemory($data['memory']) - ->setDisk($data['disk']) - ->handle((int) $request->query('per_page'), (int) $request->query('page')); + + $nodes = $this->viableNodesService->handle( + $data['disk'] ?? 0, + $data['memory'] ?? 0, + $data['cpu'] ?? 0, + $data['location_ids'] ?? $data['tags'] ?? [], + ); return $this->fractal->collection($nodes) ->transformWith($this->getTransformer(NodeTransformer::class)) diff --git a/app/Services/Deployment/FindViableNodesService.php b/app/Services/Deployment/FindViableNodesService.php index 384f81aa0..37dff5fae 100644 --- a/app/Services/Deployment/FindViableNodesService.php +++ b/app/Services/Deployment/FindViableNodesService.php @@ -3,37 +3,10 @@ namespace App\Services\Deployment; use App\Models\Node; -use Webmozart\Assert\Assert; use Illuminate\Support\Collection; class FindViableNodesService { - protected ?int $disk = null; - protected ?int $memory = null; - - /** - * Set the amount of disk that will be used by the server being created. Nodes will be - * filtered out if they do not have enough available free disk space for this server - * to be placed on. - */ - public function setDisk(int $disk): self - { - $this->disk = $disk; - - return $this; - } - - /** - * Set the amount of memory that this server will be using. As with disk space, nodes that - * do not have enough free memory will be filtered out. - */ - public function setMemory(int $memory): self - { - $this->memory = $memory; - - return $this; - } - /** * Returns a collection of nodes that meet the provided requirements and can then * be passed to the AllocationSelectionService to return a single allocation. @@ -44,21 +17,20 @@ class FindViableNodesService * are tossed out, as are any nodes marked as non-public, meaning automatic * deployments should not be done against them. */ - public function handle(int $disk = null, int $memory = null, int $cpu = null): Collection + public function handle(int $disk = 0, int $memory = 0, int $cpu = 0, $tags = []): Collection { - Assert::integer($this->disk, 'Disk space must be an int, got %s'); - Assert::integer($this->memory, 'Memory usage must be an int, got %s'); + $nodes = Node::query() + ->withSum('servers', 'disk') + ->withSum('servers', 'memory') + ->withSum('servers', 'cpu') + ->where('public', true) + ->get(); - $query = Node::query()->select('nodes.*') - ->selectRaw('IFNULL(SUM(servers.memory), 0) as sum_memory') - ->selectRaw('IFNULL(SUM(servers.disk), 0) as sum_disk') - ->leftJoin('servers', 'servers.node_id', '=', 'nodes.id') - ->where('nodes.public', 1); - - $results = $query->groupBy('nodes.id') - ->havingRaw('(IFNULL(SUM(servers.memory), 0) + ?) <= (nodes.memory * (1 + (nodes.memory_overallocate / 100)))', [$this->memory]) - ->havingRaw('(IFNULL(SUM(servers.disk), 0) + ?) <= (nodes.disk * (1 + (nodes.disk_overallocate / 100)))', [$this->disk]); - - return $results->get(); + return $nodes + ->filter(fn (Node $node) => !$tags || collect($node->tags)->intersect($tags)) + ->filter(fn (Node $node) => $node->servers_sum_disk + $disk <= $node->disk * (1 + $node->disk_overallocate / 100)) + ->filter(fn (Node $node) => $node->servers_sum_memory + $memory <= $node->memory * (1 + $node->memory_overallocate / 100)) + ->filter(fn (Node $node) => $node->servers_sum_cpu + $cpu <= $node->cpu * (1 + $node->cpu_overallocate / 100)) + ; } } diff --git a/app/Services/Servers/ServerCreationService.php b/app/Services/Servers/ServerCreationService.php index d1110ade4..8953b1325 100644 --- a/app/Services/Servers/ServerCreationService.php +++ b/app/Services/Servers/ServerCreationService.php @@ -107,11 +107,13 @@ class ServerCreationService */ private function configureDeployment(array $data, DeploymentObject $deployment): Allocation { - /** @var \Illuminate\Support\Collection $nodes */ - $nodes = $this->findViableNodesService - ->setDisk(Arr::get($data, 'disk')) - ->setMemory(Arr::get($data, 'memory')) - ->handle(); + /** @var Collection<\App\Models\Node> $nodes */ + $nodes = $this->findViableNodesService->handle( + Arr::get($data, 'disk', 0), + Arr::get($data, 'memory', 0), + Arr::get($data, 'cpu', 0), + Arr::get($data, 'tags', []), + ); return $this->allocationSelectionService->setDedicated($deployment->isDedicated()) ->setNodes($nodes->pluck('id')->toArray()) diff --git a/tests/Integration/Services/Deployment/FindViableNodesServiceTest.php b/tests/Integration/Services/Deployment/FindViableNodesServiceTest.php deleted file mode 100644 index d9a94cbc9..000000000 --- a/tests/Integration/Services/Deployment/FindViableNodesServiceTest.php +++ /dev/null @@ -1,42 +0,0 @@ -delete(); - Server::query()->delete(); - Node::query()->delete(); - } - - public function testExceptionIsThrownIfNoDiskSpaceHasBeenSet(): void - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('Disk space must be an int, got NULL'); - - $this->getService()->handle(); - } - - public function testExceptionIsThrownIfNoMemoryHasBeenSet(): void - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('Memory usage must be an int, got NULL'); - - $this->getService()->setDisk(10)->handle(); - } - - private function getService(): FindViableNodesService - { - return $this->app->make(FindViableNodesService::class); - } -}