From 6e0c5d16af08ee67b548604d0601b60ac6c10e42 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Tue, 5 Jan 2016 18:31:25 -0500 Subject: [PATCH] Allow updating settings and show configuration for node --- .../Controllers/Admin/NodesController.php | 30 +- app/Http/Routes/AdminRoutes.php | 4 + app/Repositories/NodeRepository.php | 62 +- public/css/pterodactyl.css | 2 + resources/views/admin/nodes/view.blade.php | 545 ++++++++++++++++-- 5 files changed, 601 insertions(+), 42 deletions(-) diff --git a/app/Http/Controllers/Admin/NodesController.php b/app/Http/Controllers/Admin/NodesController.php index 44e902037..402cd6659 100644 --- a/app/Http/Controllers/Admin/NodesController.php +++ b/app/Http/Controllers/Admin/NodesController.php @@ -72,8 +72,36 @@ class NodesController extends Controller 'servers' => Models\Server::select('servers.*', 'users.email as a_ownerEmail', 'services.name as a_serviceName') ->join('users', 'users.id', '=', 'servers.owner') ->join('services', 'services.id', '=', 'servers.service') - ->where('node', $id)->paginate(10) + ->where('node', $id)->paginate(10), + 'stats' => Models\Server::select(DB::raw('SUM(memory) as memory, SUM(disk) as disk'))->where('node', $node->id)->first(), + 'locations' => Models\Location::all(), ]); } + public function postView(Request $request, $id) + { + try { + $node = new NodeRepository; + $node->update($id, $request->except([ + '_token' + ])); + Alert::success('Successfully update this node\'s information. If you changed any daemon settings you will need to restart it now.')->flash(); + return redirect()->route('admin.nodes.view', [ + 'id' => $id, + 'tab' => 'tab_settings' + ]); + } catch (\Pterodactyl\Exceptions\DisplayValidationException $e) { + return redirect()->route('admin.nodes.view', $id)->withErrors(json_decode($e->getMessage()))->withInput(); + } catch (\Pterodactyl\Exceptions\DisplayException $e) { + Alert::danger($e->getMessage())->flash(); + } catch (\Exception $e) { + Log::error($e); + Alert::danger('An unhandled exception occured while attempting to edit this node. Please try again.')->flash(); + } + return redirect()->route('admin.nodes.view', [ + 'id' => $id, + 'tab' => 'tab_settings' + ])->withInput(); + } + } diff --git a/app/Http/Routes/AdminRoutes.php b/app/Http/Routes/AdminRoutes.php index c00da60b9..bf4131a1e 100644 --- a/app/Http/Routes/AdminRoutes.php +++ b/app/Http/Routes/AdminRoutes.php @@ -168,6 +168,10 @@ class AdminRoutes { 'uses' => 'Admin\NodesController@getView' ]); + $router->post('/view/{id}', [ + 'uses' => 'Admin\NodesController@postView' + ]); + }); } diff --git a/app/Repositories/NodeRepository.php b/app/Repositories/NodeRepository.php index c4316d910..91d9eaa6e 100644 --- a/app/Repositories/NodeRepository.php +++ b/app/Repositories/NodeRepository.php @@ -32,7 +32,7 @@ class NodeRepository { 'disk_overallocate' => 'required|numeric|min:-1', 'daemonBase' => 'required|regex:/^([\/][\d\w.\-\/]+)$/', 'daemonSFTP' => 'required|numeric|between:1,65535', - 'daemonListen' => 'required|numeric|between:1,65535' + 'daemonListen' => 'required|numeric|between:1,65535', ]); // Run validator, throw catchable and displayable exception if it fails. @@ -42,6 +42,9 @@ class NodeRepository { } // Verify the FQDN + if (filter_var($data['fqdn'], FILTER_VALIDATE_IP)) { + throw new DisplayException('The FQDN provided was an IP address. You must use a FQDN.'); + } if (!filter_var(gethostbyname($data['fqdn']), FILTER_VALIDATE_IP)) { throw new DisplayException('The FQDN provided does not resolve to a valid IP address.'); } @@ -63,4 +66,61 @@ class NodeRepository { } + public function update($id, array $data) + { + // Validate Fields + $validator = $validator = Validator::make($data, [ + 'name' => 'regex:/^([\w .-]{1,100})$/', + 'location' => 'numeric|min:1|exists:locations,id', + 'public' => 'numeric|between:0,1', + 'fqdn' => 'string|unique:nodes,fqdn,' . $id, + 'scheme' => 'regex:/^(http(s)?)$/', + 'memory' => 'numeric|min:1', + 'memory_overallocate' => 'numeric|min:-1', + 'disk' => 'numeric|min:1', + 'disk_overallocate' => 'numeric|min:-1', + 'daemonBase' => 'regex:/^([\/][\d\w.\-\/]+)$/', + 'daemonSFTP' => 'numeric|between:1,65535', + 'daemonListen' => 'numeric|between:1,65535', + 'reset_secret' => 'sometimes|accepted', + ]); + + // 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()); + } + + // Verify the FQDN + if (isset($data['fqdn'])) { + if (filter_var($data['fqdn'], FILTER_VALIDATE_IP)) { + throw new DisplayException('The FQDN provided was an IP address. You must use a FQDN.'); + } + if (!filter_var(gethostbyname($data['fqdn']), FILTER_VALIDATE_IP)) { + throw new DisplayException('The FQDN provided does not resolve to a valid IP address.'); + } + } + + // Should we be nulling the overallocations? + if (isset($data['memory_overallocate'])) { + $data['memory_overallocate'] = ($data['memory_overallocate'] < 0) ? null : $data['memory_overallocate']; + } + + if (isset($data['disk_overallocate'])) { + $data['disk_overallocate'] = ($data['disk_overallocate'] < 0) ? null : $data['disk_overallocate']; + } + + // Set the Secret + if (isset($data['reset_secret'])) { + $uuid = new UuidService; + $data['daemonSecret'] = (string) $uuid->generate('nodes', 'daemonSecret'); + unset($data['reset_secret']); + } + + // Store the Data + $node = Models\Node::findOrFail($id); + return $node->update($data); + + } + } diff --git a/public/css/pterodactyl.css b/public/css/pterodactyl.css index b5d42870d..9a0cf1e8f 100755 --- a/public/css/pterodactyl.css +++ b/public/css/pterodactyl.css @@ -77,3 +77,5 @@ 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;} +.label{border-radius: .25em;padding: .2em .6em .3em;} +kbd{border-radius: .25em} diff --git a/resources/views/admin/nodes/view.blade.php b/resources/views/admin/nodes/view.blade.php index dac4b8f6b..fd6357c73 100644 --- a/resources/views/admin/nodes/view.blade.php +++ b/resources/views/admin/nodes/view.blade.php @@ -4,6 +4,29 @@ Managing Node: {{ $node->name }} @endsection +@section('scripts') + @parent + + + + +@endsection + @section('content')
+
+
+
+
+
+ Changing some details below may require that you change the configuration file on the node as well as restart the daemon. They have been marked with below. +
+
+
+ +
+ +

