mirror of
				https://github.com/pelican-dev/panel.git
				synced 2025-11-04 04:06:51 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			118 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			118 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
 | 
						|
namespace Pterodactyl\Services\Deployment;
 | 
						|
 | 
						|
use Pterodactyl\Models\Node;
 | 
						|
use Webmozart\Assert\Assert;
 | 
						|
use Pterodactyl\Exceptions\Service\Deployment\NoViableNodeException;
 | 
						|
 | 
						|
class FindViableNodesService
 | 
						|
{
 | 
						|
    /**
 | 
						|
     * @var array
 | 
						|
     */
 | 
						|
    protected $locations = [];
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var int
 | 
						|
     */
 | 
						|
    protected $disk;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var int
 | 
						|
     */
 | 
						|
    protected $memory;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Set the locations that should be searched through to locate available nodes.
 | 
						|
     *
 | 
						|
     * @return $this
 | 
						|
     */
 | 
						|
    public function setLocations(array $locations): self
 | 
						|
    {
 | 
						|
        Assert::allIntegerish($locations, 'An array of location IDs should be provided when calling setLocations.');
 | 
						|
 | 
						|
        $this->locations = $locations;
 | 
						|
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * 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.
 | 
						|
     *
 | 
						|
     * @return $this
 | 
						|
     */
 | 
						|
    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.
 | 
						|
     *
 | 
						|
     * @return $this
 | 
						|
     */
 | 
						|
    public function setMemory(int $memory): self
 | 
						|
    {
 | 
						|
        $this->memory = $memory;
 | 
						|
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns an array of nodes that meet the provided requirements and can then
 | 
						|
     * be passed to the AllocationSelectionService to return a single allocation.
 | 
						|
     *
 | 
						|
     * This functionality is used for automatic deployments of servers and will
 | 
						|
     * attempt to find all nodes in the defined locations that meet the disk and
 | 
						|
     * memory availability requirements. Any nodes not meeting those requirements
 | 
						|
     * are tossed out, as are any nodes marked as non-public, meaning automatic
 | 
						|
     * deployments should not be done against them.
 | 
						|
     *
 | 
						|
     * @param int|null $page If provided the results will be paginated by returning
 | 
						|
     *                       up to 50 nodes at a time starting at the provided page.
 | 
						|
     *                       If "null" is provided as the value no pagination will
 | 
						|
     *                       be used.
 | 
						|
     *
 | 
						|
     * @return \Illuminate\Support\Collection|\Illuminate\Contracts\Pagination\LengthAwarePaginator
 | 
						|
     *
 | 
						|
     * @throws \Pterodactyl\Exceptions\Service\Deployment\NoViableNodeException
 | 
						|
     */
 | 
						|
    public function handle(int $page = null)
 | 
						|
    {
 | 
						|
        Assert::integer($this->disk, 'Disk space must be an int, got %s');
 | 
						|
        Assert::integer($this->memory, 'Memory usage must be an int, got %s');
 | 
						|
 | 
						|
        $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);
 | 
						|
 | 
						|
        if (!empty($this->locations)) {
 | 
						|
            $query = $query->whereIn('nodes.location_id', $this->locations);
 | 
						|
        }
 | 
						|
 | 
						|
        $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]);
 | 
						|
 | 
						|
        if (!is_null($page)) {
 | 
						|
            $results = $results->paginate(50, ['*'], 'page', $page);
 | 
						|
        } else {
 | 
						|
            $results = $results->get()->toBase();
 | 
						|
        }
 | 
						|
 | 
						|
        if ($results->isEmpty()) {
 | 
						|
            throw new NoViableNodeException(trans('exceptions.deployment.no_viable_nodes'));
 | 
						|
        }
 | 
						|
 | 
						|
        return $results;
 | 
						|
    }
 | 
						|
}
 |