Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
pterodactyl
GitHub Repository: pterodactyl/panel
Path: blob/1.0-develop/app/Models/Node.php
14039 views
1
<?php
2
3
namespace Pterodactyl\Models;
4
5
use Illuminate\Support\Str;
6
use Symfony\Component\Yaml\Yaml;
7
use Illuminate\Container\Container;
8
use Illuminate\Notifications\Notifiable;
9
use Illuminate\Contracts\Encryption\Encrypter;
10
use Pterodactyl\Contracts\Models\Identifiable;
11
use Illuminate\Database\Eloquent\Relations\HasMany;
12
use Pterodactyl\Models\Traits\HasRealtimeIdentifier;
13
use Illuminate\Database\Eloquent\Relations\BelongsTo;
14
use Illuminate\Database\Eloquent\Factories\HasFactory;
15
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
16
17
/**
18
* @property int $id
19
* @property string $uuid
20
* @property bool $public
21
* @property string $name
22
* @property string|null $description
23
* @property int $location_id
24
* @property string $fqdn
25
* @property string $scheme
26
* @property bool $behind_proxy
27
* @property bool $maintenance_mode
28
* @property int $memory
29
* @property int $memory_overallocate
30
* @property int $disk
31
* @property int $disk_overallocate
32
* @property int $upload_size
33
* @property string $daemon_token_id
34
* @property string $daemon_token
35
* @property int $daemonListen
36
* @property int $daemonSFTP
37
* @property string $daemonBase
38
* @property \Carbon\Carbon $created_at
39
* @property \Carbon\Carbon $updated_at
40
* @property Location $location
41
* @property \Pterodactyl\Models\Mount[]|\Illuminate\Database\Eloquent\Collection $mounts
42
* @property \Pterodactyl\Models\Server[]|\Illuminate\Database\Eloquent\Collection $servers
43
* @property \Pterodactyl\Models\Allocation[]|\Illuminate\Database\Eloquent\Collection $allocations
44
*/
45
#[Attributes\Identifiable('node')]
46
class Node extends Model implements Identifiable
47
{
48
/** @use HasFactory<\Database\Factories\NodeFactory> */
49
use HasFactory;
50
use Notifiable;
51
use HasRealtimeIdentifier;
52
53
/**
54
* The resource name for this model when it is transformed into an
55
* API representation using fractal.
56
*/
57
public const RESOURCE_NAME = 'node';
58
59
public const DAEMON_TOKEN_ID_LENGTH = 16;
60
public const DAEMON_TOKEN_LENGTH = 64;
61
62
/**
63
* The table associated with the model.
64
*/
65
protected $table = 'nodes';
66
67
/**
68
* The attributes excluded from the model's JSON form.
69
*/
70
protected $hidden = ['daemon_token_id', 'daemon_token'];
71
72
/**
73
* Cast values to correct type.
74
*/
75
protected $casts = [
76
'location_id' => 'integer',
77
'memory' => 'integer',
78
'disk' => 'integer',
79
'daemonListen' => 'integer',
80
'daemonSFTP' => 'integer',
81
'behind_proxy' => 'boolean',
82
'public' => 'boolean',
83
'maintenance_mode' => 'boolean',
84
];
85
86
/**
87
* Fields that are mass assignable.
88
*/
89
protected $fillable = [
90
'public', 'name', 'location_id',
91
'description', 'fqdn', 'scheme', 'behind_proxy',
92
'memory', 'memory_overallocate', 'disk',
93
'disk_overallocate', 'upload_size', 'daemonBase',
94
'daemonSFTP', 'daemonListen',
95
'description', 'maintenance_mode',
96
];
97
98
public static array $validationRules = [
99
'name' => 'required|regex:/^([\w .-]{1,100})$/',
100
'description' => 'string|nullable',
101
'location_id' => 'required|exists:locations,id',
102
'public' => 'boolean',
103
'fqdn' => 'required|string',
104
'scheme' => 'required',
105
'behind_proxy' => 'boolean',
106
'memory' => 'required|numeric|min:1',
107
'memory_overallocate' => 'required|numeric|min:-1',
108
'disk' => 'required|numeric|min:1',
109
'disk_overallocate' => 'required|numeric|min:-1',
110
'daemonBase' => 'sometimes|required|regex:/^([\/][\d\w.\-\/]+)$/',
111
'daemonSFTP' => 'required|numeric|between:1,65535',
112
'daemonListen' => 'required|numeric|between:1,65535',
113
'maintenance_mode' => 'boolean',
114
'upload_size' => 'int|min:1',
115
];
116
117
/**
118
* Default values for specific columns that are generally not changed on base installs.
119
*/
120
protected $attributes = [
121
'public' => true,
122
'behind_proxy' => false,
123
'memory_overallocate' => 0,
124
'disk_overallocate' => 0,
125
'daemonBase' => '/var/lib/pterodactyl/volumes',
126
'daemonSFTP' => 2022,
127
'daemonListen' => 8080,
128
'maintenance_mode' => false,
129
];
130
131
/**
132
* Get the connection address to use when making calls to this node.
133
*/
134
public function getConnectionAddress(): string
135
{
136
return sprintf('%s://%s:%s', $this->scheme, $this->fqdn, $this->daemonListen);
137
}
138
139
/**
140
* Returns the configuration as an array.
141
*/
142
public function getConfiguration(): array
143
{
144
return [
145
'debug' => false,
146
'uuid' => $this->uuid,
147
'token_id' => $this->daemon_token_id,
148
'token' => Container::getInstance()->make(Encrypter::class)->decrypt($this->daemon_token),
149
'api' => [
150
'host' => '0.0.0.0',
151
'port' => $this->daemonListen,
152
'ssl' => [
153
'enabled' => (!$this->behind_proxy && $this->scheme === 'https'),
154
'cert' => '/etc/letsencrypt/live/' . Str::lower($this->fqdn) . '/fullchain.pem',
155
'key' => '/etc/letsencrypt/live/' . Str::lower($this->fqdn) . '/privkey.pem',
156
],
157
'upload_limit' => $this->upload_size,
158
],
159
'system' => [
160
'data' => $this->daemonBase,
161
'sftp' => [
162
'bind_port' => $this->daemonSFTP,
163
],
164
],
165
'allowed_mounts' => $this->mounts->pluck('source')->toArray(),
166
'remote' => route('index'),
167
];
168
}
169
170
/**
171
* Returns the configuration in Yaml format.
172
*/
173
public function getYamlConfiguration(): string
174
{
175
return Yaml::dump($this->getConfiguration(), 4, 2, Yaml::DUMP_EMPTY_ARRAY_AS_SEQUENCE);
176
}
177
178
/**
179
* Returns the configuration in JSON format.
180
*/
181
public function getJsonConfiguration(bool $pretty = false): string
182
{
183
return json_encode($this->getConfiguration(), $pretty ? JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT : JSON_UNESCAPED_SLASHES);
184
}
185
186
/**
187
* Helper function to return the decrypted key for a node.
188
*/
189
public function getDecryptedKey(): string
190
{
191
return (string) Container::getInstance()->make(Encrypter::class)->decrypt(
192
$this->daemon_token
193
);
194
}
195
196
public function isUnderMaintenance(): bool
197
{
198
return $this->maintenance_mode;
199
}
200
201
/**
202
* @return \Illuminate\Database\Eloquent\Relations\HasManyThrough<\Pterodactyl\Models\Mount, \Pterodactyl\Models\MountNode, $this>
203
*/
204
public function mounts(): HasManyThrough
205
{
206
return $this->hasManyThrough(Mount::class, MountNode::class, 'node_id', 'id', 'id', 'mount_id');
207
}
208
209
/**
210
* Gets the location associated with a node.
211
*
212
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo<\Pterodactyl\Models\Location, $this>
213
*/
214
public function location(): BelongsTo
215
{
216
return $this->belongsTo(Location::class);
217
}
218
219
/**
220
* Gets the servers associated with a node.
221
*
222
* @return \Illuminate\Database\Eloquent\Relations\HasMany<\Pterodactyl\Models\Server, $this>
223
*/
224
public function servers(): HasMany
225
{
226
return $this->hasMany(Server::class);
227
}
228
229
/**
230
* Gets the allocations associated with a node.
231
*
232
* @return \Illuminate\Database\Eloquent\Relations\HasMany<\Pterodactyl\Models\Allocation, $this>
233
*/
234
public function allocations(): HasMany
235
{
236
return $this->hasMany(Allocation::class);
237
}
238
239
/**
240
* Returns a boolean if the node is viable for an additional server to be placed on it.
241
*/
242
public function isViable(int $memory, int $disk): bool
243
{
244
$memoryLimit = $this->memory * (1 + ($this->memory_overallocate / 100));
245
$diskLimit = $this->disk * (1 + ($this->disk_overallocate / 100));
246
247
// @phpstan-ignore-next-line property.notFound, property.notFound
248
return ($this->sum_memory + $memory) <= $memoryLimit && ($this->sum_disk + $disk) <= $diskLimit;
249
}
250
}
251
252