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