Fix server deletion logic, and clean up suspend/unsuspend operations

This commit is contained in:
Dane Everitt 2017-04-17 20:16:05 -04:00
parent bdfab16af3
commit de923bbb83
No known key found for this signature in database
GPG key ID: EEA66103B3D71F53
5 changed files with 56 additions and 81 deletions

View file

@ -11,6 +11,12 @@ This project follows [Semantic Versioning](http://semver.org) guidelines.
* `[beta.2]` — Fixes exception in tasks when deleting a server. * `[beta.2]` — Fixes exception in tasks when deleting a server.
* `[beta.2]` — Fixes bug with Terarria and Voice servers reporting a `TypeError: Service is not a constructor` in the daemon due to a missing service configuration. * `[beta.2]` — Fixes bug with Terarria and Voice servers reporting a `TypeError: Service is not a constructor` in the daemon due to a missing service configuration.
### Changed
* Deleting a server safely now continues even if the daemon reports a `HTTP/404` missing server error (requires `Daemon@0.4.0-beta.2.1`)
### Added
* Server listing and view in Admin CP now shows the SFTP username/Docker container name.
## v0.6.0-beta.2 (Courageous Carniadactylus) ## v0.6.0-beta.2 (Courageous Carniadactylus)
### Fixed ### Fixed
* `[beta.1]` — Fixes task management ststem not running correctly. * `[beta.1]` — Fixes task management ststem not running correctly.

View file

@ -318,7 +318,7 @@ class ServerController extends Controller
} }
try { try {
$repo->$action($id); $repo->toggleAccess($id, ($action === 'unsuspend'));
return response('', 204); return response('', 204);
} catch (DisplayException $ex) { } catch (DisplayException $ex) {

View file

@ -367,7 +367,7 @@ class ServersController extends Controller
} }
try { try {
$repo->$action($id); $repo->toggleAccess($id, ($action === 'unsuspend'));
Alert::success('Server has been ' . $action . 'ed.'); Alert::success('Server has been ' . $action . 'ed.');
} catch (TransferException $ex) { } catch (TransferException $ex) {

View file

@ -333,6 +333,16 @@ class Server extends Model
return $this->hasMany(Database::class); return $this->hasMany(Database::class);
} }
/**
* Gets all downloads associated with a server.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function downloads()
{
return $this->hasMany(Download::class, 'server', 'id');
}
/** /**
* Gets the location of the server. * Gets the location of the server.
* *

View file

@ -29,6 +29,7 @@ use Crypt;
use Validator; use Validator;
use Pterodactyl\Models; use Pterodactyl\Models;
use Pterodactyl\Services\UuidService; use Pterodactyl\Services\UuidService;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Exception\TransferException; use GuzzleHttp\Exception\TransferException;
use Pterodactyl\Services\DeploymentService; use Pterodactyl\Services\DeploymentService;
use Pterodactyl\Exceptions\DisplayException; use Pterodactyl\Exceptions\DisplayException;
@ -722,6 +723,16 @@ class ServerRepository
'X-Access-Token' => $server->node->daemonSecret, 'X-Access-Token' => $server->node->daemonSecret,
'X-Access-Server' => $server->uuid, 'X-Access-Server' => $server->uuid,
])->request('DELETE', '/servers'); ])->request('DELETE', '/servers');
} catch (ClientException $ex) {
// Exception is thrown on 4XX HTTP errors, so catch and determine
// if we should continue, or if there is a permissions error.
//
// Daemon throws a 404 if the server doesn't exist, if that is returned
// continue with deletion, even if not a force deletion.
$response = $ex->getResponse();
if ($ex->getResponse()->getStatusCode() !== 404 && ! $force) {
throw new DisplayException($ex->getMessage());
}
} catch (TransferException $ex) { } catch (TransferException $ex) {
if (! $force) { if (! $force) {
throw new DisplayException($ex->getMessage()); throw new DisplayException($ex->getMessage());
@ -736,30 +747,26 @@ class ServerRepository
$item->save(); $item->save();
}); });
$server->variables->each(function ($item) { $server->variables->each->delete();
$item->delete();
$server->load('subusers.permissions');
$server->subusers->each(function ($subuser) {
$subuser->permissions->each(function ($permission) {
$perm->delete();
});
$subuser->delete();
}); });
foreach (Models\Subuser::with('permissions')->where('server_id', $server->id)->get() as &$subuser) { $server->downloads->each->delete();
foreach ($subuser->permissions as &$permission) { $server->tasks->each->delete();
$permission->delete();
}
$subuser->delete();
}
// Remove Downloads
Models\Download::where('server', $server->uuid)->delete();
// Clear Tasks
Models\Task::where('server_id', $server->id)->delete();
// Delete Databases // Delete Databases
// This is the one un-recoverable point where // This is the one un-recoverable point where
// transactions will not save us. // transactions will not save us.
$repository = new DatabaseRepository; $repository = new DatabaseRepository;
foreach (Models\Database::select('id')->where('server_id', $server->id)->get() as $database) { $server->databases->each(function ($item) {
$repository->drop($database->id); $repository->drop($item->id);
} });
// Fully delete the server. // Fully delete the server.
$server->delete(); $server->delete();
@ -786,71 +793,32 @@ class ServerRepository
} }
/** /**
* Suspends a server. * Suspends or unsuspends a server.
* *
* @param int $id * @param int $id
* @param bool $deleted * @param bool $unsuspend
* @return void * @return void
*/ */
public function suspend($id, $deleted = false) public function toggleAccess($id, $unsuspend = true)
{ {
$server = Models\Server::with('node')->findOrFail($id); $server = Models\Server::with('node')->findOrFail($id);
DB::beginTransaction(); DB::transaction(function () use ($server, $unsuspend) {
if (
try { (! $unsuspend && $server->suspended) ||
($unsuspend && ! $server->suspended)
// Already suspended, no need to make more requests. ) {
if ($server->suspended) {
return true; return true;
} }
$server->suspended = 1; $server->suspended = ! $unsuspend;
$server->save(); $server->save();
$server->node->guzzleClient([ $server->node->guzzleClient([
'X-Access-Token' => $server->node->daemonSecret, 'X-Access-Token' => $server->node->daemonSecret,
'X-Access-Server' => $server->uuid, 'X-Access-Server' => $server->uuid,
])->request('POST', '/server/suspend'); ])->request('POST', ($unsuspend) ? '/server/unsuspend' : '/server/suspend');
});
return DB::commit();
} catch (\Exception $ex) {
DB::rollBack();
throw $ex;
}
}
/**
* Unsuspends a server.
*
* @param int $id
* @return void
*/
public function unsuspend($id)
{
$server = Models\Server::with('node')->findOrFail($id);
DB::beginTransaction();
try {
// Already unsuspended, no need to make more requests.
if ($server->suspended === 0) {
return true;
}
$server->suspended = 0;
$server->save();
$server->node->guzzleClient([
'X-Access-Token' => $server->node->daemonSecret,
'X-Access-Server' => $server->uuid,
])->request('POST', '/server/unsuspend');
return DB::commit();
} catch (\Exception $ex) {
DB::rollBack();
throw $ex;
}
} }
/** /**
@ -874,10 +842,8 @@ class ServerRepository
throw new DisplayValidationException(json_encode($validator->errors())); throw new DisplayValidationException(json_encode($validator->errors()));
} }
DB::beginTransaction(); DB::transaction(function () use ($password, $server) {
$server->sftp_password = Crypt::encrypt($password); $server->sftp_password = Crypt::encrypt($password);
try {
$server->save(); $server->save();
$server->node->guzzleClient([ $server->node->guzzleClient([
@ -886,13 +852,6 @@ class ServerRepository
])->request('POST', '/server/password', [ ])->request('POST', '/server/password', [
'json' => ['password' => $password], 'json' => ['password' => $password],
]); ]);
});
DB::commit();
return true;
} catch (\Exception $ex) {
DB::rollBack();
throw $ex;
}
} }
} }