Begin implementation of server admin view
Currently completed tabs: About, Details, Build Configuration
This commit is contained in:
parent
bbf9fd12ae
commit
fb21bf9282
6 changed files with 464 additions and 147 deletions
|
@ -149,71 +149,13 @@ class ServersController extends Controller
|
||||||
})->values();
|
})->values();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a JSON tree of all avaliable IPs and Ports on a given node.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function postNewServerGetIps(Request $request)
|
|
||||||
{
|
|
||||||
return Models\Allocation::select('id', 'ip')->where('node_id', $request->input('node'))->whereNull('server_id')->get()->unique('ip')->values()->all();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a JSON tree of all avaliable options for a given service.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function postNewServerServiceOption(Request $request)
|
|
||||||
{
|
|
||||||
if (! $request->input('service')) {
|
|
||||||
return response()->json([
|
|
||||||
'error' => 'Missing service in request.',
|
|
||||||
], 500);
|
|
||||||
}
|
|
||||||
|
|
||||||
$service = Models\Service::select('executable', 'startup')->where('id', $request->input('service'))->first();
|
|
||||||
|
|
||||||
return response()->json(Models\ServiceOption::select('id', 'name', 'docker_image')->where('service_id', $request->input('service'))->orderBy('name', 'asc')->get());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a JSON tree of all avaliable variables for a given service option.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function postNewServerOptionDetails(Request $request)
|
|
||||||
{
|
|
||||||
if (! $request->input('option')) {
|
|
||||||
return response()->json([
|
|
||||||
'error' => 'Missing option in request.',
|
|
||||||
], 500);
|
|
||||||
}
|
|
||||||
|
|
||||||
$option = Models\ServiceOption::with('variables')->with(['packs' => function ($query) {
|
|
||||||
$query->where('selectable', true);
|
|
||||||
}])->findOrFail($request->input('option'));
|
|
||||||
|
|
||||||
return response()->json([
|
|
||||||
'packs' => $option->packs,
|
|
||||||
'variables' => $option->variables,
|
|
||||||
'exec' => $option->display_executable,
|
|
||||||
'startup' => $option->display_startup,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function postUpdateServerDetails(Request $request, $id)
|
public function postUpdateServerDetails(Request $request, $id)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$server = new ServerRepository;
|
$server = new ServerRepository;
|
||||||
$server->updateDetails($id, [
|
$server->updateDetails($id, $request->intersect([
|
||||||
'owner' => $request->input('owner'),
|
'owner_id', 'name', 'reset_token'
|
||||||
'name' => $request->input('name'),
|
]));
|
||||||
'reset_token' => ($request->input('reset_token', false) === 'on') ? true : false,
|
|
||||||
]);
|
|
||||||
|
|
||||||
Alert::success('Server details were successfully updated.')->flash();
|
Alert::success('Server details were successfully updated.')->flash();
|
||||||
} catch (DisplayValidationException $ex) {
|
} catch (DisplayValidationException $ex) {
|
||||||
|
@ -238,7 +180,7 @@ class ServersController extends Controller
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$server = new ServerRepository;
|
$server = new ServerRepository;
|
||||||
$server->updateContainer($id, ['image' => $request->input('docker_image')]);
|
$server->updateContainer($id, $request->intersect('docker_image'));
|
||||||
Alert::success('Successfully updated this server\'s docker image.')->flash();
|
Alert::success('Successfully updated this server\'s docker image.')->flash();
|
||||||
} catch (DisplayValidationException $ex) {
|
} catch (DisplayValidationException $ex) {
|
||||||
return redirect()->route('admin.servers.view', [
|
return redirect()->route('admin.servers.view', [
|
||||||
|
@ -283,9 +225,9 @@ class ServersController extends Controller
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$server = new ServerRepository;
|
$server = new ServerRepository;
|
||||||
$server->changeBuild($id, $request->only([
|
$server->changeBuild($id, $request->intersect([
|
||||||
'default', 'add_additional',
|
'allocation_id', 'add_allocations',
|
||||||
'remove_additional', 'memory',
|
'remove_allocations', 'memory',
|
||||||
'swap', 'io', 'cpu',
|
'swap', 'io', 'cpu',
|
||||||
]));
|
]));
|
||||||
Alert::success('Server details were successfully updated.')->flash();
|
Alert::success('Server details were successfully updated.')->flash();
|
||||||
|
|
|
@ -140,22 +140,6 @@ class AdminRoutes
|
||||||
'uses' => 'Admin\ServersController@postNewServerGetNodes',
|
'uses' => 'Admin\ServersController@postNewServerGetNodes',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$router->post('/new/get-ips', [
|
|
||||||
'as' => 'admin.servers.new.get-ips',
|
|
||||||
'uses' => 'Admin\ServersController@postNewServerGetIps',
|
|
||||||
]);
|
|
||||||
|
|
||||||
$router->post('/new/service-options', [
|
|
||||||
'as' => 'admin.servers.new.service-options',
|
|
||||||
'uses' => 'Admin\ServersController@postNewServerServiceOption',
|
|
||||||
]);
|
|
||||||
|
|
||||||
$router->post('/new/option-details', [
|
|
||||||
'as' => 'admin.servers.new.option-details',
|
|
||||||
'uses' => 'Admin\ServersController@postNewServerOptionDetails',
|
|
||||||
]);
|
|
||||||
// End Assorted Page Helpers
|
|
||||||
|
|
||||||
// View Specific Server
|
// View Specific Server
|
||||||
$router->get('/view/{id}', [
|
$router->get('/view/{id}', [
|
||||||
'as' => 'admin.servers.view',
|
'as' => 'admin.servers.view',
|
||||||
|
@ -170,6 +154,7 @@ class AdminRoutes
|
||||||
|
|
||||||
// Change Server Details
|
// Change Server Details
|
||||||
$router->post('/view/{id}/details', [
|
$router->post('/view/{id}/details', [
|
||||||
|
'as' => 'admin.servers.view.details',
|
||||||
'uses' => 'Admin\ServersController@postUpdateServerDetails',
|
'uses' => 'Admin\ServersController@postUpdateServerDetails',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
|
@ -352,8 +352,9 @@ class ServerRepository
|
||||||
|
|
||||||
// Validate Fields
|
// Validate Fields
|
||||||
$validator = Validator::make($data, [
|
$validator = Validator::make($data, [
|
||||||
'owner' => 'email|exists:users,email',
|
'owner_id' => 'sometimes|required|numeric|exists:users,id',
|
||||||
'name' => 'regex:([\w .-]{1,200})',
|
'name' => 'sometimes|required|regex:([\w .-]{1,200})',
|
||||||
|
'reset_token' => 'sometimes|required|accepted'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Run validator, throw catchable and displayable exception if it fails.
|
// Run validator, throw catchable and displayable exception if it fails.
|
||||||
|
@ -368,16 +369,15 @@ class ServerRepository
|
||||||
$server = Models\Server::with('user')->findOrFail($id);
|
$server = Models\Server::with('user')->findOrFail($id);
|
||||||
|
|
||||||
// Update daemon secret if it was passed.
|
// Update daemon secret if it was passed.
|
||||||
if ((isset($data['reset_token']) && $data['reset_token'] === true) || (isset($data['owner']) && $data['owner'] !== $server->user->email)) {
|
if (isset($data['reset_token']) || (isset($data['owner_id']) && $data['owner_id'] !== $server->user->id)) {
|
||||||
$oldDaemonKey = $server->daemonSecret;
|
$oldDaemonKey = $server->daemonSecret;
|
||||||
$server->daemonSecret = $uuid->generate('servers', 'daemonSecret');
|
$server->daemonSecret = $uuid->generate('servers', 'daemonSecret');
|
||||||
$resetDaemonKey = true;
|
$resetDaemonKey = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update Server Owner if it was passed.
|
// Update Server Owner if it was passed.
|
||||||
if (isset($data['owner']) && $data['owner'] !== $server->user->email) {
|
if (isset($data['owner_id']) && $data['owner_id'] !== $server->user->id) {
|
||||||
$newOwner = Models\User::select('id')->where('email', $data['owner'])->first();
|
$server->owner_id = $data['owner_id'];
|
||||||
$server->owner_id = $newOwner->id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update Server Name if it was passed.
|
// Update Server Name if it was passed.
|
||||||
|
@ -431,7 +431,7 @@ class ServerRepository
|
||||||
public function updateContainer($id, array $data)
|
public function updateContainer($id, array $data)
|
||||||
{
|
{
|
||||||
$validator = Validator::make($data, [
|
$validator = Validator::make($data, [
|
||||||
'image' => 'required|string',
|
'docker_image' => 'required|string',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Run validator, throw catchable and displayable exception if it fails.
|
// Run validator, throw catchable and displayable exception if it fails.
|
||||||
|
@ -444,7 +444,7 @@ class ServerRepository
|
||||||
try {
|
try {
|
||||||
$server = Models\Server::findOrFail($id);
|
$server = Models\Server::findOrFail($id);
|
||||||
|
|
||||||
$server->image = $data['image'];
|
$server->image = $data['docker_image'];
|
||||||
$server->save();
|
$server->save();
|
||||||
|
|
||||||
$server->node->guzzleClient([
|
$server->node->guzzleClient([
|
||||||
|
@ -479,17 +479,14 @@ class ServerRepository
|
||||||
public function changeBuild($id, array $data)
|
public function changeBuild($id, array $data)
|
||||||
{
|
{
|
||||||
$validator = Validator::make($data, [
|
$validator = Validator::make($data, [
|
||||||
'default' => [
|
'allocation_id' => 'sometimes|required|exists:allocations,id',
|
||||||
'string',
|
'add_allocations' => 'sometimes|required|array',
|
||||||
'regex:/^(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))\.(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))\.(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))\.(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5])):(\d{1,5})$/',
|
'remove_allocations' => 'sometimes|required|array',
|
||||||
],
|
'memory' => 'sometimes|required|integer|min:0',
|
||||||
'add_additional' => 'nullable|array',
|
'swap' => 'sometimes|required|integer|min:-1',
|
||||||
'remove_additional' => 'nullable|array',
|
'io' => 'sometimes|required|integer|min:10|max:1000',
|
||||||
'memory' => 'integer|min:0',
|
'cpu' => 'sometimes|required|integer|min:0',
|
||||||
'swap' => 'integer|min:-1',
|
'disk' => 'sometimes|required|integer|min:0',
|
||||||
'io' => 'integer|min:10|max:1000',
|
|
||||||
'cpu' => 'integer|min:0',
|
|
||||||
'disk' => 'integer|min:0',
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Run validator, throw catchable and displayable exception if it fails.
|
// Run validator, throw catchable and displayable exception if it fails.
|
||||||
|
@ -503,43 +500,33 @@ class ServerRepository
|
||||||
try {
|
try {
|
||||||
$server = Models\Server::with('allocation', 'allocations')->findOrFail($id);
|
$server = Models\Server::with('allocation', 'allocations')->findOrFail($id);
|
||||||
$newBuild = [];
|
$newBuild = [];
|
||||||
|
$newAllocations = [];
|
||||||
|
|
||||||
if (isset($data['default'])) {
|
if (isset($data['allocation_id'])) {
|
||||||
list($ip, $port) = explode(':', $data['default']);
|
if ((int) $data['allocation_id'] !== $server->allocation_id) {
|
||||||
if ($ip !== $server->allocation->ip || (int) $port !== $server->allocation->port) {
|
$selection = $server->allocations->where('id', $data['allocation_id'])->first();
|
||||||
$selection = $server->allocations->where('ip', $ip)->where('port', $port)->first();
|
|
||||||
if (! $selection) {
|
if (! $selection) {
|
||||||
throw new DisplayException('The requested default connection (' . $ip . ':' . $port . ') is not allocated to this server.');
|
throw new DisplayException('The requested default connection is not allocated to this server.');
|
||||||
}
|
}
|
||||||
|
|
||||||
$server->allocation_id = $selection->id;
|
$server->allocation_id = $selection->id;
|
||||||
$newBuild['default'] = [
|
$newBuild['default'] = ['ip' => $selection->ip, 'port' => $selection->port];
|
||||||
'ip' => $ip,
|
|
||||||
'port' => (int) $port,
|
|
||||||
];
|
|
||||||
|
|
||||||
// Re-Run to keep updated for rest of function
|
|
||||||
$server->load('allocation');
|
$server->load('allocation');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$newPorts = false;
|
$newPorts = false;
|
||||||
// Remove Assignments
|
// Remove Assignments
|
||||||
if (isset($data['remove_additional'])) {
|
if (isset($data['remove_allocations'])) {
|
||||||
foreach ($data['remove_additional'] as $id => $combo) {
|
foreach ($data['remove_allocations'] as $allocation) {
|
||||||
list($ip, $port) = explode(':', $combo);
|
|
||||||
// Invalid, not worth killing the whole thing, we'll just skip over it.
|
|
||||||
if (! filter_var($ip, FILTER_VALIDATE_IP) || ! preg_match('/^(\d{1,5})$/', $port)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Can't remove the assigned IP/Port combo
|
// Can't remove the assigned IP/Port combo
|
||||||
if ($ip === $server->allocation->ip && (int) $port === (int) $server->allocation->port) {
|
if ((int) $allocation === $server->allocation_id) {
|
||||||
break;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$newPorts = true;
|
$newPorts = true;
|
||||||
$server->allocations->where('ip', $ip)->where('port', $port)->update([
|
Models\Allocation::where('id', $allocation)->where('server_id', $server->id)->update([
|
||||||
'server_id' => null,
|
'server_id' => null,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
@ -548,21 +535,15 @@ class ServerRepository
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add Assignments
|
// Add Assignments
|
||||||
if (isset($data['add_additional'])) {
|
if (isset($data['add_allocations'])) {
|
||||||
foreach ($data['add_additional'] as $id => $combo) {
|
foreach ($data['add_allocations'] as $allocation) {
|
||||||
list($ip, $port) = explode(':', $combo);
|
$model = Models\Allocation::where('id', $allocation)->whereNull('server_id')->first();
|
||||||
// Invalid, not worth killing the whole thing, we'll just skip over it.
|
if (! $model) {
|
||||||
if (! filter_var($ip, FILTER_VALIDATE_IP) || ! preg_match('/^(\d{1,5})$/', $port)) {
|
continue;
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't allow double port assignments
|
|
||||||
if ($server->allocations->where('port', $port)->count() !== 0) {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$newPorts = true;
|
$newPorts = true;
|
||||||
Models\Allocation::where('ip', $ip)->where('port', $port)->whereNull('server_id')->update([
|
$model->update([
|
||||||
'server_id' => $server->id,
|
'server_id' => $server->id,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
@ -570,18 +551,10 @@ class ServerRepository
|
||||||
$server->load('allocations');
|
$server->load('allocations');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loop All Assignments
|
if ($newPorts) {
|
||||||
$additionalAssignments = [];
|
$newBuild['ports|overwrite'] = $server->allocations->groupBy('ip')->map(function ($item) {
|
||||||
foreach ($server->allocations as &$assignment) {
|
return $item->pluck('port');
|
||||||
if (array_key_exists((string) $assignment->ip, $additionalAssignments)) {
|
})->toArray();
|
||||||
array_push($additionalAssignments[(string) $assignment->ip], (int) $assignment->port);
|
|
||||||
} else {
|
|
||||||
$additionalAssignments[(string) $assignment->ip] = [(int) $assignment->port];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($newPorts === true) {
|
|
||||||
$newBuild['ports|overwrite'] = $additionalAssignments;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// @TODO: verify that server can be set to this much memory without
|
// @TODO: verify that server can be set to this much memory without
|
||||||
|
@ -617,6 +590,7 @@ class ServerRepository
|
||||||
// This won't be committed unless the HTTP request succeedes anyways
|
// This won't be committed unless the HTTP request succeedes anyways
|
||||||
$server->save();
|
$server->save();
|
||||||
|
|
||||||
|
dd($newBuild);
|
||||||
if (! empty($newBuild)) {
|
if (! empty($newBuild)) {
|
||||||
$server->node->guzzleClient([
|
$server->node->guzzleClient([
|
||||||
'X-Access-Server' => $server->uuid,
|
'X-Access-Server' => $server->uuid,
|
||||||
|
@ -630,7 +604,7 @@ class ServerRepository
|
||||||
|
|
||||||
DB::commit();
|
DB::commit();
|
||||||
|
|
||||||
return true;
|
return $server;
|
||||||
} catch (TransferException $ex) {
|
} catch (TransferException $ex) {
|
||||||
DB::rollBack();
|
DB::rollBack();
|
||||||
throw new DisplayException('An error occured while attempting to update the configuration.', $ex);
|
throw new DisplayException('An error occured while attempting to update the configuration.', $ex);
|
||||||
|
|
|
@ -198,3 +198,29 @@ span[aria-labelledby="select2-pUserId-container"] {
|
||||||
color: #777 !important;
|
color: #777 !important;
|
||||||
background: transparent !important;
|
background: transparent !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tab-pane .box-footer {
|
||||||
|
margin: 0 -10px -10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select2-container{ width: 100% !important; }
|
||||||
|
|
||||||
|
.nav-tabs-custom > .nav-tabs > li:hover {
|
||||||
|
border-top-color:#3c8dbc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tabs-custom > .nav-tabs > li.active.tab-danger, .nav-tabs-custom > .nav-tabs > li.tab-danger:hover {
|
||||||
|
border-top-color: #c23321;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tabs-custom > .nav-tabs > li.active.tab-success, .nav-tabs-custom > .nav-tabs > li.tab-success:hover {
|
||||||
|
border-top-color: #00733e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tabs-custom > .nav-tabs > li.active.tab-info, .nav-tabs-custom > .nav-tabs > li.tab-info:hover {
|
||||||
|
border-top-color: #0097bc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tabs-custom > .nav-tabs > li.active.tab-warning, .nav-tabs-custom > .nav-tabs > li.tab-warning:hover {
|
||||||
|
border-top-color: #c87f0a;
|
||||||
|
}
|
||||||
|
|
390
resources/themes/pterodactyl/admin/servers/view.blade.php
Normal file
390
resources/themes/pterodactyl/admin/servers/view.blade.php
Normal file
|
@ -0,0 +1,390 @@
|
||||||
|
{{-- Copyright (c) 2015 - 2017 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.admin')
|
||||||
|
|
||||||
|
@section('title')
|
||||||
|
Manage Server: {{ $server->name }}
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('content-header')
|
||||||
|
<h1>{{ $server->name }}<small>{{ $server->uuid }}</small></h1>
|
||||||
|
<ol class="breadcrumb">
|
||||||
|
<li><a href="{{ route('admin.index') }}">Admin</a></li>
|
||||||
|
<li><a href="{{ route('admin.servers') }}">Servers</a></li>
|
||||||
|
<li class="active">{{ $server->username }}</li>
|
||||||
|
</ol>
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
@if($server->suspended && ! $server->trashed())
|
||||||
|
<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>
|
||||||
|
@elseif($server->trashed())
|
||||||
|
<div class="callout callout-danger">
|
||||||
|
This server is marked for deletion <strong>{{ Carbon::parse($server->deleted_at)->addMinutes(env('APP_DELETE_MINUTES', 10))->diffForHumans() }}</strong>. If you want to cancel this action simply click the button below.
|
||||||
|
<br /><br />
|
||||||
|
<form action="{{ route('admin.servers.post.queuedDeletion', $server->id) }}" method="POST">
|
||||||
|
<button class="btn btn-sm btn-default" name="cancel" value="1">Cancel Deletion</button>
|
||||||
|
<button class="btn btn-sm btn-danger pull-right" name="force_delete" value="1"><strong>Force</strong> Delete</button>
|
||||||
|
<button class="btn btn-sm btn-danger pull-right" name="delete" style="margin-right:10px;" value="1">Delete</button>
|
||||||
|
{!! csrf_field() !!}
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
@if(! $server->installed)
|
||||||
|
<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.
|
||||||
|
</div>
|
||||||
|
@elseif($server->installed === 2)
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
This server <strong>failed</strong> to install properly. You should delete it and try to create it again or check the daemon logs.
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-12">
|
||||||
|
<div class="nav-tabs-custom">
|
||||||
|
<ul class="nav nav-tabs">
|
||||||
|
<li class="active"><a href="#tab_about" data-toggle="tab">About</a></li>
|
||||||
|
@if($server->installed)
|
||||||
|
<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_startup" data-toggle="tab">Startup</a></li>
|
||||||
|
<li><a href="#tab_database" data-toggle="tab">Database</a></li>
|
||||||
|
@endif
|
||||||
|
@if($server->installed !== 2)
|
||||||
|
<li><a href="#tab_manage" data-toggle="tab">Manage</a></li>
|
||||||
|
@endif
|
||||||
|
@if(! $server->trashed())
|
||||||
|
<li class="tab-danger"><a href="#tab_delete" data-toggle="tab">Delete</a></li>
|
||||||
|
@endif
|
||||||
|
</ul>
|
||||||
|
<div class="tab-content">
|
||||||
|
{{-- Start About --}}
|
||||||
|
<div class="tab-pane active" id="tab_about" style="margin: -10px -10px -30px;">
|
||||||
|
<table class="table table-hover">
|
||||||
|
<tr>
|
||||||
|
<td>UUID</td>
|
||||||
|
<td>{{ $server->uuid }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Docker Container ID</td>
|
||||||
|
<td data-attr="container-id"><i class="fa fa-fw fa-refresh fa-spin"></i></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Docker User ID</td>
|
||||||
|
<td data-attr="container-user"><i class="fa fa-fw fa-refresh fa-spin"></i></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Owner</td>
|
||||||
|
<td><a href="{{ route('admin.users.view', $server->owner_id) }}">{{ $server->user->email }}</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Location</td>
|
||||||
|
<td><a href="{{ route('admin.locations') }}">{{ $server->node->location->short }}</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Node</td>
|
||||||
|
<td><a href="{{ route('admin.nodes.view', $server->node_id) }}">{{ $server->node->name }}</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Service</td>
|
||||||
|
<td>{{ $server->option->service->name }} :: {{ $server->option->name }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Name</td>
|
||||||
|
<td>{{ $server->name }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Memory</td>
|
||||||
|
<td><code>{{ $server->memory }}MB</code> / <code data-toggle="tooltip" data-placement="top" title="Swap Space">{{ $server->swap }}MB</code></td>
|
||||||
|
</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>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Disk Space</td>
|
||||||
|
<td><code>{{ $server->disk }}MB</code></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->allocation->ip }}:{{ $server->allocation->port }}</code></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Connection Alias</td>
|
||||||
|
<td>
|
||||||
|
@if($server->allocation->alias !== $server->allocation->ip)
|
||||||
|
<code>{{ $server->allocation->alias }}:{{ $server->allocation->port }}</code>
|
||||||
|
@else
|
||||||
|
<span class="label label-default">No Alias Assigned</span>
|
||||||
|
@endif
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<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>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{{-- End About / Start Details --}}
|
||||||
|
@if($server->installed)
|
||||||
|
<div class="tab-pane" id="tab_details">
|
||||||
|
<div class="row">
|
||||||
|
<form class="col-sm-6" action="{{ route('admin.servers.view.details', $server->id) }}" method="POST" style="border-right: 1px solid #f4f4f4;">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="name" class="control-label">Server Name</label>
|
||||||
|
<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).</p>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="pUserId" class="control-label">Server Owner</label>
|
||||||
|
<select name="owner_id" class="form-control" id="pUserId">
|
||||||
|
<option value="{{ $server->owner_id }}" selected>{{ $server->user->email }}</option>
|
||||||
|
</select>
|
||||||
|
{{-- <input type="text" name="owner" value="{{ old('owner', $server->user->email) }}" 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.</p>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="name" class="control-label">Daemon Secret Token</label>
|
||||||
|
<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.</p>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="checkbox" name="reset_token" id="pResetToken"/> <label for="pResetToken">Reset Daemon Token</label>
|
||||||
|
<p class="text-muted small">Resetting this token will cause any requests using the old token to fail.</p>
|
||||||
|
</div>
|
||||||
|
<div class="box-footer">
|
||||||
|
{!! csrf_field() !!}
|
||||||
|
<input type="submit" class="btn btn-sm btn-primary" value="Update Details" />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<form class="col-sm-6" action="{{ route('admin.servers.post.container', $server->id) }}" method="POST">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="name" class="control-label">Docker Container Image</label>
|
||||||
|
<input type="text" name="docker_image" value="{{ $server->image }}" class="form-control" />
|
||||||
|
<p class="text-muted small">The docker image to use for this server. The default image for this service and option combination is <code>{{ $server->option->docker_image }}</code>.</p>
|
||||||
|
</div>
|
||||||
|
<div class="box-footer">
|
||||||
|
{!! csrf_field() !!}
|
||||||
|
<input type="submit" class="btn btn-sm btn-primary" value="Update Docker Container" />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{-- End Details / Start Build --}}
|
||||||
|
<div class="tab-pane" id="tab_build">
|
||||||
|
<form action="/admin/servers/view/{{ $server->id }}/build" method="POST">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-3 col-sm-6 form-group">
|
||||||
|
<label for="memory" class="control-label">Allocated Memory</label>
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="text" name="memory" data-multiplicator="true" class="form-control" value="{{ old('memory', $server->memory) }}"/>
|
||||||
|
<span class="input-group-addon">MB</span>
|
||||||
|
</div>
|
||||||
|
<p class="text-muted small">The maximum amount of memory allowed for this container.</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3 col-sm-6 form-group">
|
||||||
|
<label for="swap" class="control-label">Allocated Swap</label>
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="text" name="swap" data-multiplicator="true" class="form-control" value="{{ old('swap', $server->swap) }}"/>
|
||||||
|
<span class="input-group-addon">MB</span>
|
||||||
|
</div>
|
||||||
|
<p class="text-muted small">Setting this to <code>0</code> will disable swap space on this server. Setting to <code>-1</code> will allow unlimited swap.</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3 col-sm-6 form-group">
|
||||||
|
<label for="cpu" class="control-label">CPU Limit</label>
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="text" name="cpu" class="form-control" value="{{ old('cpu', $server->cpu) }}"/>
|
||||||
|
<span class="input-group-addon">%</span>
|
||||||
|
</div>
|
||||||
|
<p class="text-muted small">Each <em>physical</em> core on the system is considered to be <code>100%</code>. Setting this value to <code>0</code> will allow a server to use CPU time without restrictions.</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3 col-sm-6 form-group">
|
||||||
|
<label for="io" class="control-label">Block IO Proportion</label>
|
||||||
|
<div>
|
||||||
|
<input type="text" name="io" class="form-control" value="{{ old('io', $server->io) }}"/>
|
||||||
|
</div>
|
||||||
|
<p class="text-muted small">Changing this value can have negative effects on all containers on the system. We strongly recommend leaving this value as <code>500</code>.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-4 form-group">
|
||||||
|
<label for="pAllocation" class="control-label">Game Port</label>
|
||||||
|
<select id="pAllocation" name="allocation_id" class="form-control">
|
||||||
|
@foreach ($assigned as $assignment)
|
||||||
|
<option value="{{ $assignment->id }}"
|
||||||
|
@if($assignment->id === $server->allocation_id)
|
||||||
|
selected="selected"
|
||||||
|
@endif
|
||||||
|
>{{ $assignment->alias }}:{{ $assignment->port }}</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
<p class="text-muted small">The default connection address that will be used for this game server.</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4 form-group">
|
||||||
|
<label for="pAddAllocations" class="control-label">Assign Additional Ports</label>
|
||||||
|
<div>
|
||||||
|
<select name="add_allocations[]" class="form-control" multiple id="pAddAllocations">
|
||||||
|
@foreach ($unassigned as $assignment)
|
||||||
|
<option value="{{ $assignment->id }}">{{ $assignment->alias }}:{{ $assignment->port }}</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<p class="text-muted small">Please note that due to software limitations you cannot assign identical ports on different IPs to the same server.</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4 form-group">
|
||||||
|
<label for="pRemoveAllocations" class="control-label">Remove Additional Ports</label>
|
||||||
|
<div>
|
||||||
|
<select name="remove_allocations[]" class="form-control" multiple id="pRemoveAllocations">
|
||||||
|
@foreach ($assigned as $assignment)
|
||||||
|
<option value="{{ $assignment->id }}" @if($server->allocation_id === $assignment->id)disabled @endif>{{ $assignment->alias }}:{{ $assignment->port }}</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<p class="text-muted small">Simply select which ports you would like to remove from the list above. If you want to assign a port on a different IP that is already in use you can select it from the left and delete it here.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="box-footer">
|
||||||
|
{!! csrf_field() !!}
|
||||||
|
<input type="submit" class="btn btn-sm btn-primary" value="Update Build Configuration" />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{{-- End Build / Start Startup --}}
|
||||||
|
<div class="tab-pane" id="tab_startup">
|
||||||
|
Startup
|
||||||
|
</div>
|
||||||
|
{{-- End Startup / Start Database --}}
|
||||||
|
<div class="tab-pane" id="tab_database">
|
||||||
|
Database
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
{{-- End Database / Start Manage --}}
|
||||||
|
@if($server->installed !== 2)
|
||||||
|
<div class="tab-pane" id="tab_manage">
|
||||||
|
Manage
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
{{-- End Manage / Start Delete --}}
|
||||||
|
@if(! $server->trashed())
|
||||||
|
<div class="tab-pane" id="tab_delete">
|
||||||
|
Delete
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
{{-- End Delete --}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('footer-scripts')
|
||||||
|
@parent
|
||||||
|
<script>
|
||||||
|
$('#pAddAllocations').select2();
|
||||||
|
$('#pRemoveAllocations').select2();
|
||||||
|
$('#pAllocation').select2();
|
||||||
|
$('#pUserId').select2({
|
||||||
|
ajax: {
|
||||||
|
url: Router.route('admin.users.json'),
|
||||||
|
dataType: 'json',
|
||||||
|
delay: 250,
|
||||||
|
data: function (params) {
|
||||||
|
return {
|
||||||
|
q: params.term, // search term
|
||||||
|
page: params.page,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
processResults: function (data, params) {
|
||||||
|
return { results: data };
|
||||||
|
},
|
||||||
|
cache: true,
|
||||||
|
},
|
||||||
|
escapeMarkup: function (markup) { return markup; },
|
||||||
|
minimumInputLength: 2,
|
||||||
|
templateResult: function (data) {
|
||||||
|
if (data.loading) return data.text;
|
||||||
|
|
||||||
|
return '<div class="user-block"> \
|
||||||
|
<img class="img-circle img-bordered-xs" src="https://www.gravatar.com/avatar/' + data.md5 + '?s=120" alt="User Image"> \
|
||||||
|
<span class="username"> \
|
||||||
|
<a href="#">' + data.name_first + ' ' + data.name_last +'</a> \
|
||||||
|
</span> \
|
||||||
|
<span class="description"><strong>' + data.email + '</strong> - ' + data.username + '</span> \
|
||||||
|
</div>';
|
||||||
|
},
|
||||||
|
templateSelection: function (data) {
|
||||||
|
if (typeof data.name_first === 'undefined') {
|
||||||
|
data = {
|
||||||
|
md5: '{{ md5(strtolower($server->user->email)) }}',
|
||||||
|
name_first: '{{ $server->user->name_first }}',
|
||||||
|
name_last: '{{ $server->user->name_last }}',
|
||||||
|
email: '{{ $server->user->email }}',
|
||||||
|
id: {{ $server->owner_id }}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return '<div> \
|
||||||
|
<span> \
|
||||||
|
<img class="img-rounded img-bordered-xs" src="https://www.gravatar.com/avatar/' + data.md5 + '?s=120" style="height:28px;margin-top:-4px;" alt="User Image"> \
|
||||||
|
</span> \
|
||||||
|
<span style="padding-left:5px;"> \
|
||||||
|
' + data.name_first + ' ' + data.name_last + ' (<strong>' + data.email + '</strong>) \
|
||||||
|
</span> \
|
||||||
|
</div>';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
(function checkServerInfo() {
|
||||||
|
$.ajax({
|
||||||
|
type: 'GET',
|
||||||
|
headers: {
|
||||||
|
'X-Access-Token': '{{ $server->daemonSecret }}',
|
||||||
|
'X-Access-Server': '{{ $server->uuid }}'
|
||||||
|
},
|
||||||
|
url: '{{ $server->node->scheme }}://{{ $server->node->fqdn }}:{{ $server->node->daemonListen }}/server',
|
||||||
|
dataType: 'json',
|
||||||
|
timeout: 5000,
|
||||||
|
}).done(function (data) {
|
||||||
|
$('td[data-attr="container-id"]').html('<code>' + data.container.id + '</code>');
|
||||||
|
$('td[data-attr="container-user"]').html('<code>' + data.user + '</code>');
|
||||||
|
}).fail(function (jqXHR) {
|
||||||
|
$('td[data-attr="container-id"]').html('<code>error</code>');
|
||||||
|
$('td[data-attr="container-user"]').html('<code>error</code>');
|
||||||
|
console.error(jqXHR);
|
||||||
|
}).always(function () {
|
||||||
|
setTimeout(checkServerInfo, 60000);
|
||||||
|
})
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
@endsection
|
|
@ -67,7 +67,7 @@
|
||||||
<a href="#" data-action="control-sidebar" data-toggle="tooltip" data-placement="bottom" title="Quick Access"><i class="fa fa-fighter-jet" style="margin-top:4px;padding-bottom:2px;"></i></a>
|
<a href="#" data-action="control-sidebar" data-toggle="tooltip" data-placement="bottom" title="Quick Access"><i class="fa fa-fighter-jet" style="margin-top:4px;padding-bottom:2px;"></i></a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<li><a href="{{ route('admin.index') }}" data-toggle="tooltip" data-placement="bottom" title="Exit Admin Control"><i class="fa fa-server" style="margin-top:4px;padding-bottom:2px;"></i></a></li>
|
<li><a href="{{ route('index') }}" data-toggle="tooltip" data-placement="bottom" title="Exit Admin Control"><i class="fa fa-server" style="margin-top:4px;padding-bottom:2px;"></i></a></li>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<li><a href="{{ route('auth.logout') }}" data-toggle="tooltip" data-placement="bottom" title="Logout"><i class="fa fa-power-off" style="margin-top:4px;padding-bottom:2px;"></i></a></li>
|
<li><a href="{{ route('auth.logout') }}" data-toggle="tooltip" data-placement="bottom" title="Logout"><i class="fa fa-power-off" style="margin-top:4px;padding-bottom:2px;"></i></a></li>
|
||||||
|
|
Loading…
Reference in a new issue