Skip to content

Commit f842aae

Browse files
committed
Add build modification settings, fix exception handling to log to file
1 parent ace70a3 commit f842aae

File tree

15 files changed

+428
-51
lines changed

15 files changed

+428
-51
lines changed

app/Contracts/Repository/RepositoryInterface.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ public function create(array $fields, $validate = true);
8383
/**
8484
* Delete a given record from the database.
8585
*
86-
* @param int $id
86+
* @param int $id
8787
* @return bool|null
8888
*/
8989
public function delete($id);
@@ -130,6 +130,17 @@ public function findFirstWhere(array $fields);
130130
*/
131131
public function update($id, array $fields, $validate = true, $force = false);
132132

133+
/**
134+
* Perform a mass update where matching records are updated using whereIn.
135+
* This does not perform any model data validation.
136+
*
137+
* @param string $column
138+
* @param array $values
139+
* @param array $fields
140+
* @return int
141+
*/
142+
public function updateWhereIn($column, array $values, array $fields);
143+
133144
/**
134145
* Update multiple records matching the passed clauses.
135146
*

app/Http/Controllers/Admin/ServersController.php

Lines changed: 19 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
use Pterodactyl\Repositories\Eloquent\DatabaseHostRepository;
4545
use Pterodactyl\Exceptions\DisplayValidationException;
4646
use Pterodactyl\Services\Database\CreationService as DatabaseCreationService;
47+
use Pterodactyl\Services\Servers\BuildModificationService;
4748
use Pterodactyl\Services\Servers\ContainerRebuildService;
4849
use Pterodactyl\Services\Servers\CreationService;
4950
use Pterodactyl\Services\Servers\DetailsModificationService;
@@ -62,6 +63,11 @@ class ServersController extends Controller
6263
*/
6364
protected $allocationRepository;
6465