Character limits: a-zA-Z0-9_.- and [Space] (min 1, max 100 characters).

+
+
+
+ +
+ +
+
+
+ +
+ public) === '1') ? 'checked' : '' }} id="public_1" checked>
+ public) === '0') ? 'checked' : '' }} id="public_0"> +
+
+
+
+
+ +
+ +
+

This must be a fully qualified domain name, you may not enter an IP address or a domain that does not exist. + Why? +

+
+
+ +
+
+ scheme) === 'https') ? 'checked' : '' }}/> +
+
+ scheme) === 'http') ? 'checked' : '' }}/> +
+
+

You should always leave SSL enabled for nodes. Disabling SSL could allow a malicious user to intercept traffic between the panel and the daemon potentially exposing sensitive information.

+
+
+
+
+
+
+
+ +
+ + MB +
+
+
+ +
+ + % +
+
+
+ +
+ + MB +
+
+
+ +
+ + % +
+
+
+
+
+

Enter the total amount of disk space and memory avaliable for new servers. If you would like to allow overallocation of disk space or memory enter the percentage that you want to allow. To disable checking for overallocation enter -1 into the field. Entering 0 will prevent creating new servers if it would put the node over the limit.

+
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+
+

The daemon runs its own SFTP management container and does not use the SSHd process on the main physical server. Do not use the same port that you have assigned for your physcial server's SSH process.

+
+
+
+
+
+
+ +
+ Reset Daemon Master Key +
+
+
+

Resetting the daemon master key will void any request coming from the old key. This key is used for all sensitive operations on the daemon including server creation and deletion. We suggest changing this key regularly for security.

+
+
+
+
+
+
+
+
+
+ {!! csrf_field() !!} + +
+
+
+
+
+
+
- Settings +
+ Below is the configuration file for your daemon on this node. We recommend not simply copy and pasting the code below unless you know what you are doing. You should run the auto-installer or auto-updater to setup the daemon. +
+
+
{
+    "web": {
+        "listen": {{ $node->daemonListen }},
+        "ssl": {
+            "enabled": {{ $node->sceheme === 'https' ? 'true' : 'false' }},
+            "certificate": "~/.ssl/ssl.cert",
+            "key": "~/.ssl/ssl.key"
+        }
+    },
+    "docker": {
+        "socket": "/var/run/docker.sock"
+    },
+    "sftp": {
+        "path": "{{ $node->daemonBase }}",
+        "port": {{ $node->daemonSFTP }},
+        "container": "container_id"
+    },
+    "logger": {
+        "path": "logs/",
+        "src": false,
+        "level": "info",
+        "period": "1d",
+        "count": 3
+    },
+    "remote": {
+        "download": "{{ url('/remote/download') }}"
+    },
+    "uploads": {
+        "maximumSize": 1000000
+    },
+    "keys": [
+        "{{ $node->daemonSecret }}"
+    ]
+}
+
@@ -48,7 +294,7 @@
- The data below is updated every 30 seconds, or on page load. CPU usage is displayed relative to the assigned CPU allocation. For example, if a server is assigned 10% and the CPU usage below displays 90% that means the server is using 9% of the total system CPU. + The data below is live output from the daemon. CPU usage is displayed relative to the assigned CPU allocation. For example, if a server is assigned 10% and the CPU usage below displays 90% that means the server is using 9% of the total system CPU.
@@ -91,50 +337,269 @@ +
+
+
@endsection