forked from pterodactyl/panel
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathFindAssignableAllocationService.php
More file actions
130 lines (110 loc) · 4.89 KB
/
FindAssignableAllocationService.php
File metadata and controls
130 lines (110 loc) · 4.89 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
<?php
namespace Pterodactyl\Services\Allocations;
use Webmozart\Assert\Assert;
use Pterodactyl\Models\Server;
use Pterodactyl\Models\Allocation;
use Pterodactyl\Exceptions\DisplayException;
use Pterodactyl\Exceptions\Service\Allocation\AutoAllocationNotEnabledException;
use Pterodactyl\Exceptions\Service\Allocation\NoAutoAllocationSpaceAvailableException;
class FindAssignableAllocationService
{
/**
* @var \Pterodactyl\Services\Allocations\AssignmentService
*/
private $service;
/**
* FindAssignableAllocationService constructor.
*
* @param \Pterodactyl\Services\Allocations\AssignmentService $service
*/
public function __construct(AssignmentService $service)
{
$this->service = $service;
}
/**
* 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.
*
* @param \Pterodactyl\Models\Server $server
* @return \Pterodactyl\Models\Allocation
*
* @throws \Pterodactyl\Exceptions\DisplayException
* @throws \Pterodactyl\Exceptions\Service\Allocation\CidrOutOfRangeException
* @throws \Pterodactyl\Exceptions\Service\Allocation\InvalidPortMappingException
* @throws \Pterodactyl\Exceptions\Service\Allocation\PortOutOfRangeException
* @throws \Pterodactyl\Exceptions\Service\Allocation\TooManyPortsInRangeException
*/
public function handle(Server $server)
{
if (!config('pterodactyl.client_features.allocations.enabled')) {
throw new AutoAllocationNotEnabledException;
}
if ($server->allocations()->count() >= $server->allocation_limit) {
throw new DisplayException(
'Cannot assign additional allocations to this server: limit has been reached.'
);
}
// 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 \Pterodactyl\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();
}
/**
* @param \Pterodactyl\Models\Server $server
* @return \Pterodactyl\Models\Allocation
*
* @throws \Pterodactyl\Exceptions\DisplayException
* @throws \Pterodactyl\Exceptions\Service\Allocation\CidrOutOfRangeException
* @throws \Pterodactyl\Exceptions\Service\Allocation\InvalidPortMappingException
* @throws \Pterodactyl\Exceptions\Service\Allocation\PortOutOfRangeException
* @throws \Pterodactyl\Exceptions\Service\Allocation\TooManyPortsInRangeException
*/
protected function createNewAllocation(Server $server): Allocation
{
$start = config('pterodactyl.client_features.allocations.range_start', null);
$end = config('pterodactyl.client_features.allocations.range_end', null);
if (!$start || !$end) {
throw new NoAutoAllocationSpaceAvailableException;
}
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.
$ports = $server->node->allocations()
->where('ip', $server->allocation->ip)
->whereBetween('port', [$start, $end])
->pluck('port');
// Compute the difference of the range and the currently created ports, finding
// any port that does not already exist in the database. We will then use this
// 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;
}
// dd($available, array_rand($available));
// Pick a random port out of the remaining available ports.
/** @var int $port */
$port = $available[array_rand($available)];
$this->service->handle($server->node, [
'server_id' => $server->id,
'allocation_ip' => $server->allocation->ip,
'allocation_ports' => [$port],
]);
/** @var \Pterodactyl\Models\Allocation $allocation */
$allocation = $server->node->allocations()
->where('ip', $server->allocation->ip)
->where('port', $port)
->firstOrFail();
return $allocation;
}
}