Add initial support for viewing basic server details
Includes support for changing server name, owner, and daemon secret.
This commit is contained in:
parent
41652d7384
commit
2c054e7edc
6 changed files with 327 additions and 4 deletions
|
@ -4,6 +4,7 @@ namespace Pterodactyl\Http\Controllers\Admin;
|
||||||
|
|
||||||
use Alert;
|
use Alert;
|
||||||
use Debugbar;
|
use Debugbar;
|
||||||
|
use Log;
|
||||||
|
|
||||||
use Pterodactyl\Models;
|
use Pterodactyl\Models;
|
||||||
use Pterodactyl\Repositories\ServerRepository;
|
use Pterodactyl\Repositories\ServerRepository;
|
||||||
|
@ -49,7 +50,21 @@ class ServersController extends Controller
|
||||||
|
|
||||||
public function getView(Request $request, $id)
|
public function getView(Request $request, $id)
|
||||||
{
|
{
|
||||||
//
|
return view('admin.servers.view', [
|
||||||
|
'server' => Models\Server::select(
|
||||||
|
'servers.*',
|
||||||
|
'nodes.name as a_nodeName',
|
||||||
|
'users.email as a_ownerEmail',
|
||||||
|
'locations.long as a_locationName',
|
||||||
|
'services.name as a_serviceName',
|
||||||
|
'service_options.name as a_servceOptionName'
|
||||||
|
)->join('nodes', 'servers.node', '=', 'nodes.id')
|
||||||
|
->join('users', 'servers.owner', '=', 'users.id')
|
||||||
|
->join('locations', 'nodes.location', '=', 'locations.id')
|
||||||
|
->join('services', 'servers.service', '=', 'services.id')
|
||||||
|
->join('service_options', 'servers.option', '=', 'service_options.id')
|
||||||
|
->first()
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function postNewServer(Request $request)
|
public function postNewServer(Request $request)
|
||||||
|
@ -170,4 +185,44 @@ class ServersController extends Controller
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function postUpdateServerDetails(Request $request, $id)
|
||||||
|
{
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
$server = new ServerRepository;
|
||||||
|
$server->updateDetails($id, [
|
||||||
|
'owner' => $request->input('owner'),
|
||||||
|
'name' => $request->input('name'),
|
||||||
|
'reset_token' => ($request->input('reset_token', false) === 'on') ? true : false
|
||||||
|
]);
|
||||||
|
|
||||||
|
Alert::success('Server details were successfully updated.')->flash();
|
||||||
|
return redirect()->route('admin.servers.view', [
|
||||||
|
'id' => $id,
|
||||||
|
'tab' => 'tab_details'
|
||||||
|
]);
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
|
||||||
|
if ($e instanceof \Pterodactyl\Exceptions\DisplayValidationException) {
|
||||||
|
return redirect()->route('admin.servers.view', [
|
||||||
|
'id' => $id,
|
||||||
|
'tab' => 'tab_details'
|
||||||
|
])->withErrors(json_decode($e->getMessage()))->withInput();
|
||||||
|
} else if ($e instanceof \Pterodactyl\Exceptions\DisplayException) {
|
||||||
|
Alert::danger($e->getMessage())->flash();
|
||||||
|
} else {
|
||||||
|
Log::error($e);
|
||||||
|
Alert::danger('An unhandled exception occured while attemping to add this server. Please try again.')->flash();
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->route('admin.servers.view', [
|
||||||
|
'id' => $id,
|
||||||
|
'tab' => 'tab_details'
|
||||||
|
])->withInput();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,8 @@ class AdminRoutes {
|
||||||
$router->get('/new', [ 'as' => 'admin.servers.new', 'uses' => 'Admin\ServersController@getNew' ]);
|
$router->get('/new', [ 'as' => 'admin.servers.new', 'uses' => 'Admin\ServersController@getNew' ]);
|
||||||
$router->get('/view/{id}', [ 'as' => 'admin.servers.view', 'uses' => 'Admin\ServersController@getView' ]);
|
$router->get('/view/{id}', [ 'as' => 'admin.servers.view', 'uses' => 'Admin\ServersController@getView' ]);
|
||||||
|
|
||||||
|
$router->post('/view/{id}/details', [ 'uses' => 'Admin\ServersController@postUpdateServerDetails' ]);
|
||||||
|
|
||||||
$router->post('/new', [ 'uses' => 'Admin\ServersController@postNewServer']);
|
$router->post('/new', [ 'uses' => 'Admin\ServersController@postNewServer']);
|
||||||
$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' ]);
|
||||||
|
|
|
@ -5,6 +5,7 @@ namespace Pterodactyl\Repositories;
|
||||||
use DB;
|
use DB;
|
||||||
use Debugbar;
|
use Debugbar;
|
||||||
use Validator;
|
use Validator;
|
||||||
|
use Log;
|
||||||
|
|
||||||
use Pterodactyl\Models;
|
use Pterodactyl\Models;
|
||||||
use Pterodactyl\Services\UuidService;
|
use Pterodactyl\Services\UuidService;
|
||||||
|
@ -41,7 +42,8 @@ class ServerRepository
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a new server to the system.
|
* Adds a new server to the system.
|
||||||
* @param array $data An array of data descriptors for creating the server. These should align to the columns in the database.
|
* @param array $data An array of data descriptors for creating the server. These should align to the columns in the database.
|
||||||
|
* @return integer
|
||||||
*/
|
*/
|
||||||
public function create(array $data)
|
public function create(array $data)
|
||||||
{
|
{
|
||||||
|
@ -209,4 +211,104 @@ class ServerRepository
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [updateDetails description]
|
||||||
|
* @param integer $id
|
||||||
|
* @param array $data
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function updateDetails($id, array $data)
|
||||||
|
{
|
||||||
|
|
||||||
|
$uuid = new UuidService;
|
||||||
|
$resetDaemonKey = false;
|
||||||
|
|
||||||
|
// Validate Fields
|
||||||
|
$validator = Validator::make($data, [
|
||||||
|
'owner' => 'email|exists:users,email',
|
||||||
|
'name' => 'regex:([\w -]{4,35})'
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Run validator, throw catchable and displayable exception if it fails.
|
||||||
|
// Exception includes a JSON result of failed validation rules.
|
||||||
|
if ($validator->fails()) {
|
||||||
|
throw new DisplayValidationException($validator->errors());
|
||||||
|
}
|
||||||
|
|
||||||
|
DB::beginTransaction();
|
||||||
|
$server = Models\Server::findOrFail($id);
|
||||||
|
$owner = Models\User::findOrFail($server->owner);
|
||||||
|
|
||||||
|
// Update daemon secret if it was passed.
|
||||||
|
if ((isset($data['reset_token']) && $data['reset_token'] === true) || (isset($data['owner']) && $data['owner'] !== $owner->email)) {
|
||||||
|
$oldDaemonKey = $server->daemonSecret;
|
||||||
|
$server->daemonSecret = $uuid->generate('servers', 'daemonSecret');
|
||||||
|
$resetDaemonKey = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update Server Owner if it was passed.
|
||||||
|
if (isset($data['owner']) && $data['owner'] !== $owner->email) {
|
||||||
|
$newOwner = Models\User::select('id')->where('email', $data['owner'])->first();
|
||||||
|
$server->owner = $newOwner->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update Server Name if it was passed.
|
||||||
|
if (isset($data['name'])) {
|
||||||
|
$server->name = $data['name'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save our changes
|
||||||
|
$server->save();
|
||||||
|
|
||||||
|
// Do we need to update? If not, return successful.
|
||||||
|
if (!$resetDaemonKey) {
|
||||||
|
DB::commit();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we need to update do it here.
|
||||||
|
try {
|
||||||
|
|
||||||
|
$node = Models\Node::getByID($server->node);
|
||||||
|
$client = Models\Node::guzzleRequest($server->node);
|
||||||
|
|
||||||
|
$res = $client->request('PATCH', '/server', [
|
||||||
|
'headers' => [
|
||||||
|
'X-Access-Server' => $server->uuid,
|
||||||
|
'X-Access-Token' => $node->daemonSecret
|
||||||
|
],
|
||||||
|
'exceptions' => false,
|
||||||
|
'json' => [
|
||||||
|
'keys' => [
|
||||||
|
(string) $oldDaemonKey => [],
|
||||||
|
(string) $server->daemonSecret => [
|
||||||
|
's:get',
|
||||||
|
's:power',
|
||||||
|
's:console',
|
||||||
|
's:command',
|
||||||
|
's:files:get',
|
||||||
|
's:files:read',
|
||||||
|
's:files:post',
|
||||||
|
's:files:delete',
|
||||||
|
's:files:upload',
|
||||||
|
's:set-password'
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($res->getStatusCode() === 204) {
|
||||||
|
DB::commit();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
throw new DisplayException('Daemon returned a a non HTTP/204 error code. HTTP/' + $res->getStatusCode());
|
||||||
|
}
|
||||||
|
} catch (\Exception $ex) {
|
||||||
|
DB::rollback();
|
||||||
|
Log::error($ex);
|
||||||
|
throw new DisplayException('An error occured while attempting to update this server\'s information.');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,3 +74,6 @@ pre{display:block;padding:12px 12px;margin:0;font-size:12px;color:#c7254e;backgr
|
||||||
.close:hover {color:#000;opacity:0.5;}
|
.close:hover {color:#000;opacity:0.5;}
|
||||||
.filename {outline: none;width:450px;background: transparent;margin-left:-5px;padding:0;border: 0px;font-family: "Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif;font-weight: 250;line-height: 1.1;font-size: 19px;color: #aaa}
|
.filename {outline: none;width:450px;background: transparent;margin-left:-5px;padding:0;border: 0px;font-family: "Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif;font-weight: 250;line-height: 1.1;font-size: 19px;color: #aaa}
|
||||||
form .text-muted {margin: 0 0 -5.5px}
|
form .text-muted {margin: 0 0 -5.5px}
|
||||||
|
.tab-pane.active .panel.panel-default {border-top:0 !important}
|
||||||
|
.tabs_with_panel > li.active > a {background-color: #f5f5f5 !important}
|
||||||
|
.tabs_with_panel > li > a {background: transparent;}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
@extends('layouts.admin')
|
@extends('layouts.admin')
|
||||||
|
|
||||||
@section('title')
|
@section('title')
|
||||||
Server List
|
Create New Server
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
|
@ -43,7 +43,7 @@
|
||||||
<div class="form-group col-md-6">
|
<div class="form-group col-md-6">
|
||||||
<label for="owner" class="control-label">Owner Email</label>
|
<label for="owner" class="control-label">Owner Email</label>
|
||||||
<div>
|
<div>
|
||||||
<input type="text" autocomplete="off" name="owner" class="form-control" value="{{ old('owner') }}" />
|
<input type="text" autocomplete="off" name="owner" class="form-control" value="{{ old('owner', Input::get('email')) }}" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
161
resources/views/admin/servers/view.blade.php
Normal file
161
resources/views/admin/servers/view.blade.php
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
@extends('layouts.admin')
|
||||||
|
|
||||||
|
@section('title')
|
||||||
|
Managing Server: {{ $server->name }} ({{ $server->uuidShort}})
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<div class="col-md-9">
|
||||||
|
<ul class="breadcrumb">
|
||||||
|
<li><a href="/admin">Admin Control</a></li>
|
||||||
|
<li><a href="/admin/servers">Servers</a></li>
|
||||||
|
<li class="active">{{ $server->name }} ({{ $server->uuidShort}})</li>
|
||||||
|
</ul>
|
||||||
|
@if (count($errors) > 0)
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<strong>{{ trans('strings.whoops') }}!</strong> {{ trans('base.validation_error') }}<br><br>
|
||||||
|
<ul>
|
||||||
|
@foreach ($errors->all() as $error)
|
||||||
|
<li>{{ $error }}</li>
|
||||||
|
@endforeach
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
@foreach (Alert::getMessages() as $type => $messages)
|
||||||
|
@foreach ($messages as $message)
|
||||||
|
<div class="alert alert-{{ $type }} alert-dismissable" role="alert">
|
||||||
|
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
|
{!! $message !!}
|
||||||
|
</div>
|
||||||
|
@endforeach
|
||||||
|
@endforeach
|
||||||
|
<ul class="nav nav-tabs tabs_with_panel" id="config_tabs">
|
||||||
|
<li class="active"><a href="#tab_about" data-toggle="tab">About</a></li>
|
||||||
|
<li><a href="#tab_details" data-toggle="tab">Details</a></li>
|
||||||
|
<li><a href="#tab_build" data-toggle="tab">Build Configuration</a></li>
|
||||||
|
<li><a href="#tab_manage" data-toggle="tab">Manage</a></li>
|
||||||
|
</ul>
|
||||||
|
<div class="tab-content">
|
||||||
|
<div class="tab-pane active" id="tab_about">
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading"></div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<table class="table table-striped" style="margin-bottom: 0;">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>UUID</td>
|
||||||
|
<td>{{ $server->uuid }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Owner</td>
|
||||||
|
<td>{{ $server->a_ownerEmail }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Location</td>
|
||||||
|
<td>{{ $server->a_locationName }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Node</td>
|
||||||
|
<td>{{ $server->a_nodeName }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Service</td>
|
||||||
|
<td>{{ $server->a_serviceName }} :: {{ $server->a_servceOptionName }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Name</td>
|
||||||
|
<td>{{ $server->name }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Memory</td>
|
||||||
|
<td><code>{{ $server->memory }}MB</code> (Swap: {{ $server->swap }}MB) (OOM Killer: <strong>{{ ($server->oom_disabled === 0) ? 'enabled' : 'disabled' }}</strong>)</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Disk Space</td>
|
||||||
|
<td><code>{{ $server->disk }}MB</code> (Enforced: <strong>no</strong>)</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Block IO Weight</td>
|
||||||
|
<td><code>{{ $server->io }}</code></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>CPU Limit</td>
|
||||||
|
<td><code>{{ $server->cpu }}%</code></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Default Connection</td>
|
||||||
|
<td><code>{{ $server->ip }}:{{ $server->port }}</code></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Installed</td>
|
||||||
|
<td>{{ ($server->installed === 1) ? 'Yes' : 'No' }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="tab-pane" id="tab_details">
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading"></div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<form method="POST" action="/admin/servers/view/{{ $server->id }}/details">
|
||||||
|
<div class="form-group {{ $errors->has('name') ? 'has-error' : '' }}">
|
||||||
|
<label for="name" class="control-label">Server Name</label>
|
||||||
|
<div>
|
||||||
|
<input type="text" name="name" value="{{ old('name', $server->name) }}" class="form-control" />
|
||||||
|
<p class="text-muted"><small>Character limits: <code>a-zA-Z0-9_-</code> and <code>[Space]</code> (max 35 characters).</small></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group {{ $errors->has('owner') ? 'has-error' : '' }}">
|
||||||
|
<label for="name" class="control-label">Server Owner</label>
|
||||||
|
<div>
|
||||||
|
<input type="text" name="owner" value="{{ old('owner', $server->a_ownerEmail) }}" class="form-control" />
|
||||||
|
<p class="text-muted"><small>You can change the owner of this server by changing this field to an email matching another use on this system. If you do this a new daemon security token will be generated automatically.</small></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="name" class="control-label">Daemon Secret Token</label>
|
||||||
|
<div>
|
||||||
|
<input type="text" disabled value="{{ $server->daemonSecret }}" class="form-control" />
|
||||||
|
<p class="text-muted"><small>This token should not be shared with anyone as it has full control over this server.</small></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div>
|
||||||
|
<input type="checkbox" name="reset_token"/> Yes, Reset Daemon Token
|
||||||
|
<p class="text-muted"><small>Resetting this token will cause any requests using the old token to fail.</small></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
{!! csrf_field() !!}
|
||||||
|
<input type="submit" class="btn btn-sm btn-primary" value="Update Details" />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="tab-pane" id="tab_build">
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading"></div>
|
||||||
|
<div class="panel-body">
|
||||||
|
Build
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="tab-pane" id="tab_manage">
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading"></div>
|
||||||
|
<div class="panel-body">
|
||||||
|
Manage
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
$(document).ready(function () {
|
||||||
|
$('#sidebar_links').find("a[href='/admin/servers']").addClass('active');
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@endsection
|
Loading…
Reference in a new issue