1
1
mirror of https://github.com/pterodactyl/panel.git synced 2024-11-26 02:52:30 +01:00

Merge pull request #75 from Pterodactyl/features/suspension

Add server suspension, closes #73
This commit is contained in:
Dane Everitt 2016-09-01 21:22:51 -04:00 committed by GitHub
commit 8c40f647d3
13 changed files with 260 additions and 33 deletions

View File

@ -67,7 +67,7 @@ class RunTasks extends Command
*/
public function handle()
{
$tasks = Models\Task::where('queued', 0)->where('active', 1)->where('next_run', '<=', (Carbon::now())->toAtomString())->get();
$tasks = Models\Task::where('queued', 0)->where('suspended', 0)->where('next_run', '<=', (Carbon::now())->toAtomString())->get();
$this->info(sprintf('Preparing to queue %d tasks.', count($tasks)));
$bar = $this->output->createProgressBar(count($tasks));

View File

@ -424,4 +424,42 @@ class ServersController extends Controller
])->withInput();
}
public function postSuspendServer(Request $request, $id)
{
try {
$repo = new ServerRepository;
$repo->suspend($id);
Alert::success('Server has been suspended on the system. All running processes have been stopped and will not be startable until it is un-suspended.');
} catch (\Pterodactyl\Exceptions\DisplayException $e) {
Alert::danger($e->getMessage())->flash();
} catch(\Exception $e) {
Log::error($e);
Alert::danger('An unhandled exception occured while attemping to suspend this server. Please try again.')->flash();
} finally {
return redirect()->route('admin.servers.view', [
'id' => $id,
'tab' => 'tab_manage'
]);
}
}
public function postUnsuspendServer(Request $request, $id)
{
try {
$repo = new ServerRepository;
$repo->unsuspend($id);
Alert::success('Server has been unsuspended on the system. Access has been re-enabled.');
} catch (\Pterodactyl\Exceptions\DisplayException $e) {
Alert::danger($e->getMessage())->flash();
} catch(\Exception $e) {
Log::error($e);
Alert::danger('An unhandled exception occured while attemping to unsuspend this server. Please try again.')->flash();
} finally {
return redirect()->route('admin.servers.view', [
'id' => $id,
'tab' => 'tab_manage'
]);
}
}
}

View File

@ -69,7 +69,6 @@ class UserController extends Controller
->join('nodes', 'servers.node', '=', 'nodes.id')
->join('locations', 'nodes.location', '=', 'locations.id')
->where('owner', $id)
->where('active', 1)
->get(),
]);
}

View File

@ -46,11 +46,15 @@ class CheckServer
$server = Server::getByUUID($request->route()->server);
if (!$server) {
return response()->view('errors.403', [], 403);
return response()->view('errors.404', [], 404);
}
if ($server->suspended === 1) {
return response()->view('errors.suspended', [], 403);
}
if ($server->installed !== 1) {
return response()->view('errors.installing', [], 503);
return response()->view('errors.installing', [], 403);
}
return $next($request);

View File