66+
/**
67+
* @var \Pterodactyl\Services\Servers\BuildModificationService
68+
*/
69+
protected $buildModificationService;
70+
6571
/**
6672
* @var \Illuminate\Contracts\Config\Repository
6773
*/
@@ -132,6 +138,7 @@ class ServersController extends Controller
132138
*
133139
* @param \Prologue\Alerts\AlertsMessageBag $alert
134140
* @param \Pterodactyl\Contracts\Repository\AllocationRepositoryInterface $allocationRepository
141+
* @param \Pterodactyl\Services\Servers\BuildModificationService $buildModificationService
135142
* @param \Illuminate\Contracts\Config\Repository $config
136143
* @param \Pterodactyl\Services\Servers\ContainerRebuildService $containerRebuildService
137144
* @param \Pterodactyl\Services\Servers\CreationService $service
@@ -149,6 +156,7 @@ class ServersController extends Controller
149156
public function __construct(
150157
AlertsMessageBag $alert,
151158
AllocationRepositoryInterface $allocationRepository,
159+
BuildModificationService $buildModificationService,
152160
ConfigRepository $config,
153161
ContainerRebuildService $containerRebuildService,
154162
CreationService $service,
@@ -165,6 +173,7 @@ public function __construct(
165173
) {
166174
$this->alert = $alert;
167175
$this->allocationRepository = $allocationRepository;
176+
$this->buildModificationService = $buildModificationService;
168177
$this->config = $config;
169178
$this->containerRebuildService = $containerRebuildService;
170179
$this->databaseCreationService = $databaseCreationService;
@@ -490,39 +499,22 @@ public function manageSuspension(Request $request, Server $server)
490499
/**
491500
* Update the build configuration for a server.
492501
*
493-
* @param \Illuminate\Http\Request $request
494-
* @param int $id
502+
* @param \Illuminate\Http\Request $request
503+
* @param \Pterodactyl\Models\Server $server
495504
* @return \Illuminate\Http\RedirectResponse
505+
* @throws \Pterodactyl\Exceptions\DisplayException
506+
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
507+
* @internal param int $id
496508
*/
497-
public function updateBuild(Request $request, $id)
509+
public function updateBuild(Request $request, Server $server)
498510
{
499-
$repo = new ServerRepository;
500-
501-
try {
502-
$repo->changeBuild($id, $request->intersect([
511+
$this->buildModificationService->handle($server, $request->intersect([
503512
'allocation_id', 'add_allocations', 'remove_allocations',
504513
'memory', 'swap', 'io', 'cpu', 'disk',
505-
]));
506-
507-
Alert::success('Server details were successfully updated.')->flash();
508-
} catch (DisplayValidationException $ex) {
509-
return redirect()
510-
->route('admin.servers.view.build', $id)
511-
->withErrors(json_decode($ex->getMessage()))
512-
->withInput();
513-
} catch (DisplayException $ex) {
514-
Alert::danger($ex->getMessage())->flash();
515-
} catch (TransferException $ex) {
516-
Log::warning($ex);
517-
Alert::danger('A TransferException was encountered while trying to contact the daemon, please ensure it is online and accessible. This error has been logged.')
518-
->flash();
519-
} catch (\Exception $ex) {
520-
Log::error($ex);
521-
Alert::danger('An unhandled exception occured while attemping to add this server. This error has been logged.')
522-
->flash();
523-
}
514+
]));
515+
$this->alert->success(trans('admin/server.alerts.build_updated'))->flash();
524516

525-
return redirect()->route('admin.servers.view.build', $id);
517+
return redirect()->route('admin.servers.view.build', $server->id);
526518
}
527519

528520
/**

app/Repositories/Eloquent/EloquentRepository.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,14 @@ public function update($id, array $fields, $validate = true, $force = false)
145145
return ($this->withFresh) ? $instance->fresh() : $saved;
146146
}
147147

148+
/**
149+
* {@inheritdoc}
150+
*/
151+
public function updateWhereIn($column, array $values, array $fields)
152+
{
153+
return $this->getBuilder()->whereIn($column, $values)->update($fields);
154+
}
155+
148156
/**
149157
* {@inheritdoc}
150158
*/
Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
<?php
2+
/*
3+
* Pterodactyl - Panel
4+
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*/
24+
25+
namespace Pterodactyl\Services\Servers;
26+
27+
use GuzzleHttp\Exception\RequestException;
28+
use Illuminate\Database\ConnectionInterface;
29+
use Illuminate\Log\Writer;
30+
use Pterodactyl\Contracts\Repository\AllocationRepositoryInterface;
31+
use Pterodactyl\Contracts\Repository\Daemon\ServerRepositoryInterface as DaemonServerRepositoryInterface;
32+
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
33+
use Pterodactyl\Exceptions\DisplayException;
34+
use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
35+
use Pterodactyl\Models\Server;
36+
37+
class BuildModificationService
38+
{
39+
/**
40+
* @var \Pterodactyl\Contracts\Repository\AllocationRepositoryInterface
41+
*/
42+
protected $allocationRepository;
43+
44+
/**
45+
* @var array
46+
*/
47+
protected $build = [];
48+
49+
/**
50+
* @var \Pterodactyl\Contracts\Repository\Daemon\ServerRepositoryInterface
51+
*/
52+
protected $daemonServerRepository;
53+
54+
/**
55+
* @var \Illuminate\Database\ConnectionInterface
56+
*/
57+
protected $database;
58+
59+
/**
60+
* @var null|int
61+
*/
62+
protected $firstAllocationId = null;
63+
64+
/**
65+
* @var \Pterodactyl\Contracts\Repository\ServerRepositoryInterface
66+
*/
67+
protected $repository;
68+
69+
/**
70+
* @var \Illuminate\Log\Writer
71+
*/
72+
protected $writer;
73+
74+
/**
75+
* BuildModificationService constructor.
76+
*
77+
* @param \Pterodactyl\Contracts\Repository\AllocationRepositoryInterface $allocationRepository
78+
* @param \Illuminate\Database\ConnectionInterface $database
79+
* @param \Pterodactyl\Contracts\Repository\Daemon\ServerRepositoryInterface $daemonServerRepository
80+
* @param \Pterodactyl\Contracts\Repository\ServerRepositoryInterface $repository
81+
* @param \Illuminate\Log\Writer $writer
82+
*/
83+
public function __construct(
84+
AllocationRepositoryInterface $allocationRepository,
85+
ConnectionInterface $database,
86+
DaemonServerRepositoryInterface $daemonServerRepository,
87+
ServerRepositoryInterface $repository,
88+
Writer $writer
89+
) {
90+
$this->allocationRepository = $allocationRepository;
91+
$this->daemonServerRepository = $daemonServerRepository;
92+
$this->database = $database;
93+
$this->repository = $repository;
94+
$this->writer = $writer;
95+
}
96+
97+
/**
98+
* Set build array parameters.
99+
*
100+
* @param string $key
101+
* @param mixed $value
102+
*/
103+
public function setBuild($key, $value)
104+
{
105+
$this->build[$key] = $value;
106+
}
107+
108+
/**
109+
* Return the build array.
110+
*
111+
* @return array
112+
*/
113+
public function getBuild()
114+
{
115+
return $this->build;
116+
}
117+
118+
/**
119+
* Change the build details for a specified server.
120+
*
121+
* @param int|\Pterodactyl\Models\Server $server
122+
* @param array $data
123+
*
124+
* @throws \Pterodactyl\Exceptions\DisplayException
125+
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
126+
*/
127+
public function handle($server, array $data)
128+
{
129+
if (! $server instanceof Server) {
130+
$server = $this->repository->find($server);
131+
}
132+
133+
$data['allocation_id'] = array_get($data, 'allocation_id', $server->allocation_id);
134+
$this->database->beginTransaction();
135+
136+
$this->setBuild('memory', (int) array_get($data, 'memory', $server->memory));
137+
$this->setBuild('swap', (int) array_get($data, 'swap', $server->swap));
138+
$this->setBuild('io', (int) array_get($data, 'io', $server->io));
139+
$this->setBuild('cpu', (int) array_get($data, 'cpu', $server->cpu));
140+
$this->setBuild('disk', (int) array_get($data, 'disk', $server->disk));
141+
142+
$this->processAllocations($server, $data);
143+
$allocations = $this->allocationRepository->findWhere([
144+
['server_id', '=', $server->id],
145+
]);
146+
147+
if (isset($data['allocation_id']) && $data['allocation_id'] != $server->allocation_id) {
148+
try {
149+
$allocation = $this->allocationRepository->findFirstWhere([
150+
['id', '=', $data['allocation_id']],
151+
['server_id', '=', $server->id],
152+
]);
153+
} catch (RecordNotFoundException $ex) {
154+
throw new DisplayException(trans('admin/server.exceptions.default_allocation_not_found'));
155+
}
156+
157+
$this->setBuild('default', ['ip' => $allocation->ip, 'port' => $allocation->port]);
158+
}
159+
160+
$this->setBuild('ports|overwrite', $allocations->groupBy('ip')->map(function ($item) {
161+
return $item->pluck('port');
162+
})->toArray());
163+
164+
try {
165+
$this->daemonServerRepository->setNode($server->node_id)->setAccessServer($server->uuid)->update([
166+
'build' => $this->getBuild(),
167+
]);
168+
169+
$this->database->commit();
170+
} catch (RequestException $exception) {
171+
$response = $exception->getResponse();
172+
$this->writer->warning($exception);
173+
174+
throw new DisplayException(trans('admin/server.exceptions.daemon_exception', [
175+
'code' => is_null($response) ? 'E_CONN_REFUSED' : $response->getStatusCode(),
176+
]));
177+
}
178+
}
179+
180+
/**
181+
* Process the allocations being assigned in the data and ensure they are available for a server.
182+
*
183+
* @param \Pterodactyl\Models\Server $server
184+
* @param array $data
185+
*
186+
* @throws \Pterodactyl\Exceptions\DisplayException
187+
*/
188+
public function processAllocations(Server $server, array &$data)
189+
{
190+
if (! array_key_exists('add_allocations', $data) && ! array_key_exists('remove_allocations', $data)) {
191+
return;
192+
}
193+
194+
// Loop through allocations to add.
195+
if (array_key_exists('add_allocations', $data) && ! empty($data['add_allocations'])) {
196+
$unassigned = $this->allocationRepository->findWhere([
197+
['server_id', '=', null],
198+
['node_id', '=', $server->node_id],
199+
])->pluck('id')->toArray();
200+
201+
foreach ($data['add_allocations'] as $allocation) {
202+
if (! in_array($allocation, $unassigned)) {
203+
continue;
204+
}
205+
206+
$this->firstAllocationId = $this->firstAllocationId ?? $allocation;
207+
$toUpdate[] = [$allocation];
208+
}
209+
210+
if (isset($toUpdate)) {
211+
$this->allocationRepository->updateWhereIn('id', $toUpdate, ['server_id' => $server->id]);
212+
unset($toUpdate);
213+
}
214+
}
215+
216+
// Loop through allocations to remove.
217+
if (array_key_exists('remove_allocations', $data) && ! empty($data['remove_allocations'])) {
218+
$assigned = $this->allocationRepository->findWhere([
219+
['server_id', '=', $server->id],
220+
])->pluck('id')->toArray();
221+
222+
foreach ($data['remove_allocations'] as $allocation) {
223+
if (! in_array($allocation, $assigned)) {
224+
continue;
225+
}
226+
227+
if ($allocation == $data['allocation_id']) {
228+
if (is_null($this->firstAllocationId)) {
229+
throw new DisplayException(trans('admin/server.exceptions.no_new_default_allocation'));
230+
}
231+
232+
$data['allocation_id'] = $this->firstAllocationId;
233+
}
234+
235+
$toUpdate[] = [$allocation];
236+
}
237+
238+
if (isset($toUpdate)) {
239+
$this->allocationRepository->updateWhereIn('id', $toUpdate, ['server_id' => null]);
240+
unset($toUpdate);
241+
}
242+
}
243+
}
244+
}

0 commit comments

Comments
 (0)