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
125 lines (106 loc) · 4.78 KB
/
FindAssignableAllocationService.php
File metadata and controls
125 lines (106 loc) · 4.78 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
<?php
namespace Pterodactyl\Services\Allocations;
use Webmozart\Assert\Assert;
use Pterodactyl\Models\Server;
use Pterodactyl\Models\Allocation;
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;
}
// 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();
}
/**
* Create a new allocation on the server's node with a random port from the defined range
* 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.
*
* @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;
}
// 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 \Pterodactyl\Models\Allocation $allocation */
$allocation = $server->node->allocations()
->where('ip', $server->allocation->ip)
->where('port', $port)
->firstOrFail();
return $allocation;
}
}