@ -129,21 +129,21 @@ class AdminRoutes {
]);
// Assorted Page Helpers
$router->post('/new/get-nodes', [
'uses' => 'Admin\ServersController@postNewServerGetNodes'
]);
$router->post('/new/get-nodes', [
'uses' => 'Admin\ServersController@postNewServerGetNodes'
]);
$router->post('/new/get-ips', [
'uses' => 'Admin\ServersController@postNewServerGetIps'
]);
$router->post('/new/get-ips', [
'uses' => 'Admin\ServersController@postNewServerGetIps'
]);
$router->post('/new/service-options', [
'uses' => 'Admin\ServersController@postNewServerServiceOptions'
]);
$router->post('/new/service-options', [
'uses' => 'Admin\ServersController@postNewServerServiceOptions'
]);
$router->post('/new/service-variables', [
'uses' => 'Admin\ServersController@postNewServerServiceVariables'
]);
$router->post('/new/service-variables', [
'uses' => 'Admin\ServersController@postNewServerServiceVariables'
]);
// End Assorted Page Helpers
// View Specific Server
@ -179,6 +179,16 @@ class AdminRoutes {
'uses' => 'Admin\ServersController@postUpdateServerUpdateBuild'
]);
// Suspend Server
$router->post('/view/{id}/suspend', [
'uses' => 'Admin\ServersController@postSuspendServer'
]);
// Unsuspend Server
$router->post('/view/{id}/unsuspend', [
'uses' => 'Admin\ServersController@postUnsuspendServer'
]);
// Change Install Status
$router->post('/view/{id}/installed', [
'uses' => 'Admin\ServersController@postToggleInstall'

View File

@ -59,7 +59,7 @@ class Server extends Model
*/
protected $casts = [
'node' => 'integer',
'active' => 'integer',
'suspended' => 'integer',
'owner' => 'integer',
'memory' => 'integer',
'swap' => 'integer',
@ -117,7 +117,7 @@ class Server extends Model
/**
* Returns array of all servers owned by the logged in user.
* Returns all active servers if user is a root admin.
* Returns all users servers if user is a root admin.
*
* @return \Illuminate\Database\Eloquent\Collection
*/
@ -132,8 +132,7 @@ class Server extends Model
'allocations.port'
)->join('nodes', 'servers.node', '=', 'nodes.id')
->join('locations', 'nodes.location', '=', 'locations.id')
->join('allocations', 'servers.allocation', '=', 'allocations.id')
->where('active', 1);
->join('allocations', 'servers.allocation', '=', 'allocations.id');
if (self::$user->root_admin !== 1) {
$query->whereIn('servers.id', Subuser::accessServers());
@ -164,7 +163,7 @@ class Server extends Model
$query = self::select('servers.*', 'services.file as a_serviceFile')
->join('services', 'services.id', '=', 'servers.service')
->where('uuidShort', $uuid)->where('active', 1);
->where('uuidShort', $uuid);
if (self::$user->root_admin !== 1) {
$query->whereIn('servers.id', Subuser::accessServers());

View File

@ -205,7 +205,7 @@ class ServerRepository
'uuidShort' => $uuid->generateShort('servers', 'uuidShort', $generatedUuid),
'node' => $data['node'],
'name' => $data['name'],
'active' => 1,
'suspended' => 0,
'owner' => $user->id,
'memory' => $data['memory'],
'swap' => $data['swap'],
@ -728,9 +728,31 @@ class ServerRepository
*/
public function suspend($id)
{
// @TODO: Implement logic; not doing it now since that is outside of the
// scope of this API brance.
return true;
$server = Models\Server::findOrFail($id);
$node = Models\Node::findOrFail($server->node);
DB::beginTransaction();
try {
$server->suspended = 1;
$server->save();
$client = Models\Node::guzzleRequest($server->node);
$client->request('POST', '/server/suspend', [
'headers' => [
'X-Access-Token' => $node->daemonSecret,
'X-Access-Server' => $server->uuid
]
]);
return DB::commit();
} catch (\GuzzleHttp\Exception\TransferException $ex) {
DB::rollBack();
throw new DisplayException('An error occured while attempting to suspend this server.', $ex);
} catch (\Exception $ex) {
DB::rollBack();
throw $ex;
}
}
/**
@ -740,9 +762,31 @@ class ServerRepository
*/
public function unsuspend($id)
{
// @TODO: Implement logic; not doing it now since that is outside of the
// scope of this API brance.
return true;
$server = Models\Server::findOrFail($id);
$node = Models\Node::findOrFail($server->node);
DB::beginTransaction();
try {
$server->suspended = 0;
$server->save();
$client = Models\Node::guzzleRequest($server->node);
$client->request('POST', '/server/unsuspend', [
'headers' => [
'X-Access-Token' => $node->daemonSecret,
'X-Access-Server' => $server->uuid
]
]);
return DB::commit();
} catch (\GuzzleHttp\Exception\TransferException $ex) {
DB::rollBack();
throw new DisplayException('An error occured while attempting to un-suspend this server.', $ex);
} catch (\Exception $ex) {
DB::rollBack();
throw $ex;
}
}
public function updateSFTPPassword($id, $password)

View File

@ -0,0 +1,31 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddSuspensionForServers extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('servers', function (Blueprint $table) {
$table->tinyInteger('suspended')->unsigned()->default(0)->after('active');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('servers', function (Blueprint $table) {
$table->dropColumn('suspended');
});
}
}

View File

@ -0,0 +1,31 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class RemoveActiveColumn extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('servers', function (Blueprint $table) {
$table->dropColumn('active');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('servers', function (Blueprint $table) {
$table->tinyInteger('active')->after('name')->unsigned()->default(0);
});
}
}

View File

@ -42,8 +42,8 @@
</thead>
<tbody>
@foreach ($servers as $server)
<tr class="dynUpdate @if($server->active !== 1)active @endif" id="{{ $server->uuidShort }}">
<td><a href="/admin/servers/view/{{ $server->id }}">{{ $server->name }}</td>
<tr class="dynUpdate @if($server->suspended === 1)warning @endif" id="{{ $server->uuidShort }}">
<td><a href="/admin/servers/view/{{ $server->id }}">{{ $server->name }}</a>@if($server->suspended === 1) <span class="label label-warning">Suspended</span>@endif</td>
<td><a href="/admin/users/view/{{ $server->owner }}">{{ $server->a_ownerEmail }}</a></td>
<td class="hidden-xs"><a href="/admin/nodes/view/{{ $server->node }}">{{ $server->a_nodeName }}</a></td>
<td><code>{{ $server->ip_alias }}:{{ $server->port }}</code> @if($server->ip !== $server->ip_alias)<span class="label label-default">alias</span>@endif</td>

View File

@ -30,6 +30,11 @@
<li><a href="/admin/servers">Servers</a></li>
<li class="active">{{ $server->name }} ({{ $server->uuidShort}})</li>
</ul>
@if($server->suspended === 1)
<div class="alert alert-warning">
This server is suspended and has no user access. Processes cannot be started and files cannot be modified. All API access is disabled unless using a master token.
</div>
@endif
@if($server->installed === 0)
<div class="alert alert-warning">
This server is still running through the install process and is not avaliable for use just yet. This message will disappear once this process is completed.
@ -89,7 +94,7 @@
</tr>
<tr>
<td><abbr title="Out of Memory">OOM</abbr> Killer</td>
<td>{!! ($server->oom_disabled === 0) ? '<span class="label label-success">enabled</span>' : '<span class="label label-default">disabled</span>' !!}</td>
<td>{!! ($server->oom_disabled === 0) ? '<span class="label label-success">Enabled</span>' : '<span class="label label-default">Disabled</span>' !!}</td>
</tr>
<tr>
<td>Disk Space</td>
@ -121,6 +126,10 @@
<td>Installed</td>
<td>{!! ($server->installed === 1) ? '<span class="label label-success">Yes</span>' : '<span class="label label-danger">No</span>' !!}</td>
</tr>
<tr>
<td>Suspended</td>
<td>{!! ($server->suspended === 1) ? '<span class="label label-warning">Suspended</span>' : '<span class="label label-success">No</span>' !!}</td>
</tr>
</tbody>
</table>
</div>
@ -437,6 +446,32 @@
</div>
</div>
@endif
<div class="panel-heading" style="border-top: 1px solid #ddd;"></div>
<div class="panel-body">
<div class="row">
@if($server->suspended === 0)
<div class="col-md-4 text-center">
<form action="/admin/servers/view/{{ $server->id }}/suspend" method="POST">
{!! csrf_field() !!}
<button type="submit" class="btn btn-sm btn-warning">Suspend Server</button>
</form>
</div>
<div class="col-md-8">
<p>This will suspend the server, stop any running processes, and immediately block the user from being able to access their files or otherwise manage the server through the panel or API.</p>
</div>
@else
<div class="col-md-4 text-center">
<form action="/admin/servers/view/{{ $server->id }}/unsuspend" method="POST">
{!! csrf_field() !!}
<button type="submit" class="btn btn-sm btn-success">Unsuspend Server</button>
</form>
</div>
<div class="col-md-8">
<p>This will unsuspend the server and restore normal user access.</p>
</div>
@endif
</div>
</div>
</div>
</div>
@endif

View File

@ -47,7 +47,7 @@
</thead>
<tbody>
@foreach ($servers as $server)
<tr class="dynUpdate" data-server="{{ $server->uuidShort }}">
<tr class="dynUpdate @if($server->suspended === 1)warning @endif" data-server="{{ $server->uuidShort }}">
@if (Auth::user()->root_admin == 1)
<td style="width:26px;">
@if ($server->owner === Auth::user()->id)
@ -63,7 +63,7 @@
<td class="text-center" data-action="players">--</td>
<td class="text-center"><span data-action="memory">--</span> / {{ $server->memory === 0 ? '&infin;' : $server->memory }} MB</td>
<td class="text-center"><span data-action="cpu" data-cpumax="{{ $server->cpu }}">--</span> %</td>
<td class="text-center" data-action="status">--</td>
<td class="text-center" data-action="status">@if($server->suspended === 1)<span class="label label-warning">Suspended</span>@else--@endif</td>
</tr>
@endforeach
</tbody>

View File

@ -0,0 +1,36 @@
{{-- Copyright (c) 2015 - 2016 Dane Everitt <dane@daneeveritt.com> --}}
{{-- Permission is hereby granted, free of charge, to any person obtaining a copy --}}
{{-- of this software and associated documentation files (the "Software"), to deal --}}
{{-- in the Software without restriction, including without limitation the rights --}}
{{-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --}}
{{-- copies of the Software, and to permit persons to whom the Software is --}}
{{-- furnished to do so, subject to the following conditions: --}}
{{-- The above copyright notice and this permission notice shall be included in all --}}
{{-- copies or substantial portions of the Software. --}}
{{-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --}}
{{-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --}}
{{-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --}}
{{-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --}}
{{-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --}}
{{-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --}}
{{-- SOFTWARE. --}}
@extends('layouts.master')
@section('title', '503: Server Temporarily Unavaliable')
@section('content')
<div class="col-md-12">
<div class="panel panel-danger">
<div class="panel-heading">
<h3 class="panel-title">HTTP 403: Access Denied</h3>
</div>
<div class="panel-body">
<p style="margin-bottom:0;">This server has been suspended and cannot be accessed.</p>
</div>
</div>
<p style="text-align:center;"><a href="{{ URL::previous() }}">Take me back</a> or <a href="/">go home</a>.</p>
</div>
@endsection