Compare commits

..

21 commits

Author SHA1 Message Date
matthewalanpenning
31f878a586 v3.8.0 2023-08-31 05:02:29 -04:00
matthewalanpenning
2c2acd2c4c v3.7.0 2023-03-20 05:12:22 -04:00
Matthew Penning
74b2a1ab3f
Merge pull request #61 from danieldean/master
Close exec websockets on exit.
2023-01-07 13:04:43 -05:00
Daniel Dean
dfffdb7efe Close exec websockets on exit. 2022-12-24 18:26:19 +00:00
matthewalanpenning
7dd0561e41 v3.6.0 2022-12-09 10:17:03 -05:00
Matthew Penning
031554e100
Merge pull request #44 from fthorns/master
Cloud-init support for LXC containers
2022-12-09 09:59:37 -05:00
matthewalanpenning
c538f09a3a v3.5.0 2022-10-23 22:35:53 -04:00
matthewalanpenning
229a085075 v3.5.0 2022-10-23 22:33:34 -04:00
Matthew Penning
9f7c3f6e46
Merge pull request #42 from kay0u/master
Fix some MySQL queries
2022-10-22 11:48:26 -04:00
Fabian Thorns
426b3eb451 Cloud-init support for LXC containers 2022-08-22 11:15:35 +02:00
Kay0u
58d60ae1a6
fix MySQL date 2022-06-20 13:16:59 +02:00
Kay0u
6d38fe8da9
fix MySQL AUTO_INCREMENT 2022-06-20 13:16:34 +02:00
matthewalanpenning
bf5a33664a v3.4.0 2022-04-03 17:00:40 -04:00
matthewalanpenning
db310f6afd v3.3.0 2022-03-31 20:24:40 -04:00
matthewalanpenning
28730dbea1 v3.3.0 2022-03-31 20:22:18 -04:00
matthewalanpenning
fbff359d99 v3.2.0 2022-03-21 05:30:46 -04:00
matthewalanpenning
426f632ba5 v3.1.0 2021-12-17 14:34:39 -05:00
matthewalanpenning
2f4e458d44 v3.1.0 2021-12-17 14:22:03 -05:00
matthewalanpenning
22732a6504 v3.0.0 2021-11-30 21:23:20 -05:00
matthewalanpenning
b782fbb2cb v3.0.0 2021-11-30 21:20:27 -05:00
matthewalanpenning
2c40dd5743 v2.3.0 2021-09-24 15:45:54 -04:00
76 changed files with 25221 additions and 8612 deletions

View file

@ -1,25 +1,50 @@
# v2.2.0
- Feature: Additional configuration properties have been added to the web form for creating Storage Pools and Storage Volumes, including clustered servers
- Feature: Additional configuration properties have been added to the web form for creating Projects
- Feature: Added cluster configuration to the creation of networks from form entries
- Feature: Filtered the default view of Storage Volumes to show only custom type storage volumes by default and provided link to remove this filter
# v3.8.0
- Added a check for a null config in storage pools
- Added image token cleanup with downloading images while in a cluster
# v2.1.0
- Feature: Users can now add network, disk, and proxy devices directly to an instance from a form
- Feature: Users can now remove network, disk, and proxy devices from an instance using the dashboard
- Feature: Additional configuration properties have been added to the web form for creating Networks
- Feature: Users can add/remove Network ACL egress/ingress rules using the dashboard
- Feature: The Exec terminal experience has been added to instances
- Feature: Users can click on the "Check for updates" button in the About modal to get a version status
# v2.0.3
- Bug Fix: Continuing the bug fix from previous version, used float type casting for memory variables on remote-single page rather than letting PHP automatically deciding on variable type.
# v3.7.0
- Set console/exec terminal height to 25 rows because xterm.js defaults to 24 and lxd defaults to 25 there was a single row mismatch
- Added qemu.conf to virtual machine configuration options
- Changed cloud-init user data to use POST method rather than GET
- Merged pull request improving websocket close on exec/console websockets
- Added check for empty storage pool source configuration array item
# v2.0.2
- Bug Fix: Replaced PHP round() function with number_format() to force the format of two decimal places on instance-single and remote-single pages.
# v3.6.0
- Merged pull request adding cloud init user data option for new containers via form
- Fixed typo preventing OS version number from showing in remotes-single.php page, under LXD Information
# v2.0.1
- Bug Fix: Added strtolower() when comparing if cluster member is fully operational. Both "Fully operational" and "fully operational" messages now result to true when providing a list of cluster members to migrate an instance to.
# v3.5.0
- Updated container image catalog based on results from from https://us.lxd.images
- Merged pull request updating MySQL statements for auto increment and now time
# v2.0.0
- initial release of the LXDWARE LXD dashboard version 2.0.0
# v3.4.0
- Added additional delete option for powered-off instances on the containers and virtual machines pages
- Fixed bug in populating both profile and cluster member options in drop-down box for virtual machine configurations
- Added verification for numeric values in instance memory gauge display
# v3.3.0
- Updated PDO try-catch exception for PHP 8
- Created recursive PHP in_array for SQLite Pragma array search in PHP 8
- Improved handling of external port for remotes
- Fixed bug with scope of curl variables
# v3.2.0
- added removal confirmation of remote hosts
- added preference choices for logging and logs page
- added preferences for custom page refresh rates
- added preferences for custom API connection and operation timeout
- improved CPU gauge, changing from top to /proc/stat readings
- improved handling connection to unresponsive remote hosts
- fixed bug with adding hosts due to data type
# v3.1.0
- improved performance of page loads
- updated instance backups to include a filesize of exported files
- updated exporting backup image to using a script to spawn it off into a background process
- updated remote host table header
- updated link to display all volume types on storage volumes page
- reduced curl connection timeout
# v3.0.0
- initial release of the LXDWARE LXD dashboard version 3.0.0

View file

@ -2,7 +2,7 @@ server {
listen 80 default_server;
listen [::]:80 default_server;
root /var/www/html/lxd-dashboard;
index index.html;
index index.php index.html;
server_name _;
location / {
@ -13,6 +13,7 @@ server {
#include snippets/fastcgi-php.conf;
#fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
fastcgi_pass unix:/run/php/php7.4-fpm.sock;
#fastcgi_pass unix:/run/php/php8.1-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
include snippets/fastcgi-php.conf;

View file

@ -1,27 +1,192 @@
.bg-dark {
background-color: #262626 !important;
background-size: cover;
}
background-color: #262626 !important;
background-size: cover;
}
.btn-danger {
color: #fff;
background-color: #ff0000;
border-color: #ff0000;
}
.btn-danger {
color: #fff;
background-color: #ff0000;
border-color: #ff0000;
}
.text-danger {
color: #ff0000 !important;
}
.text-danger {
color: #ff0000 !important;
}
code {
font-size: 87.5%;
color: #ff0000 !important;
word-break: break-word;
}
code {
font-size: 87.5%;
color: #ff0000 !important;
word-break: break-word;
}
.sidebar.toggled .nav-item .nav-link {
text-align: center;
padding: 0.5rem 1rem;
width: 6.5rem;
.sidebar.toggled .nav-item .nav-link {
text-align: center;
padding: 0.5rem 1rem;
width: 6.5rem;
}
.sidebar .nav-item .nav-link {
display: block;
width: 100%;
text-align: left;
padding: 0.8rem 1rem;
width: 14rem;
}
.pb-6,
.py-6 {
padding-bottom: 6rem !important;
}
.sidebar-divider-right {
border-right: 1px solid #444 !important;
}
.btn-xs, .btn-group-xs > .btn {
padding: 0.25rem 0.5rem;
font-size: 0.7rem;
line-height: .7;
border-radius: 0.2rem;
}
.progress-circle {
width: 150px;
height: 150px;
background: none;
position: relative;
}
.progress-circle::after {
content: "";
width: 100%;
height: 100%;
border-radius: 50%;
border: 12px solid #eee;
position: absolute;
top: 0;
left: 0;
}
.progress-circle>span {
width: 50%;
height: 100%;
overflow: hidden;
position: absolute;
top: 0;
z-index: 1;
}
.progress-circle .progress-circle-left {
left: 0;
}
.progress-circle .progress-circle-bar {
width: 100%;
height: 100%;
background: none;
border-width: 12px;
border-style: solid;
position: absolute;
top: 0;
}
.progress-circle .progress-circle-left .progress-circle-bar {
left: 100%;
border-top-right-radius: 80px;
border-bottom-right-radius: 80px;
border-left: 0;
-webkit-transform-origin: center left;
transform-origin: center left;
}
.progress-circle .progress-circle-right {
right: 0;
}
.progress-circle .progress-circle-right .progress-circle-bar {
left: -100%;
border-top-left-radius: 80px;
border-bottom-left-radius: 80px;
border-right: 0;
-webkit-transform-origin: center right;
transform-origin: center right;
}
.progress-circle .progress-circle-value {
position: absolute;
top: 0;
left: 0;
}
.progress-circle-xs {
width: 75px;
height: 75px;
background: none;
position: relative;
}
.progress-circle-xs::after {
content: "";
width: 100%;
height: 100%;
border-radius: 50%;
border: 4px solid #eee;
position: absolute;
top: 0;
left: 0;
}
.progress-circle-xs>span {
width: 50%;
height: 100%;
overflow: hidden;
position: absolute;
top: 0;
z-index: 1;
}
.progress-circle-xs .progress-circle-left-xs {
left: 0;
}
.progress-circle-xs .progress-circle-bar-xs {
width: 100%;
height: 100%;
background: none;
border-width: 4px;
border-style: solid;
position: absolute;
top: 0;
}
.progress-circle-xs .progress-circle-left-xs .progress-circle-bar-xs {
left: 100%;
border-top-right-radius: 80px;
border-bottom-right-radius: 80px;
border-left: 0;
-webkit-transform-origin: center left;
transform-origin: center left;
}
.progress-circle-xs .progress-circle-right-xs {
right: 0;
}
.progress-circle-xs .progress-circle-right-xs .progress-circle-bar-xs {
left: -100%;
border-top-left-radius: 80px;
border-bottom-left-radius: 80px;
border-right: 0;
-webkit-transform-origin: center right;
transform-origin: center right;
}
.progress-circle-xs .progress-circle-value-xs {
position: absolute;
top: 0;
left: 0;
}

View file

@ -22,10 +22,20 @@ if (!isset($_SESSION)) {
session_start();
}
//Require code from lxd-dashboard/php/config/db.php
//Require code from lxd-dashboard/backend/config/db.php
require_once('../config/db.php');
function logEvent($action, $remote, $project, $object, $status_code, $message){
//Will be used in future releases with remote database option
function logEvent($action, $remote, $project, $object, $status_code, $message, $user_id = 0){
$logs_enabled_value = retrievePreference("logs_enabled");
if ($logs_enabled_value == 'true'){
$hostname = gethostname();
if ($user_id == 0){
$user_id = (!empty($_SESSION['user_id'])) ? $_SESSION['user_id'] : 0;
}
$event_added = addLogEvent($action, $remote, $project, $object, $status_code, $message, $hostname, $user_id);
}
}
?>

View file

@ -0,0 +1,184 @@
<?php
/*
LXDWARE LXD Dashboard - A web-based interface for managing LXD servers
Copyright (C) 2020-2021 LXDWARE.COM
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//Start session if not already started
if (!isset($_SESSION)) {
session_start();
}
//Declare and instantiate GET variables
$action = (isset($_GET['action'])) ? filter_var(urldecode($_GET['action']), FILTER_SANITIZE_STRING) : "";
$project = (isset($_GET['project'])) ? filter_var(urldecode($_GET['project']), FILTER_SANITIZE_STRING) : "";
$remote = (isset($_GET['remote'])) ? filter_var(urldecode($_GET['remote']), FILTER_SANITIZE_NUMBER_INT) : "";
//Declare and instantiate POST variables
$username = (isset($_POST['username'])) ? filter_var(urldecode($_POST['username']), FILTER_SANITIZE_STRING) : "";
$password = (isset($_POST['password'])) ? filter_var(urldecode($_POST['password']), FILTER_SANITIZE_STRING) : "";
//Require code from lxd-dashboard/backend/config/db.php
require_once('../config/db.php');
//Require code from lxd-dashboard/backend/aaa/authorization.php
require_once('../aaa/authorization.php');
//Require code from lxd-dashboard/backend/aaa/accounting.php
require_once('../aaa/accounting.php');
//Run the matching action
switch ($action) {
case "authenticateUser":
//Determine user info from database
foreach (retrieveUserRecord($username) as $record){
$user_id = $record['id'];
$passwd_hash = $record['passwd_hash'];
}
//Verify password matches existing database passwd_hash
if (password_verify($password, $passwd_hash)) {
//Store username and user_id in SESSION variable
$_SESSION['username'] = $username;
$_SESSION['user_id'] = $user_id;
//Get all the roles that the user belongs to
$roles = array();
foreach (retrieveUserRoles($user_id) as $role){
array_push($roles, $role['name']);
}
//Make sure array only has unique values
$roles = array_unique($roles);
//Get array of contols based on the user's roles
$controls = getControls($roles);
//Store user's controls in a SESSION array
$_SESSION['controls'] = $controls;
//Store preference values in SESSION array
$preferences = retrieveTableRows("lxd_preferences");
foreach ($preferences as $preference){
//API Preferences
if ($preference['name'] == "get_connection_timeout")
$_SESSION['get_connection_timeout'] = $preference['value'];
if ($preference['name'] == "get_operation_timeout")
$_SESSION['get_operation_timeout'] = $preference['value'];
if ($preference['name'] == "post_connection_timeout")
$_SESSION['post_connection_timeout'] = $preference['value'];
if ($preference['name'] == "post_operation_timeout")
$_SESSION['post_operation_timeout'] = $preference['value'];
if ($preference['name'] == "patch_connection_timeout")
$_SESSION['patch_connection_timeout'] = $preference['value'];
if ($preference['name'] == "patch_operation_timeout")
$_SESSION['patch_operation_timeout'] = $preference['value'];
if ($preference['name'] == "put_connection_timeout")
$_SESSION['put_connection_timeout'] = $preference['value'];
if ($preference['name'] == "put_operation_timeout")
$_SESSION['put_operation_timeout'] = $preference['value'];
if ($preference['name'] == "delete_connection_timeout")
$_SESSION['delete_connection_timeout'] = $preference['value'];
if ($preference['name'] == "delete_operation_timeout")
$_SESSION['delete_operation_timeout'] = $preference['value'];
//Page Refresh Preferences
if ($preference['name'] == "certificates_page_rate")
$_SESSION['certificates_page_rate'] = $preference['value'];
if ($preference['name'] == "cluster_members_page_rate")
$_SESSION['cluster_members_page_rate'] = $preference['value'];
if ($preference['name'] == "containers_page_rate")
$_SESSION['containers_page_rate'] = $preference['value'];
if ($preference['name'] == "containers_single_page_rate")
$_SESSION['containers_single_page_rate'] = $preference['value'];
if ($preference['name'] == "images_page_rate")
$_SESSION['images_page_rate'] = $preference['value'];
if ($preference['name'] == "logs_page_rate")
$_SESSION['logs_page_rate'] = $preference['value'];
if ($preference['name'] == "network_acls_page_rate")
$_SESSION['network_acls_page_rate'] = $preference['value'];
if ($preference['name'] == "networks_page_rate")
$_SESSION['networks_page_rate'] = $preference['value'];
if ($preference['name'] == "operations_page_rate")
$_SESSION['operations_page_rate'] = $preference['value'];
if ($preference['name'] == "profiles_page_rate")
$_SESSION['profiles_page_rate'] = $preference['value'];
if ($preference['name'] == "projects_page_rate")
$_SESSION['projects_page_rate'] = $preference['value'];
if ($preference['name'] == "remotes_single_page_rate")
$_SESSION['remotes_single_page_rate'] = $preference['value'];
if ($preference['name'] == "remotes_page_rate")
$_SESSION['remotes_page_rate'] = $preference['value'];
if ($preference['name'] == "simplestreams_page_rate")
$_SESSION['simplestreams_page_rate'] = $preference['value'];
if ($preference['name'] == "storage_pools_page_rate")
$_SESSION['storage_pools_page_rate'] = $preference['value'];
if ($preference['name'] == "storage_volumes_page_rate")
$_SESSION['storage_volumes_page_rate'] = $preference['value'];
if ($preference['name'] == "virtual_machines_page_rate")
$_SESSION['virtual_machines_page_rate'] = $preference['value'];
if ($preference['name'] == "virtual_machines_single_page_rate")
$_SESSION['virtual_machines_single_page_rate'] = $preference['value'];
}
$results = '{"status": "Ok", "status_code": 200, "metadata": "{}"}';
}
else {
//Return 401 Unauthorized despite it technically being unauthenticated
$results = '{"status": "Unauthorized", "status_code": 401, "metadata": {"error": "Incorrect username or password"}}';
}
echo $results;
//Send event to accounting
$event = json_decode($results, true);
$object = $username;
logEvent($action, $remote, $project, $object, $event['status_code'], $event['status']);
break;
case "deauthenticateUser":
$username = $_SESSION['username'];
$user_id = $_SESSION['user_id'];
//Clear the SESSION variables
$_SESSION = array();
if (session_destroy())
$results = '{"status": "Ok", "status_code": 200, "metadata": "{}"}';
echo $results;
//Send event to accounting
$event = json_decode($results, true);
$object = $username;
logEvent($action, $remote, $project, $object, $event['status_code'], $event['status'], $user_id);
break;
case "validateAuthentication":
if (isset($_SESSION['username'])){
echo '{"status": "Ok", "status_code": 200, "metadata": "{}"}';
}
else {
echo '{"status": "Unauthorized", "status_code": 401, "metadata": {"error": "Failed authentication validation"}}';
}
break;
default:
echo "LXDWARE";
}
?>

View file

@ -0,0 +1,86 @@
<?php
/*
LXDWARE LXD Dashboard - A web-based interface for managing LXD servers
Copyright (C) 2020-2021 LXDWARE.COM
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//Start session if not already started
if (!isset($_SESSION)) {
session_start();
}
//Declare and instantiate GET variables
$action = (isset($_GET['action'])) ? filter_var(urldecode($_GET['action']), FILTER_SANITIZE_STRING) : "";
//Require code from lxd-dashboard/backend/config/db.php
require_once('../config/db.php');
//Require code from lxd-dashboard/backend/aaa/accounting.php
require_once('../aaa/accounting.php');
if (isset($_SESSION['username'])) {
require_once('../aaa/authorization.php');
//Run the matching action
switch ($action) {
case "listLogEvents":
$logs_retrieval = intval(retrievePreference("logs_retrieval"));
if ($logs_retrieval < 1){
$logs_retrieval = 100;
}
$rows = retrieveTableRows('lxd_logs', $logs_retrieval);
$i = 0;
echo '{ "data": [';
foreach ($rows as $row){
if ($i > 0){
echo ",";
}
$i++;
echo "[ ";
echo '"';
echo "<i class='fas fa-history fa-lg' style='color:#4e73df'></i>";
echo '",';
echo '"' . htmlentities($row['id']) . '",';
echo '"' . htmlentities($row['control']) . '",';
echo '"' . htmlentities($row['remote_id']) . '",';
echo '"' . htmlentities($row['project']) . '",';
echo '"' . htmlentities($row['object']) . '",';
echo '"' . htmlentities($row['status_code']) . '",';
echo '"' . htmlentities($row['message']) . '",';
echo '"' . htmlentities($row['hostname']) . '",';
echo '"' . htmlentities($row['user_id']) . '",';
echo '"' . htmlentities($row['date']) . '"';
echo " ]";
}
echo " ]}";
break;
}
}
?>

View file

@ -0,0 +1,779 @@
<?php
/*
LXDWARE LXD Dashboard - A web-based interface for managing LXD servers
Copyright (C) 2020-2021 LXDWARE.COM
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//Start session if not already started
if (!isset($_SESSION)) {
session_start();
}
//Declare and instantiate GET variables
$action = (isset($_GET['action'])) ? filter_var(urldecode($_GET['action']), FILTER_SANITIZE_STRING) : "";
$certificates_page_rate = (isset($_GET['certificates_page_rate'])) ? filter_var(urldecode($_GET['certificates_page_rate']), FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION) : "5";
$cluster_members_page_rate = (isset($_GET['cluster_members_page_rate'])) ? filter_var(urldecode($_GET['cluster_members_page_rate']), FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION) : "5";
$containers_page_rate = (isset($_GET['containers_page_rate'])) ? filter_var(urldecode($_GET['containers_page_rate']), FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION) : "5";
$containers_single_page_rate = (isset($_GET['containers_single_page_rate'])) ? filter_var(urldecode($_GET['containers_single_page_rate']), FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION) : "5";
$delete_connection_timeout = (isset($_GET['delete_connection_timeout'])) ? filter_var(urldecode($_GET['delete_connection_timeout']), FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION) : "5";
$delete_operation_timeout = (isset($_GET['delete_operation_timeout'])) ? filter_var(urldecode($_GET['delete_operation_timeout']), FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION) : "5";
$description = (isset($_GET['description'])) ? filter_var(urldecode($_GET['description']), FILTER_SANITIZE_STRING) : "";
$get_connection_timeout = (isset($_GET['get_connection_timeout'])) ? filter_var(urldecode($_GET['get_connection_timeout']), FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION) : "2";
$get_operation_timeout = (isset($_GET['get_operation_timeout'])) ? filter_var(urldecode($_GET['get_operation_timeout']), FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION) : "5";
$images_page_rate = (isset($_GET['images_page_rate'])) ? filter_var(urldecode($_GET['images_page_rate']), FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION) : "5";
$logs_enabled_status = (isset($_GET['logs_enabled_status'])) ? filter_var(urldecode($_GET['logs_enabled_status']), FILTER_SANITIZE_STRING) : "";
$logs_page_rate = (isset($_GET['logs_page_rate'])) ? filter_var(urldecode($_GET['logs_page_rate']), FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION) : "5";
$logs_retrieval_number = (isset($_GET['logs_retrieval_number'])) ? filter_var(urldecode($_GET['logs_retrieval_number']), FILTER_SANITIZE_NUMBER_INT) : "";
$id = (isset($_GET['id'])) ? filter_var(urldecode($_GET['id']), FILTER_SANITIZE_NUMBER_INT) : "";
$group_id = (isset($_GET['group_id'])) ? filter_var(urldecode($_GET['group_id']), FILTER_SANITIZE_NUMBER_INT) : "";
$name = (isset($_GET['name'])) ? filter_var(urldecode($_GET['name']), FILTER_SANITIZE_STRING) : "";
$network_acls_page_rate = (isset($_GET['network_acls_page_rate'])) ? filter_var(urldecode($_GET['network_acls_page_rate']), FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION) : "5";
$networks_page_rate = (isset($_GET['networks_page_rate'])) ? filter_var(urldecode($_GET['networks_page_rate']), FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION) : "5";
$operations_page_rate = (isset($_GET['operations_page_rate'])) ? filter_var(urldecode($_GET['operations_page_rate']), FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION) : "5";
$patch_connection_timeout = (isset($_GET['patch_connection_timeout'])) ? filter_var(urldecode($_GET['patch_connection_timeout']), FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION) : "5";
$patch_operation_timeout = (isset($_GET['patch_operation_timeout'])) ? filter_var(urldecode($_GET['patch_operation_timeout']), FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION) : "5";
$post_connection_timeout = (isset($_GET['post_connection_timeout'])) ? filter_var(urldecode($_GET['post_connection_timeout']), FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION) : "5";
$post_operation_timeout = (isset($_GET['post_operation_timeout'])) ? filter_var(urldecode($_GET['post_operation_timeout']), FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION) : "5";
$profiles_page_rate = (isset($_GET['profiles_page_rate'])) ? filter_var(urldecode($_GET['profiles_page_rate']), FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION) : "5";
$project = (isset($_GET['project'])) ? filter_var(urldecode($_GET['project']), FILTER_SANITIZE_STRING) : "";
$projects_page_rate = (isset($_GET['projects_page_rate'])) ? filter_var(urldecode($_GET['projects_page_rate']), FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION) : "5";
$put_connection_timeout = (isset($_GET['put_connection_timeout'])) ? filter_var(urldecode($_GET['put_connection_timeout']), FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION) : "5";
$put_operation_timeout = (isset($_GET['put_operation_timeout'])) ? filter_var(urldecode($_GET['put_operation_timeout']), FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION) : "5";
$remote = (isset($_GET['remote'])) ? filter_var(urldecode($_GET['remote']), FILTER_SANITIZE_NUMBER_INT) : "";
$remotes_single_page_rate = (isset($_GET['remotes_single_page_rate'])) ? filter_var(urldecode($_GET['remotes_single_page_rate']), FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION) : "5";
$remotes_page_rate = (isset($_GET['remotes_page_rate'])) ? filter_var(urldecode($_GET['remotes_page_rate']), FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION) : "5";
$role_id = (isset($_GET['role_id'])) ? filter_var(urldecode($_GET['role_id']), FILTER_SANITIZE_NUMBER_INT) : "";
$simplestreams_page_rate = (isset($_GET['simplestreams_page_rate'])) ? filter_var(urldecode($_GET['simplestreams_page_rate']), FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION) : "5";
$storage_pools_page_rate = (isset($_GET['storage_pools_page_rate'])) ? filter_var(urldecode($_GET['storage_pools_page_rate']), FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION) : "5";
$storage_volumes_page_rate = (isset($_GET['storage_volumes_page_rate'])) ? filter_var(urldecode($_GET['storage_volumes_page_rate']), FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION) : "5";
$virtual_machines_page_rate = (isset($_GET['virtual_machines_page_rate'])) ? filter_var(urldecode($_GET['virtual_machines_page_rate']), FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION) : "5";
$virtual_machines_single_page_rate = (isset($_GET['virtual_machines_single_page_rate'])) ? filter_var(urldecode($_GET['virtual_machines_single_page_rate']), FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION) : "5";
//Declare and instantiate POST variables
$email = (isset($_POST['email'])) ? filter_var(urldecode($_POST['email']), FILTER_SANITIZE_STRING) : "";
$first_name = (isset($_POST['first_name'])) ? filter_var(urldecode($_POST['first_name']), FILTER_SANITIZE_STRING) : "";
$last_name = (isset($_POST['last_name'])) ? filter_var(urldecode($_POST['last_name']), FILTER_SANITIZE_STRING) : "";
$password = (isset($_POST['password'])) ? $_POST['password'] : "";
$username = (isset($_POST['username'])) ? filter_var(urldecode($_POST['username']), FILTER_SANITIZE_STRING) : "";
//Require code from lxd-dashboard/backend/config/db.php
require_once('../config/db.php');
//Require code from lxd-dashboard/backend/aaa/accounting.php
require_once('../aaa/accounting.php');
if (isset($_SESSION['username'])) {
require_once('../aaa/authorization.php');
//Run the matching action
switch ($action) {
case "addRoleToGroup":
if (validateAuthorization($action)) {
$record_added = addGroupRoleMapping($id, $role_id);
if ($record_added)
$results = '{"status": "Ok", "status_code": 200, "metadata": {"status": "Record added"}}';
else
$results = '{"status": "Bad Request", "status_code": 400, "metadata": {"error": "Unable to add the record to the database"}}';
}
else {
$results = '{"status": "Forbidden", "status_code": 403, "metadata": {"error": "You are not authorized to execute this action"}}';
}
echo $results;
//Send event to accounting
$event = json_decode($results, true);
$object = $id . " - " . $role_id;
logEvent($action, $remote, $project, $object, $event['status_code'], $event['status']);
break;
case "addUserToGroup":
if (validateAuthorization($action)) {
$record_added = addUserGroupMapping($id, $group_id);
if ($record_added)
$results = '{"status": "Ok", "status_code": 200, "metadata": {"status": "Record added"}}';
else
$results = '{"status": "Bad Request", "status_code": 400, "metadata": {"error": "Unable to add the record to the database"}}';
}
else {
$results = '{"status": "Forbidden", "status_code": 403, "metadata": {"error": "You are not authorized to execute this action"}}';
}
echo $results;
//Send event to accounting
$event = json_decode($results, true);
$object = $id . " - " . $group_id;
logEvent($action, $remote, $project, $object, $event['status_code'], $event['status']);
break;
case "createGroup":
if (validateAuthorization($action)) {
$record_added = addGroup($name, $description);
if($record_added){
$results = '{"status": "Ok", "status_code": 200, "metadata": "{}"}';
$group_id = retrieveGroupId($name);
}
else {
$results = '{"status": "Bad Request", "status_code": 400, "metadata": {"error": "Unable to add the record to the database"}}';
}
}
else {
$results = '{"status": "Forbidden", "status_code": 403, "metadata": {"error": "You are not authorized to execute this action"}}';
}
echo $results;
//Send event to accounting
$event = json_decode($results, true);
$object = $group_id . " - " . $name;
logEvent($action, $remote, $project, $object, $event['status_code'], $event['status']);
break;
case "createUser":
if (validateAuthorization($action)) {
//Test to verify username and password both have a value
if (!empty($username) && !empty($password)) {
//Hash and salt password with bcrypt
$passwd_hash = password_hash($password, PASSWORD_BCRYPT);
if(isFirstUser()){
$record_added = addUser($username, $first_name, $last_name, $passwd_hash, $email);
if($record_added){
$user_id = retrieveUserId($username);
$group_id = retrieveGroupId('admin');
addUserGroupMapping($user_id, $group_id);
}
$results = '{"status": "Ok", "status_code": 200, "metadata": "{}"}';
}
else {
$record_added = addUser($username, $first_name, $last_name, $passwd_hash, $email);
if($record_added){
$user_id = retrieveUserId($username);
$group_id = retrieveGroupId('auditor');
if($group_id){
addUserGroupMapping($user_id, $group_id);
}
$results = '{"status": "Ok", "status_code": 200, "metadata": "{}"}';
}
else {
$results = '{"status": "Bad Request", "status_code": 400, "metadata": {"error": "Unable to add the record to the database"}}';
}
}
}
else {
$results = '{"status": "Bad Request", "status_code": 400, "metadata": {"error": "Both a username and password must be supplied"}}';
}
}
else {
$results = '{"status": "Forbidden", "status_code": 403, "metadata": {"error": "You are not authorized to execute this action"}}';
}
echo $results;
//Send event to accounting
$event = json_decode($results, true);
$object = $user_id . " - " . $username;
logEvent($action, $remote, $project, $object, $event['status_code'], $event['status']);
break;
case "deleteGroup":
if (validateAuthorization($action)) {
$record_removed = deleteGroup($id);
if ($record_removed)
$results = '{"status": "Ok", "status_code": 200, "metadata": {"status": "Record removed"}}';
else
$results = '{"status": "Bad Request", "status_code": 400, "metadata": {"error": "Unable to remove record from database"}}';
}
else {
$results = '{"status": "Forbidden", "status_code": 403, "metadata": {"error": "You are not authorized to execute this action"}}';
}
echo $results;
//Send event to accounting
$event = json_decode($results, true);
$object = $id;
logEvent($action, $remote, $project, $object, $event['status_code'], $event['status']);
break;
case "deleteUser":
if (validateAuthorization($action)) {
$record_removed = deleteUser($id);
if ($record_removed)
$results = '{"status": "Ok", "status_code": 200, "metadata": {"status": "Record removed"}}';
else
$results = '{"status": "Bad Request", "status_code": 400, "metadata": {"error": "Unable to remove record from database"}}';
}
else {
$results = '{"status": "Forbidden", "status_code": 403, "metadata": {"error": "You are not authorized to execute this action"}}';
}
echo $results;
//Send event to accounting
$event = json_decode($results, true);
$object = $id;
logEvent($action, $remote, $project, $object, $event['status_code'], $event['status']);
break;
case "displayUsername":
echo htmlentities($_SESSION['username']);
break;
case "listGroups":
if (validateAuthorization($action)) {
$rows = retrieveTableRows('lxd_groups');
$i = 0;
echo '{ "data": [';
foreach ($rows as $row){
$roles = retrieveGroupRoles($row['id']);
$users = retrieveGroupUsers($row['id']);
if ($i > 0){
echo ",";
}
$i++;
echo "[ ";
echo '"';
echo "<i class='fas fa-users fa-lg' style='color:#4e73df'></i>";
echo '",';
echo '"' . htmlentities($row['name']) . '",';
echo '"' . htmlentities($row['description']) . '",';
echo '"';
$ii = 0;
foreach ($roles as $role){
if ($ii > 0){
echo ", ";
}
$ii++;
echo htmlentities($role['name']);
}
echo '",';
echo '"';
echo "<a href='#' onclick='loadAddRoleModal(".$row['id'].")'><i class='fas fa-plus fa-lg' style='color:#ddd' title='Add Role' aria-hidden='true'></i></a>";
echo ' &nbsp ';
echo "<a href='#' onclick='loadRemoveRoleModal(".$row['id'].")'><i class='fas fa-minus fa-lg' style='color:#ddd' title='Remove Role' aria-hidden='true'></i></a>";
echo ' &nbsp ';
echo "<a href='#' onclick='loadDeleteGroupModal(".$row['id'].")'><i class='fas fa-trash-alt fa-lg' style='color:#ddd' title='Delete Group' aria-hidden='true'></i></a>";
echo '"';
echo " ]";
}
echo " ]}";
}
else {
echo '{ "data": [] }';
}
break;
case "listGroupsAssignedToUserForSelect":
if (validateAuthorization($action)) {
$groups = retrieveUserGroups($id);
foreach ($groups as $group){
echo '<option value="' . $group['id'] . '">' . htmlentities($group['name']) . '</option>';
}
}
break;
case "listGroupsNotAssignedToUserForSelect":
if (validateAuthorization($action)) {
$groups = retrieveTableRows('lxd_groups');
$user_groups = retrieveUserGroups($id);
foreach ($groups as $group){
$group_belongs_to_user = false;
foreach ($user_groups as $user_group){
if ($user_group['name'] == $group['name']){
$group_belongs_to_user = true;
}
}
if(!$group_belongs_to_user){
echo '<option value="' . $group['id'] . '">' . htmlentities($group['name']) . '</option>';
}
}
}
break;
case "listRolesAssignedToGroupForSelect":
if (validateAuthorization($action)) {
$roles = retrieveGroupRoles($id);
foreach ($roles as $role){
echo '<option value="' . $role['id'] . '">' . htmlentities($role['name']) . '</option>';
}
}
break;
case "listRolesNotAssignedToGroupForSelect":
if (validateAuthorization($action)) {
$roles = retrieveDefaultRoles();
$group_roles = retrieveGroupRoles($id);
foreach ($roles as $role){
$role_belongs_to_group = false;
foreach ($group_roles as $group_role){
if ($group_role['name'] == $role['name']){
$role_belongs_to_group = true;
}
}
if(!$role_belongs_to_group){
echo '<option value="' . $role['id'] . '">' . htmlentities($role['name']) . '</option>';
}
}
}
break;
case "listUsers":
if (validateAuthorization($action)) {
$rows = retrieveTableRows('lxd_users');
$i = 0;
echo '{ "data": [';
foreach ($rows as $row){
$groups = retrieveUserGroups($row['id']);
if ($i > 0){
echo ",";
}
$i++;
echo "[ ";
echo '"';
echo "<a href='user-profile.php?user=".$row['id']."'><i class='fas fa-user fa-lg' style='color:#4e73df'></i> </a>";
echo '",';
echo '"';
echo "<a href='user-profile.php?user=".$row['id']."'> ".htmlentities($row['username'])."</a>";
echo '",';
echo '"' . htmlentities($row['email']) . '",';
echo '"' . htmlentities($row['type']) . '",';
echo '"';
$ii = 0;
foreach ($groups as $group){
if ($ii > 0){
echo ", ";
}
$ii++;
echo htmlentities($group['name']);
}
echo '",';
echo '"';
echo "<a href='#' onclick='loadAddGroupModal(".$row['id'].")'><i class='fas fa-plus fa-lg' style='color:#ddd' title='Add Group' aria-hidden='true'></i></a>";
echo ' &nbsp ';
echo "<a href='#' onclick='loadRemoveGroupModal(".$row['id'].")'><i class='fas fa-minus fa-lg' style='color:#ddd' title='Remove Group' aria-hidden='true'></i></a>";
echo ' &nbsp ';
echo "<a href='#' onclick='loadDeleteUserModal(".$row['id'].")'><i class='fas fa-trash-alt fa-lg' style='color:#ddd' title='Delete User' aria-hidden='true'></i></a>";
echo '"';
echo " ]";
}
echo " ]}";
}
else {
echo '{ "data": [] }';
}
break;
case "retrieveCurlTimeoutValues":
//Retrieve SESSION variables and return JSON
$arr = array();
$arr['get_connection_timeout'] = $_SESSION['get_connection_timeout'];
$arr['get_operation_timeout'] = $_SESSION['get_operation_timeout'];
$arr['post_connection_timeout'] = $_SESSION['post_connection_timeout'];
$arr['post_operation_timeout'] = $_SESSION['post_operation_timeout'];
$arr['patch_connection_timeout'] = $_SESSION['patch_connection_timeout'];
$arr['patch_operation_timeout'] = $_SESSION['patch_operation_timeout'];
$arr['put_connection_timeout'] = $_SESSION['put_connection_timeout'];
$arr['put_operation_timeout'] = $_SESSION['put_operation_timeout'];
$arr['delete_connection_timeout'] = $_SESSION['delete_connection_timeout'];
$arr['delete_operation_timeout'] = $_SESSION['delete_operation_timeout'];
echo json_encode($arr);
break;
case "retrieveLogPreferences":
$arr = array();
$arr['logs_enabled'] = retrievePreference("logs_enabled");
$arr['logs_retrieval'] = intval(retrievePreference("logs_retrieval"));
echo json_encode($arr);
break;
case "retrievePageRefreshRateValues":
//Retrieve SESSION variables and return JSON
$arr = array();
$arr['certificates_page_rate'] = $_SESSION['certificates_page_rate'];
$arr['cluster_members_page_rate'] = $_SESSION['cluster_members_page_rate'];
$arr['containers_page_rate'] = $_SESSION['containers_page_rate'];
$arr['containers_single_page_rate'] = $_SESSION['containers_single_page_rate'];
$arr['images_page_rate'] = $_SESSION['images_page_rate'];
$arr['logs_page_rate'] = $_SESSION['logs_page_rate'];
$arr['network_acls_page_rate'] = $_SESSION['network_acls_page_rate'];
$arr['networks_page_rate'] = $_SESSION['networks_page_rate'];
$arr['operations_page_rate'] = $_SESSION['operations_page_rate'];
$arr['profiles_page_rate'] = $_SESSION['profiles_page_rate'];
$arr['projects_page_rate'] = $_SESSION['projects_page_rate'];
$arr['remotes_single_page_rate'] = $_SESSION['remotes_single_page_rate'];
$arr['remotes_page_rate'] = $_SESSION['remotes_page_rate'];
$arr['simplestreams_page_rate'] = $_SESSION['simplestreams_page_rate'];
$arr['storage_pools_page_rate'] = $_SESSION['storage_pools_page_rate'];
$arr['storage_volumes_page_rate'] = $_SESSION['storage_volumes_page_rate'];
$arr['virtual_machines_page_rate'] = $_SESSION['virtual_machines_page_rate'];
$arr['virtual_machines_single_page_rate'] = $_SESSION['virtual_machines_single_page_rate'];
echo json_encode($arr);
break;
case "removeGroupFromUser":
if (validateAuthorization($action)) {
$record_removed = deleteUserGroupMapping($id, $group_id);
if ($record_removed)
$results = '{"status": "Ok", "status_code": 200, "metadata": {"status": "Record removed"}}';
else
$results = '{"status": "Bad Request", "status_code": 400, "metadata": {"error": "Unable to remove record from database"}}';
}
else {
$results = '{"status": "Forbidden", "status_code": 403, "metadata": {"error": "You are not authorized to execute this action"}}';
}
echo $results;
//Send event to accounting
$event = json_decode($results, true);
$object = $id . " - " . $group_id;
logEvent($action, $remote, $project, $object, $event['status_code'], $event['status']);
break;
case "removeRoleFromGroup":
if (validateAuthorization($action)) {
$record_removed = deleteGroupRoleMapping($id, $role_id);
if ($record_removed)
$results = '{"status": "Ok", "status_code": 200, "metadata": {"status": "Record removed"}}';
else
$results = '{"status": "Bad Request", "status_code": 400, "metadata": {"error": "Unable to remove record from database"}}';
}
else {
$results = '{"status": "Forbidden", "status_code": 403, "metadata": {"error": "You are not authorized to execute this action"}}';
}
echo $results;
//Send event to accounting
$event = json_decode($results, true);
$object = $id . " - " . $role_id;
logEvent($action, $remote, $project, $object, $event['status_code'], $event['status']);
break;
case "updateLogPreferences":
if (validateAuthorization($action)) {
if ($logs_enabled_status == "true" || $logs_enabled_status == "false"){
$logs_enabled_status_updated = updatePreference("logs_enabled", $logs_enabled_status);
}
if (is_numeric($logs_retrieval_number) && $logs_retrieval_number >= 1){
$logs_retrieval_number_updated = updatePreference("logs_retrieval", $logs_retrieval_number);
}
if ($logs_enabled_status_updated && $logs_retrieval_number_updated)
$results = '{"status": "Ok", "status_code": 200, "metadata": {"status": "Record added"}}';
else
$results = '{"status": "Bad Request", "status_code": 400, "metadata": {"error": "There was an error while updating the lxd_preferences table"}}';
}
else {
$results = '{"status": "Forbidden", "status_code": 403, "metadata": {"error": "You are not authorized to execute this action"}}';
}
echo $results;
//Send event to accounting
$event = json_decode($results, true);
$object = "";
logEvent($action, $remote, $project, $object, $event['status_code'], $event['status']);
break;
case "updateOutboundRequestPreferences":
if (validateAuthorization($action)) {
if (is_numeric($get_connection_timeout) && $get_connection_timeout >= 1)
$get_connection_timeout_updated = updatePreference("get_connection_timeout", $get_connection_timeout);
if ($get_connection_timeout_updated)
$_SESSION['get_connection_timeout'] = $get_connection_timeout;
if (is_numeric($get_operation_timeout) && $get_operation_timeout >= 1)
$get_operation_timeout_updated = updatePreference("get_operation_timeout", $get_operation_timeout);
if ($get_operation_timeout_updated)
$_SESSION['get_operation_timeout'] = $get_operation_timeout;
if (is_numeric($post_connection_timeout) && $post_connection_timeout >= 1)
$post_connection_timeout_updated = updatePreference("post_connection_timeout", $post_connection_timeout);
if ($post_connection_timeout_updated)
$_SESSION['post_connection_timeout'] = $post_connection_timeout;
if (is_numeric($post_operation_timeout) && $post_operation_timeout >= 1)
$post_operation_timeout_updated = updatePreference("post_operation_timeout", $post_operation_timeout);
if ($post_operation_timeout_updated)
$_SESSION['post_operation_timeout'] = $post_operation_timeout;
if (is_numeric($patch_connection_timeout) && $patch_connection_timeout >= 1)
$patch_connection_timeout_updated = updatePreference("patch_connection_timeout", $patch_connection_timeout);
if ($patch_connection_timeout_updated)
$_SESSION['patch_connection_timeout'] = $patch_connection_timeout;
if (is_numeric($patch_operation_timeout) && $patch_operation_timeout >= 1)
$patch_operation_timeout_updated = updatePreference("patch_operation_timeout", $patch_operation_timeout);
if ($patch_operation_timeout_updated)
$_SESSION['patch_operation_timeout'] = $patch_operation_timeout;
if (is_numeric($put_connection_timeout) && $put_connection_timeout >= 1)
$put_connection_timeout_updated = updatePreference("put_connection_timeout", $put_connection_timeout);
if ($put_connection_timeout_updated)
$_SESSION['put_connection_timeout'] = $put_connection_timeout;
if (is_numeric($put_operation_timeout) && $put_operation_timeout >= 1)
$put_operation_timeout_updated = updatePreference("put_operation_timeout", $put_operation_timeout);
if ($put_operation_timeout_updated)
$_SESSION['put_operation_timeout'] = $put_operation_timeout;
if (is_numeric($delete_connection_timeout) && $delete_connection_timeout >= 1)
$delete_connection_timeout_updated = updatePreference("delete_connection_timeout", $delete_connection_timeout);
if ($delete_connection_timeout_updated)
$_SESSION['delete_connection_timeout'] = $delete_connection_timeout;
if (is_numeric($delete_operation_timeout) && $delete_operation_timeout >= 1)
$delete_operation_timeout_updated = updatePreference("delete_operation_timeout", $delete_operation_timeout);
if ($delete_operation_timeout_updated)
$_SESSION['delete_operation_timeout'] = $delete_operation_timeout;
if ($get_connection_timeout_updated && $get_operation_timeout_updated && $post_connection_timeout_updated && $post_operation_timeout_updated && $patch_connection_timeout_updated && $patch_operation_timeout_updated && $put_connection_timeout_updated && $put_operation_timeout_updated && $delete_connection_timeout_updated && $delete_operation_timeout_updated)
$results = '{"status": "Ok", "status_code": 200, "metadata": {"status": "Record added"}}';
else
$results = '{"status": "Bad Request", "status_code": 400, "metadata": {"error": "There was an error while updating the lxd_preferences table"}}';
}
else {
$results = '{"status": "Forbidden", "status_code": 403, "metadata": {"error": "You are not authorized to execute this action"}}';
}
echo $results;
//Send event to accounting
$event = json_decode($results, true);
$object = "";
logEvent($action, $remote, $project, $object, $event['status_code'], $event['status']);
break;
case "updateRefreshRatePreferences":
if (validateAuthorization($action)) {
if (is_numeric($certificates_page_rate) && $certificates_page_rate >= 1)
$certificates_page_rate_updated = updatePreference("certificates_page_rate", $certificates_page_rate);
if ($certificates_page_rate_updated)
$_SESSION['certificates_page_rate'] = $certificates_page_rate;
if (is_numeric($cluster_members_page_rate) && $cluster_members_page_rate >= 1)
$cluster_members_page_rate_updated = updatePreference("cluster_members_page_rate", $cluster_members_page_rate);
if ($cluster_members_page_rate_updated)
$_SESSION['cluster_members_page_rate'] = $cluster_members_page_rate;
if (is_numeric($containers_page_rate) && $containers_page_rate >= 1)
$containers_page_rate_updated = updatePreference("containers_page_rate", $containers_page_rate);
if ($containers_page_rate_updated)
$_SESSION['containers_page_rate'] = $containers_page_rate;
if (is_numeric($containers_single_page_rate) && $containers_single_page_rate >= 1)
$containers_single_page_rate_updated = updatePreference("containers_single_page_rate", $containers_single_page_rate);
if ($containers_single_page_rate_updated )
$_SESSION['containers_single_page_rate'] = $containers_single_page_rate;
if (is_numeric($images_page_rate) && $images_page_rate >= 1)
$images_page_rate_updated = updatePreference("images_page_rate", $images_page_rate);
if ($images_page_rate_updated)
$_SESSION['images_page_rate'] = $images_page_rate;
if (is_numeric($logs_page_rate) && $logs_page_rate >= 1)
$logs_page_rate_updated = updatePreference("logs_page_rate", $logs_page_rate);
if ($logs_page_rate_updated)
$_SESSION['logs_page_rate'] = $logs_page_rate;
if (is_numeric($network_acls_page_rate) && $network_acls_page_rate >= 1)
$network_acls_page_rate_updated = updatePreference("network_acls_page_rate", $network_acls_page_rate);
if ($network_acls_page_rate_updated)
$_SESSION['network_acls_page_rate'] = $network_acls_page_rate;
if (is_numeric($networks_page_rate) && $networks_page_rate >= 1)
$networks_page_rate_updated = updatePreference("networks_page_rate", $networks_page_rate);
if ($networks_page_rate_updated)
$_SESSION['networks_page_rate'] = $networks_page_rate;
if (is_numeric($operations_page_rate) && $operations_page_rate >= 1)
$operations_page_rate_updated = updatePreference("operations_page_rate", $operations_page_rate);
if ($operations_page_rate_updated)
$_SESSION['operations_page_rate'] = $operations_page_rate;
if (is_numeric($profiles_page_rate) && $profiles_page_rate >= 1)
$profiles_page_rate_updated = updatePreference("profiles_page_rate", $profiles_page_rate);
if ($profiles_page_rate_updated)
$_SESSION['profiles_page_rate'] = $profiles_page_rate;
if (is_numeric($projects_page_rate) && $projects_page_rate >= 1)
$projects_page_rate_updated = updatePreference("projects_page_rate", $projects_page_rate);
if ($projects_page_rate_updated)
$_SESSION['projects_page_rate'] = $projects_page_rate;
if (is_numeric($remotes_single_page_rate) && $remotes_single_page_rate >= 1)
$remotes_single_page_rate_updated = updatePreference("remotes_single_page_rate", $remotes_single_page_rate);
if ($remotes_single_page_rate_updated)
$_SESSION['remotes_single_page_rate'] = $remotes_single_page_rate;
if (is_numeric($remotes_page_rate) && $remotes_page_rate >= 1)
$remotes_page_rate_updated = updatePreference("remotes_page_rate", $remotes_page_rate);
if ($remotes_page_rate_updated)
$_SESSION['remotes_page_rate'] = $remotes_page_rate;
if (is_numeric($simplestreams_page_rate) && $simplestreams_page_rate >= 1)
$simplestreams_page_rate_updated = updatePreference("simplestreams_page_rate", $simplestreams_page_rate);
if ($simplestreams_page_rate_updated)
$_SESSION['simplestreams_page_rate'] = $simplestreams_page_rate;
if (is_numeric($storage_pools_page_rate) && $storage_pools_page_rate >= 1)
$storage_pools_page_rate_updated = updatePreference("storage_pools_page_rate", $storage_pools_page_rate);
if ($storage_pools_page_rate_updated)
$_SESSION['storage_pools_page_rate'] = $storage_pools_page_rate;
if (is_numeric($storage_volumes_page_rate) && $storage_volumes_page_rate >= 1)
$storage_volumes_page_rate_updated = updatePreference("storage_volumes_page_rate", $storage_volumes_page_rate);
if ($storage_volumes_page_rate_updated)
$_SESSION['storage_volumes_page_rate'] = $storage_volumes_page_rate;
if (is_numeric($virtual_machines_page_rate) && $virtual_machines_page_rate >= 1)
$virtual_machines_page_rate_updated = updatePreference("virtual_machines_page_rate", $virtual_machines_page_rate);
if ($virtual_machines_page_rate_updated)
$_SESSION['virtual_machines_page_rate'] = $virtual_machines_page_rate;
if (is_numeric($virtual_machines_single_page_rate) && $virtual_machines_single_page_rate >= 1)
$virtual_machines_single_page_rate_updated = updatePreference("virtual_machines_single_page_rate", $virtual_machines_single_page_rate);
if ($virtual_machines_single_page_rate_updated)
$_SESSION['virtual_machines_single_page_rate'] = $virtual_machines_single_page_rate;
if ($certificates_page_rate_updated && $cluster_members_page_rate_updated && $containers_page_rate_updated && $containers_single_page_rate_updated && $images_page_rate_updated && $logs_page_rate_updated && $network_acls_page_rate_updated && $networks_page_rate_updated && $operations_page_rate_updated && $profiles_page_rate_updated && $projects_page_rate_updated && $remotes_single_page_rate_updated && $remotes_page_rate_updated && $simplestreams_page_rate_updated && $storage_pools_page_rate_updated && $storage_volumes_page_rate_updated && $virtual_machines_page_rate_updated && $virtual_machines_single_page_rate_updated)
$results = '{"status": "Ok", "status_code": 200, "metadata": {"status": "Record added"}}';
else
$results = '{"status": "Bad Request", "status_code": 400, "metadata": {"error": "There was an error while updating the lxd_preferences table"}}';
}
else {
$results = '{"status": "Forbidden", "status_code": 403, "metadata": {"error": "You are not authorized to execute this action"}}';
}
echo $results;
//Send event to accounting
$event = json_decode($results, true);
$object = "";
logEvent($action, $remote, $project, $object, $event['status_code'], $event['status']);
break;
}
}
else {
switch ($action) {
case "createUser":
//Test to verify username and password both have a value
if (!empty($username) && !empty($password)) {
//Hash and salt password with bcrypt
$passwd_hash = password_hash($password, PASSWORD_BCRYPT);
if(isFirstUser()){
$record_added = addUser($username, $first_name, $last_name, $passwd_hash, $email);
if($record_added){
$user_id = retrieveUserId($username);
$group_id = retrieveGroupId('admin');
addUserGroupMapping($user_id, $group_id);
}
$results = '{"status": "Ok", "status_code": 200, "metadata": "{}"}';
}
else {
$results = '{"status": "Bad Request", "status_code": 400, "metadata": {"error": "User was not added as there are already existing user accounts"}}';
}
}
else {
$results = '{"status": "Bad Request", "status_code": 400, "metadata": {"error": "Must supply both a username and password"}}';
}
echo $results;
break;
}
}
?>

View file

@ -34,10 +34,10 @@ $remote = (isset($_GET['remote'])) ? filter_var(urldecode($_GET['remote']), FILT
//Declare and instantiate POST variables
$password = (isset($_POST['password'])) ? $_POST['password'] : "";
//Require code from lxd-dashboard/php/config/db.php
//Require code from lxd-dashboard/backend/config/db.php
require_once('../config/db.php');
//Require code from lxd-dashboard/php/aaa/accounting.php
//Require code from lxd-dashboard/backend/aaa/accounting.php
require_once('../aaa/accounting.php');
if (isset($_SESSION['username'])) {

View file

@ -1,4 +1,5 @@
<!--
<?php
/*
LXDWARE LXD Dashboard - A web-based interface for managing LXD servers
Copyright (C) 2020-2021 LXDWARE.COM
@ -14,17 +15,42 @@ GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
*/
//Start session if not already started
if (!isset($_SESSION)) {
session_start();
}
if (isset($_SESSION['username'])) {
//Include db_config.php file
include_once('/var/lxdware/data/db_config.php');
switch (DB_TYPE) {
case "sqlite":
$database_type = "SQLite";
break;
case "mysql":
$database_type = "MySQL";
break;
}
?>
<!DOCTYPE html>
<html lang="en">
<body class="">
<p>This open source LXD dashboard is developed by LXDWARE and provides a web-based user interface capable of managing multiple LXD servers from a single location.</p>
<p>The open source LXD Dashboard is developed by LXDWARE and provides a web-based user interface capable of managing multiple LXD servers from a single location.</p>
<p>
<strong>Version</strong>: <span id="versionNumber">v2.2.0</span> <br />
<strong>Version</strong>: <span id="versionNumber">v3.8.0</span> <br />
<strong>License</strong>: AGPL-3.0 <br />
<strong>URL</strong>: https://lxdware.com <br />
</p>
</p>
<p>
<strong>Hostname</strong>: <?php echo gethostname(); ?> <br />
<strong>Database Type</strong>: <?php echo $database_type ?>
</p>
<div class="text-center">
<p class="text-primary" id="updateMessage"></p>
@ -47,4 +73,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
});
}
</script>
</html>
</html>
<?php
}
?>

View file

@ -0,0 +1,151 @@
<?php
/*
LXDWARE LXD Dashboard - A web-based interface for managing LXD servers
Copyright (C) 2020-2021 LXDWARE.COM
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//Start session if not already started
if (!isset($_SESSION)) {
session_start();
}
function createCertificate($certificateFilename, $numberofDays = 3650){
//Only create the certificate if it does not already exist
if (!file_exists('/var/lxdware/data/lxd/'.$certificateFilename.'.crt')){
$subject = array(
"commonName" => "LXDWARE",
);
//Generate a new private (and public) key pair
$private_key = openssl_pkey_new(array(
"private_key_type" => OPENSSL_KEYTYPE_EC,
"curve_name" => 'secp384r1',
));
//Generate a certificate signing request
$csr = openssl_csr_new($subject, $private_key);
//Generate self-signed EC cert
$x509 = openssl_csr_sign($csr, null, $private_key, $numberofDays);
openssl_x509_export_to_file($x509, '/var/lxdware/data/lxd/'.$certificateFilename.'.crt');
openssl_pkey_export_to_file($private_key, '/var/lxdware/data/lxd/'.$certificateFilename.'.key');
//Change permissions to lock down private key
chmod('/var/lxdware/data/lxd/'.$certificateFilename.'.key',0600);
}
}
//Create default client.crt certificate if it does not already exist, ensuring that it is always available to the system, even if deleted.
createCertificate('client');
if (isset($_SESSION['username'])) {
//Declare and instantiate GET variables
$action = (isset($_GET['action'])) ? filter_var(urldecode($_GET['action']), FILTER_SANITIZE_STRING) : "";
$name = (isset($_GET['name'])) ? filter_var(urldecode($_GET['name']), FILTER_SANITIZE_STRING) : "";
$days = (isset($_GET['days'])) ? filter_var(urldecode($_GET['days']), FILTER_SANITIZE_NUMBER_INT) : "3650";
require_once('../aaa/authorization.php');
//Run the matching action
switch ($action) {
case "createCertificateFiles":
if (validateAuthorization($action)) {
if (!empty($name)){
if (!file_exists('/var/lxdware/data/lxd/'.$name.'.crt')){
createCertificate($name, $days);
if (file_exists('/var/lxdware/data/lxd/'.$name.'.crt') && file_exists('/var/lxdware/data/lxd/'.$name.'.key'))
echo '{"status": "Ok", "status_code": 200, "metadata": {"status": "Certificate files created"}}';
else
echo '{"status": "Bad Request", "status_code": 400, "metadata": {"error": "Unable to create all certificate files"}}';
}
else {
echo '{"status": "Bad Request", "status_code": 400, "metadata": {"error": "A certificate by that name already exists"}}';
}
}
else {
echo '{"status": "Bad Request", "status_code": 400, "metadata": {"error": "A certificate name must be supplied"}}';
}
}
break;
case "deleteCertificateFiles":
if (validateAuthorization($action)) {
if (!empty($name)){
unlink('/var/lxdware/data/lxd/'.$name.'.crt');
unlink('/var/lxdware/data/lxd/'.$name.'.key');
}
if (file_exists('/var/lxdware/data/lxd/'.$name.'.crt') || file_exists('/var/lxdware/data/lxd/'.$name.'.key'))
echo '{"status": "Bad Request", "status_code": 400, "metadata": {"error": "Unable to remove all certificate files"}}';
else
echo '{"status": "Ok", "status_code": 200, "metadata": {"status": "Certificate files removed"}}';
if ($name == 'client'){
createCertificate('client');
}
}
break;
case "listCertificateFiles":
if (validateAuthorization($action)) {
$i = 0;
echo '{ "data": [';
foreach (glob("/var/lxdware/data/lxd/*.crt") as $filename) {
$data = openssl_x509_parse(file_get_contents($filename));
$validFrom = date('Y-m-d H:i:s', $data['validFrom_time_t']);
$validTo = date('Y-m-d H:i:s', $data['validTo_time_t']);
if ($i > 0){
echo ",";
}
$i++;
echo "[ ";
echo '"';
echo "<i class='fas fa-wallet fa-lg' style='color:#4e73df'></i>";
echo '",';
echo '"' . htmlentities(basename($filename)) . '",';
echo '"' . htmlentities($data['issuer']['CN']) . '",';
echo '"' . htmlentities($validFrom) . '",';
echo '"' . htmlentities($validTo) . '",';
echo '"';
echo "<a href='#' onclick=loadDeleteCertModal('".basename($filename, ".crt")."')><i class='fas fa-trash-alt fa-lg' style='color:#ddd' title='Delete Certificate' aria-hidden='true'></i></a>";
echo '"';
echo " ]";
}
echo " ]}";
}
break;
case "viewCertificate":
if (validateAuthorization($action)) {
$results = shell_exec("cat /var/lxdware/data/lxd/client.crt");
echo htmlentities($results);
}
else {
echo "You are not authorized to view the certificate";
}
break;
}
}
?>

View file

@ -17,13 +17,35 @@ You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//Require code from lxd-dashboard/php/aaa/authorization.php
//Start session if not already started
if (!isset($_SESSION)) {
session_start();
}
//Require code from lxd-dashboard/backend/aaa/authorization.php
require_once('../aaa/authorization.php');
//Require code from lxd-dashboard/backend/config/db.php
require_once('../config/db.php');
function sendCurlRequest($request_action, $request_type, $request_url, $request_data = "{}"){
$cert = "/var/lxdware/data/lxd/client.crt";
$key = "/var/lxdware/data/lxd/client.key";
//Set required variables
$get_connection_timeout = (isset($_SESSION['get_connection_timeout'])) ? $_SESSION['get_connection_timeout'] : 3;
$get_operation_timeout = (isset($_SESSION['get_operation_timeout'])) ? $_SESSION['get_operation_timeout'] : 5;
$post_connection_timeout = (isset($_SESSION['post_connection_timeout'])) ? $_SESSION['post_connection_timeout'] : 3;
$post_operation_timeout = (isset($_SESSION['post_operation_timeout'])) ? $_SESSION['post_operation_timeout'] : 5;
$patch_connection_timeout = (isset($_SESSION['patch_connection_timeout'])) ? $_SESSION['patch_connection_timeout'] : 3;
$patch_operation_timeout = (isset($_SESSION['patch_operation_timeout'])) ? $_SESSION['patch_operation_timeout'] : 5;
$put_connection_timeout = (isset($_SESSION['put_connection_timeout'])) ? $_SESSION['put_connection_timeout'] : 3;
$put_operation_timeout = (isset($_SESSION['put_operation_timeout'])) ? $_SESSION['put_operation_timeout'] : 5;
$delete_connection_timeout = (isset($_SESSION['delete_connection_timeout'])) ? $_SESSION['delete_connection_timeout'] : 3;
$delete_operation_timeout = (isset($_SESSION['delete_operation_timeout'])) ? $_SESSION['delete_operation_timeout'] : 5;
if (validateAuthorization($request_action)) {
switch ($request_type) {
case "GET":
@ -32,8 +54,8 @@ function sendCurlRequest($request_action, $request_type, $request_url, $request_
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSLCERT, $cert);
curl_setopt($ch, CURLOPT_SSLKEY, $key);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $get_connection_timeout);
curl_setopt($ch, CURLOPT_TIMEOUT, $get_operation_timeout);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type:application/json'));
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
@ -55,8 +77,8 @@ function sendCurlRequest($request_action, $request_type, $request_url, $request_
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSLCERT, $cert);
curl_setopt($ch, CURLOPT_SSLKEY, $key);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $post_connection_timeout);
curl_setopt($ch, CURLOPT_TIMEOUT, $post_operation_timeout);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POSTFIELDS, $request_data);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type:application/json'));
@ -78,8 +100,8 @@ function sendCurlRequest($request_action, $request_type, $request_url, $request_
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSLCERT, $cert);
curl_setopt($ch, CURLOPT_SSLKEY, $key);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $put_connection_timeout);
curl_setopt($ch, CURLOPT_TIMEOUT, $put_operation_timeout);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
curl_setopt($ch, CURLOPT_POSTFIELDS, $request_data);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type:application/json'));
@ -101,8 +123,8 @@ function sendCurlRequest($request_action, $request_type, $request_url, $request_
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSLCERT, $cert);
curl_setopt($ch, CURLOPT_SSLKEY, $key);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $patch_connection_timeout);
curl_setopt($ch, CURLOPT_TIMEOUT, $patch_operation_timeout);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PATCH");
curl_setopt($ch, CURLOPT_POSTFIELDS, $request_data);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type:application/json'));
@ -124,8 +146,8 @@ function sendCurlRequest($request_action, $request_type, $request_url, $request_
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSLCERT, $cert);
curl_setopt($ch, CURLOPT_SSLKEY, $key);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $delete_connection_timeout);
curl_setopt($ch, CURLOPT_TIMEOUT, $delete_operation_timeout);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE");
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type:application/json'));
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

File diff suppressed because it is too large Load diff

View file

@ -27,7 +27,7 @@ $database_user = (isset($_GET['database_user'])) ? filter_var(urldecode($_GET['d
//Declare and instantiate POST variables
$database_password = (isset($_POST['database_password'])) ? filter_var(urldecode($_POST['database_password']), FILTER_SANITIZE_STRING) : "";
//Require code from lxd-dashboard/php/config/db.php
//Require code from lxd-dashboard/backend/config/db.php
require_once('../config/db.php');
switch ($action) {

View file

@ -36,13 +36,13 @@ if (isset($_SESSION['username'])) {
$certificate = (isset($_POST['certificate'])) ? $_POST['certificate'] : "";
$json = (isset($_POST['json'])) ? $_POST['json'] : "";
//Require code from lxd-dashboard/php/config/curl.php
//Require code from lxd-dashboard/backend/config/curl.php
require_once('../config/curl.php');
//Require code from lxd-dashboard/php/config/db.php
//Require code from lxd-dashboard/backend/config/db.php
require_once('../config/db.php');
//Require code from lxd-dashboard/php/aaa/accounting.php
//Require code from lxd-dashboard/backend/aaa/accounting.php
require_once('../aaa/accounting.php');
//Query database for remote host record
@ -116,32 +116,36 @@ if (isset($_SESSION['username'])) {
echo '{ "data": [';
foreach ($certificates as $certificate){
if ($i > 0){
echo ",";
}
$i++;
if ($results['status_code'] == "200"){
foreach ($certificates as $certificate){
if ($i > 0){
echo ",";
}
$i++;
echo "[ ";
echo "[ ";
echo '"';
echo "<i class='fas fa-wallet fa-lg' style='color:#4e73df'></i>";
echo '",';
echo '"';
echo htmlentities($certificate['name']);
echo '",';
echo '"' . htmlentities($certificate['type']) . '",';
echo '"' . htmlentities($certificate['fingerprint']) . '",';
echo '"';
echo "<a href='#' onclick=loadCertificateJson('".$certificate['fingerprint']."')><i class='fas fa-edit fa-lg' style='color:#ddd' title='Edit' aria-hidden='true'></i></a>";
echo " &nbsp ";
echo "<a href='#' onclick=deleteCertificate('".$certificate['fingerprint']."')><i class='fas fa-trash-alt fa-lg' style='color:#ddd' title='Delete' aria-hidden='true'></i></a>";
echo '"';
echo " ]";
}
echo '"';
echo "<i class='fas fa-wallet fa-lg' style='color:#4e73df'></i>";
echo '",';
echo '"';
echo htmlentities($certificate['name']);
echo '",';
echo '"' . htmlentities($certificate['type']) . '",';
echo '"' . htmlentities($certificate['fingerprint']) . '",';
echo '"';
echo "<a href='#' onclick=loadCertificateJson('".$certificate['fingerprint']."')><i class='fas fa-edit fa-lg' style='color:#ddd' title='Edit' aria-hidden='true'></i></a>";
echo " &nbsp ";
echo "<a href='#' onclick=deleteCertificate('".$certificate['fingerprint']."')><i class='fas fa-trash-alt fa-lg' style='color:#ddd' title='Delete' aria-hidden='true'></i></a>";
echo '"';
echo " ]";
}
echo " ]}";

View file

@ -33,13 +33,13 @@ if (isset($_SESSION['username'])) {
$project = (isset($_GET['project'])) ? filter_var(urldecode($_GET['project']), FILTER_SANITIZE_STRING) : "";
$remote = (isset($_GET['remote'])) ? filter_var(urldecode($_GET['remote']), FILTER_SANITIZE_NUMBER_INT) : "";
//Require code from lxd-dashboard/php/config/curl.php
//Require code from lxd-dashboard/backend/config/curl.php
require_once('../config/curl.php');
//Require code from lxd-dashboard/php/config/db.php
//Require code from lxd-dashboard/backend/config/db.php
require_once('../config/db.php');
//Require code from lxd-dashboard/php/aaa/accounting.php
//Require code from lxd-dashboard/backend/aaa/accounting.php
require_once('../aaa/accounting.php');
//Query database for remote host record
@ -88,33 +88,37 @@ if (isset($_SESSION['username'])) {
$i = 0;
foreach ($members as $member){
if ($results['status_code'] == "200"){
foreach ($members as $member){
$database_status = ($member['database']) ? "true" : "false";
$database_status = ($member['database']) ? "true" : "false";
if ($i > 0){
echo ",";
}
$i++;
if ($i > 0){
echo ",";
}
$i++;
echo "[ ";
echo "[ ";
echo '"';
echo "<i class='fas fa-layer-group fa-lg' style='color:#4e73df'></i>";
echo '",';
echo '"';
echo "<i class='fas fa-layer-group fa-lg' style='color:#4e73df'></i>";
echo '",';
echo '"' . htmlentities($member['server_name']) . '",';
echo '"' . htmlentities($member['url']) . '",';
echo '"' . $database_status . '",';
echo '"' . htmlentities($member['status']) . '",';
echo '"' . htmlentities($member['message']) . '",';
echo '"' . htmlentities($member['server_name']) . '",';
echo '"' . htmlentities($member['url']) . '",';
echo '"' . $database_status . '",';
echo '"' . htmlentities($member['status']) . '",';
echo '"' . htmlentities($member['message']) . '",';
echo '"';
echo "<a href='#' onclick=loadDeleteClusterMemberModal('".$member['server_name']."')> <i class='fas fa-trash-alt fa-lg' style='color:#ddd' title='Delete' aria-hidden='true'></i> </a>";
echo '"';
echo '"';
echo "<a href='#' onclick=loadDeleteClusterMemberModal('".$member['server_name']."')> <i class='fas fa-trash-alt fa-lg' style='color:#ddd' title='Delete' aria-hidden='true'></i> </a>";
echo '"';
echo " ]";
echo " ]";
}
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -37,13 +37,13 @@ if (isset($_SESSION['username'])) {
//Declare and instantiate POST variables
$json = (isset($_POST['json'])) ? $_POST['json'] : "";
//Require code from lxd-dashboard/php/config/curl.php
//Require code from lxd-dashboard/backend/config/curl.php
require_once('../config/curl.php');
//Require code from lxd-dashboard/php/config/db.php
//Require code from lxd-dashboard/backend/config/db.php
require_once('../config/db.php');
//Require code from lxd-dashboard/php/aaa/accounting.php
//Require code from lxd-dashboard/backend/aaa/accounting.php
require_once('../aaa/accounting.php');
//Query database for remote host record
@ -93,35 +93,39 @@ if (isset($_SESSION['username'])) {
$i = 0;
echo '{ "data": [';
if ($results['status_code'] == "200"){
foreach ($images as $image){
foreach ($images as $image){
if ($image['fingerprint'] == "")
continue;
if ($image['fingerprint'] == "")
continue;
if ($i > 0){
echo ",";
if ($i > 0){
echo ",";
}
$i++;
echo "[ ";
echo '"' . "<i class='fas fa-box-open fa-lg' style='color:#4e73df'></i>" . '",';
echo '"' . htmlentities($image['properties']['description']) . '",';
echo '"' . htmlentities($image['fingerprint']) . '",';
echo '"' . htmlentities($image['type']) . '",';
echo '"' . htmlentities(number_format($image['size'] / 1048576, 2)) . ' MiB",';
echo '"';
echo "<a href='#' onclick=refreshImage('".$image['fingerprint']."')><i class='fas fa-sync-alt fa-lg' style='color:#ddd' title='Refresh' aria-hidden='true'></i></a>";
echo " &nbsp ";
echo "<a href='#' onclick=loadImageJson('".$image['fingerprint']."')><i class='fas fa-edit fa-lg' style='color:#ddd' title='Edit' aria-hidden='true'></i></a>";
echo " &nbsp ";
echo "<a href='#' onclick=deleteImage('".$image['fingerprint']."')><i class='fas fa-trash-alt fa-lg' style='color:#ddd' title='Delete' aria-hidden='true'></i></a>";
echo '"';
echo " ]";
}
$i++;
echo "[ ";
echo '"' . "<i class='fas fa-box-open fa-lg' style='color:#4e73df'></i>" . '",';
echo '"' . htmlentities($image['properties']['description']) . '",';
echo '"' . htmlentities($image['fingerprint']) . '",';
echo '"' . htmlentities($image['type']) . '",';
echo '"' . htmlentities(number_format($image['size'] / 1048576, 2)) . ' MB",';
echo '"';
echo "<a href='#' onclick=refreshImage('".$image['fingerprint']."')><i class='fas fa-sync-alt fa-lg' style='color:#ddd' title='Refresh' aria-hidden='true'></i></a>";
echo " &nbsp ";
echo "<a href='#' onclick=loadImageJson('".$image['fingerprint']."')><i class='fas fa-edit fa-lg' style='color:#ddd' title='Edit' aria-hidden='true'></i></a>";
echo " &nbsp ";
echo "<a href='#' onclick=deleteImage('".$image['fingerprint']."')><i class='fas fa-trash-alt fa-lg' style='color:#ddd' title='Delete' aria-hidden='true'></i></a>";
echo '"';
echo " ]";
}
echo " ]}";
@ -140,9 +144,15 @@ if (isset($_SESSION['username'])) {
echo '<option value="none">none</option>';
foreach ($images as $image){
if ($image_type == "virtual-machine"){
if ($image['fingerprint'] == "" || $image['type'] != $image_type)
continue;
}
else {
if ($image['fingerprint'] == "" || $image['type'] == "virtual-machine")
continue;
}
if ($image['fingerprint'] == "" || $image['type'] != $image_type)
continue;
echo '<option value="' . $image['fingerprint'] . '">' . htmlentities($image['properties']['description']) . '</option>';

View file

@ -48,13 +48,13 @@ if (isset($_SESSION['username'])) {
//Declare and instantiate POST variables
$json = (isset($_POST['json'])) ? $_POST['json'] : "";
//Require code from lxd-dashboard/php/config/curl.php
//Require code from lxd-dashboard/backend/config/curl.php
require_once('../config/curl.php');
//Require code from lxd-dashboard/php/config/db.php
//Require code from lxd-dashboard/backend/config/db.php
require_once('../config/db.php');
//Require code from lxd-dashboard/php/aaa/accounting.php
//Require code from lxd-dashboard/backend/aaa/accounting.php
require_once('../aaa/accounting.php');
//Query database for remote host record
@ -359,59 +359,63 @@ if (isset($_SESSION['username'])) {
$i = 0;
echo '{ "data": [';
foreach ($network_acls as $network_acl){
$network_acl_name = (isset($network_acl['name'])) ? htmlentities($network_acl['name']) : "";
if ($network_acl_name == "")
continue;
if ($results['status_code'] == "200"){
if ($i > 0){
echo ",";
}
$i++;
foreach ($network_acls as $network_acl){
$network_acl_name = (isset($network_acl['name'])) ? htmlentities($network_acl['name']) : "";
if ($network_acl_name == "")
continue;
echo "[ ";
echo '"';
echo "<i class='fas fa-shield-alt fa-lg' style='color:#4e73df'></i>";
echo '",';
echo '"';
echo $network_acl_name;
echo '",';
echo '"' . htmlentities($network_acl['description']) . '",';
echo '"';
echo "<a href='network-acls-ingress.html?network_acl=".$network_acl['name']."&remote=".$remote."&project=".$project."'>".count($network_acl['ingress'])."</a>";
echo '",';
echo '"';
echo "<a href='network-acls-egress.html?network_acl=".$network_acl['name']."&remote=".$remote."&project=".$project."'>".count($network_acl['egress'])."</a>";
echo '",';
$used_by = "";
$ii = 0;
foreach($network_acl['used_by'] as $network){
if ($ii > 0){
$used_by .= ", ";
if ($i > 0){
echo ",";
}
$ii++;
$used_by .= $network;
$i++;
echo "[ ";
echo '"';
echo "<i class='fas fa-shield-alt fa-lg' style='color:#4e73df'></i>";
echo '",';
echo '"';
echo $network_acl_name;
echo '",';
echo '"' . htmlentities($network_acl['description']) . '",';
echo '"';
echo "<a href='network-acls-ingress.php?network_acl=".$network_acl['name']."&remote=".$remote."&project=".$project."'>".count($network_acl['ingress'])."</a>";
echo '",';
echo '"';
echo "<a href='network-acls-egress.php?network_acl=".$network_acl['name']."&remote=".$remote."&project=".$project."'>".count($network_acl['egress'])."</a>";
echo '",';
$used_by = "";
$ii = 0;
foreach($network_acl['used_by'] as $network){
if ($ii > 0){
$used_by .= ", ";
}
$ii++;
$used_by .= $network;
}
echo '"' . htmlentities($used_by) . '",';
echo '"';
echo "<a href='#' onclick=loadNetworkAclJson('".$network_acl['name']."')><i class='fas fa-edit fa-lg' style='color:#ddd' title='Edit' aria-hidden='true'></i></a>";
echo " &nbsp ";
echo "<a href='#' onclick=loadRenameNetworkAcl('".$network_acl['name']."')><i class='fas fa-tag fa-lg' style='color:#ddd' title='Rename' aria-hidden='true'></i></a>";
echo " &nbsp ";
echo "<a href='#' onclick=deleteNetworkAcl('".$network_acl['name']."')><i class='fas fa-trash-alt fa-lg' style='color:#ddd' title='Delete' aria-hidden='true'></i></a>";
echo '"';
echo " ]";
}
echo '"' . htmlentities($used_by) . '",';
echo '"';
echo "<a href='#' onclick=loadNetworkAclJson('".$network_acl['name']."')><i class='fas fa-edit fa-lg' style='color:#ddd' title='Edit' aria-hidden='true'></i></a>";
echo " &nbsp ";
echo "<a href='#' onclick=loadRenameNetworkAcl('".$network_acl['name']."')><i class='fas fa-tag fa-lg' style='color:#ddd' title='Rename' aria-hidden='true'></i></a>";
echo " &nbsp ";
echo "<a href='#' onclick=deleteNetworkAcl('".$network_acl['name']."')><i class='fas fa-trash-alt fa-lg' style='color:#ddd' title='Delete' aria-hidden='true'></i></a>";
echo '"';
echo " ]";
}
echo " ]}";

View file

@ -86,13 +86,13 @@ if (isset($_SESSION['username'])) {
//Declare and instantiate POST variables
$json = (isset($_POST['json'])) ? $_POST['json'] : "";
//Require code from lxd-dashboard/php/config/curl.php
//Require code from lxd-dashboard/backend/config/curl.php
require_once('../config/curl.php');
//Require code from lxd-dashboard/php/config/db.php
//Require code from lxd-dashboard/backend/config/db.php
require_once('../config/db.php');
//Require code from lxd-dashboard/php/aaa/accounting.php
//Require code from lxd-dashboard/backend/aaa/accounting.php
require_once('../aaa/accounting.php');
//Query database for remote host record
@ -348,9 +348,70 @@ if (isset($_SESSION['username'])) {
break;
case "createNetworkUsingJSON":
$url = $base_url . "/1.0/networks?project=" . $project;
$data = $json;
$results = sendCurlRequest($action, "POST", $url, $data);
//Check to see if host is part of a cluster. Clusted hosts need network created first on each of the hosts
$url = $base_url . "/1.0/cluster";
$remote_data = sendCurlRequest($action, "GET", $url);
$remote_data = json_decode($remote_data, true);
$cluster_status = $remote_data['metadata'];
if ($cluster_status['enabled'] == true){
//Get a list of cluster members
$url = $base_url . "/1.0/cluster/members?recursion=1";
$cluster_api_data = sendCurlRequest($action, "GET", $url);
$cluster_api_data = json_decode($cluster_api_data, true);
$cluster_api_data = $cluster_api_data['metadata'];
//Setup Network data for REST API
$target_json_array = json_decode($json, true);
//Setup Network data for REST API
$target_device_array = array();
$target_device_array['config'] = new ArrayObject();
$target_device_array['name'] = $target_json_array['name'];
$target_device_array['type'] = $target_json_array['type'];
$target_device_array['description'] = $target_json_array['description'];
if ($target_device_array['type'] == "bridge"){
if (!empty($target_json_array['config']['bridge.external_interfaces'])){ $target_device_array['config']['bridge.external_interfaces'] = $target_json_array['config']['bridge.external_interfaces'];}
}
if ($target_device_array['type'] == "macvlan" || $target_device_array['type'] == "sriov"){
if (!empty($target_json_array['config']['parent'])){ $target_device_array['config']['parent'] = $target_json_array['config']['parent'];}
}
if ($target_device_array['type'] == "ovn"){
}
if ($target_device_array['type'] == "physical"){
if (!empty($target_json_array['config']['parent'])){ $target_device_array['config']['parent'] = $target_json_array['config']['parent'];}
}
$target_data = json_encode($target_device_array);
//Loop through each cluster member to create the network, this will put the network in pending status
foreach ($cluster_api_data as $cluster_data){
$url = $base_url . "/1.0/networks?project=" . $project . "&target=".$cluster_data['server_name'];
$results = sendCurlRequest($action, "POST", $url, $target_data);
}
//Now lets create the network without target config options, moving the pending status to created
$url = $base_url . "/1.0/networks?project=" . $project;
//Setup Network data for REST API
$device_array = json_decode($json, true);
unset($device_array['config']['bridge.external_interfaces']);
unset($device_array['config']['parent']);
$data = json_encode($device_array);
$results = sendCurlRequest($action, "POST", $url, $data);
}
else {
$url = $base_url . "/1.0/networks?project=" . $project;
$data = $json;
$results = sendCurlRequest($action, "POST", $url, $data);
}
echo $results;
//Send event to accounting
@ -390,61 +451,65 @@ if (isset($_SESSION['username'])) {
$i = 0;
echo '{ "data": [';
foreach ($networks as $network){
if ($network['name'] == "")
continue;
if ($results['status_code'] == "200"){
$network_data_managed = ($network['managed']) ? "true" : "false";
foreach ($networks as $network){
if ($network['name'] == "")
continue;
//This array key is not availabe on unmanaged network devices
if (isset($network['config']['ipv4.address']))
$ipv4 = $network['config']['ipv4.address'];
else
$ipv4 = "";
$network_data_managed = ($network['managed']) ? "true" : "false";
//This array key is not available on unmanaged network devices
if (isset($network['config']['ipv6.address']))
$ipv6 = $network['config']['ipv6.address'];
else
$ipv6 = "";
//This array key is not availabe on unmanaged network devices
if (isset($network['config']['ipv4.address']))
$ipv4 = $network['config']['ipv4.address'];
else
$ipv4 = "";
//This array key is not available on unmanaged network devices
if (isset($network['config']['ipv6.address']))
$ipv6 = $network['config']['ipv6.address'];
else
$ipv6 = "";
if ($i > 0){
echo ",";
}
$i++;
echo "[ ";
if ($network['managed'] == "true"){
echo '"' . "<i class='fas fa-network-wired fa-lg' style='color:#4e73df'></i>" . '",';
echo '"' . htmlentities($network['name']) . '",';
}
else {
echo '"' . "<i class='fas fa-network-wired fa-lg' style='color:#ddd'></i>" . '",';
echo '"' . htmlentities($network['name']) . '",';
}
echo '"' . htmlentities($network['description']) . '",';
echo '"' . htmlentities($ipv4) . '",';
echo '"' . htmlentities($ipv6) . '",';
echo '"' . htmlentities($network['type']) . '",';
echo '"' . htmlentities($network_data_managed) . '",';
echo '"';
if ($network['managed'] == "true"){
echo "<a href='#' onclick=loadNetworkJson('".$network['name']."')><i class='fas fa-edit fa-lg' style='color:#ddd' title='Edit' aria-hidden='true'></i></a>";
echo " &nbsp ";
echo "<a href='#' onclick=loadRenameNetwork('".$network['name']."')><i class='fas fa-tag fa-lg' style='color:#ddd' title='Rename' aria-hidden='true'></i></a>";
echo " &nbsp ";
echo "<a href='#' onclick=deleteNetwork('".$network['name']."')><i class='fas fa-trash-alt fa-lg' style='color:#ddd' title='Delete' aria-hidden='true'></i></a>";
}
echo '"';
echo " ]";
if ($i > 0){
echo ",";
}
$i++;
echo "[ ";
if ($network['managed'] == "true"){
echo '"' . "<i class='fas fa-network-wired fa-lg' style='color:#4e73df'></i>" . '",';
echo '"' . htmlentities($network['name']) . '",';
}
else {
echo '"' . "<i class='fas fa-network-wired fa-lg' style='color:#ddd'></i>" . '",';
echo '"' . htmlentities($network['name']) . '",';
}
echo '"' . htmlentities($network['description']) . '",';
echo '"' . htmlentities($ipv4) . '",';
echo '"' . htmlentities($ipv6) . '",';
echo '"' . htmlentities($network['type']) . '",';
echo '"' . htmlentities($network_data_managed) . '",';
echo '"';
if ($network['managed'] == "true"){
echo "<a href='#' onclick=loadNetworkJson('".$network['name']."')><i class='fas fa-edit fa-lg' style='color:#ddd' title='Edit' aria-hidden='true'></i></a>";
echo " &nbsp ";
echo "<a href='#' onclick=loadRenameNetwork('".$network['name']."')><i class='fas fa-tag fa-lg' style='color:#ddd' title='Rename' aria-hidden='true'></i></a>";
echo " &nbsp ";
echo "<a href='#' onclick=deleteNetwork('".$network['name']."')><i class='fas fa-trash-alt fa-lg' style='color:#ddd' title='Delete' aria-hidden='true'></i></a>";
}
echo '"';
echo " ]";
}
echo " ]}";
}
else {

View file

@ -34,13 +34,13 @@ if (isset($_SESSION['username'])) {
//Instantiate the POST variable
$json = (isset($_POST['json'])) ? $_POST['json'] : "";
//Require code from lxd-dashboard/php/config/curl.php
//Require code from lxd-dashboard/backend/config/curl.php
require_once('../config/curl.php');
//Require code from lxd-dashboard/php/config/db.php
//Require code from lxd-dashboard/backend/config/db.php
require_once('../config/db.php');
//Require code from lxd-dashboard/php/aaa/accounting.php
//Require code from lxd-dashboard/backend/aaa/accounting.php
require_once('../aaa/accounting.php');
//Query database for remote host record
@ -77,7 +77,9 @@ if (isset($_SESSION['username'])) {
if (!empty($operations_data['running'])){
foreach ($operations_data['running'] as $running_task){
$results = $running_task['description'];
//This is annoyingly showing when using exec terminal, will look to build indicator for when someone is executing a command on instance page instead
if ($running_task['description'] != "Executing command")
$results = $running_task['description'];
if (isset($running_task['resources']['instances'][0])) {
$instance = basename($running_task['resources']['instances'][0]);
@ -115,8 +117,8 @@ if (isset($_SESSION['username'])) {
$results .= " " . htmlentities($running_task['metadata']['download_progress']);
break;
case "Executing command":
if (isset($running_task['metadata']['command'][0]))
$results = "Executing " . htmlentities($running_task['metadata']['command'][0]) . " command on " . htmlentities($instance);
//if (isset($running_task['metadata']['command'][0]))
//$results = "Executing " . htmlentities($running_task['metadata']['command'][0]) . " command on " . htmlentities($instance);
break;
case "Freezing instance":
$results .= " " . $instance;
@ -142,13 +144,21 @@ if (isset($_SESSION['username'])) {
case "Updating instance":
$results .= " " . $instance;
break;
case "Image download token":
#Remove image tokens left over from image downloads when in a cluster
if ($running_task['may_cancel'] == true){
$url = $base_url . "/1.0/operations/" . $running_task['id'];
$results = sendCurlRequest($action, "DELETE", $url);
}
break;
}
}
}
if (!empty($operations_data['failure'])){
foreach ($operations_data['failure'] as $failed_task){
$results = $failed_task['description'] . " Error: " . $failed_task['err'];
if ($failed_task['description'] != "Executing command") //This is to prevent error message when VM is starting up due to CPU and Mem stats
$results = $failed_task['description'] . " Error: " . $failed_task['err'];
}
}
@ -166,50 +176,55 @@ if (isset($_SESSION['username'])) {
$i = 0;
echo '{ "data": [';
foreach ($operations_dict as $operations){
if ($results['status_code'] == "200"){
foreach ($operations as $operation){
foreach ($operations_dict as $operations){
if ($i > 0){
echo ",";
}
$i++;
echo "[ ";
echo '"';
echo "<a href='#' onclick=loadOperationJson('".$operation['id']."')> <i class='fas fa-exchange-alt fa-lg' style='color:#4e73df'></i> </a>";
echo '",';
foreach ($operations as $operation){
echo '"';
echo "<a href='#' onclick=loadOperationJson('".$operation['id']."')>".htmlentities($operation['id'])."</a>";
echo '",';
echo '"' . htmlentities($operation['class']) . '",';
echo '"' . htmlentities($operation['description']) . '",';
echo '"' . htmlentities($operation['status']) . '",';
echo '"' . htmlentities($operation['created_at']) . '",';
if($operation['may_cancel']){
$may_cancel = "true";
echo '"' . htmlentities($may_cancel) . '",';
if ($i > 0){
echo ",";
}
$i++;
echo "[ ";
echo '"';
echo "<a href='#' onclick=loadOperationJson('".$operation['id']."')> <i class='fas fa-exchange-alt fa-lg' style='color:#4e73df'></i> </a>";
echo '",';
echo '"';
echo "<a href='#' onclick=deleteOperation('".$operation['id']."')> <i class='fas fa-trash-alt fa-lg' style='color:#ddd' title='Delete' aria-hidden='true'></i> </a>";
echo '"';
}
echo "<a href='#' onclick=loadOperationJson('".$operation['id']."')>".htmlentities($operation['id'])."</a>";
echo '",';
echo '"' . htmlentities($operation['class']) . '",';
echo '"' . htmlentities($operation['description']) . '",';
echo '"' . htmlentities($operation['status']) . '",';
echo '"' . htmlentities($operation['created_at']) . '",';
if($operation['may_cancel']){
$may_cancel = "true";
echo '"' . htmlentities($may_cancel) . '",';
echo '"';
echo "<a href='#' onclick=deleteOperation('".$operation['id']."')> <i class='fas fa-trash-alt fa-lg' style='color:#ddd' title='Delete' aria-hidden='true'></i> </a>";
echo '"';
}
else{
$may_cancel = "false";
echo '"' . htmlentities($may_cancel) . '",';
echo '" ';
echo ' "';
}
else{
$may_cancel = "false";
echo '"' . htmlentities($may_cancel) . '",';
echo '" ';
echo ' "';
echo " ]";
}
echo " ]";
}
}
echo " ]}";
}
else {

View file

@ -37,13 +37,13 @@ if (isset($_SESSION['username'])) {
//Declare and instantiate POST variables
$json = (isset($_POST['json'])) ? $_POST['json'] : "";
//Require code from lxd-dashboard/php/config/curl.php
//Require code from lxd-dashboard/backend/config/curl.php
require_once('../config/curl.php');
//Require code from lxd-dashboard/php/config/db.php
//Require code from lxd-dashboard/backend/config/db.php
require_once('../config/db.php');
//Require code from lxd-dashboard/php/aaa/accounting.php
//Require code from lxd-dashboard/backend/aaa/accounting.php
require_once('../aaa/accounting.php');
//Query database for remote host record
@ -112,40 +112,44 @@ if (isset($_SESSION['username'])) {
$i = 0;
echo '{ "data": [';
foreach ($profiles as $profile){
if ($results['status_code'] == "200"){
if ($profile['name'] == "")
continue;
if ($i > 0){
echo ",";
}
$i++;
foreach ($profiles as $profile){
echo "[ ";
echo '"' . "<i class='fas fa-money-check' style='color:#4e73df'></i>" . '",';
echo '"' . htmlentities($profile['name']) . '",';
echo '"' . htmlentities($profile['description']) . '",';
echo '"';
$ii = 0;
foreach($profile['devices'] as $device=>$value){
if ($ii > 0)
echo ", ";
echo htmlentities($device);
$ii++;
if ($profile['name'] == "")
continue;
if ($i > 0){
echo ",";
}
echo '",';
$i++;
echo '"';
echo "<a href='#' onclick=loadProfileJson('".$profile['name']."')><i class='fas fa-edit fa-lg' style='color:#ddd' title='Edit' aria-hidden='true'></i></a>";
echo " &nbsp ";
echo "<a href='#' onclick=loadRenameProfile('".$profile['name']."')><i class='fas fa-tag fa-lg' style='color:#ddd' title='Rename' aria-hidden='true'></i></a>";
echo " &nbsp ";
echo "<a href='#' onclick=deleteProfile('".$profile['name']."')><i class='fas fa-trash-alt fa-lg' style='color:#ddd' title='Delete' aria-hidden='true'></i></a>";
echo '"';
echo "[ ";
echo '"' . "<i class='fas fa-money-check' style='color:#4e73df'></i>" . '",';
echo '"' . htmlentities($profile['name']) . '",';
echo '"' . htmlentities($profile['description']) . '",';
echo " ]";
echo '"';
$ii = 0;
foreach($profile['devices'] as $device=>$value){
if ($ii > 0)
echo ", ";
echo htmlentities($device);
$ii++;
}
echo '",';
echo '"';
echo "<a href='#' onclick=loadProfileJson('".$profile['name']."')><i class='fas fa-edit fa-lg' style='color:#ddd' title='Edit' aria-hidden='true'></i></a>";
echo " &nbsp ";
echo "<a href='#' onclick=loadRenameProfile('".$profile['name']."')><i class='fas fa-tag fa-lg' style='color:#ddd' title='Rename' aria-hidden='true'></i></a>";
echo " &nbsp ";
echo "<a href='#' onclick=deleteProfile('".$profile['name']."')><i class='fas fa-trash-alt fa-lg' style='color:#ddd' title='Delete' aria-hidden='true'></i></a>";
echo '"';
echo " ]";
}
}

View file

@ -76,13 +76,13 @@ if (isset($_SESSION['username'])) {
//Set the url when switching projects from the dropdown menu
$return_url = strtok($_SERVER["HTTP_REFERER"], '?');
//Require code from lxd-dashboard/php/config/curl.php
//Require code from lxd-dashboard/backend/config/curl.php
require_once('../config/curl.php');
//Require code from lxd-dashboard/php/config/db.php
//Require code from lxd-dashboard/backend/config/db.php
require_once('../config/db.php');
//Require code from lxd-dashboard/php/aaa/accounting.php
//Require code from lxd-dashboard/backend/aaa/accounting.php
require_once('../aaa/accounting.php');
//Query database for remote host record
@ -197,43 +197,47 @@ if (isset($_SESSION['username'])) {
$i = 0;
echo '{ "data": [';
foreach ($projects as $project_data){
if ($results['status_code'] == "200"){
$features_images = (isset($project_data['config']['features.images'])) ? htmlentities($project_data['config']['features.images']) : "true";
$features_networks = (isset($project_data['config']['features.networks'])) ? htmlentities($project_data['config']['features.networks']) : "false";
$features_profiles = (isset($project_data['config']['features.profiles'])) ? htmlentities($project_data['config']['features.profiles']) : "true";
$features_storage_volumes = (isset($project_data['config']['features.storage.volumes'])) ? htmlentities($project_data['config']['features.storage.volumes']) : "true";
if ($i > 0){
echo ",";
foreach ($projects as $project_data){
$features_images = (isset($project_data['config']['features.images'])) ? htmlentities($project_data['config']['features.images']) : "true";
$features_networks = (isset($project_data['config']['features.networks'])) ? htmlentities($project_data['config']['features.networks']) : "false";
$features_profiles = (isset($project_data['config']['features.profiles'])) ? htmlentities($project_data['config']['features.profiles']) : "true";
$features_storage_volumes = (isset($project_data['config']['features.storage.volumes'])) ? htmlentities($project_data['config']['features.storage.volumes']) : "true";
if ($i > 0){
echo ",";
}
$i++;
echo "[ ";
echo '"';
echo "<a href='remotes-single.php?remote=".$remote."&project=".$project_data['name'] ."'><i class='fas fa-chart-bar fa-lg' style='color:#4e73df'></i> </a>";
echo '",';
echo '"';
echo "<a href='remotes-single.php?remote=".$remote."&project=".$project_data['name'] ."'> ".htmlentities($project_data['name']) ."</a>";
echo '",';
echo '"' . htmlentities($project_data['description']) . '",';
echo '"' . $features_images . '",';
echo '"' . $features_networks . '",';
echo '"' . $features_profiles . '",';
echo '"' . $features_storage_volumes . '",';
echo '"';
echo "<a href='#' onclick=loadProjectJson('".$project_data['name']."')><i class='fas fa-edit fa-lg' style='color:#ddd' title='Edit' aria-hidden='true'></i></a>";
echo " &nbsp ";
echo "<a href='#' onclick=loadRenameProject('".$project_data['name']."')><i class='fas fa-tag fa-lg' style='color:#ddd' title='Rename' aria-hidden='true'></i></a>";
echo " &nbsp ";
echo "<a href='#' onclick=deleteProject('".$project_data['name']."')><i class='fas fa-trash-alt fa-lg' style='color:#ddd' title='Delete' aria-hidden='true'></i></a>";
echo '"';
echo " ]";
}
$i++;
echo "[ ";
echo '"';
echo "<a href='remotes-single.html?remote=".$remote."&project=".$project_data['name'] ."'><i class='fas fa-chart-bar fa-lg' style='color:#4e73df'></i> </a>";
echo '",';
echo '"';
echo "<a href='remotes-single.html?remote=".$remote."&project=".$project_data['name'] ."'> ".htmlentities($project_data['name']) ."</a>";
echo '",';
echo '"' . htmlentities($project_data['description']) . '",';
echo '"' . $features_images . '",';
echo '"' . $features_networks . '",';
echo '"' . $features_profiles . '",';
echo '"' . $features_storage_volumes . '",';
echo '"';
echo "<a href='#' onclick=loadProjectJson('".$project_data['name']."')><i class='fas fa-edit fa-lg' style='color:#ddd' title='Edit' aria-hidden='true'></i></a>";
echo " &nbsp ";
echo "<a href='#' onclick=loadRenameProject('".$project_data['name']."')><i class='fas fa-tag fa-lg' style='color:#ddd' title='Rename' aria-hidden='true'></i></a>";
echo " &nbsp ";
echo "<a href='#' onclick=deleteProject('".$project_data['name']."')><i class='fas fa-trash-alt fa-lg' style='color:#ddd' title='Delete' aria-hidden='true'></i></a>";
echo '"';
echo " ]";
}
echo " ]}";
@ -243,34 +247,29 @@ if (isset($_SESSION['username'])) {
}
break;
case "listProjectsForTopNavigation":
case "listProjectsForSelectOption":
$url = $base_url . "/1.0/projects?recursion=1";
$results = sendCurlRequest($action, "GET", $url);
$results = json_decode($results, true);
$projects = (isset($results['metadata'])) ? $results['metadata'] : [];
echo '<a class="nav-link dropdown-toggle" href="#" id="userDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">';
echo '<i class="fas fa-chart-bar mr-2 text-gray-600"></i>';
echo '<span class="mr-2 d-none d-lg-inline text-gray-600">Project: <font class="text-primary">'. htmlentities($project) . '</font></span>';
echo '</a>';
echo '<!-- Dropdown - User Information -->';
echo '<div class="dropdown-menu dropdown-menu-right shadow animated--grow-in" aria-labelledby="userDropdown">';
foreach ($projects as $project_data){
if ($project_data['name'] == $project)
echo '<a class="dropdown-item" href="'.$return_url.'?remote=' . $remote . '&project=' . $project_data['name'] . '"><i class="fas fa-chart-bar fa-sm fa-fw mr-2 text-gray-900"></i><strong>' . htmlentities($project_data['name']) . '</strong></a>';
echo '<option value="' . $return_url . '?remote=' . $remote . '&project=' . $project_data['name'] . '" selected>' . htmlentities($project_data['name']) . '</option>';
else {
if (basename($return_url) == "instance.html")
echo '<a class="dropdown-item" href="instances.html?remote=' . $remote . '&project=' . $project_data['name'] . '"><i class="fas fa-chart-bar fa-sm fa-fw mr-2 text-gray-600"></i>' . htmlentities($project_data['name']) . '</a>';
elseif (basename($return_url) == "storage-volumes.html")
echo '<a class="dropdown-item" href="storage-pools.html?remote=' . $remote . '&project=' . $project_data['name'] . '"><i class="fas fa-chart-bar fa-sm fa-fw mr-2 text-gray-600"></i>' . htmlentities($project_data['name']) . '</a>';
if (basename($return_url) == "virtual-machines-single.php")
echo '<option value="virtual-machines.php?remote=' . $remote . '&project=' . $project_data['name'] . '" >' . htmlentities($project_data['name']) . '</option>';
elseif (basename($return_url) == "containers-single.php")
echo '<option value="containers.php?remote=' . $remote . '&project=' . $project_data['name'] . '" >' . htmlentities($project_data['name']) . '</option>';
elseif (basename($return_url) == "network-acls-egress.php" || basename($return_url) == "network-acls-ingress.php")
echo '<option value="network-acls.php?remote=' . $remote . '&project=' . $project_data['name'] . '" >' . htmlentities($project_data['name']) . '</option>';
elseif (basename($return_url) == "storage-volumes.php")
echo '<option value="storage-pools.php?remote=' . $remote . '&project=' . $project_data['name'] . '" >' . htmlentities($project_data['name']) . '</option>';
else
echo '<a class="dropdown-item" href="'.$return_url.'?remote=' . $remote . '&project=' . $project_data['name'] . '"><i class="fas fa-chart-bar fa-sm fa-fw mr-2 text-gray-600"></i>' . htmlentities($project_data['name']) . '</a>';
echo '<option value="'.$return_url.'?remote=' . $remote . '&project=' . $project_data['name'] . '" >' . htmlentities($project_data['name']) . '</option>';
}
}
echo '</div>';
break;
case "loadProject":

View file

@ -28,7 +28,7 @@ if (isset($_SESSION['username'])) {
//Declare and instantiate GET variables
$remote = (isset($_GET['remote'])) ? filter_var(urldecode($_GET['remote']), FILTER_SANITIZE_NUMBER_INT) : "";
//Require code from lxd-dashboard/php/config/db.php
//Require code from lxd-dashboard/backend/config/db.php
require_once('../config/db.php');
$alias = retrieveHostAlias($remote);

View file

@ -30,10 +30,10 @@ if (isset($_SESSION['username'])) {
$project = (isset($_GET['project'])) ? filter_var(urldecode($_GET['project']), FILTER_SANITIZE_STRING) : "";
$remote = (isset($_GET['remote'])) ? filter_var(urldecode($_GET['remote']), FILTER_SANITIZE_NUMBER_INT) : "";
//Require code from lxd-dashboard/php/config/curl.php
//Require code from lxd-dashboard/backend/config/curl.php
require_once('../config/curl.php');
//Require code from lxd-dashboard/php/config/db.php
//Require code from lxd-dashboard/backend/config/db.php
require_once('../config/db.php');
//Query database for remote host record
@ -83,6 +83,31 @@ if (isset($_SESSION['username'])) {
echo json_encode($arr);
break;
case "displayContainerInfo":
$arr = array();
//Instance Stats
$url = $base_url. "/1.0/containers?recursion=2&project=" . $project;
$instance_api_data = sendCurlRequest($action, "GET", $url);
$instance_api_data = json_decode($instance_api_data, true);
$instances = (isset($instance_api_data['metadata'])) ? $instance_api_data['metadata'] : [];
$running_instances = 0;
$total_instances = 0;
foreach ($instances as $instance){
if ($instance['state']['status'] == "Running"){
$running_instances++;
}
$total_instances++;
}
$arr['runningContainers'] = $running_instances;
$arr['totalContainers'] = $total_instances;
echo json_encode($arr);
break;
case "displayImageInfo":
$arr = array();
@ -242,14 +267,14 @@ if (isset($_SESSION['username'])) {
//Format memory values
if ($memory_total < 1073741824) {
$memory_total = number_format($memory_total/1024/1024, 2); //total amount of memory available in MB
$memory_used = number_format($memory_used/1024/1024, 2); //current amount of memory used in MB
$memory_unit = "MB";
$memory_total = number_format($memory_total/1024/1024, 2); //total amount of memory available in MiB
$memory_used = number_format($memory_used/1024/1024, 2); //current amount of memory used in MiB
$memory_unit = "MiB";
}
else {
$memory_total = number_format($memory_total/1024/1024/1024, 2); //total amount of memory available in GB
$memory_used = number_format($memory_used/1024/1024/1024, 2); //current amount of memory used in GB
$memory_unit = "GB";
$memory_total = number_format($memory_total/1024/1024/1024, 2); //total amount of memory available in GiB
$memory_used = number_format($memory_used/1024/1024/1024, 2); //current amount of memory used in GiB
$memory_unit = "GiB";
}
$arr['memoryTotal'] = $memory_total;
@ -258,7 +283,36 @@ if (isset($_SESSION['username'])) {
echo json_encode($arr);
break;
case "displayVirtualMachineInfo":
$arr = array();
//Instance Stats
$url = $base_url. "/1.0/virtual-machines?recursion=2&project=" . $project;
$instance_api_data = sendCurlRequest($action, "GET", $url);
$instance_api_data = json_decode($instance_api_data, true);
$instances = (isset($instance_api_data['metadata'])) ? $instance_api_data['metadata'] : [];
$running_instances = 0;
$total_instances = 0;
foreach ($instances as $instance){
if ($instance['state']['status'] == "Running"){
$running_instances++;
}
$total_instances++;
}
$arr['runningVirtualMachines'] = $running_instances;
$arr['totalVirtualMachines'] = $total_instances;
echo json_encode($arr);
break;
case "validateRemoteConnection":
$url = $base_url. "/1.0";
$results = sendCurlRequest($action, "GET", $url);
echo $results;
break;
}

View file

@ -28,19 +28,22 @@ if (isset($_SESSION['username'])) {
//Declare and instantiate GET variables
$action = (isset($_GET['action'])) ? filter_var(urldecode($_GET['action']), FILTER_SANITIZE_STRING) : "";
$alias = (isset($_GET['alias'])) ? filter_var(urldecode($_GET['alias']), FILTER_SANITIZE_STRING) : "";
$external_host = (isset($_GET['external_host'])) ? filter_var(urldecode($_GET['external_host']), FILTER_SANITIZE_STRING) : "";
$external_port = (isset($_GET['external_port'])) ? filter_var(urldecode($_GET['external_port']), FILTER_SANITIZE_NUMBER_INT) : "";
$host = (isset($_GET['host'])) ? filter_var(urldecode($_GET['host']), FILTER_SANITIZE_STRING) : "";
$id = (isset($_GET['id'])) ? filter_var(urldecode($_GET['id']), FILTER_SANITIZE_NUMBER_INT) : "";
$port = (isset($_GET['port'])) ? filter_var(urldecode($_GET['port']), FILTER_SANITIZE_NUMBER_INT) : "8443";
$project = (isset($_GET['project'])) ? filter_var(urldecode($_GET['project']), FILTER_SANITIZE_STRING) : "";
$remote = (isset($_GET['remote'])) ? filter_var(urldecode($_GET['remote']), FILTER_SANITIZE_NUMBER_INT) : "";
//Require code from lxd-dashboard/php/config/curl.php
//Require code from lxd-dashboard/backend/config/curl.php
require_once('../config/curl.php');
//Require code from lxd-dashboard/php/config/db.php
//Require code from lxd-dashboard/backend/config/db.php
require_once('../config/db.php');
//Require code from lxd-dashboard/php/aaa/accounting.php
//Require code from lxd-dashboard/backend/aaa/accounting.php
require_once('../aaa/accounting.php');
//Run the matching action
@ -63,8 +66,7 @@ if (isset($_SESSION['username'])) {
$data_auth = (isset($data['metadata']['auth'])) ? $data['metadata']['auth'] : "";
if ($data_auth == "trusted"){
$record_added = addHost($host, $port, $alias);
$record_added = addHost($host, $port, $alias, $external_host, $external_port);
if ($record_added)
$results = '{"status": "Ok", "status_code": 200, "metadata": {"status": "Record added"}}';
@ -121,6 +123,12 @@ if (isset($_SESSION['username'])) {
logEvent($action, $remote, $project, $object, $event['status_code'], $event['status']);
break;
case "retrieveRemoteInfo":
$results = retrieveHostInfo($id);
$results = json_encode($results);
echo $results;
break;
case "listRemotes":
if (validateAuthorization($action)) {
$rows = retrieveTableRows('lxd_hosts');
@ -138,19 +146,31 @@ if (isset($_SESSION['username'])) {
echo "[ ";
echo '"';
echo "<a href='remotes-single.html?remote=" . $row['id'] . "&project=default'> <i class='fas fa-server fa-lg' style='color:#4e73df'></i> </a>";
echo "<a href='remotes-single.php?remote=" . $row['id'] . "&project=default'> <i class='fas fa-server fa-lg' style='color:#4e73df'></i> </a>";
echo '",';
echo '"';
echo "<a href='remotes-single.html?remote=" . $row['id'] . "&project=default'>".htmlentities($row['host'])."</a>";
echo "<a href='remotes-single.php?remote=" . $row['id'] . "&project=default'>".htmlentities($row['host'])."</a>";
echo '",';
echo '"' . htmlentities($row['port']) . '",';
echo '"' . htmlentities($row['alias']) . '",';
echo '"' . htmlentities($row['external_host']) . '",';
// 0 is a valid interger value for the database but a reserved unusable port for TCP/UDP
if ($row['external_port'] == 0) {
echo '"",';
}
else {
echo '"' . htmlentities($row['external_port']) . '",';
}
echo '"' . htmlentities($row['protocol']) . '",';
echo '"';
echo "<a href='#' onclick=deleteRemote('".$row['id']."')><i class='fas fa-trash-alt fa-lg' style='color:#ddd' title='Delete' aria-hidden='true'></i></a>";
echo "<a href='#' onclick=editRemote('".$row['id']."')><i class='fas fa-edit fa-lg' style='color:#ddd' title='Edit' aria-hidden='true'></i></a>";
echo " &nbsp ";
echo "<a href='#' onclick=confirmDeleteRemote('".$row['id']."')><i class='fas fa-trash-alt fa-lg' style='color:#ddd' title='Delete' aria-hidden='true'></i></a>";
echo '"';
echo " ]";
@ -164,7 +184,7 @@ if (isset($_SESSION['username'])) {
}
break;
case "listRemotesForTopNavigation":
case "listRemotesForSelectOption":
if (validateAuthorization($action)) {
$alias = retrieveHostAlias($remote);
$hostname = retrieveHostName($remote);
@ -173,34 +193,85 @@ if (isset($_SESSION['username'])) {
$display_name = $alias;
else
$display_name = $hostname;
echo '<a class="nav-link dropdown-toggle" href="#" id="userDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">';
echo '<i class="fas fa-server mr-2 text-gray-600"></i>';
echo '<span class="mr-2 d-none d-lg-inline text-gray-600">Host: <font class="text-primary">'. htmlentities($display_name) . '</font></span>';
echo '</a>';
echo '<!-- Dropdown - User Information -->';
echo '<div class="dropdown-menu dropdown-menu-right shadow animated--grow-in" aria-labelledby="userDropdown">';
//Query database for remote host records
$rows = retrieveTableRows('lxd_hosts');
foreach ($rows as $row){
if ($row['alias'] != "")
$display_name2 = $row['alias'];
else
$display_name2 = $row['host'];
if ($row['id'] == $remote)
echo '<a class="dropdown-item" href="remotes-single.html?remote=' . $row['id'] . '&project=' . $project . '"><i class="fas fa-server fa-sm fa-fw mr-2 text-gray-900"></i><strong>' . htmlentities($display_name2) . '</strong></a>';
echo '<option value="remotes-single.php?remote=' . $row['id'] . '&project=' .$project . '" selected>' . htmlentities($display_name2) . '</option>';
else
echo '<a class="dropdown-item" href="remotes-single.html?remote=' . $row['id'] . '&project=default"><i class="fas fa-server fa-sm fa-fw mr-2 text-gray-600"></i>' . htmlentities($display_name2) . '</a>';
echo '<option value="remotes-single.php?remote=' . $row['id'] . '&project=' .$project . '">' . htmlentities($display_name2) . '</option>';
}
echo '</div>';
}
break;
case "loadRemote":
if (validateAuthorization($action)) {
$results = retrieveHostInfo($remote);
$results = json_encode($results);
echo $results;
}
break;
case "updateRemote":
if (validateAuthorization($action)) {
if (filter_var($host, FILTER_VALIDATE_IP) || filter_var($host, FILTER_VALIDATE_DOMAIN))
$valid_domain = true;
if (filter_var($port, FILTER_VALIDATE_INT))
$valid_port = true;
if ($valid_domain && $valid_port){
$url = "https://" . $host . ":" . $port . "/1.0";
$results = sendCurlRequest($action, "GET", $url);
$data = json_decode($results, true);
$data_auth = (isset($data['metadata']['auth'])) ? $data['metadata']['auth'] : "";
if ($data_auth == "trusted"){
$record_updated = updateHost($remote, $host, $port, $alias, $external_host, $external_port);
if ($record_updated)
$results = '{"status": "Ok", "status_code": 200, "metadata": {"status": "Record added"}}';
else
$results = '{"status": "Bad Request", "status_code": 400, "metadata": {"error": "Error adding record to database"}}';
}
else {
if ($data_auth == "untrusted"){
$results = '{"status": "Unauthorized", "status_code": 401, "metadata": {"error": "Remote host connection is not trusted"}}';
}
else {
$results = '{"status": "Bad Request", "status_code": 400, "metadata": {"error": "Unable to connect to remote host"}}';
}
}
}
else {
$results = '{"status": "Bad Request", "status_code": 400, "metadata": {"error": "Invalid host or port"}}';
}
}
else {
$results = '{"status": "Forbidden", "status_code": 403, "metadata": {"error": "You are not authorized to execute this action"}}';
}
echo $results;
//Send event to accounting
$event = json_decode($results, true);
$object = $host . ":" . $port;
logEvent($action, $remote, $project, $object, $event['status_code'], $event['status']);
break;
default:
echo '{"status": "Bad Request", "status_code": 400, "metadata": {"err": "Unable to execute action on remote host", "status_code": "400"}}';
}

View file

@ -0,0 +1,30 @@
#!/usr/bin/php
<?php
if (!isset($_SERVER['REQUEST_METHOD'])) {
//Capture command-line arguments
$file = $argv[1];
$url = $argv[2];
$cert = $argv[3];
$key = $argv[4];
$fp = fopen($file, "w+");
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_SSLCERT, $cert);
curl_setopt($ch, CURLOPT_SSLKEY, $key);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3);
curl_setopt($ch, CURLOPT_TIMEOUT, 0);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type:application/json'));
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$results = curl_exec($ch);
curl_close($ch);
fclose($fp);
}
?>

View file

@ -33,13 +33,13 @@ if (isset($_SESSION['username'])) {
$project = (isset($_GET['project'])) ? filter_var(urldecode($_GET['project']), FILTER_SANITIZE_STRING) : "";
$remote = (isset($_GET['remote'])) ? filter_var(urldecode($_GET['remote']), FILTER_SANITIZE_NUMBER_INT) : "";
//Require code from lxd-dashboard/php/config/curl.php
//Require code from lxd-dashboard/backend/config/curl.php
require_once('../config/curl.php');
//Require code from lxd-dashboard/php/config/db.php
//Require code from lxd-dashboard/backend/config/db.php
require_once('../config/db.php');
//Require code from lxd-dashboard/php/aaa/accounting.php
//Require code from lxd-dashboard/backend/aaa/accounting.php
require_once('../aaa/accounting.php');
//Run the matching action

View file

@ -69,13 +69,13 @@ if (isset($_SESSION['username'])) {
//Declare and instantiate POST variables
$json = (isset($_POST['json'])) ? $_POST['json'] : "";
//Require code from lxd-dashboard/php/config/curl.php
//Require code from lxd-dashboard/backend/config/curl.php
require_once('../config/curl.php');
//Require code from lxd-dashboard/php/config/db.php
//Require code from lxd-dashboard/backend/config/db.php
require_once('../config/db.php');
//Require code from lxd-dashboard/php/aaa/accounting.php
//Require code from lxd-dashboard/backend/aaa/accounting.php
require_once('../aaa/accounting.php');
//Query database for remote host record
@ -325,9 +325,70 @@ if (isset($_SESSION['username'])) {
break;
case "createStoragePoolUsingJSON":
$url = $base_url . "/1.0/storage-pools?project=" . $project;
$data = $json;
$results = sendCurlRequest($action, "POST", $url, $data);
//Check to see if host is part of a cluster. Clusted hosts need storage pool created first on each of the hosts
$url = $base_url . "/1.0/cluster";
$remote_data = sendCurlRequest($action, "GET", $url);
$remote_data = json_decode($remote_data, true);
$cluster_status = $remote_data['metadata'];
if ($cluster_status['enabled'] == true){
//Get a list of cluster members
$url = $base_url . "/1.0/cluster/members?recursion=1";
$cluster_api_data = sendCurlRequest($action, "GET", $url);
$cluster_api_data = json_decode($cluster_api_data, true);
$cluster_api_data = $cluster_api_data['metadata'];
//Setup Storage Pool data for REST API
$target_json_array = json_decode($json, true);
//Setup Storage Pool data for REST API
$target_device_array = array();
$target_device_array['config'] = new ArrayObject();
$target_device_array['name'] = $target_json_array['name'];
$target_device_array['description'] = $target_json_array['description'];
$target_device_array['driver'] = $target_json_array['driver'];
if (!empty($target_json_array['config']['source'])){ $target_device_array['config']['source'] = $target_json_array['config']['source'];}
if ($target_device_array['driver'] == "btrfs"){
if (!empty($target_json_array['config']['size'])){ $target_device_array['config']['size'] = $target_json_array['config']['size'];}
}
if ($target_device_array['driver'] == "lvm"){
if (!empty($target_json_array['config']['size'])){ $target_device_array['config']['size'] = $target_json_array['config']['size'];}
}
if ($target_device_array['driver'] == "zfs"){
if (!empty($target_json_array['config']['size'])){ $target_device_array['config']['size'] = $target_json_array['config']['size'];}
if (!empty($target_json_array['config']['zfs.pool_name'])){ $target_device_array['config']['zfs.pool_name'] = $target_json_array['config']['zfs.pool_name'];}
}
$target_data = json_encode($target_device_array);
//Loop through each cluster member to create the storage pool, this will put the storage volume in pending status
foreach ($cluster_api_data as $cluster_data){
$url = $base_url . "/1.0/storage-pools?project=" . $project . "&target=".$cluster_data['server_name'];
$results = sendCurlRequest($action, "POST", $url, $target_data);
}
//Now lets create the storage pool without target config options, moving the pending status to created
$url = $base_url . "/1.0/storage-pools?project=" . $project;
//Setup Storage Pool data for REST API
$device_array = json_decode($json, true);
unset($device_array['config']['source']);
unset($device_array['config']['size']);
unset($device_array['config']['zfs.pool_name']);
$data = json_encode($device_array);
$results = sendCurlRequest($action, "POST", $url, $data);
}
else {
$url = $base_url . "/1.0/storage-pools?project=" . $project;
$data = $json;
$results = sendCurlRequest($action, "POST", $url, $data);
}
echo $results;
//Send event to accounting
@ -367,39 +428,50 @@ if (isset($_SESSION['username'])) {
$i = 0;
echo '{ "data": [';
foreach ($storage_pools as $storage_pool){
if ($storage_pool['name'] == "")
continue;
if ($i > 0){
echo ",";
if ($results['status_code'] == "200"){
foreach ($storage_pools as $storage_pool){
if ($storage_pool['name'] == "")
continue;
if ($i > 0){
echo ",";
}
$i++;
echo "[ ";
echo '"';
echo "<a href='storage-volumes.php?pool=".$storage_pool['name']."&remote=".$remote."&project=".$project."&type=custom'><i class='fas fa-hdd fa-lg' style='color:#4e73df'></i> </a>";
echo '",';
echo '"';
echo "<a href='storage-volumes.php?pool=".$storage_pool['name']."&remote=".$remote."&project=".$project."&type=custom'> ".htmlentities($storage_pool['name'])."</a>";
echo '",';
echo '"' . htmlentities($storage_pool['description']) . '",';
echo '"' . htmlentities($storage_pool['driver']) . '",';
echo '"' . htmlentities($storage_pool['status']) . '",';
if(isset($storage_pool['config']) && array_key_exists('source', $storage_pool['config']))
$storage_pool_source = (isset($storage_pool['config']['source'])) ? $storage_pool['config']['source'] : "N/A";
else
$storage_pool_source = "N/A";
echo '"' . htmlentities($storage_pool_source) . '",';
$storage_pool_size = (isset($storage_pool['config']['size'])) ? $storage_pool['config']['size'] : "N/A";
echo '"' . htmlentities($storage_pool_size) . '",';
echo '"';
echo "<a href='#' onclick=loadStoragePoolJson('".$storage_pool['name']."')><i class='fas fa-edit fa-lg' style='color:#ddd' title='Edit' aria-hidden='true'></i></a>";
echo " &nbsp ";
echo "<a href='#' onclick=deleteStoragePool('".$storage_pool['name']."')><i class='fas fa-trash-alt fa-lg' style='color:#ddd' title='Delete' aria-hidden='true'></i></a>";
echo '"';
echo " ]";
}
$i++;
echo "[ ";
echo '"';
echo "<a href='storage-volumes.html?pool=".$storage_pool['name']."&remote=".$remote."&project=".$project."&type=custom'><i class='fas fa-hdd fa-lg' style='color:#4e73df'></i> </a>";
echo '",';
echo '"';
echo "<a href='storage-volumes.html?pool=".$storage_pool['name']."&remote=".$remote."&project=".$project."&type=custom'> ".htmlentities($storage_pool['name'])."</a>";
echo '",';
echo '"' . htmlentities($storage_pool['description']) . '",';
echo '"' . htmlentities($storage_pool['driver']) . '",';
echo '"' . htmlentities($storage_pool['status']) . '",';
echo '"' . htmlentities($storage_pool['config']['source']) . '",';
echo '"' . htmlentities($storage_pool['config']['size']) . '",';
echo '"';
echo "<a href='#' onclick=loadStoragePoolJson('".$storage_pool['name']."')><i class='fas fa-edit fa-lg' style='color:#ddd' title='Edit' aria-hidden='true'></i></a>";
echo " &nbsp ";
echo "<a href='#' onclick=deleteStoragePool('".$storage_pool['name']."')><i class='fas fa-trash-alt fa-lg' style='color:#ddd' title='Delete' aria-hidden='true'></i></a>";
echo '"';
echo " ]";
}
echo " ]}";

View file

@ -50,13 +50,13 @@ if (isset($_SESSION['username'])) {
//Declare and instantiate POST variables
$json = (isset($_POST['json'])) ? $_POST['json'] : "";
//Require code from lxd-dashboard/php/config/curl.php
//Require code from lxd-dashboard/backend/config/curl.php
require_once('../config/curl.php');
//Require code from lxd-dashboard/php/config/db.php
//Require code from lxd-dashboard/backend/config/db.php
require_once('../config/db.php');
//Require code from lxd-dashboard/php/aaa/accounting.php
//Require code from lxd-dashboard/backend/aaa/accounting.php
require_once('../aaa/accounting.php');
//Query database for remote host record
@ -144,42 +144,46 @@ if (isset($_SESSION['username'])) {
$i = 0;
echo '{ "data": [';
foreach ($storage_volumes as $storage_volume){
if ($type == "custom" && $storage_volume['type'] != $type)
continue;
if ($results['status_code'] == "200"){
foreach ($storage_volumes as $storage_volume){
if ($type == "custom" && $storage_volume['type'] != $type)
continue;
if ($i > 0){
echo ",";
}
$i++;
echo "[ ";
echo '"';
echo "<i class='fas fa-hdd fa-lg' style='color:#4e73df'></i>";
echo '",';
echo '"' . htmlentities($storage_volume['name']) . '",';
echo '"' . htmlentities($storage_volume['type']) . '",';
echo '"' . htmlentities($storage_volume['location']) . '",';
echo '"' . htmlentities($storage_volume['content_type']) . '",';
echo '"';
$ii = 0;
foreach ($storage_volume['used_by'] as $item){
if ($ii >= 1)
echo ", ";
$ii++;
echo htmlentities($item);
}
echo '",';
echo '"';
echo "<a href='#' onclick=loadStorageVolumeJson('".$storage_volume['type']."/".$storage_volume['name']."')><i class='fas fa-edit fa-lg' style='color:#ddd' title='Edit' aria-hidden='true'></i></a>";
echo " &nbsp ";
echo "<a href='#' onclick=deleteStorageVolume('".$storage_volume['type']."/".$storage_volume['name']."')><i class='fas fa-trash-alt fa-lg' style='color:#ddd' title='Delete' aria-hidden='true'></i></a>";
echo '"';
echo " ]";
if ($i > 0){
echo ",";
}
$i++;
echo "[ ";
echo '"';
echo "<i class='fas fa-hdd fa-lg' style='color:#4e73df'></i>";
echo '",';
echo '"' . htmlentities($storage_volume['name']) . '",';
echo '"' . htmlentities($storage_volume['type']) . '",';
echo '"' . htmlentities($storage_volume['location']) . '",';
echo '"' . htmlentities($storage_volume['content_type']) . '",';
echo '"';
$ii = 0;
foreach ($storage_volume['used_by'] as $item){
if ($ii >= 1)
echo ", ";
$ii++;
echo htmlentities($item);
}
echo '",';
echo '"';
echo "<a href='#' onclick=loadStorageVolumeJson('".$storage_volume['type']."/".$storage_volume['name']."')><i class='fas fa-edit fa-lg' style='color:#ddd' title='Edit' aria-hidden='true'></i></a>";
echo " &nbsp ";
echo "<a href='#' onclick=deleteStorageVolume('".$storage_volume['type']."/".$storage_volume['name']."')><i class='fas fa-trash-alt fa-lg' style='color:#ddd' title='Delete' aria-hidden='true'></i></a>";
echo '"';
echo " ]";
}

View file

@ -47,16 +47,40 @@ if (isset($_SESSION['username'])) {
$optimized_storage = (isset($_GET['optimized_storage'])) ? filter_var(urldecode($_GET['optimized_storage']), FILTER_SANITIZE_STRING) : "";
$compression_algorithm = (isset($_GET['compression_algorithm'])) ? filter_var(urldecode($_GET['compression_algorithm']), FILTER_SANITIZE_STRING) : "";
$boot_autostart = (isset($_GET['boot_autostart'])) ? filter_var(urldecode($_GET['boot_autostart']), FILTER_SANITIZE_STRING) : "";
$boot_autostart_delay = (isset($_GET['boot_autostart_delay'])) ? filter_var(urldecode($_GET['boot_autostart_delay']), FILTER_SANITIZE_STRING) : "";
$boot_autostart_priority = (isset($_GET['boot_autostart_priority'])) ? filter_var(urldecode($_GET['boot_autostart_priority']), FILTER_SANITIZE_STRING) : "";
$boot_host_shutdown_timeout = (isset($_GET['boot_host_shutdown_timeout'])) ? filter_var(urldecode($_GET['boot_host_shutdown_timeout']), FILTER_SANITIZE_STRING) : "";
$boot_stop_priority = (isset($_GET['boot_stop_priority'])) ? filter_var(urldecode($_GET['boot_stop_priority']), FILTER_SANITIZE_STRING) : "";
$cluster_evacuate = (isset($_GET['cluster_evacuate'])) ? filter_var(urldecode($_GET['cluster_evacuate']), FILTER_SANITIZE_STRING) : "";
$limits_cpu = (isset($_GET['limits_cpu'])) ? filter_var(urldecode($_GET['limits_cpu']), FILTER_SANITIZE_STRING) : "";
$limits_disk_priority = (isset($_GET['limits_disk_priority'])) ? filter_var(urldecode($_GET['limits_disk_priority']), FILTER_SANITIZE_STRING) : "";
$limits_memory = (isset($_GET['limits_memory'])) ? filter_var(urldecode($_GET['limits_memory']), FILTER_SANITIZE_STRING) : "";
$limits_memory_hugepages = (isset($_GET['limits_memory_hugepages'])) ? filter_var(urldecode($_GET['limits_memory_hugepages']), FILTER_SANITIZE_STRING) : "";
$limits_network_priority = (isset($_GET['limits_network_priority'])) ? filter_var(urldecode($_GET['limits_network_priority']), FILTER_SANITIZE_STRING) : "";
$migration_stateful = (isset($_GET['migration_stateful'])) ? filter_var(urldecode($_GET['migration_stateful']), FILTER_SANITIZE_STRING) : "";
$raw_apparmor = (isset($_GET['raw_apparmor'])) ? filter_var(urldecode($_GET['raw_apparmor']), FILTER_SANITIZE_STRING) : "";
$raw_qemu = (isset($_GET['raw_qemu'])) ? filter_var(urldecode($_GET['raw_qemu']), FILTER_SANITIZE_STRING) : "";
$raw_qemu_conf = (isset($_GET['raw_qemu_conf'])) ? filter_var(urldecode($_GET['raw_qemu_conf']), FILTER_SANITIZE_STRING) : "";
$security_devlxd = (isset($_GET['security_devlxd'])) ? filter_var(urldecode($_GET['security_devlxd']), FILTER_SANITIZE_STRING) : "";
$security_protection_delete = (isset($_GET['security_protection_delete'])) ? filter_var(urldecode($_GET['security_protection_delete']), FILTER_SANITIZE_STRING) : "";
$security_secureboot = (isset($_GET['security_secureboot'])) ? filter_var(urldecode($_GET['security_secureboot']), FILTER_SANITIZE_STRING) : "";
$snapshots_schedule = (isset($_GET['snapshots_schedule'])) ? filter_var(urldecode($_GET['snapshots_schedule']), FILTER_SANITIZE_STRING) : "";
$snapshots_schedule_stopped = (isset($_GET['snapshots_schedule_stopped'])) ? filter_var(urldecode($_GET['snapshots_schedule_stopped']), FILTER_SANITIZE_STRING) : "";
$snapshots_pattern = (isset($_GET['snapshots_pattern'])) ? filter_var(urldecode($_GET['snapshots_pattern']), FILTER_SANITIZE_STRING) : "";
$snapshots_expiry = (isset($_GET['snapshots_expiry'])) ? filter_var(urldecode($_GET['snapshots_expiry']), FILTER_SANITIZE_STRING) : "";
//Declare and instantiate POST variables
$json = (isset($_POST['json'])) ? $_POST['json'] : "";
//Require code from lxd-dashboard/php/config/curl.php
//Require code from lxd-dashboard/backend/config/curl.php
require_once('../config/curl.php');
//Require code from lxd-dashboard/php/config/db.php
//Require code from lxd-dashboard/backend/config/db.php
require_once('../config/db.php');
//Require code from lxd-dashboard/php/aaa/accounting.php
//Require code from lxd-dashboard/backend/aaa/accounting.php
require_once('../aaa/accounting.php');
//Query database for remote host record
@ -69,9 +93,10 @@ if (isset($_SESSION['username'])) {
$url = $base_url . "/1.0/instances/" . $instance . "?project=" . $project;
$results = sendCurlRequest($action, "GET", $url);
$data = json_decode($results, true);
$description = $data['metadata']['description'];
$data = $data['metadata']['profiles'];
array_push($data, $name);
$data = '{"profiles":' . json_encode($data) . '}';
$data = '{"description":"'.$description.'", "profiles":' . json_encode($data) . '}';
$results = sendCurlRequest($action, "PATCH", $url, $data);
echo $results;
@ -199,14 +224,52 @@ if (isset($_SESSION['username'])) {
else {
$url = $base_url . "/1.0/instances?target=" . $location . "&project=" . $project;
}
//If fingerprint == none create an empty instance
if ($fingerprint == "none") {
$data = '{"name":"' . $name . '", "profiles": ["'. $profile . '"], "type": "' . $type . '", "instance_type": "' . $instance_type . '", "source": {"type": "none"} }';
$instance_array = array();
$instance_array['name'] = $name;
$instance_array['description'] = $description;
$instance_array['profiles'] = array();
array_push($instance_array['profiles'], $profile);
$instance_array['type'] = "virtual-machine";
$instance_array['instance_type'] = $instance_type;
if ($fingerprint == "none"){
$instance_array['source']['type'] = "none";
}
else {
$data = '{"name":"' . $name . '", "profiles": ["'. $profile . '"], "type": "' . $type . '", "instance_type": "' . $instance_type . '", "source": {"type": "image", "fingerprint": "' . $fingerprint . '"} }';
$instance_array['source']['type'] = "image";
$instance_array['source']['fingerprint'] = $fingerprint;
}
$instance_array['config'] = new ArrayObject();
if (!empty($boot_autostart)){ $instance_array['config']['boot.autostart'] = $boot_autostart;}
if (!empty($boot_autostart_delay)){ $instance_array['config']['boot.autostart.delay'] = $boot_autostart_delay;}
if (!empty($boot_autostart_priority)){ $instance_array['config']['boot.autostart.priority'] = $boot_autostart_priority;}
if (!empty($boot_host_shutdown_timeout)){ $instance_array['config']['boot.host_shutdown_timeout'] = $boot_host_shutdown_timeout;}
if (!empty($boot_stop_priority)){ $instance_array['config']['boot.stop.priority'] = $boot_stop_priority;}
if (!empty($cluster_evacuate)){ $instance_array['config']['cluster.evacuate'] = $cluster_evacuate;}
if (!empty($limits_cpu)){ $instance_array['config']['limits.cpu'] = $limits_cpu;}
if (!empty($limits_disk_priority)){ $instance_array['config']['limits.disk.priority'] = $limits_disk_priority;}
if (!empty($limits_memory)){ $instance_array['config']['limits.memory'] = $limits_memory;}
if (!empty($limits_memory_hugepages)){ $instance_array['config']['limits.memory.hugepages'] = $limits_memory_hugepages;}
if (!empty($limits_network_priority)){ $instance_array['config']['limits.network.priority'] = $limits_network_priority;}
if (!empty($migration_stateful)){ $instance_array['config']['migration.stateful'] = $migration_stateful;}
if (!empty($raw_apparmor)){ $instance_array['config']['raw.apparmor'] = $raw_apparmor;}
if (!empty($raw_qemu)){ $instance_array['config']['raw.qemu'] = $raw_qemu;}
if (!empty($raw_qemu_conf)){ $instance_array['config']['raw.qemu.conf'] = $raw_qemu_conf;}
if (!empty($security_devlxd)){ $instance_array['config']['security.devlxd'] = $security_devlxd;}
if (!empty($security_protection_delete)){ $instance_array['config']['security.protection.delete'] = $security_protection_delete;}
if (!empty($security_secureboot)){ $instance_array['config']['security.secureboot'] = $security_secureboot;}
if (!empty($snapshots_schedule)){ $instance_array['config']['snapshots.schedule'] = $snapshots_schedule;}
if (!empty($snapshots_schedule_stopped)){ $instance_array['config']['snapshots.schedule.stopped'] = $snapshots_schedule_stopped;}
if (!empty($snapshots_pattern)){ $instance_array['config']['snapshots.pattern'] = $snapshots_pattern;}
if (!empty($snapshots_expiry)){ $instance_array['config']['snapshots.expiry'] = $snapshots_expiry;}
$data = json_encode($instance_array);
$results = sendCurlRequest($action, "POST", $url, $data);
echo $results;
//Send event to accounting
@ -237,7 +300,7 @@ if (isset($_SESSION['username'])) {
}
break;
case "deleteInstance":
case "deleteInstance":
$url = $base_url . "/1.0/instances/" . $instance . "?project=" . $project;
$results = sendCurlRequest($action, "DELETE", $url);
echo $results;
@ -308,6 +371,7 @@ if (isset($_SESSION['username'])) {
$url = $base_url . "/1.0/instances/" . $instance . "?project=" . $project;
$results = sendCurlRequest($action, "GET", $url);
$data = json_decode($results, true);
$description = $data['metadata']['description'];
$data = $data['metadata']['profiles'];
$i = 0;
foreach ($data as $element){
@ -316,7 +380,7 @@ if (isset($_SESSION['username'])) {
}
$i++;
}
$data = '{"profiles":' . json_encode($data) . '}';
$data = '{"description":"'.$description.'", "profiles":' . json_encode($data) . '}';
$results = sendCurlRequest($action, "PATCH", $url, $data);
echo $results;
@ -380,23 +444,10 @@ if (isset($_SESSION['username'])) {
}
$url = $base_url . "/1.0/instances/" . $instance . "/backups/" . $name . "/export?project=" . $project;
$fp = fopen($file, "w+");
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_SSLCERT, $cert);
curl_setopt($ch, CURLOPT_SSLKEY, $key);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type:application/json'));
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$results = curl_exec($ch);
curl_close($ch);
fclose($fp);
//Calling a script to execute the export. This will run in a seperate process so that it doesn't block other PHP requests from completing
$results = exec("php ./scripts/curl-export-file.php $file $url $cert $key > /dev/null &");
if ($results == false){
$results = '{"status": "Bad Request", "status_code": 400, "metadata": {"err": "Unable to execute action on remote host", "status_code": "400"}}';
}
@ -436,7 +487,7 @@ if (isset($_SESSION['username'])) {
case "listInstances":
if (validateAuthorization($action)) {
$url = $base_url . "/1.0/instances?recursion=2&project=" . $project;
$url = $base_url . "/1.0/virtual-machines?recursion=2&project=" . $project;
$results = sendCurlRequest($action, "GET", $url);
$results = json_decode($results, true);
$instance_api_data = (isset($results['metadata'])) ? $results['metadata'] : [];
@ -444,131 +495,139 @@ if (isset($_SESSION['username'])) {
$i = 0;
echo '{ "data": [';
foreach ($instance_api_data as $instance_data){
if ($results['status_code'] == "200"){
if ($instance_data['name'] == "")
continue;
foreach ($instance_api_data as $instance_data){
if ($i > 0){
echo ",";
}
$i++;
if ($instance_data['name'] == "")
continue;
echo "[ ";
if ($instance_data['status'] == "Running"){
if ($i > 0){
echo ",";
}
$i++;
echo "[ ";
if ($instance_data['status'] == "Running"){
echo '"';
echo "<a href='virtual-machines-single.php?instance=".$instance_data['name']."&remote=".$remote."&project=".$project."'><i class='fas fa-cube fa-lg' style='color:#4e73df'></i> </a>";
echo '",';
echo '"';
echo "<a href='virtual-machines-single.php?instance=".$instance_data['name']."&remote=".$remote."&project=".$project."'> ".htmlentities($instance_data['name'])."</a>";
echo '",';
}
else {
echo '"';
echo "<a href='virtual-machines-single.php?instance=".$instance_data['name']."&remote=".$remote."&project=".$project."'><i class='fas fa-cube fa-lg' style='color:#ddd'></i> </a>";
echo '",';
echo '"';
echo "<a href='virtual-machines-single.php?instance=".$instance_data['name']."&remote=".$remote."&project=".$project."'> ".htmlentities($instance_data['name'])."</a>";
echo '",';
}
echo '"';
echo "<a href='instances-single.html?instance=".$instance_data['name']."&remote=".$remote."&project=".$project."'><i class='fas fa-cube fa-lg' style='color:#4e73df'></i> </a>";
if (isset($instance_data['config']['image.os']))
echo htmlentities($instance_data['config']['image.os']);
else
echo "";
echo '",';
echo '"' . htmlentities($instance_data['location']) . '",';
//IPv4
echo '"';
echo "<a href='instances-single.html?instance=".$instance_data['name']."&remote=".$remote."&project=".$project."'> ".htmlentities($instance_data['name'])."</a>";
echo '",';
}
else {
echo '"';
echo "<a href='instances-single.html?instance=".$instance_data['name']."&remote=".$remote."&project=".$project."'><i class='fas fa-cube fa-lg' style='color:#ddd'></i> </a>";
if (isset($instance_data['state']['network'])){
foreach ($instance_data['state']['network'] as $nic => $nic_properties){
foreach ($nic_properties['addresses'] as $nic_address){
if ($nic_address['family'] == "inet" && $nic_address['scope'] == "global"){
echo htmlentities($nic_address['address']) . " (" . htmlentities($nic) . ")<br />";
}
}
}
}
echo '",';
//IPv6
echo '"';
echo "<a href='instances-single.html?instance=".$instance_data['name']."&remote=".$remote."&project=".$project."'> ".htmlentities($instance_data['name'])."</a>";
if (isset($instance_data['state']['network'])){
foreach ($instance_data['state']['network'] as $nic => $nic_properties){
foreach ($nic_properties['addresses'] as $nic_address){
if ($nic_address['family'] == "inet6" && $nic_address['scope'] == "global"){
echo htmlentities($nic_address['address']) . " (" . htmlentities($nic) . ")<br />";
}
}
}
}
echo '",';
//Convert the memory usage to an appropriate unit
if ($instance_data['state']['memory']['usage'] < 1073741824){
$memory = number_format($instance_data['state']['memory']['usage']/1024/1024, 2);
$memory_unit = "MiB";
}
else {
$memory = number_format($instance_data['state']['memory']['usage']/1024/1024/1024, 2);
$memory_unit = "GiB";
}
echo '"' . htmlentities($memory) . " " . $memory_unit . '",';
//When first created, the root disk usage is not set for brief second causing a PHP Notice in error log for Undefined index: root
if (isset($instance_data['state']['disk']['root']['usage'])){
//Convert the storage usage to an approprate unit
if ($instance_data['state']['disk']['root']['usage'] < 1073741824){
$disk_total = number_format($instance_data['state']['disk']['root']['usage']/1024/1024,2);
$disk_unit = "MiB";
}
if ($instance_data['state']['disk']['root']['usage'] >= 1073741824 && $instance_data['state']['disk']['root']['usage'] < 1099511627776) {
$disk_total = number_format($instance_data['state']['disk']['root']['usage']/1024/1024/1024,2);
$disk_unit = "GiB";
}
if ($instance_data['state']['disk']['root']['usage'] >= 1099511627776){
$disk_total = number_format($instance_data['state']['disk']['root']['usage']/1024/1024/1024/1024,2);
$disk_unit = "TiB";
}
}
else {
$disk_total = "N/A";
$disk_unit = "";
}
echo '"' . htmlentities($disk_total) . " " . $disk_unit . '",';
echo '"' . htmlentities($instance_data['status']) . '",';
switch ($instance_data['status']) {
case "Running":
echo '"';
echo "<a href='#' onclick=stopInstance('".$instance_data['name']."')> <i class='fas fa-stop fa-lg' style='color:#cdcdcd' title='Stop' aria-hidden='true'></i> </a>";
echo " &nbsp ";
echo "<a href='#'><i class='fas fa-trash-alt fa-lg' style='color:#ededed' title='Delete (disabled)' aria-hidden='true'></i></a>";
echo '"';
break;
case "Frozen":
echo '"';
echo "<a href='#' onclick=unfreezeInstance('".$instance_data['name']."')> <i class='fas fa-pause fa-lg' style='color:#cdcdcd' title='Unfreeze' aria-hidden='true'></i> </a>";
echo " &nbsp ";
echo "<a href='#'><i class='fas fa-trash-alt fa-lg' style='color:#ededed' title='Delete (disabled)' aria-hidden='true'></i></a>";
echo '"';
break;
case "Stopped":
echo '"';
echo "<a href='#' onclick=startInstance('".$instance_data['name']."')> <i class='fas fa-play fa-lg' style='color:#cdcdcd' title='Start' aria-hidden='true'></i> </a>";
echo " &nbsp ";
echo "<a href='#' onclick=confirmDeleteInstance('".$instance_data['name']."')><i class='fas fa-trash-alt fa-lg' style='color:#cdcdcd' title='Delete' aria-hidden='true'></i></a>";
echo '"';
break;
default:
echo '" "';
}
echo " ]";
}
echo '"';
if (isset($instance_data['config']['image.os']))
echo htmlentities($instance_data['config']['image.os']);
else
echo "";
echo '",';
echo '"' . htmlentities($instance_data['location']) . '",';
//IPv4
echo '"';
if (isset($instance_data['state']['network'])){
foreach ($instance_data['state']['network'] as $nic => $nic_properties){
foreach ($nic_properties['addresses'] as $nic_address){
if ($nic_address['family'] == "inet" && $nic_address['scope'] == "global"){
echo htmlentities($nic_address['address']) . " (" . htmlentities($nic) . ")<br />";
}
}
}
}
echo '",';
//IPv6
echo '"';
if (isset($instance_data['state']['network'])){
foreach ($instance_data['state']['network'] as $nic => $nic_properties){
foreach ($nic_properties['addresses'] as $nic_address){
if ($nic_address['family'] == "inet6" && $nic_address['scope'] == "global"){
echo htmlentities($nic_address['address']) . " (" . htmlentities($nic) . ")<br />";
}
}
}
}
echo '",';
echo '"' . htmlentities($instance_data['type']) . '",';
//Convert the memory usage to an appropriate unit
if ($instance_data['state']['memory']['usage'] < 1073741824){
$memory = number_format($instance_data['state']['memory']['usage']/1024/1024, 2);
$memory_unit = "MB";
}
else {
$memory = number_format($instance_data['state']['memory']['usage']/1024/1024/1024, 2);
$memory_unit = "GB";
}
echo '"' . htmlentities($memory) . " " . $memory_unit . '",';
//When first created, the root disk usage is not set for brief second causing a PHP Notice in error log for Undefined index: root
if (isset($instance_data['state']['disk']['root']['usage'])){
//Convert the storage usage to an approprate unit
if ($instance_data['state']['disk']['root']['usage'] < 1073741824){
$disk_total = number_format($instance_data['state']['disk']['root']['usage']/1024/1024,2);
$disk_unit = "MB";
}
if ($instance_data['state']['disk']['root']['usage'] >= 1073741824 && $instance_data['state']['disk']['root']['usage'] < 1099511627776) {
$disk_total = number_format($instance_data['state']['disk']['root']['usage']/1024/1024/1024,2);
$disk_unit = "GB";
}
if ($instance_data['state']['disk']['root']['usage'] >= 1099511627776){
$disk_total = number_format($instance_data['state']['disk']['root']['usage']/1024/1024/1024/1024,2);
$disk_unit = "TB";
}
}
else {
$disk_total = 0.00;
$disk_unit = "MB";
}
echo '"' . htmlentities($disk_total) . " " . $disk_unit . '",';
echo '"' . htmlentities($instance_data['status']) . '",';
switch ($instance_data['status']) {
case "Running":
echo '"';
echo "<a href='#' onclick=stopInstance('".$instance_data['name']."')> <i class='fas fa-stop fa-lg' style='color:#ddd' title='Stop' aria-hidden='true'></i> </a>";
echo '"';
break;
case "Frozen":
echo '"';
echo "<a href='#' onclick=unfreezeInstance('".$instance_data['name']."')> <i class='fas fa-pause fa-lg' style='color:#ddd' title='Unfreeze' aria-hidden='true'></i> </a>";
echo '"';
break;
case "Stopped":
echo '"';
echo "<a href='#' onclick=startInstance('".$instance_data['name']."')> <i class='fas fa-play fa-lg' style='color:#ddd' title='Start' aria-hidden='true'></i> </a>";
echo '"';
break;
default:
echo '" "';
}
echo " ]";
}
echo " ]}";
@ -579,7 +638,7 @@ if (isset($_SESSION['username'])) {
break;
case "listInstancesForSelectOption":
$url = $base_url . "/1.0/instances?recursion=1&project=" . $project;
$url = $base_url . "/1.0/virtual-machines?recursion=1&project=" . $project;
$results = sendCurlRequest($action, "GET", $url);
$results = json_decode($results, true);
$instance_api_data = (isset($results['metadata'])) ? $results['metadata'] : [];
@ -814,6 +873,73 @@ if (isset($_SESSION['username'])) {
}
break;
case "updateInstanceUsingForm":
$url = $base_url . "/1.0/instances/" . $instance . "?project=" . $project;
//Retrieve existing instance config settings
$results = sendCurlRequest($action, "GET", $url);
$existing_array = json_decode($results, true);
$existing_array = $existing_array['metadata'];
//Create array of new config settings
$instance_array = array();
$instance_array['description'] = $description;
$instance_array['config'] = new ArrayObject();
$instance_array['config']['boot.autostart'] = $boot_autostart;
$instance_array['config']['boot.autostart.delay'] = $boot_autostart_delay;
$instance_array['config']['boot.autostart.priority'] = $boot_autostart_priority;
$instance_array['config']['boot.host_shutdown_timeout'] = $boot_host_shutdown_timeout;
$instance_array['config']['boot.stop.priority'] = $boot_stop_priority;
$instance_array['config']['cluster.evacuate'] = $cluster_evacuate;
$instance_array['config']['limits.cpu'] = $limits_cpu;
$instance_array['config']['limits.disk.priority'] = $limits_disk_priority;
$instance_array['config']['limits.memory'] = $limits_memory;
$instance_array['config']['limits.memory.hugepages'] = $limits_memory_hugepages;
$instance_array['config']['limits.network.priority'] = $limits_network_priority;
$instance_array['config']['migration.stateful'] = $migration_stateful;
$instance_array['config']['raw.apparmor'] = $raw_apparmor;
$instance_array['config']['raw.qemu'] = $raw_qemu;
$instance_array['config']['raw.qemu.conf'] = $raw_qemu_conf;
$instance_array['config']['security.devlxd'] = $security_devlxd;
$instance_array['config']['security.protection.delete'] = $security_protection_delete;
$instance_array['config']['security.secureboot'] = $security_secureboot;
$instance_array['config']['snapshots.schedule'] = $snapshots_schedule;
$instance_array['config']['snapshots.schedule.stopped'] = $snapshots_schedule_stopped;
$instance_array['config']['snapshots.pattern'] = $snapshots_pattern;
$instance_array['config']['snapshots.expiry'] = $snapshots_expiry;
//Create new array based on changes between existing and new configs
$new_array = array();
$new_array['description'] = $description;
$new_array['config'] = new ArrayObject();
foreach ($instance_array['config'] as $key => $val) {
if (!isset($existing_array['config'][$key])){
$existing_array['config'][$key] = "";
}
if ($instance_array['config'][$key] != $existing_array['config'][$key]){
$new_array['config'][$key] = $instance_array['config'][$key];
}
}
$data = json_encode($new_array);
$results = sendCurlRequest($action, "PATCH", $url, $data);
echo $results;
//Send event to accounting
$event = json_decode($results, true);
$object = $name;
if ($event['error_code'] == 0){
logEvent($action, $remote, $project, $object, $event['status_code'], $event['status']);
}
else {
logEvent($action, $remote, $project, $object, $event['error_code'], $event['error']);
}
break;
default:
$results = '{"status": "Bad Request", "status_code": 400, "metadata": {"err": "Unable to execute action on remote host", "status_code": "400"}}';
echo $results;

View file

@ -37,7 +37,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Custom styles for this template-->
<link href="vendor/sb-admin-2/css/sb-admin-2.css" rel="stylesheet">
<link href="assets/css/style.css" rel="stylesheet">
<link href="assets/css/style.css?version=3.0" rel="stylesheet">
<!-- Custom styles for this page -->
<link href="vendor/datatables/dataTables.bootstrap4.min.css" rel="stylesheet">
@ -50,7 +50,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<div id="wrapper">
<!-- Sidebar -->
<ul class="navbar-nav bg-dark sidebar sidebar-dark accordion" id="accordionSidebar">
<ul class="navbar-nav bg-dark sidebar sidebar-dark accordion sidebar-divider-right" id="accordionSidebar">
<div id="sidebarLinks"></div>
@ -59,12 +59,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Sidebar Toggler (Sidebar) -->
<div class="text-center d-none d-md-inline">
<button class="rounded-circle border-0" id="sidebarToggle"></button>
<button class="rounded-circle border-0" id="sidebarToggle" onclick="setSidebarToggleValue()"></button>
</div>
</ul>
<!-- End of Sidebar -->
<!-- Content Wrapper -->
<div id="content-wrapper" class="d-flex flex-column">
@ -79,36 +78,43 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<i class="fa fa-bars"></i>
</button>
<!-- Topbar Notification -->
<div class="d-none d-sm-inline-block form-inline mr-auto ml-md-3 my-2 my-md-0 mw-100 navbar-search">
<ul class="navbar-nav ml-auto">
<li>
<div class="nav-item spinner-border m-3" role="status" style="display:none;" id="spinner">
<span class="nav-item sr-only">Loading...</span>
</div>
</li>
<li class="nav-item dropdown no-arrow" id="notificationArea" style="display: none;">
<div class="nav-link dropdown-toggle">
<span id="notification" class="mr-2 d-none d-lg-inline text-gray-600">Notification</span>
<span id="notification" class="mr-2 d-none d-lg-inline text-danger">Notification</span>
</div>
</li>
</ul>
</div>
<!-- Topbar Navbar -->
<ul class="navbar-nav ml-auto">
<li class="nav-item dropdown" id="remoteListNav">
<li class="nav-item dropdown">
<label class="h6 mt-4 mr-2 ml-4">Host: </label>
</li>
<li class="nav-item dropdown">
<div class="input-group mt-3">
<select class="form-control" id="remoteListNav" style="width:150px;" onchange="location = this.value;">
</select>
</div>
</li>
<li class="nav-item dropdown" id="projectListNav">
<li class="nav-item dropdown">
<label class="h6 mt-4 mr-2 ml-4">Project: </label>
</li>
<li class="nav-item dropdown">
<div class="input-group mt-3">
<select class="form-control" id="projectListNav" style="width:150px;" onchange="location = this.value;">
</select>
</div>
</li>
<!-- Nav Divider -->
<div class="topbar-divider d-none d-sm-block"></div>
<!-- Nav Item - User Information -->
@ -119,14 +125,18 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</a>
<!-- Dropdown - User Information -->
<div class="dropdown-menu dropdown-menu-right shadow animated--grow-in" aria-labelledby="userDropdown">
<a class="dropdown-item" href="user-profile.html">
<a class="dropdown-item" href="user-profile.php">
<i class="fas fa-user fa-sm fa-fw mr-2 text-gray-400"></i>
Profile
</a>
<a class="dropdown-item" href="settings.html">
<a class="dropdown-item" href="settings.php">
<i class="fas fa-cog fa-sm fa-fw mr-2 text-gray-400"></i>
Settings
</a>
<a class="dropdown-item" href="logs.php">
<i class="fas fa-history fa-sm fa-fw mr-2 text-gray-400"></i>
Logs
</a>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#aboutModal">
<i class="fas fa-info-circle fa-sm fa-fw mr-2 text-gray-400"></i>
About
@ -147,25 +157,48 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Begin Page Content -->
<div class="container-fluid">
<!-- BreadCrumb -->
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="#" id="remoteBreadCrumb"></a></li>
<li class="breadcrumb-item active" aria-current="page" id="certificatesBreadCrumb"></li>
</ol>
</nav>
<header class="page-header page-header-dark bg-gradient-primary-to-secondary">
<div class="container-xl px-4">
<div class="page-header-content pt-4">
<div class="row align-items-center justify-content-between mt-n5 ml-n5 mr-n5 bg-dark pb-6">
<div class="col-auto mt-4 ml-3">
<div class="page-header-subtitle">
<a href="#" id="remoteBreadCrumb"></a>
</div>
<h2 class="page-header-title mt-2">
CERTIFICATES
</h2>
<div class="page-header-subtitle">
Add and manage trusted certificates on the remote host
</div>
</div>
<div class="col-12 col-xl-auto mt-4">
<div class="input-group input-group-joined border-0" style="width: 14rem">
<span class="input-group-text bg-transparent border-0">
<a class="btn btn-outline-primary" href="#" data-toggle="modal" data-target="#addCertificateModal" title="New Certificate" aria-hidden="true">
<i class="fas fa-plus fa-sm fa-fw"></i> Certificate
</a>
</span>
</div>
</div>
</div>
</div>
</div>
</header>
<div class="row">
<div class="row mt-n5 ml-2 mr-2">
<div class="col-12">
<div class="col-12 mt-n3">
<!-- Certificate List -->
<div class="card shadow mb-4">
<!-- Card Header - Dropdown -->
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">Certificates</h6>
<h6 class="m-0 font-weight-bold">
<span class="ml-1">Certificates</span>
</h6>
<div class="dropdown no-arrow">
<a class="dropdown-toggle mr-2" href="#" data-toggle="modal" data-target="#addCertificateModal" title="New Certificate" aria-hidden="true">
<i class="fas fa-plus fa-sm fa-fw"></i> Certificate</a>
<a class="dropdown-toggle mr-2" href="#" onclick="reloadPageContent()" title="Refresh" aria-hidden="true">
<i class="fa fa-sync fa-1x fa-fw"></i></a>
</div>
</div>
<!-- Card Body -->
@ -191,7 +224,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<footer class="sticky-footer bg-white">
<div class="container my-auto">
<div class="copyright text-center my-auto">
<span>Copyright &copy; lxdware.com 2021</span>
<span>Copyright &copy; LXDWARE 2020 - Present</span>
</div>
</div>
</footer>
@ -210,7 +243,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Add Certificate Modal-->
<div class="modal fade" id="addCertificateModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-dialog modal-xl" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Add Certificate</h5>
@ -229,25 +262,33 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</ul>
<div class="tab-content" id="myTabContent">
<div class="tab-pane fade show active" id="form" role="tabpanel" aria-labelledby="form-tab">
<br />
<div class="row">
<label class="col-2 col-form-label text-right">Name: </label>
<div class="col-10">
<div class="row mt-4">
<label class="col-2 col-form-label text-right">Name: <span class="text-danger">*</span> </label>
<div class="col-8">
<div class="form-group">
<input type="text" id="certificateNameCreate" class="form-control" name="certificate_name">
<input type="text" id="certificateNameCreate" class="form-control" required="required" placeholder="">
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle" title='Enter in a name for this certificate'></i>
</div>
</div>
<div class="row">
<label class="col-2 col-form-label text-right">Certificate: </label>
<div class="col-10">
<label class="col-2 col-form-label text-right">Certificate: <span class="text-danger">*</span> </label>
<div class="col-8">
<div class="form-group">
<pre>
<textarea id="certificateCreate" class="form-control" name="certificate" rows="14" style="font-size: .9rem;"></textarea>
</pre>
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle" title='Paste in certificate contents'></i>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
<a class="btn btn-primary" href="#" onclick="addCertificateUsingForm()" data-dismiss="modal">Submit</a>
@ -351,60 +392,66 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
const remoteId = urlParams.get('remote');
const projectName = urlParams.get('project');
var certificateToUpdate = "";
var reloadTime = 5000;
function logout(){
$.get("./php/aaa/authentication.php?action=deauthenticateUser", function (data) {
$.get("./backend/aaa/authentication.php?action=deauthenticateUser", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code == 200) {
window.location = './index.html'
window.location.href = './index.php'
}
});
}
function operationStatusCheck(){
clearTimeout(operationTimeout);
//check to see if there are any running operations
$.get("./php/lxd/operations.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayOperationStatus", function (data) {
$.get("./backend/lxd/operations.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayOperationStatus", function (data) {
//Check to see if we have running operations
if (data){
//Display spinner and notification area if there are running tasks
$('#spinner').show();
if (data) {
//Display notification area if there are running tasks
$('#notificationArea').show();
$('#notification').text(data);
//Set the page to check operations again in 1 second
setTimeout(() => { operationStatusCheck(); }, 1000);
$('#notification').text("Notice: " + data);
//Set the page to check operations again in 2 seconds
operationTimeout = setTimeout(() => { operationStatusCheck(); }, 2000);
}
else {
//Hide spinner and notification area if no running tasks
$('#spinner').hide();
//Hide notification area if no running tasks
$('#notificationArea').hide();
$('#notification').text("");
//Set the page to check operations again in 3 seconds
setTimeout(() => { operationStatusCheck(); }, 3000);
//Set the page to check operations again in 4 seconds
operationTimeout = setTimeout(() => { operationStatusCheck(); }, 4000);
}
});
}
function reloadPageContent(){
clearTimeout(pageReloadTimeout);
//Check Authorization
$.get("./php/aaa/authentication.php?action=validateAuthentication", function (data) {
$.get("./backend/aaa/authentication.php?action=validateAuthentication", function (data) {
operationData = JSON.parse(data);
if (operationData.status_code != 200) {
console.log(operationData);
window.location = './index.html'
window.location.href = './index.php'
}
});
$('#certificateListTable').DataTable().ajax.reload(null, false);
//Set reload page content
pageReloadTimeout = setTimeout(() => { reloadPageContent(); }, reloadTime);
}
function loadPageContent(){
//Display current logged in username
$("#username").load("./php/admin/settings.php?action=displayUsername");
$("#username").load("./backend/admin/settings.php?action=displayUsername");
$('#certificateListTable').DataTable( {
ajax: "./php/lxd/certificates.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listCertificates",
ajax: "./backend/lxd/certificates.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listCertificates",
columns: [
{},
{ title: "Name" },
@ -419,10 +466,16 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
});
//Check for any running operations
operationStatusCheck();
operationTimeout = setTimeout(() => { operationStatusCheck(); }, 1000);
//Set reload page content
$.get("./backend/admin/settings.php?action=retrievePageRefreshRateValues", function (data) {
operationData = JSON.parse(data);
if (operationData.certificates_page_rate >= 1)
reloadTime = operationData.certificates_page_rate * 1000;
pageReloadTimeout = setTimeout(() => { reloadPageContent(); }, reloadTime);
});
//Set the page content to reload in 5 seconds
setInterval(() => { reloadPageContent(); }, 5000);
}
function addCertificateUsingForm(){
@ -430,7 +483,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
var certificateCreate = $("#certificateCreate").val();
certificateCreate = certificateCreate.replace(/\n|\r/g, "\\n");
console.log("Info: adding certificate");
$.post("./php/lxd/certificates.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&name=" + encodeURI(certificateNameCreate) + "&action=addCertificateUsingForm", {certificate: certificateCreate}, function (data) {
$.post("./backend/lxd/certificates.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&name=" + encodeURI(certificateNameCreate) + "&action=addCertificateUsingForm", {certificate: certificateCreate}, function (data) {
//Sync operation type
var operationData = JSON.parse(data);
console.log(operationData);
@ -444,7 +497,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
function addCertificateUsingJSON(){
var certificateCreateJSON = $("#jsonCreateInput").val();
console.log("Info: adding certificate");
$.post("./php/lxd/certificates.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=addCertificateUsingJSON", {json: certificateCreateJSON}, function (data) {
$.post("./backend/lxd/certificates.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=addCertificateUsingJSON", {json: certificateCreateJSON}, function (data) {
//Sync operation type
var operationData = JSON.parse(data);
console.log(operationData);
@ -458,7 +511,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
function loadCertificateJson(certificateToLoad){
console.log("Info: locading certificate " + certificateToLoad);
certificateToUpdate = certificateToLoad;
$.get("./php/lxd/certificates.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&fingerprint=" + encodeURI(certificateToLoad) + "&action=loadCertificate", function (data) {
$.get("./backend/lxd/certificates.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&fingerprint=" + encodeURI(certificateToLoad) + "&action=loadCertificate", function (data) {
//Sync operation type
var operationData = JSON.parse(data);
console.log(operationData);
@ -474,7 +527,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
function updateCertificate(){
var certificateUpdateJSON = $("#jsonEditInput").val();
console.log("Info: updating certificate " + certificateToUpdate);
$.post("./php/lxd/certificates.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&fingerprint=" + encodeURI(certificateToUpdate) + "&action=updateCertificate", {json: certificateUpdateJSON}, function (data) {
$.post("./backend/lxd/certificates.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&fingerprint=" + encodeURI(certificateToUpdate) + "&action=updateCertificate", {json: certificateUpdateJSON}, function (data) {
//Sync operation type
var operationData = JSON.parse(data);
console.log(operationData);
@ -487,7 +540,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
function deleteCertificate(certificateToDelete){
console.log("Info: deleting certificate " + certificateToDelete);
$.get("./php/lxd/certificates.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&fingerprint=" + encodeURI(certificateToDelete) + "&action=deleteCertificate", function (data) {
$.get("./backend/lxd/certificates.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&fingerprint=" + encodeURI(certificateToDelete) + "&action=deleteCertificate", function (data) {
//Sync operation type
var operationData = JSON.parse(data);
console.log(operationData);
@ -498,33 +551,64 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
});
}
function setSidebarToggleValue(){
sidebarState = localStorage.getItem('sidebarState');
if (sidebarState == "collapsed"){
localStorage.setItem('sidebarState','expanded');
}
else {
localStorage.setItem('sidebarState','collapsed');
}
}
function applySidebarToggleValue() {
sidebarState = localStorage.getItem('sidebarState');
if (sidebarState == "collapsed"){
$("body").toggleClass("sidebar-toggled"),
$(".sidebar").toggleClass("toggled"),
$(".sidebar").hasClass("toggled") && $(".sidebar .collapse").collapse("hide")
}
}
applySidebarToggleValue();
$(document).ready(function(){
//Check Authorization
$.get("./php/aaa/authentication.php?action=validateAuthentication", function (data) {
$.get("./backend/aaa/authentication.php?action=validateAuthentication", function (data) {
operationData = JSON.parse(data);
if (operationData.status_code != 200) {
console.log(operationData);
window.location = './index.html'
window.location.href = './index.php'
}
});
//Load in the sidebar
$("#sidebarLinks").load("./sidebar.html");
//Load in the sidebar
$("#sidebarLinks").load("./sidebar.php?version=3.0");
//Setup Page Breadcrumb Links/Information
$('#remoteBreadCrumb').load("./php/lxd/remote-breadcrumb.php?remote=" + encodeURI(remoteId));
$('#remoteBreadCrumb').attr("href", "remotes-single.html?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$('#certificatesBreadCrumb').text("certificates");
$('#remoteBreadCrumb').load("./backend/lxd/remote-breadcrumb.php?remote=" + encodeURI(remoteId));
$('#remoteBreadCrumb').attr("href", "remotes-single.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
//Load the card contents
loadPageContent();
//Validate remote host connection returns 200 status
$.get("./backend/lxd/remotes-single.php?remote=" + encodeURI(remoteId) + "&action=validateRemoteConnection", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code == 200) {
//Set top navbar dropdowns
$("#remoteListNav").load("./backend/lxd/remotes.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listRemotesForSelectOption");
$("#projectListNav").load("./backend/lxd/projects.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listProjectsForSelectOption");
$("#remoteListNav").load("./php/lxd/remotes.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listRemotesForTopNavigation");
$("#projectListNav").load("./php/lxd/projects.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listProjectsForTopNavigation");
//Load Page Content
loadPageContent();
}
else {
alert("Unable to connect to remote host. HTTP status code: " + operationData.status_code);
}
});
//Load the about info for the about modal
$.get("./about.html", function (data) {
$.get("./backend/config/about.php", function (data) {
$("#about").html(data);
});

View file

@ -37,7 +37,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Custom styles for this template-->
<link href="vendor/sb-admin-2/css/sb-admin-2.css" rel="stylesheet">
<link href="assets/css/style.css" rel="stylesheet">
<link href="assets/css/style.css?version=3.0" rel="stylesheet">
<!-- Custom styles for this page -->
<link href="vendor/datatables/dataTables.bootstrap4.min.css" rel="stylesheet">
@ -50,7 +50,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<div id="wrapper">
<!-- Sidebar -->
<ul class="navbar-nav bg-dark sidebar sidebar-dark accordion" id="accordionSidebar">
<ul class="navbar-nav bg-dark sidebar sidebar-dark accordion sidebar-divider-right" id="accordionSidebar">
<div id="sidebarLinks"></div>
@ -59,12 +59,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Sidebar Toggler (Sidebar) -->
<div class="text-center d-none d-md-inline">
<button class="rounded-circle border-0" id="sidebarToggle"></button>
<button class="rounded-circle border-0" id="sidebarToggle" onclick="setSidebarToggleValue()"></button>
</div>
</ul>
<!-- End of Sidebar -->
<!-- Content Wrapper -->
<div id="content-wrapper" class="d-flex flex-column">
@ -79,36 +78,43 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<i class="fa fa-bars"></i>
</button>
<!-- Topbar Notification -->
<div class="d-none d-sm-inline-block form-inline mr-auto ml-md-3 my-2 my-md-0 mw-100 navbar-search">
<ul class="navbar-nav ml-auto">
<li>
<div class="nav-item spinner-border m-3" role="status" style="display:none;" id="spinner">
<span class="nav-item sr-only">Loading...</span>
</div>
</li>
<li class="nav-item dropdown no-arrow" id="notificationArea" style="display: none;">
<div class="nav-link dropdown-toggle">
<span id="notification" class="mr-2 d-none d-lg-inline text-gray-600">Notification</span>
<span id="notification" class="mr-2 d-none d-lg-inline text-danger">Notification</span>
</div>
</li>
</ul>
</div>
<!-- Topbar Navbar -->
<ul class="navbar-nav ml-auto">
<li class="nav-item dropdown" id="remoteListNav">
<li class="nav-item dropdown">
<label class="h6 mt-4 mr-2 ml-4">Host: </label>
</li>
<li class="nav-item dropdown">
<div class="input-group mt-3">
<select class="form-control" id="remoteListNav" style="width:150px;" onchange="location = this.value;">
</select>
</div>
</li>
<li class="nav-item dropdown" id="projectListNav">
<li class="nav-item dropdown">
<label class="h6 mt-4 mr-2 ml-4">Project: </label>
</li>
<li class="nav-item dropdown">
<div class="input-group mt-3">
<select class="form-control" id="projectListNav" style="width:150px;" onchange="location = this.value;">
</select>
</div>
</li>
<!-- Nav Divider -->
<div class="topbar-divider d-none d-sm-block"></div>
<!-- Nav Item - User Information -->
@ -119,14 +125,18 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</a>
<!-- Dropdown - User Information -->
<div class="dropdown-menu dropdown-menu-right shadow animated--grow-in" aria-labelledby="userDropdown">
<a class="dropdown-item" href="user-profile.html">
<a class="dropdown-item" href="user-profile.php">
<i class="fas fa-user fa-sm fa-fw mr-2 text-gray-400"></i>
Profile
</a>
<a class="dropdown-item" href="settings.html">
<a class="dropdown-item" href="settings.php">
<i class="fas fa-cog fa-sm fa-fw mr-2 text-gray-400"></i>
Settings
</a>
<a class="dropdown-item" href="logs.php">
<i class="fas fa-history fa-sm fa-fw mr-2 text-gray-400"></i>
Logs
</a>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#aboutModal">
<i class="fas fa-info-circle fa-sm fa-fw mr-2 text-gray-400"></i>
About
@ -147,23 +157,45 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Begin Page Content -->
<div class="container-fluid">
<!-- BreadCrumb -->
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="#" id="remoteBreadCrumb"></a></li>
<li class="breadcrumb-item active" aria-current="page" id="clusterMembersBreadCrumb"></li>
</ol>
</nav>
<header class="page-header page-header-dark bg-gradient-primary-to-secondary">
<div class="container-xl px-4">
<div class="page-header-content pt-4">
<div class="row align-items-center justify-content-between mt-n5 ml-n5 mr-n5 bg-dark pb-6">
<div class="col-auto mt-4 ml-3">
<div class="page-header-subtitle">
<a href="#" id="remoteBreadCrumb"></a>
</div>
<h2 class="page-header-title mt-2">
CLUSTER MEMBERS
</h2>
<div class="page-header-subtitle">
Manage members included in the LXD cluster
</div>
</div>
<div class="col-12 col-xl-auto mt-4">
<div class="input-group input-group-joined border-0" style="width: 14rem">
<span class="input-group-text bg-transparent border-0">
</span>
</div>
</div>
</div>
</div>
</div>
</header>
<div class="row">
<div class="row mt-n5 ml-2 mr-2">
<div class="col-12">
<!-- Cluster Members List -->
<div class="col-12 mt-n3">
<!-- Cluster Member List -->
<div class="card shadow mb-4">
<!-- Card Header - Dropdown -->
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">Cluster Members</h6>
<h6 class="m-0 font-weight-bold">
<span class="ml-1">Cluster Members</span>
</h6>
<div class="dropdown no-arrow">
<a class="dropdown-toggle mr-2" href="#" onclick="reloadPageContent()" title="Refresh" aria-hidden="true">
<i class="fa fa-sync fa-1x fa-fw"></i></a>
</div>
</div>
<!-- Card Body -->
@ -174,7 +206,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</div>
</div>
</div>
<!-- End Cluster Members List -->
<!-- End Cluster Member List -->
</div>
</div>
@ -189,7 +221,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<footer class="sticky-footer bg-white">
<div class="container my-auto">
<div class="copyright text-center my-auto">
<span>Copyright &copy; lxdware.com 2021</span>
<span>Copyright &copy; LXDWARE 2020 - Present</span>
</div>
</div>
</footer>
@ -281,60 +313,66 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
const urlParams = new URLSearchParams(queryString);
const remoteId = urlParams.get('remote');
const projectName = urlParams.get('project');
var reloadTime = 5000;
function logout(){
$.get("./php/aaa/authentication.php?action=deauthenticateUser", function (data) {
$.get("./backend/aaa/authentication.php?action=deauthenticateUser", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code == 200) {
window.location = './index.html'
window.location.href = './index.php'
}
});
}
function operationStatusCheck(){
clearTimeout(operationTimeout);
//check to see if there are any running operations
$.get("./php/lxd/operations.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayOperationStatus", function (data) {
$.get("./backend/lxd/operations.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayOperationStatus", function (data) {
//Check to see if we have running operations
if (data){
//Display spinner and notification area if there are running tasks
$('#spinner').show();
if (data) {
//Display notification area if there are running tasks
$('#notificationArea').show();
$('#notification').text(data);
//Set the page to check operations again in 1 second
setTimeout(() => { operationStatusCheck(); }, 1000);
$('#notification').text("Notice: " + data);
//Set the page to check operations again in 2 seconds
operationTimeout = setTimeout(() => { operationStatusCheck(); }, 2000);
}
else {
//Hide spinner and notification area if no running tasks
$('#spinner').hide();
//Hide notification area if no running tasks
$('#notificationArea').hide();
$('#notification').text("");
//Set the page to check operations again in 3 seconds
setTimeout(() => { operationStatusCheck(); }, 3000);
//Set the page to check operations again in 4 seconds
operationTimeout = setTimeout(() => { operationStatusCheck(); }, 4000);
}
});
}
function reloadPageContent() {
clearTimeout(pageReloadTimeout);
//Check Authorization
$.get("./php/aaa/authentication.php?action=validateAuthentication", function (data) {
$.get("./backend/aaa/authentication.php?action=validateAuthentication", function (data) {
operationData = JSON.parse(data);
if (operationData.status_code != 200) {
console.log(operationData);
window.location = './index.html'
window.location.href = './index.php'
}
});
$('#clusterMemberListTable').DataTable().ajax.reload(null, false);
//Set reload page content
pageReloadTimeout = setTimeout(() => { reloadPageContent(); }, reloadTime);
}
function loadPageContent(){
//Display current logged in username
$("#username").load("./php/admin/settings.php?action=displayUsername");
$("#username").load("./backend/admin/settings.php?action=displayUsername");
$('#clusterMemberListTable').DataTable( {
ajax: "./php/lxd/cluster-members.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listClusterMembers",
ajax: "./backend/lxd/cluster-members.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listClusterMembers",
columns: [
{},
{ title: "Server Name" },
@ -351,10 +389,16 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
});
//Check for any running operations
operationStatusCheck();
operationTimeout = setTimeout(() => { operationStatusCheck(); }, 1000);
//Set the page content to reload in 5 seconds
setInterval(() => { reloadPageContent(); }, 5000);
//Set reload page content
$.get("./backend/admin/settings.php?action=retrievePageRefreshRateValues", function (data) {
operationData = JSON.parse(data);
if (operationData.cluster_members_page_rate >= 1)
reloadTime = operationData.cluster_members_page_rate * 1000;
pageReloadTimeout = setTimeout(() => { reloadPageContent(); }, reloadTime);
});
}
function loadDeleteClusterMemberModal(clusterMember){
@ -370,7 +414,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
forceDeleteCheck = "true";
}
console.log("Info: deleting cluster member " + memberToDelete);
$.get("./php/lxd/cluster-members.php?remote=" + encodeURI(remoteId) + "&name=" + encodeURI(memberToDelete) + "&force=" + encodeURI(forceDeleteCheck) + "&action=deleteClusterMember", function (data) {
$.get("./backend/lxd/cluster-members.php?remote=" + encodeURI(remoteId) + "&name=" + encodeURI(memberToDelete) + "&force=" + encodeURI(forceDeleteCheck) + "&action=deleteClusterMember", function (data) {
//Async operation type
var operationData = JSON.parse(data);
console.log(operationData);
@ -382,33 +426,64 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
});
}
function setSidebarToggleValue(){
sidebarState = localStorage.getItem('sidebarState');
if (sidebarState == "collapsed"){
localStorage.setItem('sidebarState','expanded');
}
else {
localStorage.setItem('sidebarState','collapsed');
}
}
function applySidebarToggleValue() {
sidebarState = localStorage.getItem('sidebarState');
if (sidebarState == "collapsed"){
$("body").toggleClass("sidebar-toggled"),
$(".sidebar").toggleClass("toggled"),
$(".sidebar").hasClass("toggled") && $(".sidebar .collapse").collapse("hide")
}
}
applySidebarToggleValue();
$(document).ready(function(){
//Check Authorization
$.get("./php/aaa/authentication.php?action=validateAuthentication", function (data) {
$.get("./backend/aaa/authentication.php?action=validateAuthentication", function (data) {
operationData = JSON.parse(data);
if (operationData.status_code != 200) {
console.log(operationData);
window.location = './index.html'
window.location.href = './index.php'
}
});
//Load in the sidebar
$("#sidebarLinks").load("./sidebar.html");
$("#sidebarLinks").load("./sidebar.php?version=3.0");
//Setup Page Breadcrumb Links/Information
$('#remoteBreadCrumb').load("./php/lxd/remote-breadcrumb.php?remote=" + encodeURI(remoteId));
$('#remoteBreadCrumb').attr("href", "remotes-single.html?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$('#clusterMembersBreadCrumb').text("cluster-members");
$('#remoteBreadCrumb').load("./backend/lxd/remote-breadcrumb.php?remote=" + encodeURI(remoteId));
$('#remoteBreadCrumb').attr("href", "remotes-single.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
//Load the card contents
loadPageContent();
//Validate remote host connection returns 200 status
$.get("./backend/lxd/remotes-single.php?remote=" + encodeURI(remoteId) + "&action=validateRemoteConnection", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code == 200) {
//Set top navbar dropdowns
$("#remoteListNav").load("./backend/lxd/remotes.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listRemotesForSelectOption");
$("#projectListNav").load("./backend/lxd/projects.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listProjectsForSelectOption");
//Load Page Content
loadPageContent();
}
else {
alert("Unable to connect to remote host. HTTP status code: " + operationData.status_code);
}
});
$("#remoteListNav").load("./php/lxd/remotes.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listRemotesForTopNavigation");
$("#projectListNav").load("./php/lxd/projects.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listProjectsForTopNavigation");
//Load the about info for the about modal
$.get("./about.html", function (data) {
$.get("./backend/config/about.php", function (data) {
$("#about").html(data);
});

File diff suppressed because it is too large Load diff

1746
lxd-dashboard/containers.php Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,547 +0,0 @@
<!--
LXDWARE LXD Dashboard - A web-based interface for managing LXD servers
Copyright (C) 2020-2021 LXDWARE.COM
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<link rel="icon" type="image/png" href="assets/images/logo-light.svg">
<title>LXD Dashboard</title>
<!-- Custom fonts for this template-->
<link href="vendor/fontawesome-free/css/all.min.css" rel="stylesheet" type="text/css">
<link href="vendor/fonts/nunito.css" rel="stylesheet">
<!-- Custom styles for this template-->
<link href="vendor/sb-admin-2/css/sb-admin-2.css" rel="stylesheet">
<link href="assets/css/style.css" rel="stylesheet">
<!-- Custom styles for this page -->
<link href="vendor/datatables/dataTables.bootstrap4.min.css" rel="stylesheet">
</head>
<body id="page-top">
<!-- Page Wrapper -->
<div id="wrapper">
<!-- Sidebar -->
<ul class="navbar-nav bg-dark sidebar sidebar-dark accordion" id="accordionSidebar">
<div id="sidebarLinks"></div>
<!-- Divider -->
<hr class="sidebar-divider d-none d-md-block">
<!-- Sidebar Toggler (Sidebar) -->
<div class="text-center d-none d-md-inline">
<button class="rounded-circle border-0" id="sidebarToggle"></button>
</div>
</ul>
<!-- End of Sidebar -->
<!-- Content Wrapper -->
<div id="content-wrapper" class="d-flex flex-column">
<!-- Main Content -->
<div id="content">
<!-- Topbar -->
<nav class="navbar navbar-expand navbar-light bg-white topbar mb-4 static-top shadow">
<!-- Sidebar Toggle (Topbar) -->
<button id="sidebarToggleTop" class="btn btn-link d-md-none rounded-circle mr-3">
<i class="fa fa-bars"></i>
</button>
<!-- Topbar Notification -->
<div class="d-none d-sm-inline-block form-inline mr-auto ml-md-3 my-2 my-md-0 mw-100 navbar-search">
<ul class="navbar-nav ml-auto">
<li>
<div class="nav-item spinner-border m-3" role="status" style="display:none;" id="spinner">
<span class="nav-item sr-only">Loading...</span>
</div>
</li>
<li class="nav-item dropdown no-arrow" id="notificationArea" style="display: none;">
<div class="nav-link dropdown-toggle">
<span id="notification" class="mr-2 d-none d-lg-inline text-gray-600">Notification</span>
</div>
</li>
</ul>
</div>
<!-- Topbar Navbar -->
<ul class="navbar-nav ml-auto">
<li class="nav-item dropdown" id="remoteListNav">
</li>
<li class="nav-item dropdown" id="projectListNav">
</li>
<div class="topbar-divider d-none d-sm-block"></div>
<!-- Nav Item - User Information -->
<li class="nav-item dropdown no-arrow">
<a class="nav-link dropdown-toggle" href="#" id="userDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fas fa-user-circle fa-1x fa-fw mr-2 text-gray-600"></i>
<span id="username" class="mr-2 d-none d-lg-inline text-gray-600"></span>
</a>
<!-- Dropdown - User Information -->
<div class="dropdown-menu dropdown-menu-right shadow animated--grow-in" aria-labelledby="userDropdown">
<a class="dropdown-item" href="user-profile.html">
<i class="fas fa-user fa-sm fa-fw mr-2 text-gray-400"></i>
Profile
</a>
<a class="dropdown-item" href="settings.html">
<i class="fas fa-cog fa-sm fa-fw mr-2 text-gray-400"></i>
Settings
</a>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#aboutModal">
<i class="fas fa-info-circle fa-sm fa-fw mr-2 text-gray-400"></i>
About
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#" onclick="logout()">
<i class="fas fa-sign-out-alt fa-sm fa-fw mr-2 text-gray-400"></i>
Logout
</a>
</div>
</li>
</ul>
</nav>
<!-- End of Topbar -->
<!-- Begin Page Content -->
<div class="container-fluid">
<!-- BreadCrumb -->
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="#" id="remoteBreadCrumb"></a></li>
<li class="breadcrumb-item active" aria-current="page" id="imagesBreadCrumb"></li>
</ol>
</nav>
<div class="row">
<div class="col-12">
<!-- Image List -->
<div class="card shadow mb-4">
<!-- Card Header - Dropdown -->
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">Images</h6>
<div class="dropdown no-arrow">
<a class="dropdown-toggle mr-2" href="#" data-toggle="modal" data-target="#downloadImageModal" title="Download Image" aria-hidden="true">
<i class="fas fa-plus fa-sm fa-fw"></i> Image</a>
</div>
</div>
<!-- Card Body -->
<div class="card-body">
<div class="table-responsive">
<table class="table" id="imageListTable" width="100%" cellspacing="0">
</table>
</div>
</div>
</div>
<!-- End Image List -->
</div>
</div>
</div>
<!-- /.container-fluid -->
</div>
<!-- End of Main Content -->
<!-- Footer -->
<footer class="sticky-footer bg-white">
<div class="container my-auto">
<div class="copyright text-center my-auto">
<span>Copyright &copy; lxdware.com 2021</span>
</div>
</div>
</footer>
<!-- End of Footer -->
</div>
<!-- End of Content Wrapper -->
</div>
<!-- End of Page Wrapper -->
<!-- Scroll to Top Button-->
<a class="scroll-to-top rounded" href="#page-top">
<i class="fas fa-angle-up"></i>
</a>
<!-- Download Image Modal-->
<div class="modal fade" id="downloadImageModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Download Image</h5>
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="row">
<label class="col-3 col-form-label text-right">Image/Alias: </label>
<div class="col-7">
<div class="form-group">
<input type="text" class="form-control" id="imageNameInput" required="required" placeholder="" name="image">
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle text-danger" data-toggle="tooltip" data-html="true" title='(Required) - Enter in the repository specific name. For example, ubuntu/20.04 would be used for the images repository and simply 20.04 would be used for the ubuntu repositories.'></i>
</div>
<label class="col-3 col-form-label text-right">Repository:</label>
<div class="col-7 text-right">
<div class="form-group">
<select id="selectRepoInput" class="form-control" name="repo">
</select>
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle text-danger" title='(Required) - Select a repository from the configured simplestreams.'></i>
</div>
<label class="col-3 col-form-label text-right">Image Type:</label>
<div class="col-7 text-right">
<div class="form-group">
<select id="selectTypeInput" class="form-control" name="image_type">
<option value="container" selected>container</option>
<option value="virtual-machine">virtual-machine</option>
</select>
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle" title='Select whether to download a container based image or virtual machine. Default: container'></i>
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
<a class="btn btn-primary" href="#" onclick="downloadImage()" data-dismiss="modal">Ok</a>
</div>
</div>
</div>
</div>
<!-- Edit Image Modal-->
<div class="modal fade" id="editImageModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Edit Image</h5>
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="row">
<label class="col-12 col-form-label" id="imageNameEditInput"></label>
<div class="col-12">
<div class="form-group text-right">
<pre>
<textarea name="json" class="form-control" id="jsonEditInput" rows="16" ></textarea>
</pre>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
<a class="btn btn-primary" href="#" onclick="updateImage()" data-dismiss="modal">Submit</a>
</div>
</div>
</div>
</div>
<!-- About Modal-->
<div class="modal fade" id="aboutModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">About</h5>
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="row">
<div class="col-12">
<div id="about"></div>
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" type="button" data-dismiss="modal">Dismiss</button>
</div>
</div>
</div>
</div>
<!-- Bootstrap core JavaScript-->
<script src="vendor/jquery/jquery.min.js"></script>
<script src="vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- Core plugin JavaScript-->
<script src="vendor/jquery-easing/jquery.easing.min.js"></script>
<!-- Custom scripts for all pages-->
<script src="vendor/sb-admin-2/js/sb-admin-2.min.js"></script>
<!-- Page level plugins -->
<script src="vendor/datatables/jquery.dataTables.min.js"></script>
<script src="vendor/datatables/dataTables.bootstrap4.min.js"></script>
</body>
<script>
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
const remoteId = urlParams.get('remote');
const projectName = urlParams.get('project');
var selectList = "";
var imageToUpdate = "";
function logout(){
$.get("./php/aaa/authentication.php?action=deauthenticateUser", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code == 200) {
window.location = './index.html'
}
});
}
function operationStatusCheck(){
//check to see if there are any running operations
$.get("./php/lxd/operations.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayOperationStatus", function (data) {
//Check to see if we have running operations
if (data){
//Display spinner and notification area if there are running tasks
$('#spinner').show();
$('#notificationArea').show();
$('#notification').text(data);
//Set the page to check operations again in 1 second
setTimeout(() => { operationStatusCheck(); }, 1000);
}
else {
//Hide spinner and notification area if no running tasks
$('#spinner').hide();
$('#notificationArea').hide();
$('#notification').text("");
//Set the page to check operations again in 3 seconds
setTimeout(() => { operationStatusCheck(); }, 3000);
}
});
}
function reloadPageContent() {
//Check Authorization
$.get("./php/aaa/authentication.php?action=validateAuthentication", function (data) {
operationData = JSON.parse(data);
if (operationData.status_code != 200) {
console.log(operationData);
window.location = './index.html'
}
});
$('#imageListTable').DataTable().ajax.reload(null, false);
//Load the select List for Download Image Modal
$.get("./php/lxd/simplestreams.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listSimplestreamsForSelectOption", function (data) {
if (selectList != data){
$("#selectRepoInput").html(data);
selectList = data;
}
});
}
function loadPageContent(){
//Display current logged in username
$("#username").load("./php/admin/settings.php?action=displayUsername");
$('#imageListTable').DataTable( {
ajax: "./php/lxd/images.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listImages",
columns: [
{},
{ title: "Description" },
{ title: "Fingerprint" },
{ title: "Type" },
{ title: "Size" },
{ title: "Action" }
],
order: [],
columnDefs: [
{ targets: 0, orderable: false, width: "25px" }
]
});
//Load the select List for Download Image Modal
$.get("./php/lxd/simplestreams.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listSimplestreamsForSelectOption", function (data) {
if (selectList != data){
$("#selectRepoInput").html(data);
selectList = data;
}
});
//Check for any running operations
operationStatusCheck();
//Set the page content to reload in 5 seconds
setInterval(() => { reloadPageContent(); }, 5000);
}
function refreshImage(imageFingerprint){
console.log("Info: refreshing image " + imageFingerprint);
$.get("./php/lxd/images.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&fingerprint=" + encodeURI(imageFingerprint) + "&action=refreshImage", function (data) {
//Async operation type
var operationData = JSON.parse(data);
console.log(operationData);
if (operationData.error_code >= 400){
alert(operationData.error);
}
operationStatusCheck();
setTimeout(() => { reloadPageContent(); }, 1000);
});
}
function deleteImage(imageFingerprint){
console.log("Info: deleting image " + imageFingerprint);
$.get("./php/lxd/images.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&fingerprint=" + encodeURI(imageFingerprint) + "&action=deleteImage", function (data) {
//Async operation type
var operationData = JSON.parse(data);
console.log(operationData);
if (operationData.error_code >= 400){
alert(operationData.error);
}
operationStatusCheck();
setTimeout(() => { reloadPageContent(); }, 1000);
});
}
function downloadImage(){
var imageName = $("#imageNameInput").val();
var repoName = $("#selectRepoInput").val();
var imageType = $("#selectTypeInput").val();
console.log("Info: downloading image " + imageName + " from " + repoName);
$.get("./php/lxd/images.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&image=" + encodeURI(imageName) + "&repo=" + encodeURI(repoName) + "&image_type=" + encodeURI(imageType) + "&action=downloadImage", function (data) {
//Async operation type
var operationData = JSON.parse(data);
console.log(operationData);
if (operationData.error_code >= 400){
alert(operationData.error);
}
operationStatusCheck();
setTimeout(() => { reloadPageContent(); }, 1000);
});
}
function loadImageJson(imageToLoad){
console.log("Info: loading image " + imageToLoad);
imageToUpdate = imageToLoad;
$.get("./php/lxd/images.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&fingerprint=" + encodeURI(imageToLoad) + "&action=loadImage", function (data) {
//Sync operation type
var operationData = JSON.parse(data);
console.log(operationData);
if (operationData.error_code >= 400){
alert(operationData.error);
}
$("#imageNameEditInput").text("Fingerprint: " + imageToLoad);
$("#jsonEditInput").val(JSON.stringify(operationData.metadata, null, 2));
$("#editImageModal").modal('show');
});
}
function updateImage(){
var imageUpdateJSON = $("#jsonEditInput").val();
console.log("Info: updating image " + imageToUpdate);
$.post("./php/lxd/images.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&fingerprint=" + encodeURI(imageToUpdate) + "&action=updateImage", {json: imageUpdateJSON}, function (data) {
//Sync operation type
var operationData = JSON.parse(data);
console.log(operationData);
if (operationData.error_code >= 400){
alert(operationData.error);
}
setTimeout(() => { reloadPageContent(); }, 1000);
});
}
$(document).ready(function(){
//Check Authorization
$.get("./php/aaa/authentication.php?action=validateAuthentication", function (data) {
operationData = JSON.parse(data);
if (operationData.status_code != 200) {
console.log(operationData);
window.location = './index.html'
}
});
//Load in the sidebar
$("#sidebarLinks").load("./sidebar.html");
//Setup Page Breadcrumb Links/Information
$('#remoteBreadCrumb').load("./php/lxd/remote-breadcrumb.php?remote=" + encodeURI(remoteId));
$('#remoteBreadCrumb').attr("href", "remotes-single.html?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$('#imagesBreadCrumb').text("images");
//Load the card contents
loadPageContent();
$("#remoteListNav").load("./php/lxd/remotes.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listRemotesForTopNavigation");
$("#projectListNav").load("./php/lxd/projects.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listProjectsForTopNavigation");
//Load the about info for the about modal
$.get("./about.html", function (data) {
$("#about").html(data);
});
});
</script>
</html>

1203
lxd-dashboard/images.php Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,212 +1,6 @@
<!--
LXDWARE LXD Dashboard - A web-based interface for managing LXD servers
Copyright (C) 2020-2021 LXDWARE.COM
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<link rel="icon" type="image/png" href="assets/images/logo-light.svg">
<title>LXD Dashboard</title>
<!-- Custom fonts for this template-->
<link href="vendor/fontawesome-free/css/all.min.css" rel="stylesheet" type="text/css">
<link href="vendor/fonts/nunito.css" rel="stylesheet">
<!-- Custom styles for this template-->
<link href="vendor/sb-admin-2/css/sb-admin-2.css" rel="stylesheet">
<link href="assets/css/style.css" rel="stylesheet">
<style>
body {
background-image: url('assets/images/logo-bg.svg') !important;
background-position: center center !important;
background-size: 100% auto !important;
background-repeat: no-repeat;
background-attachment: fixed;
}
</style>
</head>
<body class="bg-dark">
<div class="container">
<!-- Outer Row -->
<div class="row justify-content-center">
<div class="col-xl-10 col-lg-12 col-md-9">
<div class="card o-hidden border-0 shadow-lg my-5">
<div class="card-body p-0">
<!-- Nested Row within Card Body -->
<div class="row">
<div class="col-lg-5 d-none d-lg-block border-right">
<div class="pt-5">
<div class="text-center">
<img src="assets/images/logo-light.svg" width="50px" style="vertical-align: bottom !important;">
<span class="h1 text-gray-900"><strong>LXDWARE</strong></span>
</div>
</div>
<div class="pt-5">
<div class="pl-4">
<p class="h5 text-gray-900">Manage remote LXD servers with this open source LXD dashboard.</p>
<p class="h5 text-gray-900 pt-3">For instructions on using the dashboard, visit <a href="https://lxdware.com" target="_blank">https://lxdware.com</a>.</p>
</div>
</div>
</div>
<div class="col-lg-7 align-self-center">
<div class="p-5">
<form class="user" id="loginForm" onsubmit="return false">
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Bootstrap core JavaScript-->
<script src="vendor/jquery/jquery.min.js"></script>
<script src="vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- Core plugin JavaScript-->
<script src="vendor/jquery-easing/jquery.easing.min.js"></script>
<!-- Custom scripts for all pages-->
<script src="vendor/sb-admin-2/js/sb-admin-2.min.js"></script>
</body>
<script>
function changeDatabaseInput(){
if ($("#registerDatabaseTypeInput").val() == 'sqlite'){
$("#registerDatabaseHostDiv").hide();
$("#registerDatabaseNameDiv").hide();
$("#registerDatabaseUserDiv").hide();
$("#registerDatabasePasswordDiv").hide();
}
else {
$("#registerDatabaseHostDiv").show();
$("#registerDatabaseNameDiv").show();
$("#registerDatabaseUserDiv").show();
$("#registerDatabasePasswordDiv").show();
}
}
function registerUser(){
var registerUsernameInput = $("#registerUsernameInput").val();
var registerEmailInput = $("#registerEmailInput").val();
var registerPasswordInput = $("#registerPasswordInput").val();
var registerRepeatPasswordInput = $("#registerRepeatPasswordInput").val();
var registerDatabaseTypeInput = $("#registerDatabaseTypeInput").val();
var registerDatabaseHostInput = $("#registerDatabaseHostInput").val();
var registerDatabaseNameInput = $("#registerDatabaseNameInput").val();
var registerDatabaseUserInput = $("#registerDatabaseUserInput").val();
var registerDatabasePasswordInput = $("#registerDatabasePasswordInput").val();
if (registerPasswordInput == registerRepeatPasswordInput){
console.log("Info: setting up database");
$.post('./php/config/login.php?database_type=' + registerDatabaseTypeInput + '&database_host=' + registerDatabaseHostInput + '&database_name=' + registerDatabaseNameInput + '&database_user=' + registerDatabaseUserInput + '&action=writeDatabaseConfig', {database_password: registerDatabasePasswordInput}, function (data) {
console.log(data);
var operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code == 200) {
console.log("Info: registering user " + registerUsernameInput);
$.post('./php/admin/settings.php?action=createUser', {username: registerUsernameInput, password: registerPasswordInput, email: registerEmailInput}, function (data) {
var operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code == 200) {
location.reload();
}
if (operationData.status_code >= 400) {
console.log(operationData);
alert(operationData.metadata.error);
location.reload();
}
});
}
if (operationData.status_code >= 400) {
console.log(operationData);
alert(operationData.metadata.error);
}
});
}
else {
alert("Your passwords did not match, try again");
}
return false;
}
function loginUser(){
var loginUsernameInput = $("#loginUsernameInput").val();
var loginPasswordInput = $("#loginPasswordInput").val();
console.log("Info: logging in user " + loginUsernameInput);
$.post('./php/aaa/authentication.php?action=authenticateUser', {username: loginUsernameInput, password: loginPasswordInput}, function (data) {
var operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code == 200) {
window.location = './remotes.html';
}
if (operationData.status_code == 401) {
console.log(operationData);
alert(operationData.metadata.error);
}
return false;
});
}
$(document).ready(function(){
//Check if already authorized
$.get("./php/aaa/authentication.php?action=validateAuthentication", function (data) {
operationData = JSON.parse(data);
if (operationData.status_code == 200) {
console.log(operationData);
window.location = './remotes.html'
}
});
$("#loginForm").load( "./php/config/login.php?action=loadLoginForm", function() {
$("#loginUsernameInput").focus();
});
});
</script>
</html>
<script>
window.location.replace("index.php");
</script>
</html>

214
lxd-dashboard/index.php Normal file
View file

@ -0,0 +1,214 @@
<!--
LXDWARE LXD Dashboard - A web-based interface for managing LXD servers
Copyright (C) 2020-2021 LXDWARE.COM
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta http-equiv="Cache-control" content="no-cache">
<meta http-equiv="Expires" content="-1">
<meta name="description" content="">
<meta name="author" content="">
<link rel="icon" type="image/png" href="assets/images/logo-light.svg">
<title>LXD Dashboard</title>
<!-- Custom fonts for this template-->
<link href="vendor/fontawesome-free/css/all.min.css" rel="stylesheet" type="text/css">
<link href="vendor/fonts/nunito.css" rel="stylesheet">
<!-- Custom styles for this template-->
<link href="vendor/sb-admin-2/css/sb-admin-2.css" rel="stylesheet">
<link href="assets/css/style.css?version=3.0" rel="stylesheet">
<style>
body {
background-image: url('assets/images/logo-bg.svg') !important;
background-position: center center !important;
background-size: 100% auto !important;
background-repeat: no-repeat;
background-attachment: fixed;
}
</style>
</head>
<body class="bg-dark">
<div class="container">
<!-- Outer Row -->
<div class="row justify-content-center">
<div class="col-xl-10 col-lg-12 col-md-9">
<div class="card o-hidden border-0 shadow-lg my-5">
<div class="card-body p-0">
<!-- Nested Row within Card Body -->
<div class="row">
<div class="col-lg-5 d-none d-lg-block border-right">
<div class="pt-5">
<div class="text-center">
<img src="assets/images/logo-light.svg" width="50px" style="vertical-align: bottom !important;">
<span class="h1 text-gray-900"><strong>LXDWARE</strong></span>
</div>
</div>
<div class="pt-5">
<div class="pl-4">
<p class="h5 text-gray-900">Manage remote LXD servers with this open source LXD dashboard.</p>
<p class="h5 text-gray-900 pt-3">For instructions on using the LXD Dashboard, visit <a href="https://lxdware.com" target="_blank">https://lxdware.com</a>.</p>
</div>
</div>
</div>
<div class="col-lg-7 align-self-center">
<div class="p-5">
<form class="user" id="loginForm" onsubmit="return false">
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Bootstrap core JavaScript-->
<script src="vendor/jquery/jquery.min.js"></script>
<script src="vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- Core plugin JavaScript-->
<script src="vendor/jquery-easing/jquery.easing.min.js"></script>
<!-- Custom scripts for all pages-->
<script src="vendor/sb-admin-2/js/sb-admin-2.min.js"></script>
</body>
<script>
function changeDatabaseInput(){
if ($("#registerDatabaseTypeInput").val() == 'sqlite'){
$("#registerDatabaseHostDiv").hide();
$("#registerDatabaseNameDiv").hide();
$("#registerDatabaseUserDiv").hide();
$("#registerDatabasePasswordDiv").hide();
}
else {
$("#registerDatabaseHostDiv").show();
$("#registerDatabaseNameDiv").show();
$("#registerDatabaseUserDiv").show();
$("#registerDatabasePasswordDiv").show();
}
}
function registerUser(){
var registerUsernameInput = $("#registerUsernameInput").val();
var registerEmailInput = $("#registerEmailInput").val();
var registerPasswordInput = $("#registerPasswordInput").val();
var registerRepeatPasswordInput = $("#registerRepeatPasswordInput").val();
var registerDatabaseTypeInput = $("#registerDatabaseTypeInput").val();
var registerDatabaseHostInput = $("#registerDatabaseHostInput").val();
var registerDatabaseNameInput = $("#registerDatabaseNameInput").val();
var registerDatabaseUserInput = $("#registerDatabaseUserInput").val();
var registerDatabasePasswordInput = $("#registerDatabasePasswordInput").val();
if (registerUsernameInput.length > 0 && registerPasswordInput == registerRepeatPasswordInput){
console.log("Info: setting up database");
$.post('./backend/config/login.php?database_type=' + registerDatabaseTypeInput + '&database_host=' + registerDatabaseHostInput + '&database_name=' + registerDatabaseNameInput + '&database_user=' + registerDatabaseUserInput + '&action=writeDatabaseConfig', {database_password: registerDatabasePasswordInput}, function (data) {
console.log(data);
var operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code == 200) {
console.log("Info: registering user " + registerUsernameInput);
$.post('./backend/admin/settings.php?action=createUser', {username: registerUsernameInput, password: registerPasswordInput, email: registerEmailInput}, function (data) {
var operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code == 200) {
location.reload();
}
if (operationData.status_code >= 400) {
console.log(operationData);
alert(operationData.metadata.error);
location.reload();
}
});
}
if (operationData.status_code >= 400) {
console.log(operationData);
alert(operationData.metadata.error);
}
});
}
else {
alert("Your passwords did not match, try again");
}
return false;
}
function loginUser(){
var loginUsernameInput = $("#loginUsernameInput").val();
var loginPasswordInput = $("#loginPasswordInput").val();
console.log("Info: logging in user " + loginUsernameInput);
$.post('./backend/aaa/authentication.php?action=authenticateUser', {username: loginUsernameInput, password: loginPasswordInput}, function (data) {
var operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code == 200) {
window.location.href = './remotes.php';
}
if (operationData.status_code == 401) {
console.log(operationData);
alert(operationData.metadata.error);
}
return false;
});
}
$(document).ready(function(){
//Check if already authorized
$.get("./backend/aaa/authentication.php?action=validateAuthentication", function (data) {
operationData = JSON.parse(data);
if (operationData.status_code == 200) {
console.log(operationData);
window.location.href = './remotes.php'
}
});
$("#loginForm").load( "./backend/config/login.php?action=loadLoginForm", function() {
$("#loginUsernameInput").focus();
});
});
</script>
</html>

View file

@ -1,752 +0,0 @@
<!--
LXDWARE LXD Dashboard - A web-based interface for managing LXD servers
Copyright (C) 2020-2021 LXDWARE.COM
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<link rel="icon" type="image/png" href="assets/images/logo-light.svg">
<title>LXD Dashboard</title>
<!-- Custom fonts for this template-->
<link href="vendor/fontawesome-free/css/all.min.css" rel="stylesheet" type="text/css">
<link href="vendor/fonts/nunito.css" rel="stylesheet">
<!-- Custom styles for this template-->
<link href="vendor/sb-admin-2/css/sb-admin-2.css" rel="stylesheet">
<link href="assets/css/style.css" rel="stylesheet">
<!-- Custom styles for this page -->
<link href="vendor/datatables/dataTables.bootstrap4.min.css" rel="stylesheet">
</head>
<body id="page-top">
<!-- Page Wrapper -->
<div id="wrapper">
<!-- Sidebar -->
<ul class="navbar-nav bg-dark sidebar sidebar-dark accordion" id="accordionSidebar">
<div id="sidebarLinks"></div>
<!-- Divider -->
<hr class="sidebar-divider d-none d-md-block">
<!-- Sidebar Toggler (Sidebar) -->
<div class="text-center d-none d-md-inline">
<button class="rounded-circle border-0" id="sidebarToggle"></button>
</div>
</ul>
<!-- End of Sidebar -->
<!-- Content Wrapper -->
<div id="content-wrapper" class="d-flex flex-column">
<!-- Main Content -->
<div id="content">
<!-- Topbar -->
<nav class="navbar navbar-expand navbar-light bg-white topbar mb-4 static-top shadow">
<!-- Sidebar Toggle (Topbar) -->
<button id="sidebarToggleTop" class="btn btn-link d-md-none rounded-circle mr-3">
<i class="fa fa-bars"></i>
</button>
<!-- Topbar Notification -->
<div class="d-none d-sm-inline-block form-inline mr-auto ml-md-3 my-2 my-md-0 mw-100 navbar-search">
<ul class="navbar-nav ml-auto">
<li>
<div class="nav-item spinner-border m-3" role="status" style="display:none;" id="spinner">
<span class="nav-item sr-only">Loading...</span>
</div>
</li>
<li class="nav-item dropdown no-arrow" id="notificationArea" style="display: none;">
<div class="nav-link dropdown-toggle">
<span id="notification" class="mr-2 d-none d-lg-inline text-gray-600">Notification</span>
</div>
</li>
</ul>
</div>
<!-- Topbar Navbar -->
<ul class="navbar-nav ml-auto">
<li class="nav-item dropdown" id="remoteListNav">
</li>
<li class="nav-item dropdown" id="projectListNav">
</li>
<div class="topbar-divider d-none d-sm-block"></div>
<!-- Nav Item - User Information -->
<li class="nav-item dropdown no-arrow">
<a class="nav-link dropdown-toggle" href="#" id="userDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fas fa-user-circle fa-1x fa-fw mr-2 text-gray-600"></i>
<span id="username" class="mr-2 d-none d-lg-inline text-gray-600"></span>
</a>
<!-- Dropdown - User Information -->
<div class="dropdown-menu dropdown-menu-right shadow animated--grow-in" aria-labelledby="userDropdown">
<a class="dropdown-item" href="user-profile.html">
<i class="fas fa-user fa-sm fa-fw mr-2 text-gray-400"></i>
Profile
</a>
<a class="dropdown-item" href="settings.html">
<i class="fas fa-cog fa-sm fa-fw mr-2 text-gray-400"></i>
Settings
</a>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#aboutModal">
<i class="fas fa-info-circle fa-sm fa-fw mr-2 text-gray-400"></i>
About
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#" onclick="logout()">
<i class="fas fa-sign-out-alt fa-sm fa-fw mr-2 text-gray-400"></i>
Logout
</a>
</div>
</li>
</ul>
</nav>
<!-- End of Topbar -->
<!-- Begin Page Content -->
<div class="container-fluid">
<!-- BreadCrumb -->
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="#" id="remoteBreadCrumb"></a></li>
<li class="breadcrumb-item active" aria-current="page" id="instancesBreadCrumb"></li>
</ol>
</nav>
<div class="row">
<div class="col-12">
<!-- Instance List -->
<div class="card shadow mb-4">
<!-- Card Header - Dropdown -->
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">Instances</h6>
<div class="dropdown no-arrow">
<a class="dropdown-toggle mr-2" href="#" data-toggle="modal" data-target="#createInstanceModal" title="New Instance" aria-hidden="true">
<i class="fas fa-plus fa-sm fa-fw"></i> Instance</a>
</div>
</div>
<!-- Card Body -->
<div class="card-body">
<div class="table-responsive">
<table class="table" id="instanceListTable" width="100%" cellspacing="0">
</table>
</div>
</div>
</div>
<!-- End Instance List -->
</div>
</div>
</div>
<!-- /.container-fluid -->
</div>
<!-- End of Main Content -->
<!-- Footer -->
<footer class="sticky-footer bg-white">
<div class="container my-auto">
<div class="copyright text-center my-auto">
<span>Copyright &copy; lxdware.com 2021</span>
</div>
</div>
</footer>
<!-- End of Footer -->
</div>
<!-- End of Content Wrapper -->
</div>
<!-- End of Page Wrapper -->
<!-- Scroll to Top Button-->
<a class="scroll-to-top rounded" href="#page-top">
<i class="fas fa-angle-up"></i>
</a>
<!-- Create Instance Modal-->
<div class="modal fade" id="createInstanceModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Create Instance</h5>
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<ul class="nav nav-tabs" id="myTab" role="tablist">
<li class="nav-item">
<a class="nav-link active" id="form-tab" data-toggle="tab" href="#form" role="tab" aria-controls="form" aria-selected="true">Form</a>
</li>
<li class="nav-item">
<a class="nav-link" id="json-tab" data-toggle="tab" href="#json" role="tab" aria-controls="json" aria-selected="false">JSON</a>
</li>
</ul>
<div class="tab-content" id="myTabContent">
<div class="tab-pane fade show active" id="form" role="tabpanel" aria-labelledby="form-tab">
<br />
<div class="row">
<label class="col-3 col-form-label text-right">Name: </label>
<div class="col-7">
<div class="form-group">
<input type="text" id="instanceNameInput" class="form-control" required="required" placeholder="" name="name">
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle text-danger" title='(Required) - Enter in a name for this instance.'></i>
</div>
</div>
<div class="row">
<label class="col-3 col-form-label text-right">Type:</label>
<div class="col-7 text-right">
<div class="form-group">
<select id="selectTypeInput" onchange="changeImageInput()" class="form-control" name="type">
<option value="container" selected>container</option>
<option value="virtual-machine">virtual-machine</option>
</select>
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle" title='Select which instance type to create, container or virtual machine. Default: container'></i>
</div>
</div>
<div class="row">
<label class="col-3 col-form-label text-right">Image: </label>
<div class="col-7">
<div class="form-group">
<select id="selectImageInput" class="form-control" name="fingerprint">
</select>
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle" title='Select a downloaded image to use to build the instance.'></i>
</div>
</div>
<div class="row">
<label class="col-3 col-form-label text-right">Profile: </label>
<div class="col-7">
<div class="form-group">
<select id="selectProfileInput" class="form-control" name="profile">
</select>
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle" title='Select the initial profile to attach to this instance. Additional profiles can be attached after the instance is created. Default: default'></i>
</div>
</div>
<div class="row">
<label class="col-3 col-form-label text-right">Instance Type: </label>
<div class="col-7">
<div class="form-group">
<select id="selectInstanceTypeInput" class="form-control" name="instance_type">
<option value="" selected>(not set)</option>
<option disabled>--- AWS Instance Types ---</option>
<option value="aws:c1.medium">c1.medium</option>
<option value="aws:c1.xlarge">c1.xlarge</option>
<option value="aws:c3.2xlarge">c3.2xlarge</option>
<option value="aws:c3.4xlarge">c3.4xlarge</option>
<option value="aws:c3.8xlarge">c3.8xlarge</option>
<option value="aws:c3.large">c3.large</option>
<option value="aws:c3.xlarge">c3.xlarge</option>
<option value="aws:c4.2xlarge">c4.2xlarge</option>
<option value="aws:c4.4xlarge">c4.4xlarge</option>
<option value="aws:c4.8xlarge">c4.8xlarge</option>
<option value="aws:c4.large">c4.large</option>
<option value="aws:c4.xlarge">c4.xlarge</option>
<option value="aws:c5.large">c5.large</option>
<option value="aws:c5.xlarge">c5.xlarge</option>
<option value="aws:c5.2xlarge">c5.2xlarge</option>
<option value="aws:c5.4xlarge">c5.4xlarge</option>
<option value="aws:c5.9xlarge">c5.9xlarge</option>
<option value="aws:c5.18xlarge">c5.18xlarge</option>
<option value="aws:cc2.8xlarge">cc2.8xlarge</option>
<option value="aws:cg1.4xlarge">cg1.4xlarge</option>
<option value="aws:cr1.8xlarge">cr1.8xlarge</option>
<option value="aws:d2.xlarge">d2.xlarge</option>
<option value="aws:d2.2xlarge">d2.2xlarge</option>
<option value="aws:d2.4xlarge">d2.4xlarge</option>
<option value="aws:d2.8xlarge">d2.8xlarge</option>
<option value="aws:f1.2xlarge">f1.2xlarge</option>
<option value="aws:f1.16xlarge">f1.16xlarge</option>
<option value="aws:g2.2xlarge">g2.2xlarge</option>
<option value="aws:g2.8xlarge">g2.8xlarge</option>
<option value="aws:g3.4xlarge">g3.4xlarge</option>
<option value="aws:g3.8xlarge">g3.8xlarge</option>
<option value="aws:g3.16xlarge">g3.16xlarge</option>
<option value="aws:hi1.4xlarge">hi1.4xlarge</option>
<option value="aws:hs1.8xlarge">hs1.8xlarge</option>
<option value="aws:i2.xlarge">i2.xlarge</option>
<option value="aws:i2.2xlarge">i2.2xlarge</option>
<option value="aws:i2.4xlarge">i2.4xlarge</option>
<option value="aws:i2.8xlarge">i2.8xlarge</option>
<option value="aws:i3.large">i3.large</option>
<option value="aws:i3.xlarge">i3.xlarge</option>
<option value="aws:i3.2xlarge">i3.2xlarge</option>
<option value="aws:i3.4xlarge">i3.4xlarge</option>
<option value="aws:i3.8xlarge">i3.8xlarge</option>
<option value="aws:i3.16xlarge">i3.16xlarge</option>
<option value="aws:m1.small">m1.small</option>
<option value="aws:m1.medium">m1.medium</option>
<option value="aws:m1.large">m1.large</option>
<option value="aws:m1.xlarge">m1.xlarge</option>
<option value="aws:m2.xlarge">m2.xlarge</option>
<option value="aws:m2.2xlarge">m2.2xlarge</option>
<option value="aws:m2.4xlarge">m2.4xlarge</option>
<option value="aws:m3.medium">m3.medium</option>
<option value="aws:m3.large">m3.large</option>
<option value="aws:m3.xlarge">m3.xlarge</option>
<option value="aws:m3.2xlarge">m3.2xlarge</option>
<option value="aws:m4.large">m4.large</option>
<option value="aws:m4.xlarge">m4.xlarge</option>
<option value="aws:m4.2xlarge">m4.2xlarge</option>
<option value="aws:m4.4xlarge">m4.4xlarge</option>
<option value="aws:m4.10xlarge">m4.10xlarge</option>
<option value="aws:m4.16xlarge">m4.16xlarge</option>
<option value="aws:p2.xlarge">p2.xlarge</option>
<option value="aws:p2.8xlarge">p2.8xlarge</option>
<option value="aws:p2.16xlarge">p2.16xlarge</option>
<option value="aws:r3.large">r3.large</option>
<option value="aws:r3.xlarge">r3.xlarge</option>
<option value="aws:r3.2xlarge">r3.2xlarge</option>
<option value="aws:r3.4xlarge">r3.4xlarge</option>
<option value="aws:r3.8xlarge">r3.8xlarge</option>
<option value="aws:r4.large">r4.large</option>
<option value="aws:r4.xlarge">r4.xlarge</option>
<option value="aws:r4.2xlarge">r4.2xlarge</option>
<option value="aws:r4.4xlarge">r4.4xlarge</option>
<option value="aws:r4.8xlarge">r4.8xlarge</option>
<option value="aws:r4.16xlarge">r4.16xlarge</option>
<option value="aws:t1.micro">t1.micro</option>
<option value="aws:t2.nano">t2.nano</option>
<option value="aws:t2.micro">t2.micro</option>
<option value="aws:t2.small">t2.small</option>
<option value="aws:t2.medium">t2.medium</option>
<option value="aws:t2.large">t2.large</option>
<option value="aws:t2.xlarge">t2.xlarge</option>
<option value="aws:t2.2xlarge">t2.2xlarge</option>
<option value="aws:t3.nano">t3.nano</option>
<option value="aws:t3.micro">t3.micro</option>
<option value="aws:t3.small">t3.small</option>
<option value="aws:t3.medium">t3.medium</option>
<option value="aws:t3.large">t3.large</option>
<option value="aws:t3.xlarge">t3.xlarge</option>
<option value="aws:t3.2xlarge">t3.2xlarge</option>
<option value="aws:x1.16xlarge">x1.16xlarge</option>
<option value="aws:x1.32xlarge">x1.32xlarge</option>
<option disabled>--- Azure Instance Types ---</option>
<option value="azure:A5">A5</option>
<option value="azure:A6">A6</option>
<option value="azure:A7">A7</option>
<option value="azure:A8">A8</option>
<option value="azure:A9">A9</option>
<option value="azure:A10">A10</option>
<option value="azure:A11">A11</option>
<option value="azure:ExtraSmall">ExtraSmall</option>
<option value="azure:Small">Small</option>
<option value="azure:Medium">Medium</option>
<option value="azure:Large">Large</option>
<option value="azure:ExtraLarge">ExtraLarge</option>
<option value="azure:Standard_A1_v2">Standard_A1_v2</option>
<option value="azure:Standard_A2m_v2">Standard_A2m_v2</option>
<option value="azure:Standard_A2_v2">Standard_A2_v2</option>
<option value="azure:Standard_A4m_v2">Standard_A4m_v2</option>
<option value="azure:Standard_A4_v2">Standard_A4_v2</option>
<option value="azure:Standard_A8m_v2">Standard_A8m_v2</option>
<option value="azure:Standard_A8_v2">Standard_A8_v2</option>
<option value="azure:Standard_D1">Standard_D1</option>
<option value="azure:Standard_D1_v2">Standard_D1_v2</option>
<option value="azure:Standard_D2">Standard_D2</option>
<option value="azure:Standard_D2_v2">Standard_D2_v2</option>
<option value="azure:Standard_D3">Standard_D3</option>
<option value="azure:Standard_D3_v2">Standard_D3_v2</option>
<option value="azure:Standard_D4">Standard_D4</option>
<option value="azure:Standard_D4_v2">Standard_D4_v2</option>
<option value="azure:Standard_D5_v2">Standard_D5_v2</option>
<option value="azure:Standard_D11">Standard_D11</option>
<option value="azure:Standard_D11_v2">Standard_D11_v2</option>
<option value="azure:Standard_D12">Standard_D12</option>
<option value="azure:Standard_D12_v2">Standard_D12_v2</option>
<option value="azure:Standard_D13">Standard_D13</option>
<option value="azure:Standard_D13_v2">Standard_D13_v2</option>
<option value="azure:Standard_D14">Standard_D14</option>
<option value="azure:Standard_D14_v2">Standard_D14_v2</option>
<option value="azure:Standard_D15_v2">Standard_D15_v2</option>
<option value="azure:Standard_G1">Standard_G1</option>
<option value="azure:Standard_G2">Standard_G2</option>
<option value="azure:Standard_G3">Standard_G3</option>
<option value="azure:Standard_G4">Standard_G4</option>
<option value="azure:Standard_G5">Standard_G5</option>
<option value="azure:Standard_H8">Standard_H8</option>
<option value="azure:Standard_H8m">Standard_H8m</option>
<option value="azure:Standard_H16">Standard_H16</option>
<option value="azure:Standard_H16m">Standard_H16m</option>
<option value="azure:Standard_H16mr">Standard_H16mr</option>
<option value="azure:Standard_H16r">Standard_H16r</option>
<option disabled>--- GCE Instance Types ---</option>
<option value="gce:f1-micro">f1-micro</option>
<option value="gce:g1-small">g1-small</option>
<option value="gce:n1-highcpu-2">n1-highcpu-2</option>
<option value="gce:n1-highcpu-4">n1-highcpu-4</option>
<option value="gce:n1-highcpu-8">n1-highcpu-8</option>
<option value="gce:n1-highcpu-16">n1-highcpu-16</option>
<option value="gce:n1-highcpu-32">n1-highcpu-32</option>
<option value="gce:n1-highcpu-64">n1-highcpu-64</option>
<option value="gce:n1-highmem-2">n1-highmem-2</option>
<option value="gce:n1-highmem-4">n1-highmem-4</option>
<option value="gce:n1-highmem-8">n1-highmem-8</option>
<option value="gce:n1-highmem-16">n1-highmem-16</option>
<option value="gce:n1-highmem-32">n1-highmem-32</option>
<option value="gce:n1-highmem-64">n1-highmem-64</option>
<option value="gce:n1-standard-1">n1-standard-1</option>
<option value="gce:n1-standard-2">n1-standard-2</option>
<option value="gce:n1-standard-4">n1-standard-4</option>
<option value="gce:n1-standard-8">n1-standard-8</option>
<option value="gce:n1-standard-16">n1-standard-16</option>
<option value="gce:n1-standard-32">n1-standard-32</option>
<option value="gce:n1-standard-64">n1-standard-64</option>
</select>
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle" title='Select from a variety of preconfigured instance configurations. Default: (not set)'></i>
</div>
</div>
<div class="row">
<label class="col-3 col-form-label text-right">Location: </label>
<div class="col-7">
<div class="form-group">
<select id="selectLocationInput" class="form-control" name="location">
</select>
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle" title='Select the LXD cluster member to deploy this instance on. Default: none'></i>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
<a class="btn btn-primary" href="#" onclick="createInstanceUsingForm()" data-dismiss="modal">Ok</a>
</div>
</div>
<div class="tab-pane fade" id="json" role="tabpanel" aria-labelledby="json-tab">
<br />
<div class="row">
<div class="col-12">
<div class="form-group text-right">
<pre>
<textarea name="json" class="form-control" id="jsonCreateInput" rows="16" placeholder="Enter JSON data"></textarea>
</pre>
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
<a class="btn btn-primary" href="#" onclick="createInstanceUsingJSON()" data-dismiss="modal">Submit</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- About Modal-->
<div class="modal fade" id="aboutModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">About</h5>
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="row">
<div class="col-12">
<div id="about"></div>
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" type="button" data-dismiss="modal">Dismiss</button>
</div>
</div>
</div>
</div>
<!-- Bootstrap core JavaScript-->
<script src="vendor/jquery/jquery.min.js"></script>
<script src="vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- Core plugin JavaScript-->
<script src="vendor/jquery-easing/jquery.easing.min.js"></script>
<!-- Custom scripts for all pages-->
<script src="vendor/sb-admin-2/js/sb-admin-2.min.js"></script>
<!-- Page level plugins -->
<script src="vendor/datatables/jquery.dataTables.min.js"></script>
<script src="vendor/datatables/dataTables.bootstrap4.min.js"></script>
</body>
<script>
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
const remoteId = urlParams.get('remote');
const projectName = urlParams.get('project');
function logout(){
$.get("./php/aaa/authentication.php?action=deauthenticateUser", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code == 200) {
window.location = './index.html'
}
});
}
function operationStatusCheck(){
//check to see if there are any running operations
$.get("./php/lxd/operations.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayOperationStatus", function (data) {
//Check to see if we have running operations
if (data) {
//Display spinner and notification area if there are running tasks
$('#spinner').show();
$('#notificationArea').show();
$('#notification').text(data);
//Set the page to check operations again in 1 second
setTimeout(() => { operationStatusCheck(); }, 1000);
}
else {
//Hide spinner and notification area if no running tasks
$('#spinner').hide();
$('#notificationArea').hide();
$('#notification').text("");
//Set the page to check operations again in 3 seconds
setTimeout(() => { operationStatusCheck(); }, 3000);
}
});
}
function reloadPageContent(){
//Check Authorization
$.get("./php/aaa/authentication.php?action=validateAuthentication", function (data) {
operationData = JSON.parse(data);
if (operationData.status_code != 200) {
console.log(operationData);
window.location = './index.html'
}
});
$('#instanceListTable').DataTable().ajax.reload(null, false);
}
function loadPageContent(){
//Display current logged in username
$("#username").load("./php/admin/settings.php?action=displayUsername");
$('#instanceListTable').DataTable( {
ajax: "./php/lxd/instances.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listInstances",
columns: [
{},
{ title: "Name" },
{ title: "OS" },
{ title: "Location" },
{ title: "IPv4" },
{ title: "IPv6" },
{ title: "Type" },
{ title: "Memory" },
{ title: "Root Disk" },
{ title: "Status" },
{ title: "Action" }
],
order: [],
columnDefs: [
{ targets: 0, orderable: false, width: "25px" }
]
});
//Check for any running operations
operationStatusCheck();
//Set the page content to reload in 5 seconds
setInterval(() => { reloadPageContent(); }, 5000);
}
function createInstanceUsingForm(){
var instanceName = $("#instanceNameInput").val();
var profileName = $("#selectProfileInput").val();
var fingerprint = $("#selectImageInput").val();
var type = $("#selectTypeInput").val();
var instanceType = $("#selectInstanceTypeInput").val();
var location = $("#selectLocationInput").val();
console.log("Info: creating instance " + instanceName);
$.get("./php/lxd/instances.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&name=" + encodeURI(instanceName) + "&profile=" + encodeURI(profileName) + "&fingerprint=" + encodeURI(fingerprint) + "&type=" + encodeURI(type) + "&instance_type=" + encodeURI(instanceType) + "&location=" + encodeURI(location) + "&action=createInstanceUsingForm", function (data) {
//Sync type
var operationData = JSON.parse(data);
console.log(operationData);
if (operationData.error_code >= 400){
alert(operationData.error);
}
setTimeout(() => { reloadPageContent(); }, 1000);
});
}
function createInstanceUsingJSON(){
var instanceCreateJSON = $("#jsonCreateInput").val();
console.log("Info: creating instance");
$.post("./php/lxd/instances.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=createInstanceUsingJSON", {json: instanceCreateJSON}, function (data) {
//Sync type
var operationData = JSON.parse(data);
console.log(operationData);
if (operationData.error_code >= 400){
alert(operationData.error);
}
setTimeout(() => { reloadPageContent(); }, 1000);
});
}
function startInstance(instanceName){
console.log("Info: starting instance " + instanceName);
$.get("./php/lxd/instances.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&instance=" + encodeURI(instanceName) + "&action=startInstance", function (data) {
//Async type
var operationData = JSON.parse(data);
console.log(operationData);
if (operationData.error_code >= 400){
alert(operationData.error);
}
operationStatusCheck();
setTimeout(() => { reloadPageContent(); }, 1000);
});
}
function stopInstance(instanceName){
console.log("Info: stopping instance " + instanceName);
$.get("./php/lxd/instances.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&instance=" + encodeURI(instanceName) + "&action=stopInstance", function (data) {
//Async type
var operationData = JSON.parse(data);
console.log(operationData);
if (operationData.error_code >= 400){
alert(operationData.error);
}
operationStatusCheck();
setTimeout(() => { reloadPageContent(); }, 1000);
});
}
function unfreezeInstance(instanceName){
console.log("Info: unfreezing instance " + instanceName);
$.get("./php/lxd/instances.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&instance=" + encodeURI(instanceName) + "&action=unfreezeInstance", function (data) {
//Async type
var operationData = JSON.parse(data);
console.log(operationData);
if (operationData.error_code >= 400){
alert(operationData.error);
}
operationStatusCheck();
setTimeout(() => { reloadPageContent(); }, 1000);
});
}
//If use creates a new instance load the images based on container or virtual-machine selection
function changeImageInput(){
var imageType = $("#selectTypeInput").val();
$("#selectImageInput").load("./php/lxd/images.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&image_type=" + encodeURI(imageType) + "&action=listImagesForSelectOption");
}
$(document).ready(function(){
//Check Authorization
$.get("./php/aaa/authentication.php?action=validateAuthentication", function (data) {
operationData = JSON.parse(data);
if (operationData.status_code != 200) {
console.log(operationData);
window.location = './index.html'
}
});
//Load in the sidebar
$("#sidebarLinks").load("./sidebar.html");
//Setup Page Breadcrumb Links/Information
$('#remoteBreadCrumb').load("./php/lxd/remote-breadcrumb.php?remote=" + encodeURI(remoteId));
$('#remoteBreadCrumb').attr("href", "remotes-single.html?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$('#instancesBreadCrumb').text("instances");
//Load the card contents
loadPageContent();
$("#remoteListNav").load("./php/lxd/remotes.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listRemotesForTopNavigation");
$("#projectListNav").load("./php/lxd/projects.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listProjectsForTopNavigation");
//Load the about info for the about modal
$.get("./about.html", function (data) {
$("#about").html(data);
});
//Populate the select options fields used in modals
$("#selectProfileInput").load("./php/lxd/profiles.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listProfilesForSelectOption");
$("#selectLocationInput").load("./php/lxd/cluster-members.php?remote=" + encodeURI(remoteId) + "&include_none=true&action=listClusterMembersForSelectOption");
//Populate initial list of images available for container
changeImageInput();
});
</script>
</html>

378
lxd-dashboard/logs.php Normal file
View file

@ -0,0 +1,378 @@
<!--
LXDWARE LXD Dashboard - A web-based interface for managing LXD servers
Copyright (C) 2020-2021 LXDWARE.COM
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<link rel="icon" type="image/png" href="assets/images/logo-light.svg">
<title>LXD Dashboard</title>
<!-- Custom fonts for this template-->
<link href="vendor/fontawesome-free/css/all.min.css" rel="stylesheet" type="text/css">
<link href="vendor/fonts/nunito.css" rel="stylesheet">
<!-- Custom styles for this template-->
<link href="vendor/sb-admin-2/css/sb-admin-2.css" rel="stylesheet">
<link href="assets/css/style.css?version=3.0" rel="stylesheet">
<!-- Custom styles for this page -->
<link href="vendor/datatables/dataTables.bootstrap4.min.css" rel="stylesheet">
</head>
<body id="page-top">
<!-- Page Wrapper -->
<div id="wrapper">
<!-- Sidebar -->
<ul class="navbar-nav bg-dark sidebar sidebar-dark accordion sidebar-divider-right" id="accordionSidebar">
<!-- Sidebar - Brand -->
<a class="sidebar-brand d-flex align-items-center justify-content-center" href="index.php">
<div class="sidebar-brand-icon rotate-n-0">
<img src="assets/images/logo-dark.svg" style="width: 2rem;"></img>
<!-- <i class="fas fa-cube" style="width: 2rem;"></i> -->
</div>
<div class="sidebar-brand-text mx-3">LXDWARE</div>
</a>
<!-- Divider -->
<hr class="sidebar-divider">
<!-- Nav Item - Dashboard -->
<li class="nav-item">
<a class="nav-link" href="remotes.php">
<i class="fas fa-fw fa-server"></i>
<span>Hosts</span></a>
</li>
<!-- Divider -->
<hr class="sidebar-divider d-none d-md-block">
<!-- Sidebar Toggler (Sidebar) -->
<div class="text-center d-none d-md-inline">
<button class="rounded-circle border-0" id="sidebarToggle" onclick="setSidebarToggleValue()"></button>
</div>
</ul>
<!-- End of Sidebar -->
<!-- Content Wrapper -->
<div id="content-wrapper" class="d-flex flex-column">
<!-- Main Content -->
<div id="content">
<!-- Topbar -->
<nav class="navbar navbar-expand navbar-light bg-white topbar mb-4 static-top shadow">
<!-- Sidebar Toggle (Topbar) -->
<button id="sidebarToggleTop" class="btn btn-link d-md-none rounded-circle mr-3">
<i class="fa fa-bars"></i>
</button>
<!-- Topbar Navbar -->
<ul class="navbar-nav ml-auto">
<div class="topbar-divider d-none d-sm-block"></div>
<!-- Nav Item - User Information -->
<li class="nav-item dropdown no-arrow">
<a class="nav-link dropdown-toggle" href="#" id="userDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fas fa-user-circle fa-1x fa-fw mr-2 text-gray-600"></i>
<span id="username" class="mr-2 d-none d-lg-inline text-gray-600"></span>
</a>
<!-- Dropdown - User Information -->
<div class="dropdown-menu dropdown-menu-right shadow animated--grow-in" aria-labelledby="userDropdown">
<a class="dropdown-item" href="user-profile.php">
<i class="fas fa-user fa-sm fa-fw mr-2 text-gray-400"></i>
Profile
</a>
<a class="dropdown-item" href="settings.php">
<i class="fas fa-cog fa-sm fa-fw mr-2 text-gray-400"></i>
Settings
</a>
<a class="dropdown-item" href="logs.php">
<i class="fas fa-history fa-sm fa-fw mr-2 text-gray-400"></i>
Logs
</a>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#aboutModal">
<i class="fas fa-info-circle fa-sm fa-fw mr-2 text-gray-400"></i>
About
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#" onclick="logout()">
<i class="fas fa-sign-out-alt fa-sm fa-fw mr-2 text-gray-400"></i>
Logout
</a>
</div>
</li>
</ul>
</nav>
<!-- End of Topbar -->
<!-- Begin Page Content -->
<div class="container-fluid">
<header class="page-header page-header-dark bg-gradient-primary-to-secondary">
<div class="container-xl px-4">
<div class="page-header-content pt-4">
<div class="row align-items-center justify-content-between mt-n5 ml-n5 mr-n5 bg-dark pb-6">
<div class="col-auto mt-4 ml-3">
<div class="page-header-subtitle">
<span id="remoteBreadCrumb">LXD Dashboard</span>
</div>
<h2 class="page-header-title mt-2">
LOGS
</h2>
<div class="page-header-subtitle">
View LXD Dashboard event logs
</div>
</div>
<div class="col-12 col-xl-auto mt-4">
<div class="input-group input-group-joined border-0" style="width: 14rem">
<span class="input-group-text bg-transparent border-0">
</span>
</div>
</div>
</div>
</div>
</div>
</header>
<div class="row mt-n5 ml-2 mr-2">
<div class="col-12 mt-n3">
<!-- Logs List -->
<div class="card shadow mb-4">
<!-- Card Header - Dropdown -->
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold">
<span class="ml-1">Logs</span>
</h6>
<div class="dropdown no-arrow">
<a class="dropdown-toggle mr-2" href="#" onclick="reloadPageContent()" title="Refresh" aria-hidden="true">
<i class="fa fa-sync fa-1x fa-fw"></i></a>
</div>
</div>
<!-- Card Body -->
<div class="card-body">
<div class="table-responsive">
<table class="table" id="eventLogTable" width="100%" cellspacing="0">
</table>
</div>
</div>
</div>
<!-- End Logs List -->
</div>
</div>
</div>
<!-- /.container-fluid -->
</div>
<!-- End of Main Content -->
<!-- Footer -->
<footer class="sticky-footer bg-white">
<div class="container my-auto">
<div class="copyright text-center my-auto">
<span>Copyright &copy; LXDWARE 2020 - Present</span>
</div>
</div>
</footer>
<!-- End of Footer -->
</div>
<!-- End of Content Wrapper -->
</div>
<!-- End of Page Wrapper -->
<!-- Scroll to Top Button-->
<a class="scroll-to-top rounded" href="#page-top">
<i class="fas fa-angle-up"></i>
</a>
<!-- About Modal-->
<div class="modal fade" id="aboutModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">About</h5>
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="row">
<div class="col-12">
<div id="about"></div>
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" type="button" data-dismiss="modal">Dismiss</button>
</div>
</div>
</div>
</div>
<!-- Bootstrap core JavaScript-->
<script src="vendor/jquery/jquery.min.js"></script>
<script src="vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- Core plugin JavaScript-->
<script src="vendor/jquery-easing/jquery.easing.min.js"></script>
<!-- Custom scripts for all pages-->
<script src="vendor/sb-admin-2/js/sb-admin-2.min.js"></script>
<!-- Page level plugins -->
<script src="vendor/datatables/jquery.dataTables.min.js"></script>
<script src="vendor/datatables/dataTables.bootstrap4.min.js"></script>
</body>
<script>
var reloadTime = 5000;
function logout(){
$.get("./backend/aaa/authentication.php?action=deauthenticateUser", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code == 200) {
window.location.href = './index.php'
}
});
}
function reloadPageContent() {
clearTimeout(pageReloadTimeout);
//Check Authorization
$.get("./backend/aaa/authentication.php?action=validateAuthentication", function (data) {
operationData = JSON.parse(data);
if (operationData.status_code != 200) {
console.log(operationData);
window.location.href = './index.php'
}
});
$('#eventLogTable').DataTable().ajax.reload(null, false);
//Set reload page content
pageReloadTimeout = setTimeout(() => { reloadPageContent(); }, reloadTime);
}
function loadPageContent(){
//Display current logged in username
$("#username").load("./backend/admin/settings.php?action=displayUsername");
$('#eventLogTable').DataTable( {
ajax: "./backend/admin/logs.php?action=listLogEvents",
columns: [
{},
{ title: "ID" },
{ title: "Control" },
{ title: "RemoteID" },
{ title: "Project" },
{ title: "Object" },
{ title: "Status Code" },
{ title: "Message" },
{ title: "Hostname" },
{ title: "UserID" },
{ title: "Date" }
],
order: [1, "desc" ],
columnDefs: [
{ targets: 0, orderable: false, width: "25px" }
]
});
//Set reload page content
$.get("./backend/admin/settings.php?action=retrievePageRefreshRateValues", function (data) {
operationData = JSON.parse(data);
if (operationData.logs_page_rate >= 1)
reloadTime = operationData.logs_page_rate * 1000;
pageReloadTimeout = setTimeout(() => { reloadPageContent(); }, reloadTime);
});
}
function setSidebarToggleValue(){
sidebarState = localStorage.getItem('sidebarState');
if (sidebarState == "collapsed"){
localStorage.setItem('sidebarState','expanded');
}
else {
localStorage.setItem('sidebarState','collapsed');
}
}
function applySidebarToggleValue() {
sidebarState = localStorage.getItem('sidebarState');
if (sidebarState == "collapsed"){
$("body").toggleClass("sidebar-toggled"),
$(".sidebar").toggleClass("toggled"),
$(".sidebar").hasClass("toggled") && $(".sidebar .collapse").collapse("hide")
}
}
applySidebarToggleValue();
$(document).ready(function(){
//Check Authorization
$.get("./backend/aaa/authentication.php?action=validateAuthentication", function (data) {
operationData = JSON.parse(data);
if (operationData.status_code != 200) {
console.log(operationData);
window.location.href = './index.php'
}
});
//Load the card contents
loadPageContent();
//Load the about info for the about modal
$.get("./backend/config/about.php", function (data) {
$("#about").html(data);
});
});
</script>
</html>

View file

@ -37,7 +37,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Custom styles for this template-->
<link href="vendor/sb-admin-2/css/sb-admin-2.css" rel="stylesheet">
<link href="assets/css/style.css" rel="stylesheet">
<link href="assets/css/style.css?version=3.0" rel="stylesheet">
<!-- Custom styles for this page -->
<link href="vendor/datatables/dataTables.bootstrap4.min.css" rel="stylesheet">
@ -50,7 +50,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<div id="wrapper">
<!-- Sidebar -->
<ul class="navbar-nav bg-dark sidebar sidebar-dark accordion" id="accordionSidebar">
<ul class="navbar-nav bg-dark sidebar sidebar-dark accordion sidebar-divider-right" id="accordionSidebar">
<div id="sidebarLinks"></div>
@ -59,12 +59,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Sidebar Toggler (Sidebar) -->
<div class="text-center d-none d-md-inline">
<button class="rounded-circle border-0" id="sidebarToggle"></button>
<button class="rounded-circle border-0" id="sidebarToggle" onclick="setSidebarToggleValue()"></button>
</div>
</ul>
<!-- End of Sidebar -->
<!-- Content Wrapper -->
<div id="content-wrapper" class="d-flex flex-column">
@ -79,37 +78,31 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<i class="fa fa-bars"></i>
</button>
<!-- Topbar Navbar -->
<ul class="navbar-nav ml-auto">
<!-- Topbar Notification -->
<div class="d-none d-sm-inline-block form-inline mr-auto ml-md-3 my-2 my-md-0 mw-100 navbar-search">
<ul class="navbar-nav ml-auto">
<li class="nav-item dropdown">
<label class="h6 mt-4 mr-2 ml-4">Host: </label>
</li>
<li class="nav-item dropdown">
<div class="input-group mt-3">
<select class="form-control" id="remoteListNav" style="width:150px;" onchange="location = this.value;">
</select>
</div>
</li>
<li>
<div class="nav-item spinner-border m-3" role="status" style="display:none;" id="spinner">
<span class="nav-item sr-only">Loading...</span>
</div>
</li>
<li class="nav-item dropdown no-arrow" id="notificationArea" style="display: none;">
<div class="nav-link dropdown-toggle">
<span id="notification" class="mr-2 d-none d-lg-inline text-gray-600">Notification</span>
</div>
</li>
</ul>
</div>
<li class="nav-item dropdown">
<label class="h6 mt-4 mr-2 ml-4">Project: </label>
</li>
<li class="nav-item dropdown">
<div class="input-group mt-3">
<select class="form-control" id="projectListNav" style="width:150px;" onchange="location = this.value;">
</select>
</div>
</li>
<!-- Topbar Navbar -->
<ul class="navbar-nav ml-auto">
<li class="nav-item dropdown" id="remoteListNav">
</li>
<li class="nav-item dropdown" id="projectListNav">
</li>
<div class="topbar-divider d-none d-sm-block"></div>
<!-- Nav Divider -->
<div class="topbar-divider d-none d-sm-block"></div>
<!-- Nav Item - User Information -->
<li class="nav-item dropdown no-arrow">
@ -119,14 +112,18 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</a>
<!-- Dropdown - User Information -->
<div class="dropdown-menu dropdown-menu-right shadow animated--grow-in" aria-labelledby="userDropdown">
<a class="dropdown-item" href="user-profile.html">
<a class="dropdown-item" href="user-profile.php">
<i class="fas fa-user fa-sm fa-fw mr-2 text-gray-400"></i>
Profile
</a>
<a class="dropdown-item" href="settings.html">
<a class="dropdown-item" href="settings.php">
<i class="fas fa-cog fa-sm fa-fw mr-2 text-gray-400"></i>
Settings
</a>
<a class="dropdown-item" href="logs.php">
<i class="fas fa-history fa-sm fa-fw mr-2 text-gray-400"></i>
Logs
</a>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#aboutModal">
<i class="fas fa-info-circle fa-sm fa-fw mr-2 text-gray-400"></i>
About
@ -147,26 +144,50 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Begin Page Content -->
<div class="container-fluid">
<!-- BreadCrumb -->
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="#" id="remoteBreadCrumb"></a></li>
<li class="breadcrumb-item"><a href="#" id="networkAclsBreadCrumb"></a></li>
<li class="breadcrumb-item active" aria-current="page" id="networkAclBreadCrumb"></li>
</ol>
</nav>
<header class="page-header page-header-dark bg-gradient-primary-to-secondary">
<div class="container-xl px-4">
<div class="page-header-content pt-4">
<div class="row align-items-center justify-content-between mt-n5 ml-n5 mr-n5 bg-dark pb-6">
<div class="col-auto mt-4 ml-3">
<div class="page-header-subtitle">
<a href="#" id="remoteBreadCrumb"></a>
/
<a href="#" id="networkAclsBreadCrumb"></a>
</div>
<h2 class="page-header-title mt-2">
<span id="networkAclBreadCrumb"></span> - Egress Rules
</h2>
<div class="page-header-subtitle">
Create and manage network egress rules
</div>
</div>
<div class="col-12 col-xl-auto mt-4">
<div class="input-group input-group-joined border-0" style="width: 14rem">
<span class="input-group-text bg-transparent border-0">
<a class="btn btn-outline-primary" href="#" data-toggle="modal" data-target="#addTrafficRuleModal" title="Add Traffic Rule" aria-hidden="true">
<i class="fas fa-plus fa-sm fa-fw"></i> Rule
</a>
</span>
</div>
</div>
</div>
</div>
</div>
</header>
<div class="row">
<div class="row mt-n5 ml-2 mr-2">
<div class="col-12">
<!-- Egress Rules -->
<div class="col-12 mt-n3">
<!-- Egress Rules List -->
<div class="card shadow mb-4">
<!-- Card Header - Dropdown -->
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">Egress Rules</h6>
<h6 class="m-0 font-weight-bold">
<span class="ml-1">Egress Rules</span>
</h6>
<div class="dropdown no-arrow">
<a class="dropdown-toggle mr-2" href="#" data-toggle="modal" data-target="#addTrafficRuleModal" title="Add Traffic Rule" aria-hidden="true">
<i class="fas fa-plus fa-sm fa-fw"></i> Rule</a>
<a class="dropdown-toggle mr-2" href="#" onclick="reloadPageContent()" title="Refresh" aria-hidden="true">
<i class="fa fa-sync fa-1x fa-fw"></i></a>
</div>
</div>
<!-- Card Body -->
@ -177,7 +198,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</div>
</div>
</div>
<!-- End Egress Rules -->
<!-- End Egress Rules List -->
</div>
</div>
@ -192,7 +213,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<footer class="sticky-footer bg-white">
<div class="container my-auto">
<div class="copyright text-center my-auto">
<span>Copyright &copy; lxdware.com 2021</span>
<span>Copyright &copy; LXDWARE 2020 - Present</span>
</div>
</div>
</footer>
@ -222,7 +243,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<div class="modal-body">
<div class="row">
<label class="col-3 col-form-label text-right">Action: </label>
<label class="col-3 col-form-label text-right">Action: <span class="text-danger">*</span></label>
<div class="col-7">
<div class="form-group">
<select id="actionTrafficRuleInput" onchange="" class="form-control" name="actionTrafficRuleInput">
@ -233,12 +254,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle text-danger" title='(Required) - Select the action to be applied to this rule.'></i>
<i class="far fa-sm fa-question-circle" title='(Required) - Select the action to be applied to this rule.'></i>
</div>
</div>
<div class="row">
<label class="col-3 col-form-label text-right">State: </label>
<label class="col-3 col-form-label text-right">State: <span class="text-danger">*</span></label>
<div class="col-7">
<div class="form-group">
<select id="stateTrafficRuleInput" onchange="" class="form-control" name="stateTrafficRuleInput">
@ -249,7 +270,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle text-danger" title='(Required) - Select the state to be applied to this rule.'></i>
<i class="far fa-sm fa-question-circle" title='(Required) - Select the state to be applied to this rule.'></i>
</div>
</div>
@ -410,61 +431,66 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
const remoteId = urlParams.get('remote');
const projectName = urlParams.get('project');
const networkAcl = urlParams.get('network_acl');
var reloadTime = 5000;
function logout(){
$.get("./php/aaa/authentication.php?action=deauthenticateUser", function (data) {
$.get("./backend/aaa/authentication.php?action=deauthenticateUser", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code == 200) {
window.location = './index.html'
window.location.href = './index.php'
}
});
}
function operationStatusCheck(){
clearTimeout(operationTimeout);
//check to see if there are any running operations
$.get("./php/lxd/operations.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayOperationStatus", function (data) {
$.get("./backend/lxd/operations.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayOperationStatus", function (data) {
//Check to see if we have running operations
if (data){
//Display spinner and notification area if there are running tasks
$('#spinner').show();
if (data) {
//Display notification area if there are running tasks
$('#notificationArea').show();
$('#notification').text(data);
//Set the page to check operations again in 1 second
setTimeout(() => { operationStatusCheck(); }, 1000);
$('#notification').text("Notice: " + data);
//Set the page to check operations again in 2 seconds
operationTimeout = setTimeout(() => { operationStatusCheck(); }, 2000);
}
else {
//Hide spinner and notification area if no running tasks
$('#spinner').hide();
//Hide notification area if no running tasks
$('#notificationArea').hide();
$('#notification').text("");
//Set the page to check operations again in 3 seconds
setTimeout(() => { operationStatusCheck(); }, 3000);
//Set the page to check operations again in 4 seconds
operationTimeout = setTimeout(() => { operationStatusCheck(); }, 4000);
}
});
}
function reloadPageContent() {
clearTimeout(pageReloadTimeout);
//Check Authorization
$.get("./php/aaa/authentication.php?action=validateAuthentication", function (data) {
$.get("./backend/aaa/authentication.php?action=validateAuthentication", function (data) {
operationData = JSON.parse(data);
if (operationData.status_code != 200) {
console.log(operationData);
window.location = './index.html'
window.location.href = './index.php'
}
});
$('#egressListTable').DataTable().ajax.reload(null, false);
//Set reload page content
pageReloadTimeout = setTimeout(() => { reloadPageContent(); }, reloadTime);
}
function loadPageContent(){
//Display current logged in username
$("#username").load("./php/admin/settings.php?action=displayUsername");
$("#username").load("./backend/admin/settings.php?action=displayUsername");
$('#egressListTable').DataTable( {
ajax: "./php/lxd/network-acls.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&network_acl=" + encodeURI(networkAcl) + "&action=listEgressRules",
ajax: "./backend/lxd/network-acls.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&network_acl=" + encodeURI(networkAcl) + "&action=listEgressRules",
columns: [
{},
{ title: "Action" },
@ -486,10 +512,16 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
});
//Check for any running operations
operationStatusCheck();
operationTimeout = setTimeout(() => { operationStatusCheck(); }, 1000);
//Set reload page content
$.get("./backend/admin/settings.php?action=retrievePageRefreshRateValues", function (data) {
operationData = JSON.parse(data);
if (operationData.network_acls_page_rate >= 1)
reloadTime = operationData.network_acls_page_rate * 1000;
pageReloadTimeout = setTimeout(() => { reloadPageContent(); }, reloadTime);
});
//Set the page content to reload in 5 seconds
setInterval(() => { reloadPageContent(); }, 5000);
}
function addTrafficRule(){
@ -505,7 +537,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
var icmpTypeTrafficRuleInput = $("#icmpTypeTrafficRuleInput").val();
var icmpCodeTrafficRuleInput = $("#icmpCodeTrafficRuleInput").val();
console.log("Info: adding " + typeTrafficRuleInput + " rule ");
$.get("./php/lxd/network-acls.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&network_acl=" + encodeURI(networkAcl) + "&type=" + encodeURI(typeTrafficRuleInput) + "&traffic_action=" + encodeURI(actionTrafficRuleInput) + "&state=" + encodeURI(stateTrafficRuleInput) + "&description=" + encodeURI(descriptionTrafficRuleInput) + "&source=" + encodeURI(sourceTrafficRuleInput) + "&destination=" + encodeURI(destinationTrafficRuleInput) + "&protocol=" + encodeURI(protocolTrafficRuleInput) + "&source_port=" + encodeURI(sourcePortTrafficRuleInput) + "&destination_port=" + encodeURI(destinationPortTrafficRuleInput) + "&icmp_type=" + encodeURI(icmpTypeTrafficRuleInput) + "&icmp_code=" + encodeURI(icmpCodeTrafficRuleInput) + "&action=addTrafficRule", function (data) {
$.get("./backend/lxd/network-acls.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&network_acl=" + encodeURI(networkAcl) + "&type=" + encodeURI(typeTrafficRuleInput) + "&traffic_action=" + encodeURI(actionTrafficRuleInput) + "&state=" + encodeURI(stateTrafficRuleInput) + "&description=" + encodeURI(descriptionTrafficRuleInput) + "&source=" + encodeURI(sourceTrafficRuleInput) + "&destination=" + encodeURI(destinationTrafficRuleInput) + "&protocol=" + encodeURI(protocolTrafficRuleInput) + "&source_port=" + encodeURI(sourcePortTrafficRuleInput) + "&destination_port=" + encodeURI(destinationPortTrafficRuleInput) + "&icmp_type=" + encodeURI(icmpTypeTrafficRuleInput) + "&icmp_code=" + encodeURI(icmpCodeTrafficRuleInput) + "&action=addTrafficRule", function (data) {
//Sync operation type
var operationData = JSON.parse(data);
console.log(operationData);
@ -518,7 +550,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
function deleteEgressRule(egressRuleToDelete){
console.log("Info: deleting egress rule " + egressRuleToDelete);
$.get("./php/lxd/network-acls.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&network_acl=" + encodeURI(networkAcl) + "&rule=" + encodeURI(egressRuleToDelete) + "&action=deleteEgressRule", function (data) {
$.get("./backend/lxd/network-acls.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&network_acl=" + encodeURI(networkAcl) + "&rule=" + encodeURI(egressRuleToDelete) + "&action=deleteEgressRule", function (data) {
//Sync type
var operationData = JSON.parse(data);
console.log(operationData);
@ -529,36 +561,67 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
});
}
function setSidebarToggleValue(){
sidebarState = localStorage.getItem('sidebarState');
if (sidebarState == "collapsed"){
localStorage.setItem('sidebarState','expanded');
}
else {
localStorage.setItem('sidebarState','collapsed');
}
}
function applySidebarToggleValue() {
sidebarState = localStorage.getItem('sidebarState');
if (sidebarState == "collapsed"){
$("body").toggleClass("sidebar-toggled"),
$(".sidebar").toggleClass("toggled"),
$(".sidebar").hasClass("toggled") && $(".sidebar .collapse").collapse("hide")
}
}
applySidebarToggleValue();
$(document).ready(function(){
//Check Authorization
$.get("./php/aaa/authentication.php?action=validateAuthentication", function (data) {
$.get("./backend/aaa/authentication.php?action=validateAuthentication", function (data) {
operationData = JSON.parse(data);
if (operationData.status_code != 200) {
console.log(operationData);
window.location = './index.html'
window.location.href = './index.php'
}
});
//Load in the sidebar
$("#sidebarLinks").load("./sidebar.html");
$("#sidebarLinks").load("./sidebar.php?version=3.0");
//Setup Page Breadcrumb Links/Information
$('#remoteBreadCrumb').load("./php/lxd/remote-breadcrumb.php?remote=" + encodeURI(remoteId));
$('#remoteBreadCrumb').attr("href", "remotes-single.html?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$('#remoteBreadCrumb').load("./backend/lxd/remote-breadcrumb.php?remote=" + encodeURI(remoteId));
$('#remoteBreadCrumb').attr("href", "remotes-single.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$('#networkAclsBreadCrumb').text("network-acls");
$('#networkAclsBreadCrumb').attr("href", "network-acls.html?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$('#networkAclsBreadCrumb').attr("href", "network-acls.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$('#networkAclBreadCrumb').text(networkAcl);
//Load the card contents
loadPageContent();
//Validate remote host connection returns 200 status
$.get("./backend/lxd/remotes-single.php?remote=" + encodeURI(remoteId) + "&action=validateRemoteConnection", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code == 200) {
//Set top navbar dropdowns
$("#remoteListNav").load("./backend/lxd/remotes.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listRemotesForSelectOption");
$("#projectListNav").load("./backend/lxd/projects.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listProjectsForSelectOption");
//Load Page Content
loadPageContent();
}
else {
alert("Unable to connect to remote host. HTTP status code: " + operationData.status_code);
}
});
$("#remoteListNav").load("./php/lxd/remotes.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listRemotesForTopNavigation");
$("#projectListNav").load("./php/lxd/projects.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listProjectsForTopNavigation");
//Load the about info for the about modal
$.get("./about.html", function (data) {
$.get("./backend/config/about.php", function (data) {
$("#about").html(data);
});

View file

@ -37,7 +37,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Custom styles for this template-->
<link href="vendor/sb-admin-2/css/sb-admin-2.css" rel="stylesheet">
<link href="assets/css/style.css" rel="stylesheet">
<link href="assets/css/style.css?version=3.0" rel="stylesheet">
<!-- Custom styles for this page -->
<link href="vendor/datatables/dataTables.bootstrap4.min.css" rel="stylesheet">
@ -50,7 +50,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<div id="wrapper">
<!-- Sidebar -->
<ul class="navbar-nav bg-dark sidebar sidebar-dark accordion" id="accordionSidebar">
<ul class="navbar-nav bg-dark sidebar sidebar-dark accordion sidebar-divider-right" id="accordionSidebar">
<div id="sidebarLinks"></div>
@ -59,12 +59,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Sidebar Toggler (Sidebar) -->
<div class="text-center d-none d-md-inline">
<button class="rounded-circle border-0" id="sidebarToggle"></button>
<button class="rounded-circle border-0" id="sidebarToggle" onclick="setSidebarToggleValue()"></button>
</div>
</ul>
<!-- End of Sidebar -->
<!-- Content Wrapper -->
<div id="content-wrapper" class="d-flex flex-column">
@ -79,37 +78,31 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<i class="fa fa-bars"></i>
</button>
<!-- Topbar Navbar -->
<ul class="navbar-nav ml-auto">
<!-- Topbar Notification -->
<div class="d-none d-sm-inline-block form-inline mr-auto ml-md-3 my-2 my-md-0 mw-100 navbar-search">
<ul class="navbar-nav ml-auto">
<li class="nav-item dropdown">
<label class="h6 mt-4 mr-2 ml-4">Host: </label>
</li>
<li class="nav-item dropdown">
<div class="input-group mt-3">
<select class="form-control" id="remoteListNav" style="width:150px;" onchange="location = this.value;">
</select>
</div>
</li>
<li>
<div class="nav-item spinner-border m-3" role="status" style="display:none;" id="spinner">
<span class="nav-item sr-only">Loading...</span>
</div>
</li>
<li class="nav-item dropdown no-arrow" id="notificationArea" style="display: none;">
<div class="nav-link dropdown-toggle">
<span id="notification" class="mr-2 d-none d-lg-inline text-gray-600">Notification</span>
</div>
</li>
</ul>
</div>
<li class="nav-item dropdown">
<label class="h6 mt-4 mr-2 ml-4">Project: </label>
</li>
<li class="nav-item dropdown">
<div class="input-group mt-3">
<select class="form-control" id="projectListNav" style="width:150px;" onchange="location = this.value;">
</select>
</div>
</li>
<!-- Topbar Navbar -->
<ul class="navbar-nav ml-auto">
<li class="nav-item dropdown" id="remoteListNav">
</li>
<li class="nav-item dropdown" id="projectListNav">
</li>
<div class="topbar-divider d-none d-sm-block"></div>
<!-- Nav Divider -->
<div class="topbar-divider d-none d-sm-block"></div>
<!-- Nav Item - User Information -->
<li class="nav-item dropdown no-arrow">
@ -119,14 +112,18 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</a>
<!-- Dropdown - User Information -->
<div class="dropdown-menu dropdown-menu-right shadow animated--grow-in" aria-labelledby="userDropdown">
<a class="dropdown-item" href="user-profile.html">
<a class="dropdown-item" href="user-profile.php">
<i class="fas fa-user fa-sm fa-fw mr-2 text-gray-400"></i>
Profile
</a>
<a class="dropdown-item" href="settings.html">
<a class="dropdown-item" href="settings.php">
<i class="fas fa-cog fa-sm fa-fw mr-2 text-gray-400"></i>
Settings
</a>
<a class="dropdown-item" href="logs.php">
<i class="fas fa-history fa-sm fa-fw mr-2 text-gray-400"></i>
Logs
</a>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#aboutModal">
<i class="fas fa-info-circle fa-sm fa-fw mr-2 text-gray-400"></i>
About
@ -147,26 +144,50 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Begin Page Content -->
<div class="container-fluid">
<!-- BreadCrumb -->
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="#" id="remoteBreadCrumb"></a></li>
<li class="breadcrumb-item"><a href="#" id="networkAclsBreadCrumb"></a></li>
<li class="breadcrumb-item active" aria-current="page" id="networkAclBreadCrumb"></li>
</ol>
</nav>
<header class="page-header page-header-dark bg-gradient-primary-to-secondary">
<div class="container-xl px-4">
<div class="page-header-content pt-4">
<div class="row align-items-center justify-content-between mt-n5 ml-n5 mr-n5 bg-dark pb-6">
<div class="col-auto mt-4 ml-3">
<div class="page-header-subtitle">
<a href="#" id="remoteBreadCrumb"></a>
/
<a href="#" id="networkAclsBreadCrumb"></a>
</div>
<h2 class="page-header-title mt-2">
<span id="networkAclBreadCrumb"></span> - Ingress Rules
</h2>
<div class="page-header-subtitle">
Create and manage network ingress rules
</div>
</div>
<div class="col-12 col-xl-auto mt-4">
<div class="input-group input-group-joined border-0" style="width: 14rem">
<span class="input-group-text bg-transparent border-0">
<a class="btn btn-outline-primary" href="#" data-toggle="modal" data-target="#addTrafficRuleModal" title="Add Traffic Rule" aria-hidden="true">
<i class="fas fa-plus fa-sm fa-fw"></i> Rule
</a>
</span>
</div>
</div>
</div>
</div>
</div>
</header>
<div class="row">
<div class="row mt-n5 ml-2 mr-2">
<div class="col-12">
<!-- Ingress Rules -->
<div class="col-12 mt-n3">
<!-- Ingress Rules List -->
<div class="card shadow mb-4">
<!-- Card Header - Dropdown -->
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">Ingress Rules</h6>
<h6 class="m-0 font-weight-bold">
<span class="ml-1">Ingress Rules</span>
</h6>
<div class="dropdown no-arrow">
<a class="dropdown-toggle mr-2" href="#" data-toggle="modal" data-target="#addTrafficRuleModal" title="Add Traffic Rule" aria-hidden="true">
<i class="fas fa-plus fa-sm fa-fw"></i> Rule</a>
<a class="dropdown-toggle mr-2" href="#" onclick="reloadPageContent()" title="Refresh" aria-hidden="true">
<i class="fa fa-sync fa-1x fa-fw"></i></a>
</div>
</div>
<!-- Card Body -->
@ -177,7 +198,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</div>
</div>
</div>
<!-- End Ingress Rules -->
<!-- End Ingress Rules List -->
</div>
</div>
@ -192,7 +213,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<footer class="sticky-footer bg-white">
<div class="container my-auto">
<div class="copyright text-center my-auto">
<span>Copyright &copy; lxdware.com 2021</span>
<span>Copyright &copy; LXDWARE 2020 - Present</span>
</div>
</div>
</footer>
@ -222,7 +243,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<div class="modal-body">
<div class="row">
<label class="col-3 col-form-label text-right">Action: </label>
<label class="col-3 col-form-label text-right">Action: <span class="text-danger">*</span></label>
<div class="col-7">
<div class="form-group">
<select id="actionTrafficRuleInput" onchange="" class="form-control" name="actionTrafficRuleInput">
@ -233,12 +254,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle text-danger" title='(Required) - Select the action to be applied to this rule.'></i>
<i class="far fa-sm fa-question-circle" title='(Required) - Select the action to be applied to this rule.'></i>
</div>
</div>
<div class="row">
<label class="col-3 col-form-label text-right">State: </label>
<label class="col-3 col-form-label text-right">State: <span class="text-danger">*</span></label>
<div class="col-7">
<div class="form-group">
<select id="stateTrafficRuleInput" onchange="" class="form-control" name="stateTrafficRuleInput">
@ -249,7 +270,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle text-danger" title='(Required) - Select the state to be applied to this rule.'></i>
<i class="far fa-sm fa-question-circle" title='(Required) - Select the state to be applied to this rule.'></i>
</div>
</div>
@ -410,61 +431,66 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
const remoteId = urlParams.get('remote');
const projectName = urlParams.get('project');
const networkAcl = urlParams.get('network_acl');
var reloadTime = 5000;
function logout(){
$.get("./php/aaa/authentication.php?action=deauthenticateUser", function (data) {
$.get("./backend/aaa/authentication.php?action=deauthenticateUser", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code == 200) {
window.location = './index.html'
window.location.href = './index.php'
}
});
}
function operationStatusCheck(){
clearTimeout(operationTimeout);
//check to see if there are any running operations
$.get("./php/lxd/operations.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayOperationStatus", function (data) {
$.get("./backend/lxd/operations.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayOperationStatus", function (data) {
//Check to see if we have running operations
if (data){
//Display spinner and notification area if there are running tasks
$('#spinner').show();
if (data) {
//Display notification area if there are running tasks
$('#notificationArea').show();
$('#notification').text(data);
//Set the page to check operations again in 1 second
setTimeout(() => { operationStatusCheck(); }, 1000);
$('#notification').text("Notice: " + data);
//Set the page to check operations again in 2 seconds
operationTimeout = setTimeout(() => { operationStatusCheck(); }, 2000);
}
else {
//Hide spinner and notification area if no running tasks
$('#spinner').hide();
//Hide notification area if no running tasks
$('#notificationArea').hide();
$('#notification').text("");
//Set the page to check operations again in 3 seconds
setTimeout(() => { operationStatusCheck(); }, 3000);
//Set the page to check operations again in 4 seconds
operationTimeout = setTimeout(() => { operationStatusCheck(); }, 4000);
}
});
}
function reloadPageContent() {
clearTimeout(pageReloadTimeout);
//Check Authorization
$.get("./php/aaa/authentication.php?action=validateAuthentication", function (data) {
$.get("./backend/aaa/authentication.php?action=validateAuthentication", function (data) {
operationData = JSON.parse(data);
if (operationData.status_code != 200) {
console.log(operationData);
window.location = './index.html'
window.location.href = './index.php'
}
});
$('#ingressListTable').DataTable().ajax.reload(null, false);
//Set reload page content
pageReloadTimeout = setTimeout(() => { reloadPageContent(); }, reloadTime);
}
function loadPageContent(){
//Display current logged in username
$("#username").load("./php/admin/settings.php?action=displayUsername");
$("#username").load("./backend/admin/settings.php?action=displayUsername");
$('#ingressListTable').DataTable( {
ajax: "./php/lxd/network-acls.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&network_acl=" + encodeURI(networkAcl) + "&action=listIngressRules",
ajax: "./backend/lxd/network-acls.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&network_acl=" + encodeURI(networkAcl) + "&action=listIngressRules",
columns: [
{},
{ title: "Action" },
@ -486,10 +512,16 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
});
//Check for any running operations
operationStatusCheck();
operationTimeout = setTimeout(() => { operationStatusCheck(); }, 1000);
//Set reload page content
$.get("./backend/admin/settings.php?action=retrievePageRefreshRateValues", function (data) {
operationData = JSON.parse(data);
if (operationData.network_acls_page_rate >= 1)
reloadTime = operationData.network_acls_page_rate * 1000;
pageReloadTimeout = setTimeout(() => { reloadPageContent(); }, reloadTime);
});
//Set the page content to reload in 5 seconds
setInterval(() => { reloadPageContent(); }, 5000);
}
function addTrafficRule(){
@ -505,7 +537,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
var icmpTypeTrafficRuleInput = $("#icmpTypeTrafficRuleInput").val();
var icmpCodeTrafficRuleInput = $("#icmpCodeTrafficRuleInput").val();
console.log("Info: adding " + typeTrafficRuleInput + " rule ");
$.get("./php/lxd/network-acls.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&network_acl=" + encodeURI(networkAcl) + "&type=" + encodeURI(typeTrafficRuleInput) + "&traffic_action=" + encodeURI(actionTrafficRuleInput) + "&state=" + encodeURI(stateTrafficRuleInput) + "&description=" + encodeURI(descriptionTrafficRuleInput) + "&source=" + encodeURI(sourceTrafficRuleInput) + "&destination=" + encodeURI(destinationTrafficRuleInput) + "&protocol=" + encodeURI(protocolTrafficRuleInput) + "&source_port=" + encodeURI(sourcePortTrafficRuleInput) + "&destination_port=" + encodeURI(destinationPortTrafficRuleInput) + "&icmp_type=" + encodeURI(icmpTypeTrafficRuleInput) + "&icmp_code=" + encodeURI(icmpCodeTrafficRuleInput) + "&action=addTrafficRule", function (data) {
$.get("./backend/lxd/network-acls.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&network_acl=" + encodeURI(networkAcl) + "&type=" + encodeURI(typeTrafficRuleInput) + "&traffic_action=" + encodeURI(actionTrafficRuleInput) + "&state=" + encodeURI(stateTrafficRuleInput) + "&description=" + encodeURI(descriptionTrafficRuleInput) + "&source=" + encodeURI(sourceTrafficRuleInput) + "&destination=" + encodeURI(destinationTrafficRuleInput) + "&protocol=" + encodeURI(protocolTrafficRuleInput) + "&source_port=" + encodeURI(sourcePortTrafficRuleInput) + "&destination_port=" + encodeURI(destinationPortTrafficRuleInput) + "&icmp_type=" + encodeURI(icmpTypeTrafficRuleInput) + "&icmp_code=" + encodeURI(icmpCodeTrafficRuleInput) + "&action=addTrafficRule", function (data) {
//Sync operation type
var operationData = JSON.parse(data);
console.log(operationData);
@ -518,7 +550,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
function deleteIngressRule(ingressRuleToDelete){
console.log("Info: deleting ingress rule " + ingressRuleToDelete);
$.get("./php/lxd/network-acls.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&network_acl=" + encodeURI(networkAcl) + "&rule=" + encodeURI(ingressRuleToDelete) + "&action=deleteIngressRule", function (data) {
$.get("./backend/lxd/network-acls.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&network_acl=" + encodeURI(networkAcl) + "&rule=" + encodeURI(ingressRuleToDelete) + "&action=deleteIngressRule", function (data) {
//Sync type
var operationData = JSON.parse(data);
console.log(operationData);
@ -529,36 +561,67 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
});
}
function setSidebarToggleValue(){
sidebarState = localStorage.getItem('sidebarState');
if (sidebarState == "collapsed"){
localStorage.setItem('sidebarState','expanded');
}
else {
localStorage.setItem('sidebarState','collapsed');
}
}
function applySidebarToggleValue() {
sidebarState = localStorage.getItem('sidebarState');
if (sidebarState == "collapsed"){
$("body").toggleClass("sidebar-toggled"),
$(".sidebar").toggleClass("toggled"),
$(".sidebar").hasClass("toggled") && $(".sidebar .collapse").collapse("hide")
}
}
applySidebarToggleValue();
$(document).ready(function(){
//Check Authorization
$.get("./php/aaa/authentication.php?action=validateAuthentication", function (data) {
$.get("./backend/aaa/authentication.php?action=validateAuthentication", function (data) {
operationData = JSON.parse(data);
if (operationData.status_code != 200) {
console.log(operationData);
window.location = './index.html'
window.location.href = './index.php'
}
});
//Load in the sidebar
$("#sidebarLinks").load("./sidebar.html");
$("#sidebarLinks").load("./sidebar.php?version=3.0");
//Setup Page Breadcrumb Links/Information
$('#remoteBreadCrumb').load("./php/lxd/remote-breadcrumb.php?remote=" + encodeURI(remoteId));
$('#remoteBreadCrumb').attr("href", "remotes-single.html?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$('#remoteBreadCrumb').load("./backend/lxd/remote-breadcrumb.php?remote=" + encodeURI(remoteId));
$('#remoteBreadCrumb').attr("href", "remotes-single.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$('#networkAclsBreadCrumb').text("network-acls");
$('#networkAclsBreadCrumb').attr("href", "network-acls.html?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$('#networkAclsBreadCrumb').attr("href", "network-acls.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$('#networkAclBreadCrumb').text(networkAcl);
//Load the card contents
loadPageContent();
//Validate remote host connection returns 200 status
$.get("./backend/lxd/remotes-single.php?remote=" + encodeURI(remoteId) + "&action=validateRemoteConnection", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code == 200) {
//Set top navbar dropdowns
$("#remoteListNav").load("./backend/lxd/remotes.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listRemotesForSelectOption");
$("#projectListNav").load("./backend/lxd/projects.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listProjectsForSelectOption");
//Load Page Content
loadPageContent();
}
else {
alert("Unable to connect to remote host. HTTP status code: " + operationData.status_code);
}
});
$("#remoteListNav").load("./php/lxd/remotes.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listRemotesForTopNavigation");
$("#projectListNav").load("./php/lxd/projects.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listProjectsForTopNavigation");
//Load the about info for the about modal
$.get("./about.html", function (data) {
$.get("./backend/config/about.php", function (data) {
$("#about").html(data);
});

View file

@ -37,7 +37,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Custom styles for this template-->
<link href="vendor/sb-admin-2/css/sb-admin-2.css" rel="stylesheet">
<link href="assets/css/style.css" rel="stylesheet">
<link href="assets/css/style.css?version=3.0" rel="stylesheet">
<!-- Custom styles for this page -->
<link href="vendor/datatables/dataTables.bootstrap4.min.css" rel="stylesheet">
@ -50,7 +50,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<div id="wrapper">
<!-- Sidebar -->
<ul class="navbar-nav bg-dark sidebar sidebar-dark accordion" id="accordionSidebar">
<ul class="navbar-nav bg-dark sidebar sidebar-dark accordion sidebar-divider-right" id="accordionSidebar">
<div id="sidebarLinks"></div>
@ -59,7 +59,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Sidebar Toggler (Sidebar) -->
<div class="text-center d-none d-md-inline">
<button class="rounded-circle border-0" id="sidebarToggle"></button>
<button class="rounded-circle border-0" id="sidebarToggle" onclick="setSidebarToggleValue()"></button>
</div>
</ul>
<!-- End of Sidebar -->
@ -79,37 +79,44 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<i class="fa fa-bars"></i>
</button>
<!-- Topbar Notification -->
<div class="d-none d-sm-inline-block form-inline mr-auto ml-md-3 my-2 my-md-0 mw-100 navbar-search">
<!-- Topbar Notification -->
<div class="d-none d-sm-inline-block form-inline mr-auto ml-md-3 my-2 my-md-0 mw-100 navbar-search">
<ul class="navbar-nav ml-auto">
<li>
<div class="nav-item spinner-border m-3" role="status" style="display:none;" id="spinner">
<span class="nav-item sr-only">Loading...</span>
</div>
</li>
<li class="nav-item dropdown no-arrow" id="notificationArea" style="display: none;">
<div class="nav-link dropdown-toggle">
<span id="notification" class="mr-2 d-none d-lg-inline text-gray-600">Notification</span>
<span id="notification" class="mr-2 d-none d-lg-inline text-danger">Notification</span>
</div>
</li>
</ul>
</div>
<!-- Topbar Navbar -->
<ul class="navbar-nav ml-auto">
<!-- Topbar Navbar -->
<ul class="navbar-nav ml-auto">
<li class="nav-item dropdown">
<label class="h6 mt-4 mr-2 ml-4">Host: </label>
</li>
<li class="nav-item dropdown">
<div class="input-group mt-3">
<select class="form-control" id="remoteListNav" style="width:150px;" onchange="location = this.value;">
</select>
</div>
</li>
<li class="nav-item dropdown" id="remoteListNav">
</li>
<li class="nav-item dropdown">
<label class="h6 mt-4 mr-2 ml-4">Project: </label>
</li>
<li class="nav-item dropdown">
<div class="input-group mt-3">
<select class="form-control" id="projectListNav" style="width:150px;" onchange="location = this.value;">
</select>
</div>
</li>
<li class="nav-item dropdown" id="projectListNav">
</li>
<div class="topbar-divider d-none d-sm-block"></div>
<!-- Nav Divider -->
<div class="topbar-divider d-none d-sm-block"></div>
<!-- Nav Item - User Information -->
<li class="nav-item dropdown no-arrow">
@ -119,14 +126,18 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</a>
<!-- Dropdown - User Information -->
<div class="dropdown-menu dropdown-menu-right shadow animated--grow-in" aria-labelledby="userDropdown">
<a class="dropdown-item" href="user-profile.html">
<a class="dropdown-item" href="user-profile.php">
<i class="fas fa-user fa-sm fa-fw mr-2 text-gray-400"></i>
Profile
</a>
<a class="dropdown-item" href="settings.html">
<a class="dropdown-item" href="settings.php">
<i class="fas fa-cog fa-sm fa-fw mr-2 text-gray-400"></i>
Settings
</a>
<a class="dropdown-item" href="logs.php">
<i class="fas fa-history fa-sm fa-fw mr-2 text-gray-400"></i>
Logs
</a>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#aboutModal">
<i class="fas fa-info-circle fa-sm fa-fw mr-2 text-gray-400"></i>
About
@ -147,25 +158,48 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Begin Page Content -->
<div class="container-fluid">
<!-- BreadCrumb -->
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="#" id="remoteBreadCrumb"></a></li>
<li class="breadcrumb-item active" aria-current="page" id="networkAclsBreadCrumb"></li>
</ol>
</nav>
<header class="page-header page-header-dark bg-gradient-primary-to-secondary">
<div class="container-xl px-4">
<div class="page-header-content pt-4">
<div class="row align-items-center justify-content-between mt-n5 ml-n5 mr-n5 bg-dark pb-6">
<div class="col-auto mt-4 ml-3">
<div class="page-header-subtitle">
<a href="#" id="remoteBreadCrumb"></a>
</div>
<h2 class="page-header-title mt-2">
NETWORK ACLS
</h2>
<div class="page-header-subtitle">
Create and manage network access control lists
</div>
</div>
<div class="col-12 col-xl-auto mt-4">
<div class="input-group input-group-joined border-0" style="width: 14rem">
<span class="input-group-text bg-transparent border-0">
<a class="btn btn-outline-primary" href="#" data-toggle="modal" data-target="#createNetworkAclModal" title="New Network ACL" aria-hidden="true">
<i class="fas fa-plus fa-sm fa-fw"></i> Network ACL
</a>
</span>
</div>
</div>
</div>
</div>
</div>
</header>
<div class="row">
<div class="row mt-n5 ml-2 mr-2">
<div class="col-12">
<div class="col-12 mt-n3">
<!-- Network ACL List -->
<div class="card shadow mb-4">
<!-- Card Header - Dropdown -->
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">Network ACLs</h6>
<h6 class="m-0 font-weight-bold">
<span class="ml-1">Network ACLs</span>
</h6>
<div class="dropdown no-arrow">
<a class="dropdown-toggle mr-2" href="#" data-toggle="modal" data-target="#createNetworkAclModal" title="New Network ACL" aria-hidden="true">
<i class="fas fa-plus fa-sm fa-fw"></i> Network ACL</a>
<a class="dropdown-toggle mr-2" href="#" onclick="reloadPageContent()" title="Refresh" aria-hidden="true">
<i class="fa fa-sync fa-1x fa-fw"></i></a>
</div>
</div>
<!-- Card Body -->
@ -191,7 +225,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<footer class="sticky-footer bg-white">
<div class="container my-auto">
<div class="copyright text-center my-auto">
<span>Copyright &copy; lxdware.com 2021</span>
<span>Copyright &copy; LXDWARE 2020 - Present</span>
</div>
</div>
</footer>
@ -231,14 +265,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<div class="tab-pane fade show active" id="form" role="tabpanel" aria-labelledby="form-tab">
<br />
<div class="row">
<label class="col-3 col-form-label text-right">Name: </label>
<label class="col-3 col-form-label text-right">Name: <span class="text-danger">*</span></label>
<div class="col-7">
<div class="form-group">
<input type="text" id="networkAclNameCreate" class="form-control" placeholder="" name="network_acl_name">
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle text-danger" title='(Required) - Enter a name for the Network ACL'></i>
<i class="far fa-sm fa-question-circle" title='(Required) - Enter a name for the Network ACL'></i>
</div>
</div>
<div class="row">
@ -322,14 +356,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</div>
<div class="modal-body">
<div class="row">
<label class="col-3 col-form-label text-right" id="newNetworkAclNameLabel">Name:</label>
<label class="col-3 col-form-label text-right" id="newNetworkAclNameLabel">Name: <span class="text-danger">*</span></label>
<div class="col-7">
<div class="form-group">
<input type="text" id="newNetworkAclName" class="form-control" placeholder="">
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle text-danger" title='(Required) - Enter in a new name for the Network ACL'></i>
<i class="far fa-sm fa-question-circle" title='(Required) - Enter in a new name for the Network ACL'></i>
</div>
</div>
<input type="hidden" id ="networkAclToRename" name="networkAclToRename">
@ -388,61 +422,66 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
const remoteId = urlParams.get('remote');
const projectName = urlParams.get('project');
var networkAclToUpdate = "";
var reloadTime = 5000;
function logout(){
$.get("./php/aaa/authentication.php?action=deauthenticateUser", function (data) {
$.get("./backend/aaa/authentication.php?action=deauthenticateUser", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code == 200) {
window.location = './index.html'
window.location.href = './index.php'
}
});
}
function operationStatusCheck(){
clearTimeout(operationTimeout);
//check to see if there are any running operations
$.get("./php/lxd/operations.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayOperationStatus", function (data) {
$.get("./backend/lxd/operations.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayOperationStatus", function (data) {
//Check to see if we have running operations
if (data){
//Display spinner and notification area if there are running tasks
$('#spinner').show();
if (data) {
//Display notification area if there are running tasks
$('#notificationArea').show();
$('#notification').text(data);
//Set the page to check operations again in 1 second
setTimeout(() => { operationStatusCheck(); }, 1000);
$('#notification').text("Notice: " + data);
//Set the page to check operations again in 2 seconds
operationTimeout = setTimeout(() => { operationStatusCheck(); }, 2000);
}
else {
//Hide spinner and notification area if no running tasks
$('#spinner').hide();
//Hide notification area if no running tasks
$('#notificationArea').hide();
$('#notification').text("");
//Set the page to check operations again in 3 seconds
setTimeout(() => { operationStatusCheck(); }, 3000);
//Set the page to check operations again in 4 seconds
operationTimeout = setTimeout(() => { operationStatusCheck(); }, 4000);
}
});
}
function reloadPageContent() {
clearTimeout(pageReloadTimeout);
//Check Authorization
$.get("./php/aaa/authentication.php?action=validateAuthentication", function (data) {
$.get("./backend/aaa/authentication.php?action=validateAuthentication", function (data) {
operationData = JSON.parse(data);
if (operationData.status_code != 200) {
console.log(operationData);
window.location = './index.html'
window.location.href = './index.php'
}
});
$('#networkAclListTable').DataTable().ajax.reload(null, false);
//Set reload page content
pageReloadTimeout = setTimeout(() => { reloadPageContent(); }, reloadTime);
}
function loadPageContent(){
//Display current logged in username
$("#username").load("./php/admin/settings.php?action=displayUsername");
$("#username").load("./backend/admin/settings.php?action=displayUsername");
$('#networkAclListTable').DataTable( {
ajax: "./php/lxd/network-acls.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listNetworkAcls",
ajax: "./backend/lxd/network-acls.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listNetworkAcls",
columns: [
{},
{ title: "Name" },
@ -459,17 +498,23 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
});
//Check for any running operations
operationStatusCheck();
operationTimeout = setTimeout(() => { operationStatusCheck(); }, 1000);
//Set reload page content
$.get("./backend/admin/settings.php?action=retrievePageRefreshRateValues", function (data) {
operationData = JSON.parse(data);
if (operationData.network_acls_page_rate >= 1)
reloadTime = operationData.network_acls_page_rate * 1000;
pageReloadTimeout = setTimeout(() => { reloadPageContent(); }, reloadTime);
});
//Set the page content to reload in 5 seconds
setInterval(() => { reloadPageContent(); }, 5000);
}
function createNetworkAclUsingForm(){
var networkAclNameCreate = $("#networkAclNameCreate").val();
var networkAclDescriptionCreate = $("#networkAclDescriptionCreate").val();
console.log("Info: creating network acl");
$.get("./php/lxd/network-acls.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&name=" + encodeURI(networkAclNameCreate) + "&description=" + encodeURI(networkAclDescriptionCreate) + "&action=createNetworkAclUsingForm", function (data) {
$.get("./backend/lxd/network-acls.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&name=" + encodeURI(networkAclNameCreate) + "&description=" + encodeURI(networkAclDescriptionCreate) + "&action=createNetworkAclUsingForm", function (data) {
//Async type
var operationData = JSON.parse(data);
console.log(operationData);
@ -484,7 +529,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
function createNetworkAclUsingJSON(){
var networkAclCreateJSON = $("#jsonCreateInput").val();
console.log("Info: creating network acl");
$.post("./php/lxd/network-acls.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=createNetworkAclUsingJSON", {json: networkAclCreateJSON}, function (data) {
$.post("./backend/lxd/network-acls.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=createNetworkAclUsingJSON", {json: networkAclCreateJSON}, function (data) {
//Async type
var operationData = JSON.parse(data);
console.log(operationData);
@ -496,11 +541,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
});
}
//Called by Edit action, loads JSON data of network acl
function loadNetworkAclJson(networkAclToLoad){
console.log("Info: loading network acl " + networkAclToLoad);
networkAclToUpdate = networkAclToLoad;
$.get("./php/lxd/network-acls.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&network_acl=" + encodeURI(networkAclToLoad) + "&action=loadNetworkAcl", function (data) {
$.get("./backend/lxd/network-acls.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&network_acl=" + encodeURI(networkAclToLoad) + "&action=loadNetworkAcl", function (data) {
//Sync type
var operationData = JSON.parse(data);
console.log(operationData);
@ -523,7 +567,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
function updateNetworkAcl(){
var networkAclUpdateJSON = $("#jsonEditInput").val();
console.log("Info: updating network acl " + networkAclToUpdate);
$.post("./php/lxd/network-acls.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&network_acl=" + encodeURI(networkAclToUpdate) + "&action=updateNetworkAcl", {json: networkAclUpdateJSON}, function (data) {
$.post("./backend/lxd/network-acls.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&network_acl=" + encodeURI(networkAclToUpdate) + "&action=updateNetworkAcl", {json: networkAclUpdateJSON}, function (data) {
//Sync type
var operationData = JSON.parse(data);
console.log(operationData);
@ -538,7 +582,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
var networkAclName = $("#newNetworkAclName").val();
var networkAcl = $("#networkAclToRename").val();
console.log("Info: renaming network acl " + networkAcl);
$.get("./php/lxd/network-acls.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&network_acl=" + encodeURI(networkAcl) + "&name=" + encodeURI(networkAclName) + "&action=renameNetworkAcl", function (data) {
$.get("./backend/lxd/network-acls.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&network_acl=" + encodeURI(networkAcl) + "&name=" + encodeURI(networkAclName) + "&action=renameNetworkAcl", function (data) {
//Sync operation type
var operationData = JSON.parse(data);
console.log(operationData);
@ -551,7 +595,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
function deleteNetworkAcl(networkAclToDelete){
console.log("Info: deleting network acl " + networkAclToDelete);
$.get("./php/lxd/network-acls.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&network_acl=" + encodeURI(networkAclToDelete) + "&action=deleteNetworkAcl", function (data) {
$.get("./backend/lxd/network-acls.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&network_acl=" + encodeURI(networkAclToDelete) + "&action=deleteNetworkAcl", function (data) {
//Sync type
var operationData = JSON.parse(data);
console.log(operationData);
@ -562,33 +606,64 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
});
}
function setSidebarToggleValue(){
sidebarState = localStorage.getItem('sidebarState');
if (sidebarState == "collapsed"){
localStorage.setItem('sidebarState','expanded');
}
else {
localStorage.setItem('sidebarState','collapsed');
}
}
function applySidebarToggleValue() {
sidebarState = localStorage.getItem('sidebarState');
if (sidebarState == "collapsed"){
$("body").toggleClass("sidebar-toggled"),
$(".sidebar").toggleClass("toggled"),
$(".sidebar").hasClass("toggled") && $(".sidebar .collapse").collapse("hide")
}
}
applySidebarToggleValue();
$(document).ready(function(){
//Check Authorization
$.get("./php/aaa/authentication.php?action=validateAuthentication", function (data) {
$.get("./backend/aaa/authentication.php?action=validateAuthentication", function (data) {
operationData = JSON.parse(data);
if (operationData.status_code != 200) {
console.log(operationData);
window.location = './index.html'
window.location.href = './index.php'
}
});
//Load in the sidebar
$("#sidebarLinks").load("./sidebar.html");
$("#sidebarLinks").load("./sidebar.php?version=3.0");
//Setup Page Breadcrumb Links/Information
$('#remoteBreadCrumb').load("./php/lxd/remote-breadcrumb.php?remote=" + encodeURI(remoteId));
$('#remoteBreadCrumb').attr("href", "remotes-single.html?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$('#networkAclsBreadCrumb').text("network-acls");
$('#remoteBreadCrumb').load("./backend/lxd/remote-breadcrumb.php?remote=" + encodeURI(remoteId));
$('#remoteBreadCrumb').attr("href", "remotes-single.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
//Validate remote host connection returns 200 status
$.get("./backend/lxd/remotes-single.php?remote=" + encodeURI(remoteId) + "&action=validateRemoteConnection", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code == 200) {
//Set top navbar dropdowns
$("#remoteListNav").load("./backend/lxd/remotes.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listRemotesForSelectOption");
$("#projectListNav").load("./backend/lxd/projects.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listProjectsForSelectOption");
//Load the card contents
loadPageContent();
$("#remoteListNav").load("./php/lxd/remotes.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listRemotesForTopNavigation");
$("#projectListNav").load("./php/lxd/projects.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listProjectsForTopNavigation");
//Load Page Content
loadPageContent();
}
else {
alert("Unable to connect to remote host. HTTP status code: " + operationData.status_code);
}
});
//Load the about info for the about modal
$.get("./about.html", function (data) {
$.get("./backend/config/about.php", function (data) {
$("#about").html(data);
});

View file

@ -37,7 +37,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Custom styles for this template-->
<link href="vendor/sb-admin-2/css/sb-admin-2.css" rel="stylesheet">
<link href="assets/css/style.css" rel="stylesheet">
<link href="assets/css/style.css?version=3.0" rel="stylesheet">
<!-- Custom styles for this page -->
<link href="vendor/datatables/dataTables.bootstrap4.min.css" rel="stylesheet">
@ -50,7 +50,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<div id="wrapper">
<!-- Sidebar -->
<ul class="navbar-nav bg-dark sidebar sidebar-dark accordion" id="accordionSidebar">
<ul class="navbar-nav bg-dark sidebar sidebar-dark accordion sidebar-divider-right" id="accordionSidebar">
<div id="sidebarLinks"></div>
@ -59,12 +59,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Sidebar Toggler (Sidebar) -->
<div class="text-center d-none d-md-inline">
<button class="rounded-circle border-0" id="sidebarToggle"></button>
<button class="rounded-circle border-0" id="sidebarToggle" onclick="setSidebarToggleValue()"></button>
</div>
</ul>
<!-- End of Sidebar -->
<!-- Content Wrapper -->
<div id="content-wrapper" class="d-flex flex-column">
@ -79,37 +78,44 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<i class="fa fa-bars"></i>
</button>
<!-- Topbar Notification -->
<div class="d-none d-sm-inline-block form-inline mr-auto ml-md-3 my-2 my-md-0 mw-100 navbar-search">
<ul class="navbar-nav ml-auto">
<li>
<div class="nav-item spinner-border m-3" role="status" style="display:none;" id="spinner">
<span class="nav-item sr-only">Loading...</span>
</div>
</li>
<li class="nav-item dropdown no-arrow" id="notificationArea" style="display: none;">
<div class="nav-link dropdown-toggle">
<span id="notification" class="mr-2 d-none d-lg-inline text-gray-600">Notification</span>
<span id="notification" class="mr-2 d-none d-lg-inline text-danger">Notification</span>
</div>
</li>
</ul>
</div>
<!-- Topbar Navbar -->
<ul class="navbar-nav ml-auto">
<!-- Topbar Navbar -->
<ul class="navbar-nav ml-auto">
<li class="nav-item dropdown">
<label class="h6 mt-4 mr-2 ml-4">Host: </label>
</li>
<li class="nav-item dropdown">
<div class="input-group mt-3">
<select class="form-control" id="remoteListNav" style="width:150px;" onchange="location = this.value;">
</select>
</div>
</li>
<li class="nav-item dropdown" id="remoteListNav">
</li>
<li class="nav-item dropdown">
<label class="h6 mt-4 mr-2 ml-4">Project: </label>
</li>
<li class="nav-item dropdown">
<div class="input-group mt-3">
<select class="form-control" id="projectListNav" style="width:150px;" onchange="location = this.value;">
</select>
</div>
</li>
<li class="nav-item dropdown" id="projectListNav">
</li>
<div class="topbar-divider d-none d-sm-block"></div>
<!-- Nav Divider -->
<div class="topbar-divider d-none d-sm-block"></div>
<!-- Nav Item - User Information -->
<li class="nav-item dropdown no-arrow">
@ -119,14 +125,18 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</a>
<!-- Dropdown - User Information -->
<div class="dropdown-menu dropdown-menu-right shadow animated--grow-in" aria-labelledby="userDropdown">
<a class="dropdown-item" href="user-profile.html">
<a class="dropdown-item" href="user-profile.php">
<i class="fas fa-user fa-sm fa-fw mr-2 text-gray-400"></i>
Profile
</a>
<a class="dropdown-item" href="settings.html">
<a class="dropdown-item" href="settings.php">
<i class="fas fa-cog fa-sm fa-fw mr-2 text-gray-400"></i>
Settings
</a>
<a class="dropdown-item" href="logs.php">
<i class="fas fa-history fa-sm fa-fw mr-2 text-gray-400"></i>
Logs
</a>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#aboutModal">
<i class="fas fa-info-circle fa-sm fa-fw mr-2 text-gray-400"></i>
About
@ -147,25 +157,48 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Begin Page Content -->
<div class="container-fluid">
<!-- BreadCrumb -->
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="#" id="remoteBreadCrumb"></a></li>
<li class="breadcrumb-item active" aria-current="page" id="networksBreadCrumb"></li>
</ol>
</nav>
<header class="page-header page-header-dark bg-gradient-primary-to-secondary">
<div class="container-xl px-4">
<div class="page-header-content pt-4">
<div class="row align-items-center justify-content-between mt-n5 ml-n5 mr-n5 bg-dark pb-6">
<div class="col-auto mt-4 ml-3">
<div class="page-header-subtitle">
<a href="#" id="remoteBreadCrumb"></a>
</div>
<h2 class="page-header-title mt-2">
NETWORKS
</h2>
<div class="page-header-subtitle">
Create and manage LXD networks
</div>
</div>
<div class="col-12 col-xl-auto mt-4">
<div class="input-group input-group-joined border-0" style="width: 14rem">
<span class="input-group-text bg-transparent border-0">
<a class="btn btn-outline-primary" href="#" onclick="loadCreateNetworkModal()" title="New Network" aria-hidden="true">
<i class="fas fa-plus fa-sm fa-fw"></i> Network
</a>
</span>
</div>
</div>
</div>
</div>
</div>
</header>
<div class="row">
<div class="row mt-n5 ml-2 mr-2">
<div class="col-12">
<div class="col-12 mt-n3">
<!-- Network List -->
<div class="card shadow mb-4">
<!-- Card Header - Dropdown -->
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">Networks</h6>
<h6 class="m-0 font-weight-bold">
<span class="ml-1">Networks</span>
</h6>
<div class="dropdown no-arrow">
<a class="dropdown-toggle mr-2" href="#" onclick="loadCreateNetworkModal()" title="New Network" aria-hidden="true">
<i class="fas fa-plus fa-sm fa-fw"></i> Network</a>
<a class="dropdown-toggle mr-2" href="#" onclick="reloadPageContent()" title="Refresh" aria-hidden="true">
<i class="fa fa-sync fa-1x fa-fw"></i></a>
</div>
</div>
<!-- Card Body -->
@ -191,7 +224,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<footer class="sticky-footer bg-white">
<div class="container my-auto">
<div class="copyright text-center my-auto">
<span>Copyright &copy; lxdware.com 2021</span>
<span>Copyright &copy; LXDWARE 2020 - Present</span>
</div>
</div>
</footer>
@ -208,7 +241,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<i class="fas fa-angle-up"></i>
</a>
<!-- Create Network Modal-->
<div class="modal fade" id="createNetworkModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
@ -232,18 +264,18 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<div class="tab-pane fade show active" id="form" role="tabpanel" aria-labelledby="form-tab">
<div class="modal-body">
<div class="row">
<label class="col-3 col-form-label text-right">Name: </label>
<label class="col-3 col-form-label text-right">Name: <span class="text-danger">*</span></label>
<div class="col-7">
<div class="form-group">
<input type="text" id="networkNameInput" class="form-control" placeholder="" name="networkNameInput">
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle text-danger" title='(Required) - Enter the name of this network.'></i>
<i class="far fa-sm fa-question-circle" title='(Required) - Enter the name of this network.'></i>
</div>
</div>
<div class="row">
<label class="col-3 col-form-label text-right">Network Type: </label>
<label class="col-3 col-form-label text-right">Network Type: <span class="text-danger">*</span></label>
<div class="col-7">
<div class="form-group">
<select id="networkTypeInput" onchange="changeNetworkTypeInput()" class="form-control" name="networkTypeInput">
@ -256,11 +288,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle text-danger" title='(Required) - Select the type of network. Default: bridge'></i>
<i class="far fa-sm fa-question-circle" title='(Required) - Select the type of network. Default: bridge'></i>
</div>
</div>
<div class="row" id="networkParentRow" style="display: none;">
<label class="col-3 col-form-label text-right">Parent: </label>
<label class="col-3 col-form-label text-right">Parent: <span class="text-danger">*</span></label>
<div class="col-7">
<div class="form-group">
<select id="networkParentInput" onchange="" class="form-control" name="networkParentInput">
@ -268,11 +300,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle text-danger" title='(Required) - Select the parent interface to create the network on'></i>
<i class="far fa-sm fa-question-circle" title='(Required) - Select the parent interface to create the network on'></i>
</div>
</div>
<div class="row" id="networkNetworkRow" style="display: none;">
<label class="col-3 col-form-label text-right">Network: </label>
<label class="col-3 col-form-label text-right">Network: <span class="text-danger">*</span></label>
<div class="col-7">
<div class="form-group">
<select id="networkNetworkInput" onchange="" class="form-control" name="networkNetworkInput">
@ -280,7 +312,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle text-danger" title='(Required) - Select the uplink network interface for external connections.'></i>
<i class="far fa-sm fa-question-circle" title='(Required) - Select the uplink network interface for external connections.'></i>
</div>
</div>
<div class="row">
@ -955,14 +987,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</div>
<div class="modal-body">
<div class="row">
<label class="col-3 col-form-label text-right" id="newNetworkNameLabel">Name:</label>
<label class="col-3 col-form-label text-right" id="newNetworkNameLabel">Name: <span class="text-danger">*</span></label>
<div class="col-7">
<div class="form-group">
<input type="text" id="newNetworkName" class="form-control" placeholder="">
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle text-danger" title='(Required) - Enter in a new name for the network.'></i>
<i class="far fa-sm fa-question-circle" title='(Required) - Enter in a new name for the network.'></i>
</div>
</div>
<input type="hidden" id ="networkToRename" name="networkToRename">
@ -1021,61 +1053,66 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
const remoteId = urlParams.get('remote');
const projectName = urlParams.get('project');
var networkToUpdate = "";
var reloadTime = 5000;
function logout(){
$.get("./php/aaa/authentication.php?action=deauthenticateUser", function (data) {
$.get("./backend/aaa/authentication.php?action=deauthenticateUser", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code == 200) {
window.location = './index.html'
window.location.href = './index.php'
}
});
}
function operationStatusCheck(){
clearTimeout(operationTimeout);
//check to see if there are any running operations
$.get("./php/lxd/operations.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayOperationStatus", function (data) {
$.get("./backend/lxd/operations.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayOperationStatus", function (data) {
//Check to see if we have running operations
if (data){
//Display spinner and notification area if there are running tasks
$('#spinner').show();
if (data) {
//Display notification area if there are running tasks
$('#notificationArea').show();
$('#notification').text(data);
//Set the page to check operations again in 1 second
setTimeout(() => { operationStatusCheck(); }, 1000);
$('#notification').text("Notice: " + data);
//Set the page to check operations again in 2 seconds
operationTimeout = setTimeout(() => { operationStatusCheck(); }, 2000);
}
else {
//Hide spinner and notification area if no running tasks
$('#spinner').hide();
//Hide notification area if no running tasks
$('#notificationArea').hide();
$('#notification').text("");
//Set the page to check operations again in 3 seconds
setTimeout(() => { operationStatusCheck(); }, 3000);
//Set the page to check operations again in 4 seconds
operationTimeout = setTimeout(() => { operationStatusCheck(); }, 4000);
}
});
}
function reloadPageContent() {
clearTimeout(pageReloadTimeout);
//Check Authorization
$.get("./php/aaa/authentication.php?action=validateAuthentication", function (data) {
$.get("./backend/aaa/authentication.php?action=validateAuthentication", function (data) {
operationData = JSON.parse(data);
if (operationData.status_code != 200) {
console.log(operationData);
window.location = './index.html'
window.location.href = './index.php'
}
});
$('#networkListTable').DataTable().ajax.reload(null, false);
//Set reload page content
pageReloadTimeout = setTimeout(() => { reloadPageContent(); }, reloadTime);
}
function loadPageContent(){
//Display current logged in username
$("#username").load("./php/admin/settings.php?action=displayUsername");
$("#username").load("./backend/admin/settings.php?action=displayUsername");
$('#networkListTable').DataTable( {
ajax: "./php/lxd/networks.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listNetworks",
ajax: "./backend/lxd/networks.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listNetworks",
columns: [
{},
{ title: "Name" },
@ -1093,10 +1130,16 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
});
//Check for any running operations
operationStatusCheck();
operationTimeout = setTimeout(() => { operationStatusCheck(); }, 1000);
//Set reload page content
$.get("./backend/admin/settings.php?action=retrievePageRefreshRateValues", function (data) {
operationData = JSON.parse(data);
if (operationData.networks_page_rate >= 1)
reloadTime = operationData.networks_page_rate * 1000;
pageReloadTimeout = setTimeout(() => { reloadPageContent(); }, reloadTime);
});
//Set the page content to reload in 5 seconds
setInterval(() => { reloadPageContent(); }, 5000);
}
function createNetworkUsingForm(){
@ -1153,7 +1196,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
var networkOvnIngressModeInput = $("#networkOvnIngressModeInput").val();
console.log("Info: creating network");
$.get("./php/lxd/networks.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) +
$.get("./backend/lxd/networks.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) +
"&name=" + encodeURI(networkNameInput) +
"&type=" + encodeURI(networkTypeInput) +
"&description=" + encodeURI(networkDescriptionInput) +
@ -1220,7 +1263,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
function createNetworkUsingJSON(){
var networkCreateJSON = $("#jsonCreateInput").val();
console.log("Info: creating network");
$.post("./php/lxd/networks.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=createNetworkUsingJSON", {json: networkCreateJSON}, function (data) {
$.post("./backend/lxd/networks.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=createNetworkUsingJSON", {json: networkCreateJSON}, function (data) {
//Async type
var operationData = JSON.parse(data);
console.log(operationData);
@ -1232,11 +1275,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
});
}
//Called by Edit action, loads JSON data of network
function loadNetworkJson(networkToLoad){
console.log("Info: loading network " + networkToLoad);
networkToUpdate = networkToLoad;
$.get("./php/lxd/networks.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&network=" + encodeURI(networkToLoad) + "&action=loadNetwork", function (data) {
$.get("./backend/lxd/networks.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&network=" + encodeURI(networkToLoad) + "&action=loadNetwork", function (data) {
//Sync type
var operationData = JSON.parse(data);
console.log(operationData);
@ -1259,7 +1301,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
function updateNetwork(){
var networkUpdateJSON = $("#jsonEditInput").val();
console.log("Info: updating network " + networkToUpdate);
$.post("./php/lxd/networks.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&network=" + encodeURI(networkToUpdate) + "&action=updateNetwork", {json: networkUpdateJSON}, function (data) {
$.post("./backend/lxd/networks.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&network=" + encodeURI(networkToUpdate) + "&action=updateNetwork", {json: networkUpdateJSON}, function (data) {
//Sync type
var operationData = JSON.parse(data);
console.log(operationData);
@ -1274,7 +1316,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
var networkName = $("#newNetworkName").val();
var network = $("#networkToRename").val();
console.log("Info: renaming network " + network);
$.get("./php/lxd/networks.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&network=" + encodeURI(network) + "&name=" + encodeURI(networkName) + "&action=renameNetwork", function (data) {
$.get("./backend/lxd/networks.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&network=" + encodeURI(network) + "&name=" + encodeURI(networkName) + "&action=renameNetwork", function (data) {
//Sync operation type
var operationData = JSON.parse(data);
console.log(operationData);
@ -1287,7 +1329,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
function deleteNetwork(networkToDelete){
console.log("Info: deleting network " + networkToDelete);
$.get("./php/lxd/networks.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&network=" + encodeURI(networkToDelete) + "&action=deleteNetwork", function (data) {
$.get("./backend/lxd/networks.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&network=" + encodeURI(networkToDelete) + "&action=deleteNetwork", function (data) {
//Sync type
var operationData = JSON.parse(data);
console.log(operationData);
@ -1300,8 +1342,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
function loadCreateNetworkModal(){
console.log("Info: loading create network modal");
$("#networkParentInput").load("./php/lxd/networks.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listNetworksForSelectOption");
$("#networkNetworkInput").load("./php/lxd/networks.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&managed_only=true" + "&action=listNetworksForSelectOption");
$("#networkParentInput").load("./backend/lxd/networks.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listNetworksForSelectOption");
$("#networkNetworkInput").load("./backend/lxd/networks.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&managed_only=true" + "&action=listNetworksForSelectOption");
changeNetworkTypeInput();
$("#createNetworkModal").modal('show');
}
@ -1511,33 +1553,64 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
}
}
function setSidebarToggleValue(){
sidebarState = localStorage.getItem('sidebarState');
if (sidebarState == "collapsed"){
localStorage.setItem('sidebarState','expanded');
}
else {
localStorage.setItem('sidebarState','collapsed');
}
}
function applySidebarToggleValue() {
sidebarState = localStorage.getItem('sidebarState');
if (sidebarState == "collapsed"){
$("body").toggleClass("sidebar-toggled"),
$(".sidebar").toggleClass("toggled"),
$(".sidebar").hasClass("toggled") && $(".sidebar .collapse").collapse("hide")
}
}
applySidebarToggleValue();
$(document).ready(function(){
//Check Authorization
$.get("./php/aaa/authentication.php?action=validateAuthentication", function (data) {
$.get("./backend/aaa/authentication.php?action=validateAuthentication", function (data) {
operationData = JSON.parse(data);
if (operationData.status_code != 200) {
console.log(operationData);
window.location = './index.html'
window.location.href = './index.php'
}
});
//Load in the sidebar
$("#sidebarLinks").load("./sidebar.html");
$("#sidebarLinks").load("./sidebar.php?version=3.0");
//Setup Page Breadcrumb Links/Information
$('#remoteBreadCrumb').load("./php/lxd/remote-breadcrumb.php?remote=" + encodeURI(remoteId));
$('#remoteBreadCrumb').attr("href", "remotes-single.html?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$('#networksBreadCrumb').text("networks");
$('#remoteBreadCrumb').load("./backend/lxd/remote-breadcrumb.php?remote=" + encodeURI(remoteId));
$('#remoteBreadCrumb').attr("href", "remotes-single.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
//Load the card contents
loadPageContent();
//Validate remote host connection returns 200 status
$.get("./backend/lxd/remotes-single.php?remote=" + encodeURI(remoteId) + "&action=validateRemoteConnection", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code == 200) {
//Set top navbar dropdowns
$("#remoteListNav").load("./backend/lxd/remotes.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listRemotesForSelectOption");
$("#projectListNav").load("./backend/lxd/projects.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listProjectsForSelectOption");
//Load Page Content
loadPageContent();
}
else {
alert("Unable to connect to remote host. HTTP status code: " + operationData.status_code);
}
});
$("#remoteListNav").load("./php/lxd/remotes.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listRemotesForTopNavigation");
$("#projectListNav").load("./php/lxd/projects.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listProjectsForTopNavigation");
//Load the about info for the about modal
$.get("./about.html", function (data) {
$.get("./backend/config/about.php", function (data) {
$("#about").html(data);
});

View file

@ -37,7 +37,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Custom styles for this template-->
<link href="vendor/sb-admin-2/css/sb-admin-2.css" rel="stylesheet">
<link href="assets/css/style.css" rel="stylesheet">
<link href="assets/css/style.css?version=3.0" rel="stylesheet">
<!-- Custom styles for this page -->
<link href="vendor/datatables/dataTables.bootstrap4.min.css" rel="stylesheet">
@ -50,7 +50,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<div id="wrapper">
<!-- Sidebar -->
<ul class="navbar-nav bg-dark sidebar sidebar-dark accordion" id="accordionSidebar">
<ul class="navbar-nav bg-dark sidebar sidebar-dark accordion sidebar-divider-right" id="accordionSidebar">
<div id="sidebarLinks"></div>
@ -59,7 +59,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Sidebar Toggler (Sidebar) -->
<div class="text-center d-none d-md-inline">
<button class="rounded-circle border-0" id="sidebarToggle"></button>
<button class="rounded-circle border-0" id="sidebarToggle" onclick="setSidebarToggleValue()"></button>
</div>
</ul>
<!-- End of Sidebar -->
@ -79,36 +79,43 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<i class="fa fa-bars"></i>
</button>
<!-- Topbar Notification -->
<div class="d-none d-sm-inline-block form-inline mr-auto ml-md-3 my-2 my-md-0 mw-100 navbar-search">
<ul class="navbar-nav ml-auto">
<li>
<div class="nav-item spinner-border m-3" role="status" style="display:none;" id="spinner">
<span class="nav-item sr-only">Loading...</span>
</div>
</li>
<li class="nav-item dropdown no-arrow" id="notificationArea" style="display: none;">
<div class="nav-link dropdown-toggle">
<span id="notification" class="mr-2 d-none d-lg-inline text-gray-600">Notification</span>
<span id="notification" class="mr-2 d-none d-lg-inline text-danger">Notification</span>
</div>
</li>
</ul>
</div>
<!-- Topbar Navbar -->
<ul class="navbar-nav ml-auto">
<li class="nav-item dropdown" id="remoteListNav">
<li class="nav-item dropdown">
<label class="h6 mt-4 mr-2 ml-4">Host: </label>
</li>
<li class="nav-item dropdown">
<div class="input-group mt-3">
<select class="form-control" id="remoteListNav" style="width:150px;" onchange="location = this.value;">
</select>
</div>
</li>
<li class="nav-item dropdown" id="projectListNav">
<li class="nav-item dropdown">
<label class="h6 mt-4 mr-2 ml-4">Project: </label>
</li>
<li class="nav-item dropdown">
<div class="input-group mt-3">
<select class="form-control" id="projectListNav" style="width:150px;" onchange="location = this.value;">
</select>
</div>
</li>
<!-- Nav Divider -->
<div class="topbar-divider d-none d-sm-block"></div>
<!-- Nav Item - User Information -->
@ -119,14 +126,18 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</a>
<!-- Dropdown - User Information -->
<div class="dropdown-menu dropdown-menu-right shadow animated--grow-in" aria-labelledby="userDropdown">
<a class="dropdown-item" href="user-profile.html">
<a class="dropdown-item" href="user-profile.php">
<i class="fas fa-user fa-sm fa-fw mr-2 text-gray-400"></i>
Profile
</a>
<a class="dropdown-item" href="settings.html">
<a class="dropdown-item" href="settings.php">
<i class="fas fa-cog fa-sm fa-fw mr-2 text-gray-400"></i>
Settings
</a>
<a class="dropdown-item" href="logs.php">
<i class="fas fa-history fa-sm fa-fw mr-2 text-gray-400"></i>
Logs
</a>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#aboutModal">
<i class="fas fa-info-circle fa-sm fa-fw mr-2 text-gray-400"></i>
About
@ -147,23 +158,45 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Begin Page Content -->
<div class="container-fluid">
<!-- BreadCrumb -->
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="#" id="remoteBreadCrumb"></a></li>
<li class="breadcrumb-item active" aria-current="page" id="operationsBreadCrumb"></li>
</ol>
</nav>
<header class="page-header page-header-dark bg-gradient-primary-to-secondary">
<div class="container-xl px-4">
<div class="page-header-content pt-4">
<div class="row align-items-center justify-content-between mt-n5 ml-n5 mr-n5 bg-dark pb-6">
<div class="col-auto mt-4 ml-3">
<div class="page-header-subtitle">
<a href="#" id="remoteBreadCrumb"></a>
</div>
<h2 class="page-header-title mt-2">
OPERATIONS
</h2>
<div class="page-header-subtitle">
Manage LXD host operations
</div>
</div>
<div class="col-12 col-xl-auto mt-4">
<div class="input-group input-group-joined border-0" style="width: 14rem">
<span class="input-group-text bg-transparent border-0">
</span>
</div>
</div>
</div>
</div>
</div>
</header>
<div class="row">
<div class="row mt-n5 ml-2 mr-2">
<div class="col-12">
<div class="col-12 mt-n3">
<!-- Operations List -->
<div class="card shadow mb-4">
<!-- Card Header - Dropdown -->
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">Operations</h6>
<h6 class="m-0 font-weight-bold">
<span class="ml-1">Operations</span>
</h6>
<div class="dropdown no-arrow">
<a class="dropdown-toggle mr-2" href="#" onclick="reloadPageContent()" title="Refresh" aria-hidden="true">
<i class="fa fa-sync fa-1x fa-fw"></i></a>
</div>
</div>
<!-- Card Body -->
@ -189,7 +222,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<footer class="sticky-footer bg-white">
<div class="container my-auto">
<div class="copyright text-center my-auto">
<span>Copyright &copy; lxdware.com 2021</span>
<span>Copyright &copy; LXDWARE 2020 - Present</span>
</div>
</div>
</footer>
@ -280,61 +313,66 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
const urlParams = new URLSearchParams(queryString);
const remoteId = urlParams.get('remote');
const projectName = urlParams.get('project');
var reloadTime = 3000;
function logout(){
$.get("./php/aaa/authentication.php?action=deauthenticateUser", function (data) {
$.get("./backend/aaa/authentication.php?action=deauthenticateUser", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code == 200) {
window.location = './index.html'
window.location.href = './index.php'
}
});
}
function operationStatusCheck(){
clearTimeout(operationTimeout);
//check to see if there are any running operations
$.get("./php/lxd/operations.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayOperationStatus", function (data) {
$.get("./backend/lxd/operations.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayOperationStatus", function (data) {
//Check to see if we have running operations
if (data){
//Display spinner and notification area if there are running tasks
$('#spinner').show();
if (data) {
//Display notification area if there are running tasks
$('#notificationArea').show();
$('#notification').text(data);
//Set the page to check operations again in 1 second
setTimeout(() => { operationStatusCheck(); }, 1000);
$('#notification').text("Notice: " + data);
//Set the page to check operations again in 2 seconds
operationTimeout = setTimeout(() => { operationStatusCheck(); }, 2000);
}
else {
//Hide spinner and notification area if no running tasks
$('#spinner').hide();
//Hide notification area if no running tasks
$('#notificationArea').hide();
$('#notification').text("");
//Set the page to check operations again in 3 seconds
setTimeout(() => { operationStatusCheck(); }, 3000);
//Set the page to check operations again in 4 seconds
operationTimeout = setTimeout(() => { operationStatusCheck(); }, 4000);
}
});
}
function reloadPageContent(){
clearTimeout(pageReloadTimeout);
//Check Authorization
$.get("./php/aaa/authentication.php?action=validateAuthentication", function (data) {
$.get("./backend/aaa/authentication.php?action=validateAuthentication", function (data) {
operationData = JSON.parse(data);
if (operationData.status_code != 200) {
console.log(operationData);
window.location = './index.html'
window.location.href = './index.php'
}
});
$('#operationListTable').DataTable().ajax.reload(null, false);
//Set reload page content
pageReloadTimeout = setTimeout(() => { reloadPageContent(); }, reloadTime);
}
function loadPageContent(){
//Display current logged in username
$("#username").load("./php/admin/settings.php?action=displayUsername");
$("#username").load("./backend/admin/settings.php?action=displayUsername");
$('#operationListTable').DataTable( {
ajax: "./php/lxd/operations.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listOperations",
ajax: "./backend/lxd/operations.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listOperations",
columns: [
{},
{ title: "ID" },
@ -352,15 +390,21 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
});
//Check for any running operations
operationStatusCheck();
operationTimeout = setTimeout(() => { operationStatusCheck(); }, 1000);
//Set reload page content
$.get("./backend/admin/settings.php?action=retrievePageRefreshRateValues", function (data) {
operationData = JSON.parse(data);
if (operationData.operations_page_rate >= 1)
reloadTime = operationData.operations_page_rate * 1000;
pageReloadTimeout = setTimeout(() => { reloadPageContent(); }, reloadTime);
});
//Set the page content to reload in 3 seconds
setInterval(() => { reloadPageContent(); }, 3000);
}
function loadOperationJson(operationToLoad){
console.log("Info: loading operation " + operationToLoad);
$.get("./php/lxd/operations.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&operation=" + encodeURI(operationToLoad) + "&action=loadOperation", function (data) {
$.get("./backend/lxd/operations.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&operation=" + encodeURI(operationToLoad) + "&action=loadOperation", function (data) {
//Sync type
var operationData = JSON.parse(data);
console.log(operationData);
@ -375,7 +419,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
function deleteOperation(operationToDelete){
console.log("Info: deleting operation " + operationToDelete);
$.get("./php/lxd/operations.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&operation=" + encodeURI(operationToDelete) + "&action=deleteOperation", function (data) {
$.get("./backend/lxd/operations.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&operation=" + encodeURI(operationToDelete) + "&action=deleteOperation", function (data) {
//Sync type
var operationData = JSON.parse(data);
console.log(operationData);
@ -386,33 +430,64 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
});
}
function setSidebarToggleValue(){
sidebarState = localStorage.getItem('sidebarState');
if (sidebarState == "collapsed"){
localStorage.setItem('sidebarState','expanded');
}
else {
localStorage.setItem('sidebarState','collapsed');
}
}
function applySidebarToggleValue() {
sidebarState = localStorage.getItem('sidebarState');
if (sidebarState == "collapsed"){
$("body").toggleClass("sidebar-toggled"),
$(".sidebar").toggleClass("toggled"),
$(".sidebar").hasClass("toggled") && $(".sidebar .collapse").collapse("hide")
}
}
applySidebarToggleValue();
$(document).ready(function(){
//Check Authorization
$.get("./php/aaa/authentication.php?action=validateAuthentication", function (data) {
$.get("./backend/aaa/authentication.php?action=validateAuthentication", function (data) {
operationData = JSON.parse(data);
if (operationData.status_code != 200) {
console.log(operationData);
window.location = './index.html'
window.location.href = './index.php'
}
});
//Load in the sidebar
$("#sidebarLinks").load("./sidebar.html");
$("#sidebarLinks").load("./sidebar.php?version=3.0");
//Setup Page Breadcrumb Links/Information
$('#remoteBreadCrumb').load("./php/lxd/remote-breadcrumb.php?remote=" + encodeURI(remoteId));
$('#remoteBreadCrumb').attr("href", "remotes-single.html?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$('#operationsBreadCrumb').text("operations");
$('#remoteBreadCrumb').load("./backend/lxd/remote-breadcrumb.php?remote=" + encodeURI(remoteId));
$('#remoteBreadCrumb').attr("href", "remotes-single.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
//Load the card contents
loadPageContent();
//Validate remote host connection returns 200 status
$.get("./backend/lxd/remotes-single.php?remote=" + encodeURI(remoteId) + "&action=validateRemoteConnection", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code == 200) {
//Set top navbar dropdowns
$("#remoteListNav").load("./backend/lxd/remotes.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listRemotesForSelectOption");
$("#projectListNav").load("./backend/lxd/projects.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listProjectsForSelectOption");
//Load Page Content
loadPageContent();
}
else {
alert("Unable to connect to remote host. HTTP status code: " + operationData.status_code);
}
});
$("#remoteListNav").load("./php/lxd/remotes.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listRemotesForTopNavigation");
$("#projectListNav").load("./php/lxd/projects.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listProjectsForTopNavigation");
//Load the about info for the about modal
$.get("./about.html", function (data) {
$.get("./backend/config/about.php", function (data) {
$("#about").html(data);
});

View file

@ -1,120 +0,0 @@
<?php
/*
LXDWARE LXD Dashboard - A web-based interface for managing LXD servers
Copyright (C) 2020-2021 LXDWARE.COM
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//Start session if not already started
if (!isset($_SESSION)) {
session_start();
}
//Declare and instantiate GET variables
$action = (isset($_GET['action'])) ? filter_var(urldecode($_GET['action']), FILTER_SANITIZE_STRING) : "";
$project = (isset($_GET['project'])) ? filter_var(urldecode($_GET['project']), FILTER_SANITIZE_STRING) : "";
$remote = (isset($_GET['remote'])) ? filter_var(urldecode($_GET['remote']), FILTER_SANITIZE_NUMBER_INT) : "";
//Declare and instantiate POST variables
$username = (isset($_POST['username'])) ? filter_var(urldecode($_POST['username']), FILTER_SANITIZE_STRING) : "";
$password = (isset($_POST['password'])) ? filter_var(urldecode($_POST['password']), FILTER_SANITIZE_STRING) : "";
//Require code from lxd-dashboard/php/config/db.php
require_once('../config/db.php');
//Require code from lxd-dashboard/php/aaa/authorization.php
require_once('../aaa/authorization.php');
//Require code from lxd-dashboard/php/aaa/accounting.php
require_once('../aaa/accounting.php');
//Run the matching action
switch ($action) {
case "authenticateUser":
//Determine user info from database
foreach (retrieveUserRecord($username) as $record){
$user_id = $record['id'];
$passwd_hash = $record['passwd_hash'];
}
//Verify password matches existing database passwd_hash
if (password_verify($password, $passwd_hash)) {
//Store username and user_id in SESSION variable
$_SESSION['username'] = $username;
$_SESSION['user_id'] = $user_id;
//Get all the roles that the user belongs to
$roles = array();
foreach (retrieveUserRoles($user_id) as $role){
array_push($roles, $role['name']);
}
//Make sure array only has unique values
$roles = array_unique($roles);
//Get array of contols based on the user's roles
$controls = getControls($roles);
//Store user's controls in a SESSION array
$_SESSION['controls'] = $controls;
$results = '{"status": "Ok", "status_code": 200, "metadata": "{}"}';
}
else {
//Return 401 Unauthorized despite it technically being unauthenticated
$results = '{"status": "Unauthorized", "status_code": 401, "metadata": {"error": "Incorrect username or password"}}';
}
echo $results;
//Send event to accounting
$event = json_decode($results, true);
$object = $username;
logEvent($action, $remote, $project, $object, $event['status_code'], $event['status']);
break;
case "deauthenticateUser":
$username = $_SESSION['username'];
//Clear the SESSION variables
$_SESSION = array();
if (session_destroy())
$results = '{"status": "Ok", "status_code": 200, "metadata": "{}"}';
echo $results;
//Send event to accounting
$event = json_decode($results, true);
$object = $username;
logEvent($action, $remote, $project, $object, $event['status_code'], $event['status']);
break;
case "validateAuthentication":
if (isset($_SESSION['username'])){
echo '{"status": "Ok", "status_code": 200, "metadata": "{}"}';
}
else {
echo '{"status": "Unauthorized", "status_code": 401, "metadata": {"error": "Failed authentication validation"}}';
}
break;
default:
echo "LXDWARE";
}
?>

View file

@ -1,489 +0,0 @@
<?php
/*
LXDWARE LXD Dashboard - A web-based interface for managing LXD servers
Copyright (C) 2020-2021 LXDWARE.COM
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//Start session if not already started
if (!isset($_SESSION)) {
session_start();
}
//Declare and instantiate GET variables
$action = (isset($_GET['action'])) ? filter_var(urldecode($_GET['action']), FILTER_SANITIZE_STRING) : "";
$description = (isset($_GET['description'])) ? filter_var(urldecode($_GET['description']), FILTER_SANITIZE_STRING) : "";
$id = (isset($_GET['id'])) ? filter_var(urldecode($_GET['id']), FILTER_SANITIZE_NUMBER_INT) : "";
$group_id = (isset($_GET['group_id'])) ? filter_var(urldecode($_GET['group_id']), FILTER_SANITIZE_NUMBER_INT) : "";
$name = (isset($_GET['name'])) ? filter_var(urldecode($_GET['name']), FILTER_SANITIZE_STRING) : "";
$project = (isset($_GET['project'])) ? filter_var(urldecode($_GET['project']), FILTER_SANITIZE_STRING) : "";
$remote = (isset($_GET['remote'])) ? filter_var(urldecode($_GET['remote']), FILTER_SANITIZE_NUMBER_INT) : "";
$role_id = (isset($_GET['role_id'])) ? filter_var(urldecode($_GET['role_id']), FILTER_SANITIZE_NUMBER_INT) : "";
//Declare and instantiate POST variables
$email = (isset($_POST['email'])) ? filter_var(urldecode($_POST['email']), FILTER_SANITIZE_STRING) : "";
$first_name = (isset($_POST['first_name'])) ? filter_var(urldecode($_POST['first_name']), FILTER_SANITIZE_STRING) : "";
$last_name = (isset($_POST['last_name'])) ? filter_var(urldecode($_POST['last_name']), FILTER_SANITIZE_STRING) : "";
$password = (isset($_POST['password'])) ? $_POST['password'] : "";
$username = (isset($_POST['username'])) ? filter_var(urldecode($_POST['username']), FILTER_SANITIZE_STRING) : "";
//Require code from lxd-dashboard/php/config/db.php
require_once('../config/db.php');
//Require code from lxd-dashboard/php/aaa/accounting.php
require_once('../aaa/accounting.php');
if (isset($_SESSION['username'])) {
require_once('../aaa/authorization.php');
//Run the matching action
switch ($action) {
case "addRoleToGroup":
if (validateAuthorization($action)) {
$record_added = addGroupRoleMapping($id, $role_id);
if ($record_added)
$results = '{"status": "Ok", "status_code": 200, "metadata": {"status": "Record added"}}';
else
$results = '{"status": "Bad Request", "status_code": 400, "metadata": {"error": "Unable to add the record to the database"}}';
}
else {
$results = '{"status": "Forbidden", "status_code": 403, "metadata": {"error": "You are not authorized to execute this action"}}';
}
echo $results;
//Send event to accounting
$event = json_decode($results, true);
$object = $id . " - " . $role_id;
logEvent($action, $remote, $project, $object, $event['status_code'], $event['status']);
break;
case "addUserToGroup":
if (validateAuthorization($action)) {
$record_added = addUserGroupMapping($id, $group_id);
if ($record_added)
$results = '{"status": "Ok", "status_code": 200, "metadata": {"status": "Record added"}}';
else
$results = '{"status": "Bad Request", "status_code": 400, "metadata": {"error": "Unable to add the record to the database"}}';
}
else {
$results = '{"status": "Forbidden", "status_code": 403, "metadata": {"error": "You are not authorized to execute this action"}}';
}
echo $results;
//Send event to accounting
$event = json_decode($results, true);
$object = $id . " - " . $group_id;
logEvent($action, $remote, $project, $object, $event['status_code'], $event['status']);
break;
case "createGroup":
if (validateAuthorization($action)) {
$record_added = addGroup($name, $description);
if($record_added){
$results = '{"status": "Ok", "status_code": 200, "metadata": "{}"}';
$group_id = retrieveGroupId($name);
}
else {
$results = '{"status": "Bad Request", "status_code": 400, "metadata": {"error": "Unable to add the record to the database"}}';
}
}
else {
$results = '{"status": "Forbidden", "status_code": 403, "metadata": {"error": "You are not authorized to execute this action"}}';
}
echo $results;
//Send event to accounting
$event = json_decode($results, true);
$object = $group_id . " - " . $name;
logEvent($action, $remote, $project, $object, $event['status_code'], $event['status']);
break;
case "createUser":
if (validateAuthorization($action)) {
//Test to verify username and password both have a value
if (!empty($username) && !empty($password)) {
//Hash and salt password with bcrypt
$passwd_hash = password_hash($password, PASSWORD_BCRYPT);
if(isFirstUser()){
$record_added = addUser($username, $first_name, $last_name, $passwd_hash, $email);
if($record_added){
$user_id = retrieveUserId($username);
$group_id = retrieveGroupId('admin');
addUserGroupMapping($user_id, $group_id);
}
$results = '{"status": "Ok", "status_code": 200, "metadata": "{}"}';
}
else {
$record_added = addUser($username, $first_name, $last_name, $passwd_hash, $email);
if($record_added){
$user_id = retrieveUserId($username);
$group_id = retrieveGroupId('auditor');
if($group_id){
addUserGroupMapping($user_id, $group_id);
}
$results = '{"status": "Ok", "status_code": 200, "metadata": "{}"}';
}
else {
$results = '{"status": "Bad Request", "status_code": 400, "metadata": {"error": "Unable to add the record to the database"}}';
}
}
}
else {
$results = '{"status": "Bad Request", "status_code": 400, "metadata": {"error": "Both a username and password must be supplied"}}';
}
}
else {
$results = '{"status": "Forbidden", "status_code": 403, "metadata": {"error": "You are not authorized to execute this action"}}';
}
echo $results;
//Send event to accounting
$event = json_decode($results, true);
$object = $user_id . " - " . $username;
logEvent($action, $remote, $project, $object, $event['status_code'], $event['status']);
break;
case "deleteGroup":
if (validateAuthorization($action)) {
$record_removed = deleteGroup($id);
if ($record_removed)
$results = '{"status": "Ok", "status_code": 200, "metadata": {"status": "Record removed"}}';
else
$results = '{"status": "Bad Request", "status_code": 400, "metadata": {"error": "Unable to remove record from database"}}';
}
else {
$results = '{"status": "Forbidden", "status_code": 403, "metadata": {"error": "You are not authorized to execute this action"}}';
}
echo $results;
//Send event to accounting
$event = json_decode($results, true);
$object = $id;
logEvent($action, $remote, $project, $object, $event['status_code'], $event['status']);
break;
case "deleteUser":
if (validateAuthorization($action)) {
$record_removed = deleteUser($id);
if ($record_removed)
$results = '{"status": "Ok", "status_code": 200, "metadata": {"status": "Record removed"}}';
else
$results = '{"status": "Bad Request", "status_code": 400, "metadata": {"error": "Unable to remove record from database"}}';
}
else {
$results = '{"status": "Forbidden", "status_code": 403, "metadata": {"error": "You are not authorized to execute this action"}}';
}
echo $results;
//Send event to accounting
$event = json_decode($results, true);
$object = $id;
logEvent($action, $remote, $project, $object, $event['status_code'], $event['status']);
break;
case "displayUsername":
echo htmlentities($_SESSION['username']);
break;
case "listGroups":
if (validateAuthorization($action)) {
$rows = retrieveTableRows('lxd_groups');
$i = 0;
echo '{ "data": [';
foreach ($rows as $row){
$roles = retrieveGroupRoles($row['id']);
$users = retrieveGroupUsers($row['id']);
if ($i > 0){
echo ",";
}
$i++;
echo "[ ";
echo '"';
echo "<i class='fas fa-users fa-lg' style='color:#4e73df'></i>";
echo '",';
echo '"' . htmlentities($row['name']) . '",';
echo '"' . htmlentities($row['description']) . '",';
echo '"';
$ii = 0;
foreach ($roles as $role){
if ($ii > 0){
echo ", ";
}
$ii++;
echo htmlentities($role['name']);
}
echo '",';
echo '"';
echo "<a href='#' onclick='loadAddRoleModal(".$row['id'].")'><i class='fas fa-plus fa-lg' style='color:#ddd' title='Add Role' aria-hidden='true'></i></a>";
echo ' &nbsp ';
echo "<a href='#' onclick='loadRemoveRoleModal(".$row['id'].")'><i class='fas fa-minus fa-lg' style='color:#ddd' title='Remove Role' aria-hidden='true'></i></a>";
echo ' &nbsp ';
echo "<a href='#' onclick='loadDeleteGroupModal(".$row['id'].")'><i class='fas fa-trash-alt fa-lg' style='color:#ddd' title='Delete Group' aria-hidden='true'></i></a>";
echo '"';
echo " ]";
}
echo " ]}";
}
else {
echo '{ "data": [] }';
}
break;
case "listGroupsAssignedToUserForSelect":
if (validateAuthorization($action)) {
$groups = retrieveUserGroups($id);
foreach ($groups as $group){
echo '<option value="' . $group['id'] . '">' . htmlentities($group['name']) . '</option>';
}
}
break;
case "listGroupsNotAssignedToUserForSelect":
if (validateAuthorization($action)) {
$groups = retrieveTableRows('lxd_groups');
$user_groups = retrieveUserGroups($id);
foreach ($groups as $group){
$group_belongs_to_user = false;
foreach ($user_groups as $user_group){
if ($user_group['name'] == $group['name']){
$group_belongs_to_user = true;
}
}
if(!$group_belongs_to_user){
echo '<option value="' . $group['id'] . '">' . htmlentities($group['name']) . '</option>';
}
}
}
break;
case "listRolesAssignedToGroupForSelect":
if (validateAuthorization($action)) {
$roles = retrieveGroupRoles($id);
foreach ($roles as $role){
echo '<option value="' . $role['id'] . '">' . htmlentities($role['name']) . '</option>';
}
}
break;
case "listRolesNotAssignedToGroupForSelect":
if (validateAuthorization($action)) {
$roles = retrieveDefaultRoles();
$group_roles = retrieveGroupRoles($id);
foreach ($roles as $role){
$role_belongs_to_group = false;
foreach ($group_roles as $group_role){
if ($group_role['name'] == $role['name']){
$role_belongs_to_group = true;
}
}
if(!$role_belongs_to_group){
echo '<option value="' . $role['id'] . '">' . htmlentities($role['name']) . '</option>';
}
}
}
break;
case "listUsers":
if (validateAuthorization($action)) {
$rows = retrieveTableRows('lxd_users');
$i = 0;
echo '{ "data": [';
foreach ($rows as $row){
$groups = retrieveUserGroups($row['id']);
if ($i > 0){
echo ",";
}
$i++;
echo "[ ";
echo '"';
echo "<a href='user-profile.html?user=".$row['id']."'><i class='fas fa-user fa-lg' style='color:#4e73df'></i> </a>";
echo '",';
echo '"';
echo "<a href='user-profile.html?user=".$row['id']."'> ".htmlentities($row['username'])."</a>";
echo '",';
echo '"' . htmlentities($row['email']) . '",';
echo '"' . htmlentities($row['type']) . '",';
echo '"';
$ii = 0;
foreach ($groups as $group){
if ($ii > 0){
echo ", ";
}
$ii++;
echo htmlentities($group['name']);
}
echo '",';
echo '"';
echo "<a href='#' onclick='loadAddGroupModal(".$row['id'].")'><i class='fas fa-plus fa-lg' style='color:#ddd' title='Add Group' aria-hidden='true'></i></a>";
echo ' &nbsp ';
echo "<a href='#' onclick='loadRemoveGroupModal(".$row['id'].")'><i class='fas fa-minus fa-lg' style='color:#ddd' title='Remove Group' aria-hidden='true'></i></a>";
echo ' &nbsp ';
echo "<a href='#' onclick='loadDeleteUserModal(".$row['id'].")'><i class='fas fa-trash-alt fa-lg' style='color:#ddd' title='Delete User' aria-hidden='true'></i></a>";
echo '"';
echo " ]";
}
echo " ]}";
}
else {
echo '{ "data": [] }';
}
break;
case "removeGroupFromUser":
if (validateAuthorization($action)) {
$record_removed = deleteUserGroupMapping($id, $group_id);
if ($record_removed)
$results = '{"status": "Ok", "status_code": 200, "metadata": {"status": "Record removed"}}';
else
$results = '{"status": "Bad Request", "status_code": 400, "metadata": {"error": "Unable to remove record from database"}}';
}
else {
$results = '{"status": "Forbidden", "status_code": 403, "metadata": {"error": "You are not authorized to execute this action"}}';
}
echo $results;
//Send event to accounting
$event = json_decode($results, true);
$object = $id . " - " . $group_id;
logEvent($action, $remote, $project, $object, $event['status_code'], $event['status']);
break;
case "removeRoleFromGroup":
if (validateAuthorization($action)) {
$record_removed = deleteGroupRoleMapping($id, $role_id);
if ($record_removed)
$results = '{"status": "Ok", "status_code": 200, "metadata": {"status": "Record removed"}}';
else
$results = '{"status": "Bad Request", "status_code": 400, "metadata": {"error": "Unable to remove record from database"}}';
}
else {
$results = '{"status": "Forbidden", "status_code": 403, "metadata": {"error": "You are not authorized to execute this action"}}';
}
echo $results;
//Send event to accounting
$event = json_decode($results, true);
$object = $id . " - " . $role_id;
logEvent($action, $remote, $project, $object, $event['status_code'], $event['status']);
break;
}
}
else {
switch ($action) {
case "createUser":
//Test to verify username and password both have a value
if (!empty($username) && !empty($password)) {
//Hash and salt password with bcrypt
$passwd_hash = password_hash($password, PASSWORD_BCRYPT);
if(isFirstUser()){
$record_added = addUser($username, $first_name, $last_name, $passwd_hash, $email);
if($record_added){
$user_id = retrieveUserId($username);
$group_id = retrieveGroupId('admin');
addUserGroupMapping($user_id, $group_id);
}
$results = '{"status": "Ok", "status_code": 200, "metadata": "{}"}';
}
else {
$results = '{"status": "Bad Request", "status_code": 400, "metadata": {"error": "User was not added as there are already existing user accounts"}}';
}
}
else {
$results = '{"status": "Bad Request", "status_code": 400, "metadata": {"error": "Must supply both a username and password"}}';
}
echo $results;
break;
}
}
?>

View file

@ -1,70 +0,0 @@
<?php
/*
LXDWARE LXD Dashboard - A web-based interface for managing LXD servers
Copyright (C) 2020-2021 LXDWARE.COM
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//Start session if not already started
if (!isset($_SESSION)) {
session_start();
}
//Create Certificate if it does not already exist
if (!file_exists('/var/lxdware/data/lxd/client.crt')){
$subject = array(
"commonName" => "LXDWARE",
);
//Generate a new private (and public) key pair
$private_key = openssl_pkey_new(array(
"private_key_type" => OPENSSL_KEYTYPE_EC,
"curve_name" => 'secp384r1',
));
//Generate a certificate signing request
$csr = openssl_csr_new($subject, $private_key);
//Generate self-signed EC cert
$x509 = openssl_csr_sign($csr, null, $private_key, $days=3650);
openssl_x509_export_to_file($x509, '/var/lxdware/data/lxd/client.crt');
openssl_pkey_export_to_file($private_key, '/var/lxdware/data/lxd/client.key');
//Change permissions on private key
chmod('/var/lxdware/data/lxd/client.key',0600);
}
if (isset($_SESSION['username'])) {
//Declare and instantiate GET variables
$action = (isset($_GET['action'])) ? filter_var(urldecode($_GET['action']), FILTER_SANITIZE_STRING) : "";
require_once('../aaa/authorization.php');
//Run the matching action
switch ($action) {
case "viewCertificate":
if (validateAuthorization($action)) {
$results = shell_exec("cat /var/lxdware/data/lxd/client.crt");
echo htmlentities($results);
}
else {
echo "You are not authorized to view the certificate";
}
break;
}
}
?>

View file

@ -1,878 +0,0 @@
<?php
/*
LXDWARE LXD Dashboard - A web-based interface for managing LXD servers
Copyright (C) 2020-2021 LXDWARE.COM
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//Start session if not already started
if (!isset($_SESSION)) {
session_start();
}
function establishDatabaseConnection(){
//Require db_config.php file
require_once('/var/lxdware/data/db_config.php');
switch (DB_TYPE) {
case "sqlite":
$_SESSION['db_type'] = "SQLite";
$conn = new PDO('sqlite:/var/lxdware/data/sqlite/lxdware.sqlite');
break;
}
return $conn;
}
/*
===================================================================================
Initialize Table Functions
===================================================================================
*/
function initializeEventsTable(){
$db = establishDatabaseConnection();
if ($_SESSION['db_type'] == "SQLite"){
$db->exec('CREATE TABLE IF NOT EXISTS lxd_events (id INTEGER PRIMARY KEY AUTOINCREMENT, control TEXT, remote_id INTEGER, project TEXT, object TEXT, status_code INT, message TEXT, hostname TEXT, user_id INT, date DATETIME)');
}
$db = null;
}
function initializeHostsTable(){
$db = establishDatabaseConnection();
if ($_SESSION['db_type'] == "SQLite"){
$db->exec('CREATE TABLE IF NOT EXISTS lxd_hosts (id INTEGER PRIMARY KEY AUTOINCREMENT, host TEXT NOT NULL, port INTEGER NOT NULL, alias TEXT, protocol TEXT, user_id INTEGER)');
//If needed, upgrade database table schema from LXD Dashboard version 1.x.x to 2.x.x
$stmt = $db->query("PRAGMA table_info(lxd_hosts)");
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (!in_array('user_id', $results)){
$stmt = $db->query("ALTER TABLE lxd_hosts ADD COLUMN user_id INTEGER");
$stmt = $db->query("UPDATE lxd_hosts SET user_id = 0");
}
}
$db = null;
}
function initializeGroupsRolesMappingTable(){
$db = establishDatabaseConnection();
if ($_SESSION['db_type'] == "SQLite"){
$db->exec('CREATE TABLE IF NOT EXISTS lxd_groups_roles_mapping (id INTEGER PRIMARY KEY AUTOINCREMENT, group_id INTEGER NOT NULL, role_id INTEGER NOT NULL)');
}
//Map admin group to ADMIN role
$group_id = retrieveGroupId('admin');
$role_id = retrieveRoleId('ADMIN');
$stmt = $db->prepare('INSERT INTO lxd_groups_roles_mapping (group_id, role_id) VALUES (:group_id, :role_id)');
$stmt->bindValue(':group_id', $group_id, PDO::PARAM_INT);
$stmt->bindValue(':role_id', $role_id, PDO::PARAM_INT);
$stmt->execute();
$return_val = $stmt->fetchColumn();
//Map operator group to OPERATOR role
$group_id = retrieveGroupId('operator');
$role_id = retrieveRoleId('OPERATOR');
$stmt = $db->prepare('INSERT INTO lxd_groups_roles_mapping (group_id, role_id) VALUES (:group_id, :role_id)');
$stmt->bindValue(':group_id', $group_id, PDO::PARAM_INT);
$stmt->bindValue(':role_id', $role_id, PDO::PARAM_INT);
$stmt->execute();
$return_val = $stmt->fetchColumn();
//Map user group to USER role
$group_id = retrieveGroupId('user');
$role_id = retrieveRoleId('USER');
$stmt = $db->prepare('INSERT INTO lxd_groups_roles_mapping (group_id, role_id) VALUES (:group_id, :role_id)');
$stmt->bindValue(':group_id', $group_id, PDO::PARAM_INT);
$stmt->bindValue(':role_id', $role_id, PDO::PARAM_INT);
$stmt->execute();
$return_val = $stmt->fetchColumn();
//Map auditor group to AUDITOR role
$group_id = retrieveGroupId('auditor');
$role_id = retrieveRoleId('AUDITOR');
$stmt = $db->prepare('INSERT INTO lxd_groups_roles_mapping (group_id, role_id) VALUES (:group_id, :role_id)');
$stmt->bindValue(':group_id', $group_id, PDO::PARAM_INT);
$stmt->bindValue(':role_id', $role_id, PDO::PARAM_INT);
$stmt->execute();
$return_val = $stmt->fetchColumn();
$db = null;
}
function initializeGroupsTable(){
$db = establishDatabaseConnection();
if ($_SESSION['db_type'] == "SQLite"){
$db->exec('CREATE TABLE IF NOT EXISTS lxd_groups (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL UNIQUE, description TEXT)');
}
$adminGroupExists = false;
$operatorGroupExists = false;
$userGroupExists = false;
$auditorGroupExists = false;
$rows = $db->query('SELECT * FROM lxd_groups');
foreach ($rows as $row){
if ($row['name'] == "admin")
$adminGroupExists = true;
if ($row['name'] == "operator")
$operatorGroupExists = true;
if ($row['name'] == "user")
$userGroupExists = true;
if ($row['name'] == "auditor")
$auditorGroupExists = true;
}
if (!$adminGroupExists){
$db->exec('INSERT INTO lxd_groups (name, description) VALUES ("admin", "Default group granting users the ADMIN role permissions")');
}
if (!$operatorGroupExists){
$db->exec('INSERT INTO lxd_groups (name, description) VALUES ("operator", "Default group granting users the OPERATOR role permissions")');
}
if (!$userGroupExists){
$db->exec('INSERT INTO lxd_groups (name, description) VALUES ("user", "Default group granting users the USER role permissions")');
}
if (!$auditorGroupExists){
$db->exec('INSERT INTO lxd_groups (name, description) VALUES ("auditor", "Default group granting users the AUDITOR role permissions")');
}
$db = null;
}
function initializeRolesTable(){
$db = establishDatabaseConnection();
if ($_SESSION['db_type'] == "SQLite"){
$db->exec('CREATE TABLE IF NOT EXISTS lxd_roles (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL UNIQUE, description TEXT)');
}
//Default Roles
$adminRoleExists = false;
$operatorRoleExists = false;
$userRoleExists = false;
$auditorRoleExists = false;
//Extended Roles
$certificateOperatorRoleExists = false;
$clusterMemeberOperatorRoleExists = false;
$imageOperatorRoleExists = false;
$instanceOperatorRoleExists = false;
$networkOperatorRoleExists = false;
$operationOperatorRoleExists = false;
$profileOperatorRoleExists = false;
$projectOperatorRoleExists = false;
$remoteOperatorRoleExists = false;
$simplestreamsOperatorRoleExists = false;
$storagePoolOperatorRoleExists = false;
$storageVolumeOperatorRoleExists = false;
$rows = $db->query('SELECT * from lxd_roles');
foreach ($rows as $row){
//Default Roles
if ($row['name'] == "ADMIN")
$adminRoleExists = true;
if ($row['name'] == "OPERATOR")
$operatorRoleExists = true;
if ($row['name'] == "USER")
$userRoleExists = true;
if ($row['name'] == "AUDITOR")
$auditorRoleExists = true;
//Extended Roles
if ($row['name'] == "CERTIFICATE_OPERATOR")
$certificateOperatorRoleExists = true;
if ($row['name'] == "CLUSTER_MEMBER_OPERATOR")
$clusterMemeberOperatorRoleExists = true;
if ($row['name'] == "IMAGE_OPERATOR")
$imageOperatorRoleExists = true;
if ($row['name'] == "INSTANCE_OPERATOR")
$instanceOperatorRoleExists = true;
if ($row['name'] == "NETWORK_OPERATOR")
$networkOperatorRoleExists = true;
if ($row['name'] == "OPERATION_OPERATOR")
$operationOperatorRoleExists = true;
if ($row['name'] == "PROFILE_OPERATOR")
$profileOperatorRoleExists = true;
if ($row['name'] == "PROJECT_OPERATOR")
$projectOperatorRoleExists = true;
if ($row['name'] == "REMOTE_OPERATOR")
$remoteOperatorRoleExists = true;
if ($row['name'] == "SIMPLESTREAMS_OPERATOR")
$simplestreamsOperatorRoleExists = true;
if ($row['name'] == "STORAGE_POOL_OPERATOR")
$storagePoolOperatorRoleExists = true;
if ($row['name'] == "STORAGE_VOLUME_OPERATOR")
$storageVolumeOperatorRoleExists = true;
}
//Default Roles
if (!$adminRoleExists){
$db->exec('INSERT INTO lxd_roles (name, description) VALUES ("ADMIN", "Administer users, groups, and all LXD services")');
}
if (!$operatorRoleExists){
$db->exec('INSERT INTO lxd_roles (name, description) VALUES ("OPERATOR", "Administer all LXD services")');
}
if (!$userRoleExists){
$db->exec('INSERT INTO lxd_roles (name, description) VALUES ("USER", "Perform basic lifecycle tasks of instances")');
}
if (!$auditorRoleExists){
$db->exec('INSERT INTO lxd_roles (name, description) VALUES ("AUDITOR", "View resources")');
}
//Extended Roles
if (!$certificateOperatorRoleExists){
$db->exec('INSERT INTO lxd_roles (name, description) VALUES ("CERTIFICATE_OPERATOR", "Permissions include adding, deleting, and updating certificates")');
}
if (!$clusterMemeberOperatorRoleExists){
$db->exec('INSERT INTO lxd_roles (name, description) VALUES ("CLUSTER_MEMBER_OPERATOR", "Permissions include removing cluster members")');
}
if (!$imageOperatorRoleExists){
$db->exec('INSERT INTO lxd_roles (name, description) VALUES ("IMAGE_OPERATOR", "Permissions include downloading, editing, and deleteing images")');
}
if (!$instanceOperatorRoleExists){
$db->exec('INSERT INTO lxd_roles (name, description) VALUES ("INSTANCE_OPERATOR", "Permissions include creating, deleting, and updating instances")');
}
if (!$networkOperatorRoleExists){
$db->exec('INSERT INTO lxd_roles (name, description) VALUES ("NETWORK_OPERATOR", "Permissions include creating, deleting, and updating networks and network ACLs")');
}
if (!$operationOperatorRoleExists){
$db->exec('INSERT INTO lxd_roles (name, description) VALUES ("OPERATION_OPERATOR", "Permissions include deleting operations")');
}
if (!$profileOperatorRoleExists){
$db->exec('INSERT INTO lxd_roles (name, description) VALUES ("PROFILE_OPERATOR", "Permissions include creating, deleting, and updating profiles")');
}
if (!$projectOperatorRoleExists){
$db->exec('INSERT INTO lxd_roles (name, description) VALUES ("PROJECT_OPERATOR", "Permissions include creating, deleting, and updating projects")');
}
if (!$remoteOperatorRoleExists){
$db->exec('INSERT INTO lxd_roles (name, description) VALUES ("REMOTE_OPERATOR", "Permissions include adding and removing remote LXD hosts")');
}
if (!$simplestreamsOperatorRoleExists){
$db->exec('INSERT INTO lxd_roles (name, description) VALUES ("SIMPLESTREAMS_OPERATOR", "Permissions include adding and removing remote Simplestreams hosts")');
}
if (!$storagePoolOperatorRoleExists){
$db->exec('INSERT INTO lxd_roles (name, description) VALUES ("STORAGE_POOL_OPERATOR", "Permissions include creating, deleting, and updating storage pools")');
}
if (!$storageVolumeOperatorRoleExists){
$db->exec('INSERT INTO lxd_roles (name, description) VALUES ("STORAGE_VOLUME_OPERATOR", "Permissions include creating, deleting, and updating storge volumes")');
}
$db = null;
}
function initializeSimplestreamsTable(){
$db = establishDatabaseConnection();
if ($_SESSION['db_type'] == "SQLite"){
$db->exec('CREATE TABLE IF NOT EXISTS lxd_simplestreams (id INTEGER PRIMARY KEY AUTOINCREMENT, host TEXT NOT NULL, alias TEXT, protocol TEXT, user_id INTEGER)');
//If needed, upgrade database table schema from LXD Dashboard version 1.x.x to 2.x.x
$stmt = $db->query("PRAGMA table_info(lxd_simplestreams)");
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (!in_array('user_id', $results)){
$stmt = $db->query("ALTER TABLE lxd_simplestreams ADD COLUMN user_id INTEGER");
$stmt = $db->query("UPDATE lxd_simplestreams SET user_id = 0");
}
}
$imagesSimplestreamsExists = false;
$ubuntuSimplestreamsExists = false;
$ubuntuDailySimplestreamsExists = false;
$rows = $db->query('SELECT * FROM lxd_simplestreams');
foreach ($rows as $row){
if ($row['host'] == "https://images.linuxcontainers.org")
$imagesSimplestreamsExists = true;
if ($row['host'] == "https://cloud-images.ubuntu.com/releases")
$ubuntuSimplestreamsExists = true;
if ($row['host'] == "https://cloud-images.ubuntu.com/daily")
$ubuntuDailySimplestreamsExists = true;
}
if (!$imagesSimplestreamsExists){
$db->exec('INSERT INTO lxd_simplestreams (host, alias, protocol, user_id) VALUES ("https://images.linuxcontainers.org", "images", "simplestreams", 0)');
}
if (!$ubuntuSimplestreamsExists){
$db->exec('INSERT INTO lxd_simplestreams (host, alias, protocol, user_id) VALUES ("https://cloud-images.ubuntu.com/releases", "ubuntu", "simplestreams", 0)');
}
if (!$ubuntuDailySimplestreamsExists){
$db->exec('INSERT INTO lxd_simplestreams (host, alias, protocol, user_id) VALUES ("https://cloud-images.ubuntu.com/daily", "ubuntu-daily", "simplestreams", 0)');
}
$db = null;
}
function initializeUsersGroupsMappingTable(){
$db = establishDatabaseConnection();
if ($_SESSION['db_type'] == "SQLite"){
$db->exec('CREATE TABLE IF NOT EXISTS lxd_users_groups_mapping (id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, group_id INTEGER NOT NULL)');
}
$db = null;
}
function initializeUsersTable(){
$db = establishDatabaseConnection();
if ($_SESSION['db_type'] == "SQLite"){
$db->exec('CREATE TABLE IF NOT EXISTS lxd_users (id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT NOT NULL UNIQUE, first_name TEXT, last_name TEXT, passwd_hash TEXT NOT NULL, email TEXT, type TEXT)');
}
$db = null;
}
function initializeAllTables(){
initializeUsersTable();
initializeGroupsTable();
initializeRolesTable();
initializeHostsTable();
initializeSimplestreamsTable();
initializeUsersGroupsMappingTable();
initializeGroupsRolesMappingTable();
initializeEventsTable();
}
/*
===================================================================================
Add Record to Table Functions
===================================================================================
*/
function addEvent($control, $remote_id, $project, $object, $status_code, $message, $hostname, $user_id){
$db = establishDatabaseConnection();
try{
$stmt = $db->prepare("INSERT INTO lxd_events (control, remote_id, project, object, status_code, message, hostname, user_id, date) VALUES (:control, :remote_id, :project, :object, :status_code, :message, :hostname, :user_id, datetime('now'))");
$stmt->bindValue(':control', $control, PDO::PARAM_STR);
$stmt->bindValue(':remote_id', $remote_id, PDO::PARAM_INT);
$stmt->bindValue(':project', $project, PDO::PARAM_STR);
$stmt->bindValue(':object', $object, PDO::PARAM_STR);
$stmt->bindValue(':status_code', $status_code, PDO::PARAM_INT);
$stmt->bindValue(':message', $message, PDO::PARAM_STR);
$stmt->bindValue(':hostname', $hostname, PDO::PARAM_STR);
$stmt->bindValue(':user_id', $user_id, PDO::PARAM_INT);
$stmt->execute();
}
catch (\Error $e) {
initializeAllTables();
$stmt = $db->prepare("INSERT INTO lxd_events (control, remote_id, project, object, status_code, message, hostname, user_id, date) VALUES (:control, :remote_id, :project, :object, :status_code, :message, :hostname, :user_id, datetime('now'))");
$stmt->bindValue(':control', $control, PDO::PARAM_STR);
$stmt->bindValue(':remote_id', $remote_id, PDO::PARAM_INT);
$stmt->bindValue(':project', $project, PDO::PARAM_STR);
$stmt->bindValue(':object', $object, PDO::PARAM_STR);
$stmt->bindValue(':status_code', $status_code, PDO::PARAM_INT);
$stmt->bindValue(':message', $message, PDO::PARAM_STR);
$stmt->bindValue(':hostname', $hostname, PDO::PARAM_STR);
$stmt->bindValue(':user_id', $user_id, PDO::PARAM_INT);
$stmt->execute();
}
$db = null;
return $stmt;
}
function addHost($host, $port, $alias){
$db = establishDatabaseConnection();
$stmt = $db->prepare('INSERT INTO lxd_hosts (host, port, alias, protocol, user_id) VALUES (:host, :port, :alias, "lxd", :user_id)');
$stmt->bindValue(':host', $host, PDO::PARAM_STR);
$stmt->bindValue(':port', $port, PDO::PARAM_INT);
$stmt->bindValue(':alias', $alias, PDO::PARAM_STR);
$stmt->bindValue(':user_id', $_SESSION['user_id'], PDO::PARAM_INT);
$stmt->execute();
$db = null;
return $stmt;
}
function addSimplestreams($host, $alias){
$db = establishDatabaseConnection();
$stmt = $db->prepare('INSERT INTO lxd_simplestreams (host, alias, protocol, user_id) VALUES (:host, :alias, "simplestreams", :user_id)');
$stmt->bindValue(':host', $host, PDO::PARAM_STR);
$stmt->bindValue(':alias', $alias, PDO::PARAM_STR);
$stmt->bindValue(':user_id', $_SESSION['user_id'], PDO::PARAM_INT);
$stmt->execute();
$db = null;
return $stmt;
}
function addUser($username, $first_name, $last_name, $passwd_hash, $email){
$db = establishDatabaseConnection();
$stmt = $db->prepare('INSERT INTO lxd_users (username, first_name, last_name, passwd_hash, email, type) VALUES (:username, :first_name, :last_name, :passwd_hash, :email, "local")');
$stmt->bindValue(':username', $username, PDO::PARAM_STR);
$stmt->bindValue(':first_name', $first_name, PDO::PARAM_STR);
$stmt->bindValue(':last_name', $last_name, PDO::PARAM_STR);
$stmt->bindValue(':passwd_hash', $passwd_hash, PDO::PARAM_STR);
$stmt->bindValue(':email', $email, PDO::PARAM_STR);
$stmt->execute();
$db = null;
return $stmt;
}
function addGroup($name, $description){
$db = establishDatabaseConnection();
$stmt = $db->prepare('INSERT INTO lxd_groups (name, description) VALUES (:name, :description)');
$stmt->bindValue(':name', $name, PDO::PARAM_STR);
$stmt->bindValue(':description', $description, PDO::PARAM_STR);
$stmt->execute();
$db = null;
return $stmt;
}
function addUserGroupMapping($user_id, $group_id) {
$db = establishDatabaseConnection();
$stmt = $db->prepare('INSERT INTO lxd_users_groups_mapping (user_id, group_id) VALUES (:user_id, :group_id)');
$stmt->bindValue(':user_id', $user_id, PDO::PARAM_INT);
$stmt->bindValue(':group_id', $group_id, PDO::PARAM_INT);
$stmt->execute();
$db = null;
return $stmt;
}
function addGroupRoleMapping($group_id, $role_id) {
$db = establishDatabaseConnection();
$stmt = $db->prepare('INSERT INTO lxd_groups_roles_mapping (group_id, role_id) VALUES (:group_id, :role_id)');
$stmt->bindValue(':group_id', $group_id, PDO::PARAM_INT);
$stmt->bindValue(':role_id', $role_id, PDO::PARAM_INT);
$stmt->execute();
$db = null;
return $stmt;
}
/*
===================================================================================
Delete Record from Table Functions
===================================================================================
*/
function deleteHost($id){
$db = establishDatabaseConnection();
$stmt = $db->prepare('DELETE FROM lxd_hosts WHERE id = :id');
$stmt->bindValue(':id', $id, PDO::PARAM_INT);
$stmt->execute();
$db = null;
return $stmt;
}
function deleteSimplestreams($id){
$db = establishDatabaseConnection();
$stmt = $db->prepare('DELETE FROM lxd_simplestreams WHERE id = :id');
$stmt->bindValue(':id', $id, PDO::PARAM_INT);
$stmt->execute();
$db = null;
return $stmt;
}
function deleteUser($id){
$db = establishDatabaseConnection();
$stmt = $db->prepare('DELETE FROM lxd_users WHERE id = :id');
$stmt->bindValue(':id', $id, PDO::PARAM_INT);
$stmt->execute();
$stmt = $db->prepare('DELETE FROM lxd_users_groups_mapping WHERE user_id = :id');
$stmt->bindValue(':id', $id, PDO::PARAM_INT);
$stmt->execute();
$db = null;
return $stmt;
}
function deleteGroup($id){
$db = establishDatabaseConnection();
$stmt = $db->prepare('DELETE FROM lxd_groups WHERE id = :id');
$stmt->bindValue(':id', $id, PDO::PARAM_INT);
$stmt->execute();
$stmt = $db->prepare('DELETE FROM lxd_groups_roles_mapping WHERE group_id = :id');
$stmt->bindValue(':id', $id, PDO::PARAM_INT);
$stmt->execute();
$stmt = $db->prepare('DELETE FROM lxd_users_groups_mapping WHERE group_id = :id');
$stmt->bindValue(':id', $id, PDO::PARAM_INT);
$stmt->execute();
$db = null;
return $stmt;
}
function deleteUserGroupMapping($user_id, $group_id) {
$db = establishDatabaseConnection();
$stmt = $db->prepare('DELETE FROM lxd_users_groups_mapping WHERE user_id = :user_id AND group_id = :group_id');
$stmt->bindValue(':user_id', $user_id, PDO::PARAM_INT);
$stmt->bindValue(':group_id', $group_id, PDO::PARAM_INT);
$stmt->execute();
$db = null;
return $stmt;
}
function deleteGroupRoleMapping($group_id, $role_id) {
$db = establishDatabaseConnection();
$stmt = $db->prepare('DELETE FROM lxd_groups_roles_mapping WHERE group_id = :group_id AND role_id = :role_id');
$stmt->bindValue(':group_id', $group_id, PDO::PARAM_INT);
$stmt->bindValue(':role_id', $role_id, PDO::PARAM_INT);
$stmt->execute();
$db = null;
return $stmt;
}
/*
===================================================================================
Retrieve Values from Table Functions
===================================================================================
*/
function retrieveGroupId($name){
$db = establishDatabaseConnection();
$stmt = $db->prepare('SELECT id FROM lxd_groups WHERE name = :name LIMIT 1');
$stmt->bindValue(':name', $name, PDO::PARAM_STR);
$stmt->execute();
$return_val = $stmt->fetchColumn();
$db = null;
return $return_val;
}
function retrieveGroupRoles($group_id){
$db = establishDatabaseConnection();
$stmt = $db->prepare('SELECT lxd_roles.id, lxd_roles.name FROM lxd_roles, lxd_groups, lxd_groups_roles_mapping WHERE lxd_groups.id = lxd_groups_roles_mapping.group_id AND lxd_roles.id = lxd_groups_roles_mapping.role_id AND lxd_groups.id = :group_id');
$stmt->bindValue(':group_id', $group_id, PDO::PARAM_INT);
$stmt->execute();
$return_val = $stmt->fetchAll(PDO::FETCH_ASSOC);
$db = null;
return $return_val;
}
function retrieveGroupUsers($group_id){
$db = establishDatabaseConnection();
$stmt = $db->prepare('SELECT DISTINCT lxd_users.username FROM lxd_users, lxd_groups, lxd_users_groups_mapping WHERE lxd_users.id = lxd_users_groups_mapping.user_id AND lxd_groups.id = lxd_users_groups_mapping.group_id AND lxd_groups.id = :group_id');
$stmt->bindValue(':group_id', $group_id, PDO::PARAM_INT);
$stmt->execute();
$return_val = $stmt->fetchAll(PDO::FETCH_ASSOC);
$db = null;
return $return_val;
}
function retrieveRoleId($name){
$db = establishDatabaseConnection();
$stmt = $db->prepare('SELECT id FROM lxd_roles WHERE name = :name LIMIT 1');
$stmt->bindValue(':name', $name, PDO::PARAM_STR);
$stmt->execute();
$return_val = $stmt->fetchColumn();
$db = null;
return $return_val;
}
function retrieveDefaultRoles(){
$db = establishDatabaseConnection();
$stmt = $db->prepare('SELECT * FROM lxd_roles WHERE name IN ("ADMIN", "OPERATOR", "USER", "AUDITOR")');
try {
$stmt->execute();
}
catch (\Error $e) {
initializeAllTables();
$stmt->execute();
}
$return_val = $stmt->fetchAll(PDO::FETCH_ASSOC);
$db = null;
return $return_val;
}
function retrieveUserGroups($user_id){
$db = establishDatabaseConnection();
$stmt = $db->prepare('SELECT lxd_groups.id, lxd_groups.name FROM lxd_users, lxd_groups, lxd_users_groups_mapping WHERE lxd_users.id = lxd_users_groups_mapping.user_id AND lxd_groups.id = lxd_users_groups_mapping.group_id AND lxd_users.id = :user_id');
$stmt->bindValue(':user_id', $user_id, PDO::PARAM_INT);
$stmt->execute();
$return_val = $stmt->fetchAll(PDO::FETCH_ASSOC);
$db = null;
return $return_val;
}
function retrieveUserId($username){
$db = establishDatabaseConnection();
$stmt = $db->prepare('SELECT id FROM lxd_users WHERE username = :username LIMIT 1');
$stmt->bindValue(':username', $username, PDO::PARAM_STR);
$stmt->execute();
$return_val = $stmt->fetchColumn();
$db = null;
return $return_val;
}
function retrieveUserDetails($user_id){
$db = establishDatabaseConnection();
$stmt = $db->prepare('SELECT * FROM lxd_users WHERE id = :id LIMIT 1');
$stmt->bindValue(':id', $user_id, PDO::PARAM_INT);
$stmt->execute();
$return_val = $stmt->fetchAll(PDO::FETCH_ASSOC);
$db = null;
return $return_val;
}
function retrieveUserRecord($username){
$db = establishDatabaseConnection();
$stmt = $db->prepare('SELECT * FROM lxd_users WHERE username = :username LIMIT 1');
$stmt->bindValue(':username', $username, PDO::PARAM_STR);
$stmt->execute();
$return_val = $stmt->fetchAll(PDO::FETCH_ASSOC);
$db = null;
return $return_val;
}
function retrieveUserRoles($user_id){
$db = establishDatabaseConnection();
$stmt = $db->prepare('SELECT DISTINCT lxd_roles.name FROM lxd_roles, lxd_groups_roles_mapping, lxd_users_groups_mapping WHERE lxd_roles.id = lxd_groups_roles_mapping.role_id AND lxd_groups_roles_mapping.group_id = lxd_users_groups_mapping.group_id AND lxd_users_groups_mapping.user_id = :user_id');
$stmt->bindValue(':user_id', $user_id, PDO::PARAM_INT);
$stmt->execute();
$return_val = $stmt->fetchAll(PDO::FETCH_ASSOC);
$db = null;
return $return_val;
}
function retrieveHostURL($remote_id){
$db = establishDatabaseConnection();
$stmt = $db->prepare('SELECT * FROM lxd_hosts WHERE id = :id LIMIT 1;');
$stmt->bindValue(':id', $remote_id, PDO::PARAM_INT);
$stmt->execute();
$rows = $stmt->fetchAll();
$base_url = "";
foreach ($rows as $row){
$base_url = "https://" . $row['host'] . ":" . $row['port'];
}
return $base_url;
}
function retrieveHostName($remote_id){
$db = establishDatabaseConnection();
$stmt = $db->prepare('SELECT * FROM lxd_hosts WHERE id = :id LIMIT 1;');
$stmt->bindValue(':id', $remote_id, PDO::PARAM_INT);
$stmt->execute();
$rows = $stmt->fetchAll();
$hostname = "";
foreach ($rows as $row){
$hostname = $row['host'];
}
return $hostname;
}
function retrieveHostPort($remote_id){
$db = establishDatabaseConnection();
$stmt = $db->prepare('SELECT * FROM lxd_hosts WHERE id = :id LIMIT 1;');
$stmt->bindValue(':id', $remote_id, PDO::PARAM_INT);
$stmt->execute();
$rows = $stmt->fetchAll();
$port = "";
foreach ($rows as $row){
$port = $row['port'];
}
return $port;
}
function retrieveHostAlias($remote_id){
$db = establishDatabaseConnection();
$stmt = $db->prepare('SELECT * FROM lxd_hosts WHERE id = :id LIMIT 1;');
$stmt->bindValue(':id', $remote_id, PDO::PARAM_INT);
$stmt->execute();
$rows = $stmt->fetchAll();
$alias = "";
foreach ($rows as $row){
$alias = $row['alias'];
}
return $alias;
}
function retrieveTableRows($table){
$db = establishDatabaseConnection();
switch ($table){
case "lxd_hosts":
$stmt = $db->prepare('SELECT * FROM lxd_hosts');
break;
case "lxd_groups":
$stmt = $db->prepare('SELECT * FROM lxd_groups');
break;
case "lxd_roles":
$stmt = $db->prepare('SELECT * FROM lxd_roles');
break;
case "lxd_simplestreams":
$stmt = $db->prepare('SELECT * FROM lxd_simplestreams');
break;
case "lxd_users":
$stmt = $db->prepare('SELECT * FROM lxd_users');
break;
default:
$stmt = "";
}
/*
The tables are first initialized at the login screen before the first user registers an account.
If new tables are added in later releases this will rerun the initialization on failure creating
any new tables that are added to the initializeAllTables() function.
*/
try {
$stmt->execute();
}
catch (\Error $e) {
initializeAllTables();
$stmt->execute();
}
$return_val = $stmt->fetchAll(PDO::FETCH_ASSOC);
$db = null;
return $return_val;
}
/*
===================================================================================
Update Record in Table Functions
===================================================================================
*/
function updateUserAccount($id, $first_name, $last_name, $email){
$db = establishDatabaseConnection();
$stmt = $db->prepare('UPDATE lxd_users SET first_name = :first_name, last_name = :last_name, email = :email WHERE id = :id');
$stmt->bindValue(':id', $id, PDO::PARAM_INT);
$stmt->bindValue(':first_name', $first_name, PDO::PARAM_STR);
$stmt->bindValue(':last_name', $last_name, PDO::PARAM_STR);
$stmt->bindValue(':email', $email, PDO::PARAM_STR);
$stmt->execute();
$db = null;
return $stmt;
}
function updateUserPassword($id, $passwd_hash){
$db = establishDatabaseConnection();
$stmt = $db->prepare('UPDATE lxd_users SET passwd_hash = :passwd_hash WHERE id = :id');
$stmt->bindValue(':id', $id, PDO::PARAM_INT);
$stmt->bindValue(':passwd_hash', $passwd_hash, PDO::PARAM_STR);
$stmt->execute();
$db = null;
return $stmt;
}
/*
===================================================================================
Misc Database Functions
===================================================================================
*/
function isFirstUser(){
$db = establishDatabaseConnection();
/*
The very first time at login page it will request this function to determine if the user
should be presented with a login or registration form. If table does not yet exist it will cause
an error. The catch will initialize all the tables and query the users table again.
*/
try {
$db_results = $db->query('SELECT COUNT(*) from lxd_users');
$count = $db_results->fetchColumn();
}
catch (\Error $e) {
initializeAllTables();
$db_results = $db->query('SELECT COUNT(*) from lxd_users');
$count = $db_results->fetchColumn();
}
//Determine if there are any existing records
if ($count == 0)
$return_val = true;
else
$return_val = false;
$db = null;
return $return_val;
}
function retrieveDatabaseTypes(){
$datbase_types = array(
'sqlite'
);
return $datbase_types;
}
?>

View file

@ -37,7 +37,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Custom styles for this template-->
<link href="vendor/sb-admin-2/css/sb-admin-2.css" rel="stylesheet">
<link href="assets/css/style.css" rel="stylesheet">
<link href="assets/css/style.css?version=3.0" rel="stylesheet">
<!-- Custom styles for this page -->
<link href="vendor/datatables/dataTables.bootstrap4.min.css" rel="stylesheet">
@ -50,7 +50,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<div id="wrapper">
<!-- Sidebar -->
<ul class="navbar-nav bg-dark sidebar sidebar-dark accordion" id="accordionSidebar">
<ul class="navbar-nav bg-dark sidebar sidebar-dark accordion sidebar-divider-right" id="accordionSidebar">
<div id="sidebarLinks"></div>
@ -59,12 +59,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Sidebar Toggler (Sidebar) -->
<div class="text-center d-none d-md-inline">
<button class="rounded-circle border-0" id="sidebarToggle"></button>
<button class="rounded-circle border-0" id="sidebarToggle" onclick="setSidebarToggleValue()"></button>
</div>
</ul>
<!-- End of Sidebar -->
<!-- Content Wrapper -->
<div id="content-wrapper" class="d-flex flex-column">
@ -79,36 +78,43 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<i class="fa fa-bars"></i>
</button>
<!-- Topbar Notification -->
<div class="d-none d-sm-inline-block form-inline mr-auto ml-md-3 my-2 my-md-0 mw-100 navbar-search">
<ul class="navbar-nav ml-auto">
<li>
<div class="nav-item spinner-border m-3" role="status" style="display:none;" id="spinner">
<span class="nav-item sr-only">Loading...</span>
</div>
</li>
<li class="nav-item dropdown no-arrow" id="notificationArea" style="display: none;">
<div class="nav-link dropdown-toggle">
<span id="notification" class="mr-2 d-none d-lg-inline text-gray-600">Notification</span>
<span id="notification" class="mr-2 d-none d-lg-inline text-danger">Notification</span>
</div>
</li>
</ul>
</div>
<!-- Topbar Navbar -->
<ul class="navbar-nav ml-auto">
<!-- Topbar Navbar -->
<ul class="navbar-nav ml-auto">
<li class="nav-item dropdown" id="remoteListNav">
<li class="nav-item dropdown">
<label class="h6 mt-4 mr-2 ml-4">Host: </label>
</li>
<li class="nav-item dropdown">
<div class="input-group mt-3">
<select class="form-control" id="remoteListNav" style="width:150px;" onchange="location = this.value;">
</select>
</div>
</li>
<li class="nav-item dropdown" id="projectListNav">
<li class="nav-item dropdown">
<label class="h6 mt-4 mr-2 ml-4">Project: </label>
</li>
<li class="nav-item dropdown">
<div class="input-group mt-3">
<select class="form-control" id="projectListNav" style="width:150px;" onchange="location = this.value;">
</select>
</div>
</li>
<!-- Nav Divider -->
<div class="topbar-divider d-none d-sm-block"></div>
<!-- Nav Item - User Information -->
@ -119,14 +125,18 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</a>
<!-- Dropdown - User Information -->
<div class="dropdown-menu dropdown-menu-right shadow animated--grow-in" aria-labelledby="userDropdown">
<a class="dropdown-item" href="user-profile.html">
<a class="dropdown-item" href="user-profile.php">
<i class="fas fa-user fa-sm fa-fw mr-2 text-gray-400"></i>
Profile
</a>
<a class="dropdown-item" href="settings.html">
<a class="dropdown-item" href="settings.php">
<i class="fas fa-cog fa-sm fa-fw mr-2 text-gray-400"></i>
Settings
</a>
<a class="dropdown-item" href="logs.php">
<i class="fas fa-history fa-sm fa-fw mr-2 text-gray-400"></i>
Logs
</a>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#aboutModal">
<i class="fas fa-info-circle fa-sm fa-fw mr-2 text-gray-400"></i>
About
@ -147,25 +157,48 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Begin Page Content -->
<div class="container-fluid">
<!-- BreadCrumb -->
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="#" id="remoteBreadCrumb"></a></li>
<li class="breadcrumb-item active" aria-current="page" id="profilesBreadCrumb"></li>
</ol>
</nav>
<header class="page-header page-header-dark bg-gradient-primary-to-secondary">
<div class="container-xl px-4">
<div class="page-header-content pt-4">
<div class="row align-items-center justify-content-between mt-n5 ml-n5 mr-n5 bg-dark pb-6">
<div class="col-auto mt-4 ml-3">
<div class="page-header-subtitle">
<a href="#" id="remoteBreadCrumb"></a>
</div>
<h2 class="page-header-title mt-2">
PROFILES
</h2>
<div class="page-header-subtitle">
Create and manage instance profiles
</div>
</div>
<div class="col-12 col-xl-auto mt-4">
<div class="input-group input-group-joined border-0" style="width: 14rem">
<span class="input-group-text bg-transparent border-0">
<a class="btn btn-outline-primary" href="#" data-toggle="modal" data-target="#createProfileModal" title="New Profile" aria-hidden="true">
<i class="fas fa-plus fa-sm fa-fw"></i> Profile
</a>
</span>
</div>
</div>
</div>
</div>
</div>
</header>
<div class="row">
<div class="row mt-n5 ml-2 mr-2">
<div class="col-12">
<!-- Profile List -->
<div class="col-12 mt-n3">
<!-- Image List -->
<div class="card shadow mb-4">
<!-- Card Header - Dropdown -->
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">Profiles</h6>
<h6 class="m-0 font-weight-bold">
<span class="ml-1">Profiles</span>
</h6>
<div class="dropdown no-arrow">
<a class="dropdown-toggle mr-2" href="#" data-toggle="modal" data-target="#createProfileModal" title="New Profile" aria-hidden="true">
<i class="fas fa-plus fa-sm fa-fw"></i> Profile</a>
<a class="dropdown-toggle mr-2" href="#" onclick="reloadPageContent()" title="Refresh" aria-hidden="true">
<i class="fa fa-sync fa-1x fa-fw"></i></a>
</div>
</div>
<!-- Card Body -->
@ -176,7 +209,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</div>
</div>
</div>
<!-- End Profile List -->
<!-- End Image List -->
</div>
</div>
@ -191,7 +224,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<footer class="sticky-footer bg-white">
<div class="container my-auto">
<div class="copyright text-center my-auto">
<span>Copyright &copy; lxdware.com 2021</span>
<span>Copyright &copy; LXDWARE 2020 - Present</span>
</div>
</div>
</footer>
@ -231,14 +264,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<div class="tab-pane fade show active" id="form" role="tabpanel" aria-labelledby="form-tab">
<br />
<div class="row">
<label class="col-3 col-form-label text-right">Name: </label>
<label class="col-3 col-form-label text-right">Name: <span class="text-danger">*</span></label>
<div class="col-7">
<div class="form-group">
<input type="text" id="profileNameCreate" class="form-control" placeholder="" name="profile_name">
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle text-danger" title='(Required) - Enter in a name for the profile.'></i>
<i class="far fa-sm fa-question-circle" title='(Required) - Enter in a name for the profile.'></i>
</div>
</div>
<div class="row">
@ -321,14 +354,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</div>
<div class="modal-body">
<div class="row">
<label class="col-3 col-form-label text-right" id="newProfileNameLabel">Name:</label>
<label class="col-3 col-form-label text-right" id="newProfileNameLabel">Name: <span class="text-danger">*</span></label>
<div class="col-7">
<div class="form-group">
<input type="text" id="newProfileName" class="form-control" placeholder="">
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle text-danger" title='(Required) - Enter in a new name for the profile.'></i>
<i class="far fa-sm fa-question-circle" title='(Required) - Enter in a new name for the profile.'></i>
</div>
</div>
<input type="hidden" id ="profileToRename" name="profileToRename">
@ -387,61 +420,66 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
const remoteId = urlParams.get('remote');
const projectName = urlParams.get('project');
var profileToUpdate = "";
var reloadTime = 5000;
function logout(){
$.get("./php/aaa/authentication.php?action=deauthenticateUser", function (data) {
$.get("./backend/aaa/authentication.php?action=deauthenticateUser", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code == 200) {
window.location = './index.html'
window.location.href = './index.php'
}
});
}
function operationStatusCheck(){
clearTimeout(operationTimeout);
//check to see if there are any running operations
$.get("./php/lxd/operations.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayOperationStatus", function (data) {
$.get("./backend/lxd/operations.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayOperationStatus", function (data) {
//Check to see if we have running operations
if (data){
//Display spinner and notification area if there are running tasks
$('#spinner').show();
if (data) {
//Display notification area if there are running tasks
$('#notificationArea').show();
$('#notification').text(data);
//Set the page to check operations again in 1 second
setTimeout(() => { operationStatusCheck(); }, 1000);
$('#notification').text("Notice: " + data);
//Set the page to check operations again in 2 seconds
operationTimeout = setTimeout(() => { operationStatusCheck(); }, 2000);
}
else {
//Hide spinner and notification area if no running tasks
$('#spinner').hide();
//Hide notification area if no running tasks
$('#notificationArea').hide();
$('#notification').text("");
//Set the page to check operations again in 3 seconds
setTimeout(() => { operationStatusCheck(); }, 3000);
//Set the page to check operations again in 4 seconds
operationTimeout = setTimeout(() => { operationStatusCheck(); }, 4000);
}
});
}
function reloadPageContent(){
clearTimeout(pageReloadTimeout);
//Check Authorization
$.get("./php/aaa/authentication.php?action=validateAuthentication", function (data) {
$.get("./backend/aaa/authentication.php?action=validateAuthentication", function (data) {
operationData = JSON.parse(data);
if (operationData.status_code != 200) {
console.log(operationData);
window.location = './index.html'
window.location.href = './index.php'
}
});
$('#profileListTable').DataTable().ajax.reload(null, false);
//Set reload page content
pageReloadTimeout = setTimeout(() => { reloadPageContent(); }, reloadTime);
}
function loadPageContent(){
//Display current logged in username
$("#username").load("./php/admin/settings.php?action=displayUsername");
$("#username").load("./backend/admin/settings.php?action=displayUsername");
$('#profileListTable').DataTable( {
ajax: "./php/lxd/profiles.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listProfiles",
ajax: "./backend/lxd/profiles.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listProfiles",
columns: [
{},
{ title: "Name" },
@ -456,17 +494,23 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
});
//Check for any running operations
operationStatusCheck();
operationTimeout = setTimeout(() => { operationStatusCheck(); }, 1000);
//Set reload page content
$.get("./backend/admin/settings.php?action=retrievePageRefreshRateValues", function (data) {
operationData = JSON.parse(data);
if (operationData.profiles_page_rate >= 1)
reloadTime = operationData.profiles_page_rate * 1000;
pageReloadTimeout = setTimeout(() => { reloadPageContent(); }, reloadTime);
});
//Set the page content to reload in 5 seconds
setInterval(() => { reloadPageContent(); }, 5000);
}
function createProfileUsingForm(){
var profileNameCreate = $("#profileNameCreate").val();
var profileDescriptionCreate = $("#profileDescriptionCreate").val();
console.log("Info: creating profile");
$.get("./php/lxd/profiles.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&name=" + encodeURI(profileNameCreate) + "&description=" + encodeURI(profileDescriptionCreate) + "&action=createProfileUsingForm", function (data) {
$.get("./backend/lxd/profiles.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&name=" + encodeURI(profileNameCreate) + "&description=" + encodeURI(profileDescriptionCreate) + "&action=createProfileUsingForm", function (data) {
//Sync operation type
var operationData = JSON.parse(data);
console.log(operationData);
@ -480,7 +524,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
function createProfileUsingJSON(){
var profileCreateJSON = $("#jsonCreateInput").val();
console.log("Info: creating profile");
$.post("./php/lxd/profiles.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=createProfileUsingJSON", {json: profileCreateJSON}, function (data) {
$.post("./backend/lxd/profiles.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=createProfileUsingJSON", {json: profileCreateJSON}, function (data) {
//Sync operation type
var operationData = JSON.parse(data);
console.log(operationData);
@ -494,7 +538,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
function loadProfileJson(profileToLoad){
console.log("Info: loading profile " + profileToLoad);
profileToUpdate = profileToLoad;
$.get("./php/lxd/profiles.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&profile=" + encodeURI(profileToLoad) + "&action=loadProfile", function (data) {
$.get("./backend/lxd/profiles.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&profile=" + encodeURI(profileToLoad) + "&action=loadProfile", function (data) {
//Sync operation type
var operationData = JSON.parse(data);
console.log(operationData);
@ -517,7 +561,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
function updateProfile(){
var profileUpdateJSON = $("#jsonEditInput").val();
console.log("Info: updating profile " + profileToUpdate);
$.post("./php/lxd/profiles.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&profile=" + encodeURI(profileToUpdate) + "&action=updateProfile", {json: profileUpdateJSON}, function (data) {
$.post("./backend/lxd/profiles.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&profile=" + encodeURI(profileToUpdate) + "&action=updateProfile", {json: profileUpdateJSON}, function (data) {
//Sync operation type
var operationData = JSON.parse(data);
console.log(operationData);
@ -532,7 +576,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
var profileName = $("#newProfileName").val();
var profile = $("#profileToRename").val();
console.log("Info: renaming profile " + profile);
$.get("./php/lxd/profiles.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&profile=" + encodeURI(profile) + "&name=" + encodeURI(profileName) + "&action=renameProfile", function (data) {
$.get("./backend/lxd/profiles.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&profile=" + encodeURI(profile) + "&name=" + encodeURI(profileName) + "&action=renameProfile", function (data) {
//Sync operation type
var operationData = JSON.parse(data);
console.log(operationData);
@ -545,7 +589,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
function deleteProfile(profileToDelete){
console.log("Info: deleting profile " + profileToDelete);
$.get("./php/lxd/profiles.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&profile=" + encodeURI(profileToDelete) + "&action=deleteProfile", function (data) {
$.get("./backend/lxd/profiles.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&profile=" + encodeURI(profileToDelete) + "&action=deleteProfile", function (data) {
//Sync operation type
var operationData = JSON.parse(data);
console.log(operationData);
@ -556,33 +600,64 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
});
}
function setSidebarToggleValue(){
sidebarState = localStorage.getItem('sidebarState');
if (sidebarState == "collapsed"){
localStorage.setItem('sidebarState','expanded');
}
else {
localStorage.setItem('sidebarState','collapsed');
}
}
function applySidebarToggleValue() {
sidebarState = localStorage.getItem('sidebarState');
if (sidebarState == "collapsed"){
$("body").toggleClass("sidebar-toggled"),
$(".sidebar").toggleClass("toggled"),
$(".sidebar").hasClass("toggled") && $(".sidebar .collapse").collapse("hide")
}
}
applySidebarToggleValue();
$(document).ready(function(){
//Check Authorization
$.get("./php/aaa/authentication.php?action=validateAuthentication", function (data) {
$.get("./backend/aaa/authentication.php?action=validateAuthentication", function (data) {
operationData = JSON.parse(data);
if (operationData.status_code != 200) {
console.log(operationData);
window.location = './index.html'
window.location.href = './index.php'
}
});
//Load in the sidebar
$("#sidebarLinks").load("./sidebar.html");
$("#sidebarLinks").load("./sidebar.php?version=3.0");
//Setup Page Breadcrumb Links/Information
$('#remoteBreadCrumb').load("./php/lxd/remote-breadcrumb.php?remote=" + encodeURI(remoteId));
$('#remoteBreadCrumb').attr("href", "remotes-single.html?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$('#profilesBreadCrumb').text("profiles");
$('#remoteBreadCrumb').load("./backend/lxd/remote-breadcrumb.php?remote=" + encodeURI(remoteId));
$('#remoteBreadCrumb').attr("href", "remotes-single.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
//Load the card contents
loadPageContent();
//Validate remote host connection returns 200 status
$.get("./backend/lxd/remotes-single.php?remote=" + encodeURI(remoteId) + "&action=validateRemoteConnection", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code == 200) {
//Set top navbar dropdowns
$("#remoteListNav").load("./backend/lxd/remotes.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listRemotesForSelectOption");
$("#projectListNav").load("./backend/lxd/projects.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listProjectsForSelectOption");
//Load Page Content
loadPageContent();
}
else {
alert("Unable to connect to remote host. HTTP status code: " + operationData.status_code);
}
});
$("#remoteListNav").load("./php/lxd/remotes.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listRemotesForTopNavigation");
$("#projectListNav").load("./php/lxd/projects.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listProjectsForTopNavigation");
//Load the about info for the about modal
$.get("./about.html", function (data) {
$.get("./backend/config/about.php", function (data) {
$("#about").html(data);
});

View file

@ -37,7 +37,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Custom styles for this template-->
<link href="vendor/sb-admin-2/css/sb-admin-2.css" rel="stylesheet">
<link href="assets/css/style.css" rel="stylesheet">
<link href="assets/css/style.css?version=3.0" rel="stylesheet">
<!-- Custom styles for this page -->
<link href="vendor/datatables/dataTables.bootstrap4.min.css" rel="stylesheet">
@ -50,7 +50,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<div id="wrapper">
<!-- Sidebar -->
<ul class="navbar-nav bg-dark sidebar sidebar-dark accordion" id="accordionSidebar">
<ul class="navbar-nav bg-dark sidebar sidebar-dark accordion sidebar-divider-right" id="accordionSidebar">
<div id="sidebarLinks"></div>
@ -59,12 +59,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Sidebar Toggler (Sidebar) -->
<div class="text-center d-none d-md-inline">
<button class="rounded-circle border-0" id="sidebarToggle"></button>
<button class="rounded-circle border-0" id="sidebarToggle" onclick="setSidebarToggleValue()"></button>
</div>
</ul>
<!-- End of Sidebar -->
<!-- Content Wrapper -->
<div id="content-wrapper" class="d-flex flex-column">
@ -79,36 +78,43 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<i class="fa fa-bars"></i>
</button>
<!-- Topbar Notification -->
<div class="d-none d-sm-inline-block form-inline mr-auto ml-md-3 my-2 my-md-0 mw-100 navbar-search">
<ul class="navbar-nav ml-auto">
<li>
<div class="nav-item spinner-border m-3" role="status" style="display:none;" id="spinner">
<span class="nav-item sr-only">Loading...</span>
</div>
</li>
<li class="nav-item dropdown no-arrow" id="notificationArea" style="display: none;">
<div class="nav-link dropdown-toggle">
<span id="notification" class="mr-2 d-none d-lg-inline text-gray-600">Notification</span>
</div>
</li>
</ul>
</div>
<!-- Topbar Navbar -->
<!-- Topbar Notification -->
<div class="d-none d-sm-inline-block form-inline mr-auto ml-md-3 my-2 my-md-0 mw-100 navbar-search">
<ul class="navbar-nav ml-auto">
<li class="nav-item dropdown" id="remoteListNav">
<li class="nav-item dropdown no-arrow" id="notificationArea" style="display: none;">
<div class="nav-link dropdown-toggle">
<span id="notification" class="mr-2 d-none d-lg-inline text-danger">Notification</span>
</div>
</li>
</ul>
</div>
<!-- Topbar Navbar -->
<ul class="navbar-nav ml-auto">
<li class="nav-item dropdown">
<label class="h6 mt-4 mr-2 ml-4">Host: </label>
</li>
<li class="nav-item dropdown">
<div class="input-group mt-3">
<select class="form-control" id="remoteListNav" style="width:150px;" onchange="location = this.value;">
</select>
</div>
</li>
<li class="nav-item dropdown" id="projectListNav">
<li class="nav-item dropdown">
<label class="h6 mt-4 mr-2 ml-4">Project: </label>
</li>
<li class="nav-item dropdown">
<div class="input-group mt-3">
<select class="form-control" id="projectListNav" style="width:150px;" onchange="location = this.value;">
</select>
</div>
</li>
<!-- Nav Divider -->
<div class="topbar-divider d-none d-sm-block"></div>
<!-- Nav Item - User Information -->
@ -119,14 +125,18 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</a>
<!-- Dropdown - User Information -->
<div class="dropdown-menu dropdown-menu-right shadow animated--grow-in" aria-labelledby="userDropdown">
<a class="dropdown-item" href="user-profile.html">
<a class="dropdown-item" href="user-profile.php">
<i class="fas fa-user fa-sm fa-fw mr-2 text-gray-400"></i>
Profile
</a>
<a class="dropdown-item" href="settings.html">
<a class="dropdown-item" href="settings.php">
<i class="fas fa-cog fa-sm fa-fw mr-2 text-gray-400"></i>
Settings
</a>
<a class="dropdown-item" href="logs.php">
<i class="fas fa-history fa-sm fa-fw mr-2 text-gray-400"></i>
Logs
</a>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#aboutModal">
<i class="fas fa-info-circle fa-sm fa-fw mr-2 text-gray-400"></i>
About
@ -147,25 +157,48 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Begin Page Content -->
<div class="container-fluid">
<!-- BreadCrumb -->
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="#" id="remoteBreadCrumb"></a></li>
<li class="breadcrumb-item active" aria-current="page" id="projectsBreadCrumb"></li>
</ol>
</nav>
<header class="page-header page-header-dark bg-gradient-primary-to-secondary">
<div class="container-xl px-4">
<div class="page-header-content pt-4">
<div class="row align-items-center justify-content-between mt-n5 ml-n5 mr-n5 bg-dark pb-6">
<div class="col-auto mt-4 ml-3">
<div class="page-header-subtitle">
<a href="#" id="remoteBreadCrumb"></a>
</div>
<h2 class="page-header-title mt-2">
PROJECTS
</h2>
<div class="page-header-subtitle">
Create and manage projects
</div>
</div>
<div class="col-12 col-xl-auto mt-4">
<div class="input-group input-group-joined border-0" style="width: 14rem">
<span class="input-group-text bg-transparent border-0">
<a class="btn btn-outline-primary" href="#" data-toggle="modal" data-target="#createProjectModal" title="New Project" aria-hidden="true">
<i class="fas fa-plus fa-sm fa-fw"></i> Project
</a>
</span>
</div>
</div>
</div>
</div>
</div>
</header>
<div class="row">
<div class="row mt-n5 ml-2 mr-2">
<div class="col-12">
<div class="col-12 mt-n3">
<!-- Project List -->
<div class="card shadow mb-4">
<!-- Card Header - Dropdown -->
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">Projects</h6>
<h6 class="m-0 font-weight-bold">
<span class="ml-1">Projects</span>
</h6>
<div class="dropdown no-arrow">
<a class="dropdown-toggle mr-2" href="#" data-toggle="modal" data-target="#createProjectModal" title="New Project" aria-hidden="true">
<i class="fas fa-plus fa-sm fa-fw"></i> Project</a>
<a class="dropdown-toggle mr-2" href="#" onclick="reloadPageContent()" title="Refresh" aria-hidden="true">
<i class="fa fa-sync fa-1x fa-fw"></i></a>
</div>
</div>
<!-- Card Body -->
@ -191,7 +224,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<footer class="sticky-footer bg-white">
<div class="container my-auto">
<div class="copyright text-center my-auto">
<span>Copyright &copy; lxdware.com 2021</span>
<span>Copyright &copy; LXDWARE 2020 - Present</span>
</div>
</div>
</footer>
@ -235,14 +268,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<br />
<div class="row">
<label class="col-3 col-form-label text-right">Name: </label>
<label class="col-3 col-form-label text-right">Name: <span class="text-danger">*</span></label>
<div class="col-7">
<div class="form-group text-right">
<input type="text" class="form-control" id="projectNameInput" required="required" placeholder="" name="projectNameInput">
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle text-danger" title='(Required) - Enter in a name for the project.'></i>
<i class="far fa-sm fa-question-circle" title='(Required) - Enter in a name for the project.'></i>
</div>
</div>
@ -909,14 +942,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</div>
<div class="modal-body">
<div class="row">
<label class="col-3 col-form-label text-right" id="newProjectNameLabel">Name:</label>
<label class="col-3 col-form-label text-right" id="newProjectNameLabel">Name: <span class="text-danger">*</span></label>
<div class="col-7">
<div class="form-group">
<input type="text" id="newProjectName" class="form-control" placeholder="">
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle text-danger" title='Enter in a new name for the project.'></i>
<i class="far fa-sm fa-question-circle" title='Enter in a new name for the project.'></i>
</div>
</div>
<input type="hidden" id ="projectToRename" name="projectToRename">
@ -975,61 +1008,66 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
const remoteId = urlParams.get('remote');
const projectName = urlParams.get('project');
var projectToUpdate = "";
var reloadTime = 5000;
function logout(){
$.get("./php/aaa/authentication.php?action=deauthenticateUser", function (data) {
$.get("./backend/aaa/authentication.php?action=deauthenticateUser", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code == 200) {
window.location = './index.html'
window.location.href = './index.php'
}
});
}
function operationStatusCheck(){
clearTimeout(operationTimeout);
//check to see if there are any running operations
$.get("./php/lxd/operations.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayOperationStatus", function (data) {
$.get("./backend/lxd/operations.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayOperationStatus", function (data) {
//Check to see if we have running operations
if (data){
//Display spinner and notification area if there are running tasks
$('#spinner').show();
if (data) {
//Display notification area if there are running tasks
$('#notificationArea').show();
$('#notification').text(data);
//Set the page to check operations again in 1 second
setTimeout(() => { operationStatusCheck(); }, 1000);
$('#notification').text("Notice: " + data);
//Set the page to check operations again in 2 seconds
operationTimeout = setTimeout(() => { operationStatusCheck(); }, 2000);
}
else {
//Hide spinner and notification area if no running tasks
$('#spinner').hide();
//Hide notification area if no running tasks
$('#notificationArea').hide();
$('#notification').text("");
//Set the page to check operations again in 3 seconds
setTimeout(() => { operationStatusCheck(); }, 3000);
//Set the page to check operations again in 4 seconds
operationTimeout = setTimeout(() => { operationStatusCheck(); }, 4000);
}
});
}
function reloadPageContent(){
clearTimeout(pageReloadTimeout);
//Check Authorization
$.get("./php/aaa/authentication.php?action=validateAuthentication", function (data) {
$.get("./backend/aaa/authentication.php?action=validateAuthentication", function (data) {
operationData = JSON.parse(data);
if (operationData.status_code != 200) {
console.log(operationData);
window.location = './index.html'
window.location.href = './index.php'
}
});
$('#projectListTable').DataTable().ajax.reload(null, false);
//Set reload page content
pageReloadTimeout = setTimeout(() => { reloadPageContent(); }, reloadTime);
}
function loadPageContent(){
//Display current logged in username
$("#username").load("./php/admin/settings.php?action=displayUsername");
$("#username").load("./backend/admin/settings.php?action=displayUsername");
$('#projectListTable').DataTable( {
ajax: "./php/lxd/projects.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listProjects",
ajax: "./backend/lxd/projects.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listProjects",
columns: [
{},
{ title: "Name" },
@ -1047,10 +1085,16 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
});
//Check for any running operations
operationStatusCheck();
operationTimeout = setTimeout(() => { operationStatusCheck(); }, 1000);
//Set reload page content
$.get("./backend/admin/settings.php?action=retrievePageRefreshRateValues", function (data) {
operationData = JSON.parse(data);
if (operationData.projects_page_rate >= 1)
reloadTime = operationData.projects_page_rate * 1000;
pageReloadTimeout = setTimeout(() => { reloadPageContent(); }, reloadTime);
});
//Set the page content to reload in 5 seconds
setInterval(() => { reloadPageContent(); }, 5000);
}
function createProjectUsingForm(){
@ -1096,7 +1140,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
var projectRestrictedVirtualMachinesLowlevelInput = $("#projectRestrictedVirtualMachinesLowlevelInput").val();
console.log("Info: creating project " + projectNameInput);
$.get("./php/lxd/projects.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) +
$.get("./backend/lxd/projects.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) +
"&name=" + encodeURI(projectNameInput) +
"&description=" + encodeURI(projectDescriptionInput) +
"&features_images=" + encodeURI(projectFeaturesImagesInput) +
@ -1151,7 +1195,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
function createProjectUsingJSON(){
var projectCreateJSON = $("#jsonCreateInput").val();
console.log("Info: creating project");
$.post("./php/lxd/projects.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=createProjectUsingJSON", {json: projectCreateJSON}, function (data) {
$.post("./backend/lxd/projects.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=createProjectUsingJSON", {json: projectCreateJSON}, function (data) {
//Sync operation type
var operationData = JSON.parse(data);
console.log(operationData);
@ -1165,7 +1209,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
function loadProjectJson(projectToLoad){
console.log("Info: loading project " + projectToLoad);
projectToUpdate = projectToLoad;
$.get("./php/lxd/projects.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&name=" + encodeURI(projectToLoad) + "&action=loadProject", function (data) {
$.get("./backend/lxd/projects.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&name=" + encodeURI(projectToLoad) + "&action=loadProject", function (data) {
//Sync operation type
var operationData = JSON.parse(data);
console.log(operationData);
@ -1188,7 +1232,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
function updateProject(){
var projectUpdateJSON = $("#jsonInput").val();
console.log("Info: updating project " + projectToUpdate);
$.post("./php/lxd/projects.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectToUpdate) + "&action=updateProject",{json: projectUpdateJSON}, function (data) {
$.post("./backend/lxd/projects.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectToUpdate) + "&action=updateProject",{json: projectUpdateJSON}, function (data) {
//Sync operation type
var operationData = JSON.parse(data);
console.log(operationData);
@ -1203,7 +1247,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
var projectNewName = $("#newProjectName").val();
var projectToRename = $("#projectToRename").val();
console.log("Info: renaming project " + projectToRename);
$.get("./php/lxd/projects.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectToRename) + "&name=" + encodeURI(projectNewName) + "&action=renameProject", function (data) {
$.get("./backend/lxd/projects.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectToRename) + "&name=" + encodeURI(projectNewName) + "&action=renameProject", function (data) {
//Sync operation type
var operationData = JSON.parse(data);
console.log(operationData);
@ -1216,7 +1260,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
function deleteProject(projectToDelete){
console.log("Info: deleting project " + projectToDelete);
$.get("./php/lxd/projects.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&name=" + encodeURI(projectToDelete) + "&action=deleteProject", function (data) {
$.get("./backend/lxd/projects.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&name=" + encodeURI(projectToDelete) + "&action=deleteProject", function (data) {
//Sync operation type
var operationData = JSON.parse(data);
console.log(operationData);
@ -1274,33 +1318,64 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
}
}
function setSidebarToggleValue(){
sidebarState = localStorage.getItem('sidebarState');
if (sidebarState == "collapsed"){
localStorage.setItem('sidebarState','expanded');
}
else {
localStorage.setItem('sidebarState','collapsed');
}
}
function applySidebarToggleValue() {
sidebarState = localStorage.getItem('sidebarState');
if (sidebarState == "collapsed"){
$("body").toggleClass("sidebar-toggled"),
$(".sidebar").toggleClass("toggled"),
$(".sidebar").hasClass("toggled") && $(".sidebar .collapse").collapse("hide")
}
}
applySidebarToggleValue();
$(document).ready(function(){
//Check Authorization
$.get("./php/aaa/authentication.php?action=validateAuthentication", function (data) {
$.get("./backend/aaa/authentication.php?action=validateAuthentication", function (data) {
operationData = JSON.parse(data);
if (operationData.status_code != 200) {
console.log(operationData);
window.location = './index.html'
window.location.href = './index.php'
}
});
//Load in the sidebar
$("#sidebarLinks").load("./sidebar.html");
$("#sidebarLinks").load("./sidebar.php?version=3.0");
//Setup Page Breadcrumb Links/Information
$('#remoteBreadCrumb').load("./php/lxd/remote-breadcrumb.php?remote=" + encodeURI(remoteId));
$('#remoteBreadCrumb').attr("href", "remotes-single.html?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$('#projectsBreadCrumb').text("projects");
$('#remoteBreadCrumb').load("./backend/lxd/remote-breadcrumb.php?remote=" + encodeURI(remoteId));
$('#remoteBreadCrumb').attr("href", "remotes-single.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
//Load the card contents
loadPageContent();
//Validate remote host connection returns 200 status
$.get("./backend/lxd/remotes-single.php?remote=" + encodeURI(remoteId) + "&action=validateRemoteConnection", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code == 200) {
//Set top navbar dropdowns
$("#remoteListNav").load("./backend/lxd/remotes.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listRemotesForSelectOption");
$("#projectListNav").load("./backend/lxd/projects.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listProjectsForSelectOption");
$("#remoteListNav").load("./php/lxd/remotes.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listRemotesForTopNavigation");
$("#projectListNav").load("./php/lxd/projects.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listProjectsForTopNavigation");
//Load Page Content
loadPageContent();
}
else {
alert("Unable to connect to remote host. HTTP status code: " + operationData.status_code);
}
});
//Load the about info for the about modal
$.get("./about.html", function (data) {
$.get("./backend/config/about.php", function (data) {
$("#about").html(data);
});

View file

@ -1,797 +0,0 @@
<!--
LXDWARE LXD Dashboard - A web-based interface for managing LXD servers
Copyright (C) 2020-2021 LXDWARE.COM
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<link rel="icon" type="image/png" href="assets/images/logo-light.svg">
<title>LXD Dashboard</title>
<!-- Custom fonts for this template-->
<link href="vendor/fontawesome-free/css/all.min.css" rel="stylesheet" type="text/css">
<link href="vendor/fonts/nunito.css" rel="stylesheet">
<!-- Custom styles for this template-->
<link href="vendor/sb-admin-2/css/sb-admin-2.css" rel="stylesheet">
<link href="assets/css/style.css" rel="stylesheet">
</head>
<body id="page-top">
<!-- Page Wrapper -->
<div id="wrapper">
<!-- Sidebar -->
<ul class="navbar-nav bg-dark sidebar sidebar-dark accordion" id="accordionSidebar">
<div id="sidebarLinks"></div>
<!-- Divider -->
<hr class="sidebar-divider d-none d-md-block">
<!-- Sidebar Toggler (Sidebar) -->
<div class="text-center d-none d-md-inline">
<button class="rounded-circle border-0" id="sidebarToggle"></button>
</div>
</ul>
<!-- End of Sidebar -->
<!-- Content Wrapper -->
<div id="content-wrapper" class="d-flex flex-column">
<!-- Main Content -->
<div id="content">
<!-- Topbar -->
<nav class="navbar navbar-expand navbar-light bg-white topbar mb-4 static-top shadow">
<!-- Sidebar Toggle (Topbar) -->
<button id="sidebarToggleTop" class="btn btn-link d-md-none rounded-circle mr-3">
<i class="fa fa-bars"></i>
</button>
<!-- Topbar Notification -->
<div class="d-none d-sm-inline-block form-inline mr-auto ml-md-3 my-2 my-md-0 mw-100 navbar-search">
<ul class="navbar-nav ml-auto">
<li>
<div class="nav-item spinner-border m-3" role="status" style="display:none;" id="spinner">
<span class="nav-item sr-only">Loading...</span>
</div>
</li>
<li class="nav-item dropdown no-arrow" id="notificationArea" style="display: none;">
<div class="nav-link dropdown-toggle">
<span id="notification" class="mr-2 d-none d-lg-inline text-gray-600">Notification</span>
</div>
</li>
</ul>
</div>
<!-- Topbar Navbar -->
<ul class="navbar-nav ml-auto">
<li class="nav-item dropdown" id="remoteListNav">
</li>
<li class="nav-item dropdown" id="projectListNav">
</li>
<div class="topbar-divider d-none d-sm-block"></div>
<!-- Nav Item - User Information -->
<li class="nav-item dropdown no-arrow">
<a class="nav-link dropdown-toggle" href="#" id="userDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fas fa-user-circle fa-1x fa-fw mr-2 text-gray-600"></i>
<span id="username" class="mr-2 d-none d-lg-inline text-gray-600"></span>
</a>
<!-- Dropdown - User Information -->
<div class="dropdown-menu dropdown-menu-right shadow animated--grow-in" aria-labelledby="userDropdown">
<a class="dropdown-item" href="user-profile.html">
<i class="fas fa-user fa-sm fa-fw mr-2 text-gray-400"></i>
Profile
</a>
<a class="dropdown-item" href="settings.html">
<i class="fas fa-cog fa-sm fa-fw mr-2 text-gray-400"></i>
Settings
</a>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#aboutModal">
<i class="fas fa-info-circle fa-sm fa-fw mr-2 text-gray-400"></i>
About
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#" onclick="logout()">
<i class="fas fa-sign-out-alt fa-sm fa-fw mr-2 text-gray-400"></i>
Logout
</a>
</div>
</li>
</ul>
</nav>
<!-- End of Topbar -->
<!-- Begin Page Content -->
<div class="container-fluid">
<!-- BreadCrumb -->
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item active" aria-current="page" id="remoteBreadCrumb"></li>
</ol>
</nav>
<div class="col-12">
<div class="row">
<div class="col-sm-12 col-md-6 col-xl-4 py-2 mb-4">
<div class="card border-left-primary shadow h-100">
<a href="#" class="stretched-link" id="instancesLink"></a>
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col-5">
<div class="text-xs font-weight-bold text-primary text-uppercase mb-1">
Instances
</div>
<div class="h5 mb-0 font-weight-bold text-gray-600 align-middle">
<i class="fas fa-cube fa-1x mr-2 text-primary"></i>
<span id="runningInstances">0</span> / <span id="totalInstances">0</span> running
</div>
</div>
<div class="col-7">
<div class="progress progress-sm mr-2">
<div class="progress-bar bg-info" role="progressbar" id="instancePercentageProgressBar" style="width: 0%" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-sm-12 col-md-6 col-xl-4 py-2 mb-4">
<div class="card border-left-primary shadow h-100">
<a href="#" class="stretched-link" id="clusterMembersLink"></a>
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col-5">
<div class="text-xs font-weight-bold text-primary text-uppercase mb-1">
Cluster Members
</div>
<div class="h5 mb-0 font-weight-bold text-gray-600 align-middle">
<i class="fas fa-layer-group fa-1x mr-2 text-primary"></i>
<span id="onlineClusterMembers">0</span> / <span id="totalClusterMembers">0</span> online
</div>
</div>
<div class="col-7">
<div class="progress progress-sm mr-2">
<div class="progress-bar bg-info" role="progressbar" id="clusterPercentageProgressBar" style="width: 0%" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-sm-12 col-md-6 col-xl-4 py-2 mb-4">
<div class="card border-left-primary shadow h-100">
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col-5">
<div class="text-xs font-weight-bold text-primary text-uppercase mb-1">
Host Memory
</div>
<div class="h5 mb-0 font-weight-bold text-gray-600 align-middle">
<i class="fas fa-memory fa-1x mr-2 text-primary"></i>
<span id="memoryPercentage">0</span>%
</div>
</div>
<div class="col-7">
<div class="progress progress-sm mr-2">
<div class="progress-bar bg-info" role="progressbar" id="memoryPercentageProgressBar" style="width: 0%" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-sm-6 col-lg-4 col-xl-2 py-2 mb-4">
<div class="card shadow h-100">
<a href="#" class="stretched-link" id="imagesLink"></a>
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col-7">
<div class="text-xs font-weight-bold text-primary text-uppercase mb-1">
Images
</div>
<div class="h5 mb-0 font-weight-bold text-gray-600 align-middle">
<span id="totalImages">0</span>
</div>
</div>
<div class="col-5">
<i class="fas fa-box-open fa-3x text-gray-200"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-sm-6 col-lg-4 col-xl-2 py-2 mb-4">
<div class="card shadow h-100">
<a href="#" class="stretched-link" id="profilesLink"></a>
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col-7">
<div class="text-xs font-weight-bold text-primary text-uppercase mb-1">
Profiles
</div>
<div class="h5 mb-0 font-weight-bold text-gray-600 align-middle">
<span id="totalProfiles">0</span>
</div>
</div>
<div class="col-5">
<i class="fas fa-money-check fa-3x text-gray-200"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-sm-6 col-lg-4 col-xl-2 py-2 mb-4">
<div class="card shadow h-100">
<a href="#" class="stretched-link" id="networksLink"></a>
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col-7">
<div class="text-xs font-weight-bold text-primary text-uppercase mb-1">
Networks
</div>
<div class="h5 mb-0 font-weight-bold text-gray-600 align-middle">
<span id="totalNetworks">0</span>
</div>
</div>
<div class="col-5">
<i class="fas fa-network-wired fa-3x text-gray-200"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-sm-6 col-lg-4 col-xl-2 py-2 mb-4">
<div class="card shadow h-100">
<a href="#" class="stretched-link" id="storagePoolsLink"></a>
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col-7">
<div class="text-xs font-weight-bold text-primary text-uppercase mb-1">
Storage Pools
</div>
<div class="h5 mb-0 font-weight-bold text-gray-600 align-middle">
<span id="totalStoragePools">0</span>
</div>
</div>
<div class="col-5">
<i class="fas fa-hdd fa-3x text-gray-200"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-sm-6 col-lg-4 col-xl-2 py-2 mb-4">
<div class="card shadow h-100">
<a href="#" class="stretched-link" id="projectsLink"></a>
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col-7">
<div class="text-xs font-weight-bold text-primary text-uppercase mb-1">
Projects
</div>
<div class="h5 mb-0 font-weight-bold text-gray-600 align-middle">
<span id="totalProjects">0</span>
</div>
</div>
<div class="col-5">
<i class="fas fa-chart-bar fa-3x text-gray-200"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-sm-6 col-lg-4 col-xl-2 py-2 mb-4">
<div class="card shadow h-100">
<a href="#" class="stretched-link" id="networkAclsLink"></a>
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col-7">
<div class="text-xs font-weight-bold text-primary text-uppercase mb-1">
Network ACLs
</div>
<div class="h5 mb-0 font-weight-bold text-gray-600 align-middle">
<span id="totalNetworkAcls">0</span>
</div>
</div>
<div class="col-5">
<i class="fas fa-shield-alt fa-3x text-gray-200"></i>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12 col-md-6 mb-4">
<div class="card shadow h-100">
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">LXD Information</h6>
</div>
<!-- Card Body -->
<div class="card-body">
<strong>Operating System</strong>: <span id="osName"></span> <span id="osVersion"></span><br />
<strong>LXD Version</strong>: <span id="serverVersion"></span><br />
<strong>Hostname</strong>: <span id="serverName"></span><br />
<strong>Kernel</strong>: <span id="kernel"></span> <span id="kernelArchitecture"></span><br />
<strong>Firewall</strong>: <span id="firewall"></span><br />
<br />
<strong>Driver</strong>: <span id="driver"></span><br />
<strong>Driver Version</strong>: <span id="driverVersion"></span><br />
<br />
<strong>Storage Type</strong>: <span id="storage"></span><br />
<strong>Storage Version</strong>: <span id="storageVersion"></span><br />
</div>
</div>
</div>
<div class="col-sm-12 col-md-6 mb-4">
<div class="card shadow h-100">
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">Resource Information</h6>
</div>
<!-- Card Body -->
<div class="card-body">
<strong>System Vendor</strong>: <span id="systemVendor"></span> <br />
<strong>System Product</strong>: <span id="systemProduct"></span> <br />
<strong>Total Memory</strong>: <span id="memoryTotal"></span><span id="memoryUnit"></span><br />
<br />
<strong>CPU Information</strong>:
<ul>
<li><strong>Architecture</strong>: <span id="architecture"></span> </li>
<li><strong>CPU Count</strong>: <span id="cpus"></span> </li>
<li><strong>Socket</strong>: <span id="sockets"></span> </li>
<ul id="socketList"></ul>
</ul>
</div>
</div>
</div>
<div class="col-sm-12 col-md-7 mb-4">
<div class="card shadow h-100">
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">Disk Storage Information</h6>
</div>
<!-- Card Body -->
<div class="card-body">
<table class="table">
<thead>
<th>ID</th>
<th>Model</th>
<th>Type</th>
<th>Size</th>
</thead>
<tbody id="diskList"></tbody>
</table>
</div>
</div>
</div>
<div class="col-sm-12 col-md-5 mb-4">
<div class="card shadow h-100">
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">IP Addresses Information</h6>
</div>
<!-- Card Body -->
<div class="card-body">
<strong>Addresses</strong>: <br />
<ul id="addressList"></ul>
</div>
</div>
</div>
</div>
</div>
<!-- /.container-fluid -->
</div>
<!-- End of Main Content -->
<!-- Footer -->
<footer class="sticky-footer bg-white">
<div class="container my-auto">
<div class="copyright text-center my-auto">
<span>Copyright &copy; lxdware.com 2021</span>
</div>
</div>
</footer>
<!-- End of Footer -->
</div>
<!-- End of Content Wrapper -->
</div>
<!-- End of Page Wrapper -->
<!-- Scroll to Top Button-->
<a class="scroll-to-top rounded" href="#page-top">
<i class="fas fa-angle-up"></i>
</a>
<!-- About Modal-->
<div class="modal fade" id="aboutModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">About</h5>
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="row">
<div class="col-12">
<div id="about"></div>
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" type="button" data-dismiss="modal">Dismiss</button>
</div>
</div>
</div>
</div>
<!-- Bootstrap core JavaScript-->
<script src="vendor/jquery/jquery.min.js"></script>
<script src="vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- Core plugin JavaScript-->
<script src="vendor/jquery-easing/jquery.easing.min.js"></script>
<!-- Custom scripts for all pages-->
<script src="vendor/sb-admin-2/js/sb-admin-2.min.js"></script>
<!-- Page level plugins -->
</body>
<script>
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
const remoteId = urlParams.get('remote');
const projectName = urlParams.get('project');
function logout(){
$.get("./php/aaa/authentication.php?action=deauthenticateUser", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code == 200) {
window.location = './index.html'
}
});
}
function operationStatusCheck(){
//check to see if there are any running operations
$.get("./php/lxd/operations.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayOperationStatus", function (data) {
//Check to see if we have running operations
if (data){
//Display spinner and notification area if there are running tasks
$('#spinner').show();
$('#notificationArea').show();
$('#notification').text(data);
//Set the page to check operations again in 1 second
setTimeout(() => { operationStatusCheck(); }, 1000);
}
else {
//Hide spinner and notification area if no running tasks
$('#spinner').hide();
$('#notificationArea').hide();
$('#notification').text("");
//Set the page to check operations again in 3 seconds
setTimeout(() => { operationStatusCheck(); }, 3000);
}
});
}
function reloadPageContent() {
//Check Authorization
$.get("./php/aaa/authentication.php?action=validateAuthentication", function (data) {
operationData = JSON.parse(data);
if (operationData.status_code != 200) {
console.log(operationData);
window.location = './index.html'
}
});
//Resource Info
$.get("./php/lxd/remotes-single.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displaySysInfo", function (data) {
stats = JSON.parse(data);
$("#memoryPercentage").text(stats.memoryPercentage);
$("#memoryPercentageProgressBar").css("width", stats.memoryPercentage + "%")
});
//Instance Info
$.get("./php/lxd/remotes-single.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayInstanceInfo", function (data) {
stats = JSON.parse(data);
$("#runningInstances").text(stats.runningInstances);
$("#totalInstances").text(stats.totalInstances);
instancePercentage = stats.runningInstances / stats.totalInstances * 100
$("#instancePercentageProgressBar").css("width", instancePercentage + "%")
});
//Cluster Member Info
$.get("./php/lxd/remotes-single.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayClusterInfo", function (data) {
stats = JSON.parse(data);
$("#onlineClusterMembers").text(stats.onlineClusterMembers);
$("#totalClusterMembers").text(stats.totalClusterMembers);
clusterPercentage = stats.onlineClusterMembers / stats.totalClusterMembers * 100
$("#clusterPercentageProgressBar").css("width", clusterPercentage + "%")
});
//Image Info
$.get("./php/lxd/remotes-single.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayImageInfo", function (data) {
stats = JSON.parse(data);
$("#totalImages").text(stats.totalImages);
});
//Network Info
$.get("./php/lxd/remotes-single.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayNetworkInfo", function (data) {
stats = JSON.parse(data);
$("#totalNetworks").text(stats.totalNetworks);
});
//Network ACL Info
$.get("./php/lxd/remotes-single.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayNetworkAclInfo", function (data) {
stats = JSON.parse(data);
$("#totalNetworkAcls").text(stats.totalNetworkAcls);
});
//Profile Info
$.get("./php/lxd/remotes-single.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayProfileInfo", function (data) {
stats = JSON.parse(data);
$("#totalProfiles").text(stats.totalProfiles);
});
//Project Info
$.get("./php/lxd/remotes-single.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayProjectInfo", function (data) {
stats = JSON.parse(data);
$("#totalProjects").text(stats.totalProjects);
});
//Storage Pool Info
$.get("./php/lxd/remotes-single.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayStorageInfo", function (data) {
stats = JSON.parse(data);
$("#totalStoragePools").text(stats.totalStoragePools);
});
}
function loadPageContent(){
//Display current logged in username
$("#username").load("./php/admin/settings.php?action=displayUsername");
$("#sidebarLinks").load("./sidebar.html");
$('#remoteBreadCrumb').load("./php/lxd/remote-breadcrumb.php?remote=" + encodeURI(remoteId));
//Resource Info
$.get("./php/lxd/remotes-single.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displaySysInfo", function (data) {
stats = JSON.parse(data);
$("#systemVendor").text(stats.systemVendor);
$("#systemProduct").text(stats.systemProduct);
$("#architecture").text(stats.architecture);
$("#cpus").text(stats.cpus);
$("#memoryTotal").text(stats.memoryTotal);
$("#memoryUnit").text(stats.memoryUnit);
$("#memoryPercentage").text(stats.memoryPercentage);
$("#memoryPercentageProgressBar").css("width", stats.memoryPercentage + "%")
sockets = stats.sockets;
sockets.forEach(element => {
$("#socketList").append('<li>Socket '+element.socket+': '+element.name+'</li>');
});
disks = stats.storageDisks;
disks.forEach(element => {
if (element.type == "cdrom"){
return;
}
tableRow = '<tr>';
tableRow += '<td>'+element.id+'</td>';
tableRow += '<td>'+element.model+'</td>';
tableRow += '<td>'+element.type+'</td>';
if (element.size < 1099511627776){
diskTotal = Math.round(element.size/1024/1024/1024 * 100) / 100;
diskUnit = "GB";
}
else {
diskTotal = Math.round(element.size/1024/1024/1024/1024 * 100) / 100;
diskUnit = "TB";
}
tableRow += '<td>'+diskTotal + ' ' +diskUnit +'</td>';
tableRow += '</tr>';
$('#diskList').append(tableRow);
});
});
//LXD Info
$.get("./php/lxd/remotes-single.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayLxdInfo", function (data) {
stats = JSON.parse(data);
$("#driver").text(stats.driver);
$("#driverVersion").text(stats.driverVersion);
$("#firewall").text(stats.firewall);
$("#kernel").text(stats.kernel);
$("#kernelArchitecture").text(stats.kernelArchitecture);
$("#kernelVersion").text(stats.kernelVersion);
$("#osName").text(stats.osName);
$("#osVersion").css("width", stats.osVersion)
$("#serverVersion").text(stats.serverVersion);
$("#serverName").text(stats.serverName);
$("#storage").text(stats.storage);
$("#storageVersion").text(stats.storageVersion);
addresses = stats.addresses;
addresses.forEach(element => {
$("#addressList").append('<li>'+element+'</li>');
});
});
//Instance Info
$.get("./php/lxd/remotes-single.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayInstanceInfo", function (data) {
stats = JSON.parse(data);
$("#runningInstances").text(stats.runningInstances);
$("#totalInstances").text(stats.totalInstances);
instancePercentage = stats.runningInstances / stats.totalInstances * 100
$("#instancePercentageProgressBar").css("width", instancePercentage + "%")
});
//Cluster Member Info
$.get("./php/lxd/remotes-single.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayClusterInfo", function (data) {
stats = JSON.parse(data);
$("#onlineClusterMembers").text(stats.onlineClusterMembers);
$("#totalClusterMembers").text(stats.totalClusterMembers);
clusterPercentage = stats.onlineClusterMembers / stats.totalClusterMembers * 100
$("#clusterPercentageProgressBar").css("width", clusterPercentage + "%")
});
//Image Info
$.get("./php/lxd/remotes-single.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayImageInfo", function (data) {
stats = JSON.parse(data);
$("#totalImages").text(stats.totalImages);
});
//Network Info
$.get("./php/lxd/remotes-single.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayNetworkInfo", function (data) {
stats = JSON.parse(data);
$("#totalNetworks").text(stats.totalNetworks);
});
//Network ACL Info
$.get("./php/lxd/remotes-single.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayNetworkAclInfo", function (data) {
stats = JSON.parse(data);
$("#totalNetworkAcls").text(stats.totalNetworkAcls);
});
//Profile Info
$.get("./php/lxd/remotes-single.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayProfileInfo", function (data) {
stats = JSON.parse(data);
$("#totalProfiles").text(stats.totalProfiles);
});
//Project Info
$.get("./php/lxd/remotes-single.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayProjectInfo", function (data) {
stats = JSON.parse(data);
$("#totalProjects").text(stats.totalProjects);
});
//Storage Pool Info
$.get("./php/lxd/remotes-single.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayStorageInfo", function (data) {
stats = JSON.parse(data);
$("#totalStoragePools").text(stats.totalStoragePools);
});
//Check for any running operations
operationStatusCheck();
//Set the page content to reload in 10 seconds
setInterval(() => { reloadPageContent(); }, 10000);
}
$(document).ready(function(){
//Check Authorization
$.get("./php/aaa/authentication.php?action=validateAuthentication", function (data) {
operationData = JSON.parse(data);
if (operationData.status_code != 200) {
console.log(operationData);
window.location = './index.html'
}
});
$("#remoteListNav").load("./php/lxd/remotes.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listRemotesForTopNavigation");
$("#projectListNav").load("./php/lxd/projects.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listProjectsForTopNavigation");
//Load Page Content
loadPageContent();
//Set hyperlink references for cards
$("#instancesLink").attr("href", "instances.html?remote="+remoteId+"&project="+projectName)
$("#clusterMembersLink").attr("href", "cluster-members.html?remote="+remoteId+"&project="+projectName)
$("#imagesLink").attr("href", "images.html?remote="+remoteId+"&project="+projectName)
$("#profilesLink").attr("href", "profiles.html?remote="+remoteId+"&project="+projectName)
$("#networksLink").attr("href", "networks.html?remote="+remoteId+"&project="+projectName)
$("#storagePoolsLink").attr("href", "storage-pools.html?remote="+remoteId+"&project="+projectName)
$("#projectsLink").attr("href", "projects.html?remote="+remoteId+"&project="+projectName)
$("#networkAclsLink").attr("href", "network-acls.html?remote="+remoteId+"&project="+projectName)
//Load the about info for the about modal
$.get("./about.html", function (data) {
$("#about").html(data);
});
});
</script>
</html>

File diff suppressed because it is too large Load diff

View file

@ -37,7 +37,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Custom styles for this template-->
<link href="vendor/sb-admin-2/css/sb-admin-2.css" rel="stylesheet">
<link href="assets/css/style.css" rel="stylesheet">
<link href="assets/css/style.css?version=3.0" rel="stylesheet">
<!-- Custom styles for this page -->
<link href="vendor/datatables/dataTables.bootstrap4.min.css" rel="stylesheet">
@ -50,10 +50,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<div id="wrapper">
<!-- Sidebar -->
<ul class="navbar-nav bg-dark sidebar sidebar-dark accordion" id="accordionSidebar">
<ul class="navbar-nav bg-dark sidebar sidebar-dark accordion sidebar-divider-right" id="accordionSidebar">
<!-- Sidebar - Brand -->
<a class="sidebar-brand d-flex align-items-center justify-content-center" href="index.html">
<a class="sidebar-brand d-flex align-items-center justify-content-center" href="index.php">
<div class="sidebar-brand-icon rotate-n-0">
<img src="assets/images/logo-dark.svg" style="width: 2rem;"></img>
<!-- <i class="fas fa-cube" style="width: 2rem;"></i> -->
@ -66,7 +66,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Nav Item - Dashboard -->
<li class="nav-item">
<a class="nav-link" href="remotes.html">
<a class="nav-link" href="remotes.php">
<i class="fas fa-fw fa-server"></i>
<span>Hosts</span></a>
</li>
@ -76,12 +76,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Sidebar Toggler (Sidebar) -->
<div class="text-center d-none d-md-inline">
<button class="rounded-circle border-0" id="sidebarToggle"></button>
<button class="rounded-circle border-0" id="sidebarToggle" onclick="setSidebarToggleValue()"></button>
</div>
</ul>
<!-- End of Sidebar -->
<!-- Content Wrapper -->
<div id="content-wrapper" class="d-flex flex-column">
@ -96,8 +95,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<i class="fa fa-bars"></i>
</button>
<!-- Topbar Navbar -->
<ul class="navbar-nav ml-auto">
@ -111,14 +108,18 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</a>
<!-- Dropdown - User Information -->
<div class="dropdown-menu dropdown-menu-right shadow animated--grow-in" aria-labelledby="userDropdown">
<a class="dropdown-item" href="user-profile.html">
<a class="dropdown-item" href="user-profile.php">
<i class="fas fa-user fa-sm fa-fw mr-2 text-gray-400"></i>
Profile
</a>
<a class="dropdown-item" href="settings.html">
<a class="dropdown-item" href="settings.php">
<i class="fas fa-cog fa-sm fa-fw mr-2 text-gray-400"></i>
Settings
</a>
<a class="dropdown-item" href="logs.php">
<i class="fas fa-history fa-sm fa-fw mr-2 text-gray-400"></i>
Logs
</a>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#aboutModal">
<i class="fas fa-info-circle fa-sm fa-fw mr-2 text-gray-400"></i>
About
@ -139,43 +140,65 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Begin Page Content -->
<div class="container-fluid">
<!-- Page Heading -->
<div class="d-sm-flex align-items-center justify-content-between mb-4">
<h1 class="h5 mb-0 text-gray-800">REMOTE HOSTS</h1>
</div>
<div class="row">
<div class="col-12">
<!-- LXD Host List -->
<div class="card shadow mb-4">
<!-- Card Header - Dropdown -->
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">LXD Hosts</h6>
<div class="dropdown no-arrow">
<a class="dropdown-toggle mr-3" href="#" data-toggle="modal" data-target="#clientCertModal">
View Certificate</a>
<a class="dropdown-toggle mr-3" href="#" data-toggle="modal" data-target="#addLxdModal">
Add Host</a>
<header class="page-header page-header-dark bg-gradient-primary-to-secondary">
<div class="container-xl px-4">
<div class="page-header-content pt-4">
<div class="row align-items-center justify-content-between mt-n5 ml-n5 mr-n5 bg-dark pb-6">
<div class="col-auto mt-4 ml-3">
<div class="page-header-subtitle">
<span id="remoteBreadCrumb">LXD Dashboard</span>
</div>
<h2 class="page-header-title mt-2">
REMOTE HOSTS
</h2>
<div class="page-header-subtitle">
Add and manage remote LXD host servers
</div>
</div>
</div>
<!-- Card Body -->
<div class="card-body">
<div class="row">
<div class="col-12">
<div class="table-responsive">
<table class="table" id="lxdListTable" width="100%" cellspacing="0">
</table>
</div>
<div class="col-12 col-xl-auto mt-4">
<div class="input-group input-group-joined border-0" style="width: 26rem">
<span class="input-group-text bg-transparent border-0">
<a class="btn btn-outline-primary mr-3" href="#" data-toggle="modal" data-target="#clientCertModal" title="View Certificate" aria-hidden="true">
View Certificate
</a>
<a class="btn btn-outline-primary" href="#" data-toggle="modal" data-target="#addLxdModal" title="Add Host" aria-hidden="true">
<i class="fas fa-plus fa-sm fa-fw"></i> Add Host
</a>
</span>
</div>
</div>
</div>
</div>
<!-- End LXD Host List -->
</div>
</div>
</header>
<div class="row mt-n5 ml-2 mr-2">
<div class="col-12 mt-n3">
<!-- Remote Host List -->
<div class="card shadow mb-4">
<!-- Card Header - Dropdown -->
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold">
<span class="ml-1">Hosts</span>
</h6>
<div class="dropdown no-arrow">
<a class="dropdown-toggle mr-2" href="#" onclick="reloadPageContent()" title="Refresh" aria-hidden="true">
<i class="fa fa-sync fa-1x fa-fw"></i></a>
</div>
</div>
<!-- Card Body -->
<div class="card-body">
<div class="table-responsive">
<table class="table" id="lxdListTable" width="100%" cellspacing="0">
</table>
</div>
</div>
</div>
<!-- End Remote Host List -->
</div>
</div>
</div>
<!-- /.container-fluid -->
@ -188,7 +211,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<footer class="sticky-footer bg-white">
<div class="container my-auto">
<div class="copyright text-center my-auto">
<span>Copyright &copy; lxdware.com 2021</span>
<span>Copyright &copy; LXDWARE 2020 - Present</span>
</div>
</div>
</footer>
@ -205,7 +228,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<i class="fas fa-angle-up"></i>
</a>
<!-- Remote Host Modal-->
<!-- Add Remote Host Modal-->
<div class="modal fade" id="addLxdModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
@ -222,26 +245,26 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</p>
<div class="row">
<label class="col-3 col-form-label text-right">Address: </label>
<label class="col-3 col-form-label text-right">Address: <span class="text-danger">*</span></label>
<div class="col-7">
<div class="form-group">
<input type="text" class="form-control" id="hostInput" required="required" name="host">
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle text-danger" title='(Required) - Enter in the IP address or FQDN of the LXD server'></i>
<i class="far fa-sm fa-question-circle" title='(Required) - Enter in the IP address or FQDN of the LXD server'></i>
</div>
</div>
<div class="row">
<label class="col-3 col-form-label text-right">Port: </label>
<label class="col-3 col-form-label text-right">Port: <span class="text-danger">*</span></label>
<div class="col-7">
<div class="form-group">
<input type="number" class="form-control" id="portInput" required="required" value="8443" name="port">
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle text-danger" title='(Required) - Enter in the listening network port to connect to the LXD server. Default: 8443'></i>
<i class="far fa-sm fa-question-circle" title='(Required) - Enter in the listening network port to connect to the LXD server. Default: 8443'></i>
</div>
</div>
@ -257,6 +280,30 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</div>
</div>
<div class="row">
<label class="col-3 col-form-label text-right">External Address: </label>
<div class="col-7">
<div class="form-group">
<input type="text" class="form-control" id="externalHostInput" required="required" name="host">
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle" title='Enter in the IP address or FQDN of the LXD server used for making remote websocket connections. If empty, the host address will be used.'></i>
</div>
</div>
<div class="row">
<label class="col-3 col-form-label text-right">External Port: </label>
<div class="col-7">
<div class="form-group">
<input type="number" class="form-control" id="externalPortInput" required="required" name="port">
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle" title='Enter in the listening network port to connect to the LXD server used for making remote websocket connections. If empty, the host port will be used.'></i>
</div>
</div>
</div> <!-- End Modal Body-->
<div class="modal-footer">
<button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
@ -266,6 +313,89 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</div>
</div>
<!-- Edit Remote Host Modal-->
<div class="modal fade" id="editLxdHost" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Edit LXD Host</h5>
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="row">
<label class="col-3 col-form-label text-right">Address: <span class="text-danger">*</span></label>
<div class="col-7">
<div class="form-group">
<input type="text" class="form-control" id="hostEditInput" required="required" name="host">
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle" title='(Required) - Enter in the IP address or FQDN of the LXD server'></i>
</div>
</div>
<div class="row">
<label class="col-3 col-form-label text-right">Port: <span class="text-danger">*</span></label>
<div class="col-7">
<div class="form-group">
<input type="number" class="form-control" id="portEditInput" required="required" value="8443" name="port">
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle" title='(Required) - Enter in the listening network port to connect to the LXD server. Default: 8443'></i>
</div>
</div>
<div class="row">
<label class="col-3 col-form-label text-right">Alias: </label>
<div class="col-7">
<div class="form-group">
<input type="text" class="form-control" id="aliasEditInput" name="alias">
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle" title='Enter in a friendly name to identify the LXD server in the dashboard.'></i>
</div>
</div>
<div class="row">
<label class="col-3 col-form-label text-right">External Address: </label>
<div class="col-7">
<div class="form-group">
<input type="text" class="form-control" id="externalHostEditInput" required="required" name="host">
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle" title='Enter in the IP address or FQDN of the LXD server used for making remote websocket connections. If empty, the host address will be used.'></i>
</div>
</div>
<div class="row">
<label class="col-3 col-form-label text-right">External Port: </label>
<div class="col-7">
<div class="form-group">
<input type="number" class="form-control" id="externalPortEditInput" required="required" name="port">
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle" title='Enter in the listening network port to connect to the LXD server used for making remote websocket connections. If empty, the host port will be used.'></i>
</div>
</div>
<input type="hidden" id="idEditInput">
</div> <!-- End Modal Body-->
<div class="modal-footer">
<button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
<a class="btn btn-primary" href="#" onclick="updateRemote()" data-dismiss="modal">Submit</a>
</div>
</div>
</div>
</div>
<!-- Instructions Modal-->
<div class="modal fade" id="instructionsModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
@ -314,7 +444,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<div class="modal-body">
<div class="row">
<div class="col-12">
<pre><div id="clientCert"></div></pre>
<pre><div class="pl-5" id="clientCert"></div></pre>
</div>
</div>
</div>
@ -386,43 +516,51 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<script>
var reloadTime = 5000;
function logout(){
$.get("./php/aaa/authentication.php?action=deauthenticateUser", function (data) {
function logout(){
$.get("./backend/aaa/authentication.php?action=deauthenticateUser", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code == 200) {
window.location = './index.html'
window.location.href = './index.php'
}
});
}
function reloadPageContent() {
clearTimeout(pageReloadTimeout);
//Check Authorization
$.get("./php/aaa/authentication.php?action=validateAuthentication", function (data) {
$.get("./backend/aaa/authentication.php?action=validateAuthentication", function (data) {
operationData = JSON.parse(data);
if (operationData.status_code != 200) {
console.log(operationData);
window.location = './index.html'
window.location.href = './index.php'
}
});
$('#lxdListTable').DataTable().ajax.reload(null, false);
//Set reload page content
pageReloadTimeout = setTimeout(() => { reloadPageContent(); }, reloadTime);
}
function loadPageContent(){
//Display current logged in username
$("#username").load("./php/admin/settings.php?action=displayUsername");
$("#username").load("./backend/admin/settings.php?action=displayUsername");
$('#lxdListTable').DataTable( {
ajax: "./php/lxd/remotes.php?action=listRemotes",
ajax: "./backend/lxd/remotes.php?action=listRemotes",
columns: [
{},
{ title: "Host" },
{ title: "Port" },
{ title: "Alias" },
{ title: "External Address" },
{ title: "External Port" },
{ title: "Protocol" },
{ title: "Action" }
],
@ -433,12 +571,17 @@ function logout(){
});
//Load the basic info for the certificate
$.get("./php/config/cert.php?action=viewCertificate", function (data) {
$.get("./backend/config/cert.php?action=viewCertificate", function (data) {
$("#clientCert").html(data);
});
//Set the page content to reload in 5 seconds
setInterval(() => { reloadPageContent(); }, 5000);
//Set reload page content
$.get("./backend/admin/settings.php?action=retrievePageRefreshRateValues", function (data) {
operationData = JSON.parse(data);
if (operationData.remotes_page_rate >= 1)
reloadTime = operationData.remotes_page_rate * 1000;
pageReloadTimeout = setTimeout(() => { reloadPageContent(); }, reloadTime);
});
}
@ -447,7 +590,12 @@ function logout(){
var portNumber = $("#portInput").val();
var aliasName = $("#aliasInput").val();
console.log("Info: adding remote host " + hostName + ":" + portNumber);
$.get("./php/lxd/remotes.php?host=" + encodeURI(hostName) + "&port=" + encodeURI(portNumber) + "&alias=" + encodeURI(aliasName) + "&action=addRemote", function (data) {
$.get("./backend/lxd/remotes.php?host=" + encodeURI(hostName) +
"&port=" + encodeURI(portNumber) +
"&alias=" + encodeURI(aliasName) +
"&external_host=" + encodeURI($("#externalHostInput").val()) +
"&external_port=" + encodeURI($("#externalPortInput").val()) +
"&action=addRemote", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code >= 400){
@ -457,9 +605,20 @@ function logout(){
});
}
function confirmDeleteRemote(remoteID){
console.log("Info: confirming removal of remote host, id number " + remoteID);
$.get("./backend/lxd/remotes.php?id=" + encodeURI(remoteID) + "&action=retrieveRemoteInfo", function (data) {
operationData = JSON.parse(data);
if (confirm("Are you sure you want to remove host " + operationData.host + "?") == true) {
deleteRemote(remoteID);
}
reloadPageContent();
});
}
function deleteRemote(remoteID){
console.log("Info: removing remote host, id number " + remoteID);
$.get("./php/lxd/remotes.php?id=" + encodeURI(remoteID) + "&action=deleteRemote", function (data) {
$.get("./backend/lxd/remotes.php?id=" + encodeURI(remoteID) + "&action=deleteRemote", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code >= 400){
@ -470,20 +629,79 @@ function logout(){
}
function loadInstructionsModal(){
$.get("./php/config/cert.php?action=viewCertificate", function (data) {
$.get("./backend/config/cert.php?action=viewCertificate", function (data) {
$("#instructionsClientCert").html(data);
$("#instructionsModal").modal('show');
});
}
function editRemote(id){
console.log("Info: loading edit host " + id);
$.get("./backend/lxd/remotes.php?remote=" + encodeURI(id) + "&action=loadRemote", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
// 0 is a valid interger value for the database but a reserved unusable port for TCP/UDP
if (operationData.external_port == 0) { operationData.external_port = ""; };
$("#idEditInput").val(operationData.id);
$("#hostEditInput").val(operationData.host);
$("#portEditInput").val(operationData.port);
$("#aliasEditInput").val(operationData.alias);
$("#externalHostEditInput").val(operationData.external_host);
$("#externalPortEditInput").val(operationData.external_port);
$("#editLxdHost").modal('show');
});
}
function updateRemote(){
id = $("#idEditInput").val();
console.log("Info: updating host " + id);
$.get("./backend/lxd/remotes.php?remote=" + encodeURI(id) +
"&host=" + encodeURI($("#hostEditInput").val()) +
"&port=" + encodeURI($("#portEditInput").val()) +
"&alias=" + encodeURI($("#aliasEditInput").val()) +
"&external_host=" + encodeURI($("#externalHostEditInput").val()) +
"&external_port=" + encodeURI($("#externalPortEditInput").val()) +
"&action=updateRemote", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code >= 400){
alert(operationData.metadata.error);
}
setTimeout(() => { reloadPageContent(); }, 1000);
});
}
function setSidebarToggleValue(){
sidebarState = localStorage.getItem('sidebarState');
if (sidebarState == "collapsed"){
localStorage.setItem('sidebarState','expanded');
}
else {
localStorage.setItem('sidebarState','collapsed');
}
}
function applySidebarToggleValue() {
sidebarState = localStorage.getItem('sidebarState');
if (sidebarState == "collapsed"){
$("body").toggleClass("sidebar-toggled"),
$(".sidebar").toggleClass("toggled"),
$(".sidebar").hasClass("toggled") && $(".sidebar .collapse").collapse("hide")
}
}
applySidebarToggleValue();
$(document).ready(function(){
//Check Authorization
$.get("./php/aaa/authentication.php?action=validateAuthentication", function (data) {
$.get("./backend/aaa/authentication.php?action=validateAuthentication", function (data) {
operationData = JSON.parse(data);
if (operationData.status_code != 200) {
console.log(operationData);
window.location = './index.html'
window.location.href = './index.php'
}
});
@ -491,7 +709,7 @@ function logout(){
loadPageContent();
//Load the about info for the about modal
$.get("./about.html", function (data) {
$.get("./backend/config/about.php", function (data) {
$("#about").html(data);
});

View file

@ -1,822 +0,0 @@
<!--
LXDWARE LXD Dashboard - A web-based interface for managing LXD servers
Copyright (C) 2020-2021 LXDWARE.COM
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<link rel="icon" type="image/png" href="assets/images/logo-light.svg">
<title>LXD Dashboard</title>
<!-- Custom fonts for this template-->
<link href="vendor/fontawesome-free/css/all.min.css" rel="stylesheet" type="text/css">
<link href="vendor/fonts/nunito.css" rel="stylesheet">
<!-- Custom styles for this template-->
<link href="vendor/sb-admin-2/css/sb-admin-2.css" rel="stylesheet">
<link href="assets/css/style.css" rel="stylesheet">
<!-- Custom styles for this page -->
<link href="vendor/datatables/dataTables.bootstrap4.min.css" rel="stylesheet">
</head>
<body id="page-top">
<!-- Page Wrapper -->
<div id="wrapper">
<!-- Sidebar -->
<ul class="navbar-nav bg-dark sidebar sidebar-dark accordion" id="accordionSidebar">
<!-- Sidebar - Brand -->
<a class="sidebar-brand d-flex align-items-center justify-content-center" href="index.html">
<div class="sidebar-brand-icon rotate-n-0">
<img src="assets/images/logo-dark.svg" style="width: 2rem;"></img>
<!-- <i class="fas fa-cube" style="width: 2rem;"></i> -->
</div>
<div class="sidebar-brand-text mx-3">LXDWARE</div>
</a>
<!-- Divider -->
<hr class="sidebar-divider">
<!-- Nav Item - Dashboard -->
<li class="nav-item">
<a class="nav-link" href="remotes.html">
<i class="fas fa-fw fa-server"></i>
<span>Hosts</span></a>
</li>
<!-- Divider -->
<hr class="sidebar-divider d-none d-md-block">
<!-- Sidebar Toggler (Sidebar) -->
<div class="text-center d-none d-md-inline">
<button class="rounded-circle border-0" id="sidebarToggle"></button>
</div>
</ul>
<!-- End of Sidebar -->
<!-- Content Wrapper -->
<div id="content-wrapper" class="d-flex flex-column">
<!-- Main Content -->
<div id="content">
<!-- Topbar -->
<nav class="navbar navbar-expand navbar-light bg-white topbar mb-4 static-top shadow">
<!-- Sidebar Toggle (Topbar) -->
<button id="sidebarToggleTop" class="btn btn-link d-md-none rounded-circle mr-3">
<i class="fa fa-bars"></i>
</button>
<!-- Topbar Navbar -->
<ul class="navbar-nav ml-auto">
<div class="topbar-divider d-none d-sm-block"></div>
<!-- Nav Item - User Information -->
<li class="nav-item dropdown no-arrow">
<a class="nav-link dropdown-toggle" href="#" id="userDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fas fa-user-circle fa-1x fa-fw mr-2 text-gray-600"></i>
<span id="username" class="mr-2 d-none d-lg-inline text-gray-600"></span>
</a>
<!-- Dropdown - User Information -->
<div class="dropdown-menu dropdown-menu-right shadow animated--grow-in" aria-labelledby="userDropdown">
<a class="dropdown-item" href="user-profile.html">
<i class="fas fa-user fa-sm fa-fw mr-2 text-gray-400"></i>
Profile
</a>
<a class="dropdown-item" href="settings.html">
<i class="fas fa-cog fa-sm fa-fw mr-2 text-gray-400"></i>
Settings
</a>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#aboutModal">
<i class="fas fa-info-circle fa-sm fa-fw mr-2 text-gray-400"></i>
About
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#" onclick="logout()">
<i class="fas fa-sign-out-alt fa-sm fa-fw mr-2 text-gray-400"></i>
Logout
</a>
</div>
</li>
</ul>
</nav>
<!-- End of Topbar -->
<!-- Begin Page Content -->
<div class="container-fluid">
<!-- Page Heading -->
<div class="d-sm-flex align-items-center justify-content-between">
<h1 class="h5 mb-0 text-gray-800">SETTINGS</h1>
</div>
<div class="col-12">
<div class="row">
<div class="col-2 border-right mt-5">
<div class="nav flex-column nav-pills" id="v-pills-tab" role="tablist" aria-orientation="vertical">
<a class="nav-link active" id="v-pills-users-tab" data-toggle="pill" href="#v-pills-users" role="tab" aria-controls="v-pills-users" aria-selected="false">Users</a>
<a class="nav-link" id="v-pills-groups-tab" data-toggle="pill" href="#v-pills-groups" role="tab" aria-controls="v-pills-groups" aria-selected="false">Groups</a>
</div>
</div>
<div class="col-10">
<div class="tab-content" id="v-pills-tabContent">
<div class="tab-pane fade show active" id="v-pills-users" role="tabpanel" aria-labelledby="v-pills-users-tab">
<!-- Users List -->
<div class="card border-light mb-4">
<!-- Card Header - Dropdown -->
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">Users</h6>
<div class="dropdown no-arrow">
<a class="dropdown-toggle mr-2" href="#" data-toggle="modal" data-target="#createUserModal" title="New User" aria-hidden="true">
<i class="fas fa-plus fa-sm fa-fw"></i> User</a>
</div>
</div>
<!-- Card Body -->
<div class="card-body">
<div class="table-responsive">
<table class="table" id="userListTable" width="100%" cellspacing="0">
</table>
</div>
</div>
</div>
<!-- End Users List -->
</div>
<div class="tab-pane fade" id="v-pills-groups" role="tabpanel" aria-labelledby="v-pills-groups-tab">
<!-- Groups List -->
<div class="card border-light mb-4">
<!-- Card Header - Dropdown -->
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">Groups</h6>
<div class="dropdown no-arrow">
<a class="dropdown-toggle mr-2" href="#" data-toggle="modal" data-target="#createGroupModal" title="New Group" aria-hidden="true">
<i class="fas fa-plus fa-sm fa-fw"></i> Group</a>
</div>
</div>
<!-- Card Body -->
<div class="card-body">
<div class="table-responsive">
<table class="table" id="groupListTable" width="100%" cellspacing="0">
</table>
</div>
</div>
</div>
<!-- End Groups List -->
</div>
</div>
</div>
</div>
</div>
</div>
<!-- /.container-fluid -->
</div>
<!-- End of Main Content -->
<!-- Footer -->
<footer class="sticky-footer bg-white">
<div class="container my-auto">
<div class="copyright text-center my-auto">
<span>Copyright &copy; lxdware.com 2021</span>
</div>
</div>
</footer>
<!-- End of Footer -->
</div>
<!-- End of Content Wrapper -->
</div>
<!-- End of Page Wrapper -->
<!-- Scroll to Top Button-->
<a class="scroll-to-top rounded" href="#page-top">
<i class="fas fa-angle-up"></i>
</a>
<!-- Add User Modal-->
<div class="modal fade" id="createUserModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Create User</h5>
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="row">
<label class="col-3 col-form-label text-right">Username: </label>
<div class="col-7">
<div class="form-group">
<input type="text" id="usernameInput" class="form-control" required="required" placeholder="" name="usernameInput">
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle text-danger" title='(Required) - Enter in a username for the user.'></i>
</div>
</div>
<div class="row">
<label class="col-3 col-form-label text-right">Password: </label>
<div class="col-7">
<div class="form-group">
<input type="password" id="passwordInput" class="form-control" required="required" placeholder="" name="passwordInput">
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle text-danger" title='(Required) - Enter in a password for the user.'></i>
</div>
</div>
<div class="row">
<label class="col-3 col-form-label text-right">First Name: </label>
<div class="col-7">
<div class="form-group">
<input type="text" id="firstNameInput" class="form-control" placeholder="" name="firstNameInput">
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle" title='Enter in the firstname of the user.'></i>
</div>
</div>
<div class="row">
<label class="col-3 col-form-label text-right">Last Name: </label>
<div class="col-7">
<div class="form-group">
<input type="text" id="lastNameInput" class="form-control" placeholder="" name="lastNameInput">
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle" title='Enter in the lastname of the user.'></i>
</div>
</div>
<div class="row">
<label class="col-3 col-form-label text-right">Email: </label>
<div class="col-7">
<div class="form-group">
<input type="text" id="emailInput" class="form-control" required="required" placeholder="" name="emailInput">
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle" title='Enter in the email address of the user.'></i>
</div>
</div>
</div> <!-- End Modal Body-->
<div class="modal-footer">
<button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
<a class="btn btn-primary" href="#" onclick="createUser()" data-dismiss="modal">Submit</a>
</div>
</div>
</div>
</div>
<!-- Add Group Modal-->
<div class="modal fade" id="addGroupModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Add Group</h5>
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="row">
<label class="col-3 col-form-label text-right">Group:</label>
<div class="col-7 text-right">
<div class="form-group">
<select id="groupIdForAddGroupInput" class="form-control" name="groupIdForAddGroupInput">
</select>
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle" title='Select the group to add.'></i>
</div>
</div>
<input type="hidden" id="userIdForAddGroupInput" name="userIdForAddGroupInput">
</div> <!-- End Modal Body-->
<div class="modal-footer">
<button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
<a class="btn btn-primary" href="#" onclick="addGroup()" data-dismiss="modal">Submit</a>
</div>
</div>
</div>
</div>
<!-- Remove Group Modal-->
<div class="modal fade" id="removeGroupModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Remove Group</h5>
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="row">
<label class="col-3 col-form-label text-right">Group:</label>
<div class="col-7 text-right">
<div class="form-group">
<select id="groupIdForRemoveGroupInput" class="form-control" name="groupIdForRemoveGroupInput">
</select>
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle" title='Select the group to remove.'></i>
</div>
</div>
<input type="hidden" id="userIdForRemoveGroupInput" name="userIdForRemoveGroupInput">
</div> <!-- End Modal Body-->
<div class="modal-footer">
<button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
<a class="btn btn-primary" href="#" onclick="removeGroup()" data-dismiss="modal">Submit</a>
</div>
</div>
</div>
</div>
<!-- Delete User Modal-->
<div class="modal fade" id="deleteUserModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Delete User</h5>
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">Are you sure you want to delete this user?</div>
<input type="hidden" id="userIdForDeleteUserInput" name="userIdForDeleteUserInput">
<div class="modal-footer">
<button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
<a class="btn btn-primary" href="#" onclick="deleteUser()" data-dismiss="modal">Yes</a>
</div>
</div>
</div>
</div>
<!-- Create Group Modal-->
<div class="modal fade" id="createGroupModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Create Group</h5>
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="row">
<label class="col-3 col-form-label text-right">Name: </label>
<div class="col-7">
<div class="form-group">
<input type="text" id="nameInput" class="form-control" required="required" placeholder="" name="nameInput">
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle text-danger" title='(Required) - Enter in a name for the group.'></i>
</div>
</div>
<div class="row">
<label class="col-3 col-form-label text-right">Description </label>
<div class="col-7">
<div class="form-group">
<input type="text" id="descriptionInput" class="form-control" required="required" placeholder="" name="descriptionInput">
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle" title='Enter in a description for the group.'></i>
</div>
</div>
</div> <!-- End Modal Body-->
<div class="modal-footer">
<button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
<a class="btn btn-primary" href="#" onclick="createGroup()" data-dismiss="modal">Submit</a>
</div>
</div>
</div>
</div>
<!-- Add Role Modal-->
<div class="modal fade" id="addRoleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Add Role</h5>
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="row">
<label class="col-3 col-form-label text-right">Role:</label>
<div class="col-7 text-right">
<div class="form-group">
<select id="roleIdForAddRoleInput" class="form-control" name="roleIdForAddRoleInput">
</select>
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle" title='Select the role to add.'></i>
</div>
</div>
<input type="hidden" id="groupIdForAddRoleInput" name="groupIdForAddRoleInput">
</div> <!-- End Modal Body-->
<div class="modal-footer">
<button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
<a class="btn btn-primary" href="#" onclick="addRole()" data-dismiss="modal">Submit</a>
</div>
</div>
</div>
</div>
<!-- Remove Role Modal-->
<div class="modal fade" id="removeRoleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Remove Role</h5>
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="row">
<label class="col-3 col-form-label text-right">Role:</label>
<div class="col-7 text-right">
<div class="form-group">
<select id="roleIdForRemoveRoleInput" class="form-control" name="roleIdForRemoveRoleInput">
</select>
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle" title='Select the role to remove.'></i>
</div>
</div>
<input type="hidden" id="groupIdForRemoveRoleInput" name="groupIdForRemoveRoleInput">
</div> <!-- End Modal Body-->
<div class="modal-footer">
<button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
<a class="btn btn-primary" href="#" onclick="removeRole()" data-dismiss="modal">Submit</a>
</div>
</div>
</div>
</div>
<!-- Delete Group Modal-->
<div class="modal fade" id="deleteGroupModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Delete Group</h5>
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">Are you sure you want to delete this group?</div>
<input type="hidden" id="groupIdForDeleteGroupInput" name="groupIdForDeleteGroupInput">
<div class="modal-footer">
<button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
<a class="btn btn-primary" href="#" onclick="deleteGroup()" data-dismiss="modal">Yes</a>
</div>
</div>
</div>
</div>
<!-- About Modal-->
<div class="modal fade" id="aboutModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">About</h5>
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="row">
<div class="col-12">
<div id="about"></div>
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" type="button" data-dismiss="modal">Dismiss</button>
</div>
</div>
</div>
</div>
<!-- Bootstrap core JavaScript-->
<script src="vendor/jquery/jquery.min.js"></script>
<script src="vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- Core plugin JavaScript-->
<script src="vendor/jquery-easing/jquery.easing.min.js"></script>
<!-- Custom scripts for all pages-->
<script src="vendor/sb-admin-2/js/sb-admin-2.min.js"></script>
<!-- Page level plugins -->
<script src="vendor/datatables/jquery.dataTables.min.js"></script>
<script src="vendor/datatables/dataTables.bootstrap4.min.js"></script>
</body>
<script>
function logout(){
$.get("./php/aaa/authentication.php?action=deauthenticateUser", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code == 200) {
window.location = './index.html'
}
});
}
function reloadPageContent() {
//Check Authorization
$.get("./php/aaa/authentication.php?action=validateAuthentication", function (data) {
operationData = JSON.parse(data);
if (operationData.status_code != 200) {
console.log(operationData);
window.location = './index.html'
}
});
$('#userListTable').DataTable().ajax.reload(null, false);
$('#groupListTable').DataTable().ajax.reload(null, false);
}
function loadPageContent(){
//Display current logged in username
$("#username").load("./php/admin/settings.php?action=displayUsername");
$('#userListTable').DataTable( {
ajax: "./php/admin/settings.php?action=listUsers",
columns: [
{},
{ title: "Username" },
{ title: "Email" },
{ title: "Account Type" },
{ title: "Groups" },
{ title: "Action" }
],
order: [],
columnDefs: [
{ targets: 0, orderable: false, width: "25px" }
]
});
$('#groupListTable').DataTable( {
ajax: "./php/admin/settings.php?action=listGroups",
columns: [
{},
{ title: "Name" },
{ title: "Description" },
{ title: "Roles" },
{ title: "Action" }
],
order: [],
columnDefs: [
{ targets: 0, orderable: false, width: "25px" }
]
});
//Set the page content to reload in 10 seconds
setInterval(() => { reloadPageContent(); }, 10000);
}
function createUser(){
var usernameInput = $("#usernameInput").val();
var passwordInput = $("#passwordInput").val();
var firstNameInput = $("#firstNameInput").val();
var lastNameInput = $("#lastNameInput").val();
var emailInput = $("#emailInput").val();
console.log("Info: creating user " + usernameInput);
$.post('./php/admin/settings.php?action=createUser', {username: usernameInput, password: passwordInput, first_name: firstNameInput, last_name: lastNameInput, email: emailInput}, function (data) {
var operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code >= 400) {
alert(operationData.metadata.error);
}
setTimeout(() => { reloadPageContent(); }, 1000)
});
}
function deleteUser(){
var userIdForDeleteUserInput = $("#userIdForDeleteUserInput").val();
console.log("Info: deleting user, id: " + userIdForDeleteUserInput);
$.get("./php/admin/settings.php?id=" + encodeURI(userIdForDeleteUserInput) + "&action=deleteUser", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code >= 400){
alert(operationData.metadata.error);
}
setTimeout(() => { reloadPageContent(); }, 1000);
});
}
function addGroup(){
var userIdForAddGroupInput = $("#userIdForAddGroupInput").val();
var groupIdForAddGroupInput = $("#groupIdForAddGroupInput").val();
console.log("Info: adding group to user");
$.get("./php/admin/settings.php?id=" + encodeURI(userIdForAddGroupInput) + "&group_id=" + encodeURI(groupIdForAddGroupInput) + "&action=addUserToGroup", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code >= 400){
alert(operationData.metadata.error);
}
setTimeout(() => { reloadPageContent(); }, 1000);
});
}
function removeGroup(){
var userIdForRemoveGroupInput = $("#userIdForRemoveGroupInput").val();
var groupIdForRemoveGroupInput = $("#groupIdForRemoveGroupInput").val();
console.log("Info: removing group from user");
$.get("./php/admin/settings.php?id=" + encodeURI(userIdForRemoveGroupInput) + "&group_id=" + encodeURI(groupIdForRemoveGroupInput) + "&action=removeGroupFromUser", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code >= 400){
alert(operationData.metadata.error);
}
setTimeout(() => { reloadPageContent(); }, 1000);
});
}
function loadAddGroupModal(userId){
$("#groupIdForAddGroupInput").load("./php/admin/settings.php?id=" + userId + "&action=listGroupsNotAssignedToUserForSelect");
$("#userIdForAddGroupInput").val(userId);
$("#addGroupModal").modal('show');
}
function loadRemoveGroupModal(userId){
$("#groupIdForRemoveGroupInput").load("./php/admin/settings.php?id=" + userId + "&action=listGroupsAssignedToUserForSelect");
$("#userIdForRemoveGroupInput").val(userId);
$("#removeGroupModal").modal('show');
}
function loadDeleteUserModal(userId){
$("#userIdForDeleteUserInput").val(userId);
$("#deleteUserModal").modal('show');
}
function createGroup(){
var nameInput = $("#nameInput").val();
var descriptionInput = $("#descriptionInput").val();
console.log("Info: adding group " + nameInput);
$.get("./php/admin/settings.php?name=" + encodeURI(nameInput) + "&description=" + encodeURI(descriptionInput) + "&action=createGroup", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code >= 400){
alert(operationData.metadata.error);
}
setTimeout(() => { reloadPageContent(); }, 1000);
});
}
function deleteGroup(){
var groupIdForDeleteGroupInput = $("#groupIdForDeleteGroupInput").val();
console.log("Info: deleting group, id " + groupIdForDeleteGroupInput);
$.get("./php/admin/settings.php?id=" + encodeURI(groupIdForDeleteGroupInput) + "&action=deleteGroup", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code >= 400){
alert(operationData.metadata.error);
}
setTimeout(() => { reloadPageContent(); }, 1000);
});
}
function addRole(){
var groupIdForAddRoleInput = $("#groupIdForAddRoleInput").val();
var roleIdForAddRoleInput = $("#roleIdForAddRoleInput").val();
console.log("Info: adding role to group");
$.get("./php/admin/settings.php?id=" + encodeURI(groupIdForAddRoleInput) + "&role_id=" + encodeURI(roleIdForAddRoleInput) + "&action=addRoleToGroup", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code >= 400){
alert(operationData.metadata.error);
}
setTimeout(() => { reloadPageContent(); }, 1000);
});
}
function removeRole(){
var groupIdForRemoveRoleInput = $("#groupIdForRemoveRoleInput").val();
var roleIdForRemoveRoleInput = $("#roleIdForRemoveRoleInput").val();
console.log("Info: removing role from group");
$.get("./php/admin/settings.php?id=" + encodeURI(groupIdForRemoveRoleInput) + "&role_id=" + encodeURI(roleIdForRemoveRoleInput) + "&action=removeRoleFromGroup", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code >= 400){
alert(operationData.metadata.error);
}
setTimeout(() => { reloadPageContent(); }, 1000);
});
}
function loadAddRoleModal(groupId){
$("#roleIdForAddRoleInput").load("./php/admin/settings.php?id=" + groupId + "&action=listRolesNotAssignedToGroupForSelect");
$("#groupIdForAddRoleInput").val(groupId);
$("#addRoleModal").modal('show');
}
function loadRemoveRoleModal(groupId){
$("#roleIdForRemoveRoleInput").load("./php/admin/settings.php?id=" + groupId + "&action=listRolesAssignedToGroupForSelect");
$("#groupIdForRemoveRoleInput").val(groupId);
$("#removeRoleModal").modal('show');
}
function loadDeleteGroupModal(groupId){
$("#groupIdForDeleteGroupInput").val(groupId);
$("#deleteGroupModal").modal('show');
}
$(document).ready(function(){
//Check Authorization
$.get("./php/aaa/authentication.php?action=validateAuthentication", function (data) {
operationData = JSON.parse(data);
if (operationData.status_code != 200) {
console.log(operationData);
window.location = './index.html'
}
});
//Load the card contents
loadPageContent();
//Load the about info for the about modal
$.get("./about.html", function (data) {
$("#about").html(data);
});
});
</script>
</html>

1579
lxd-dashboard/settings.php Normal file

File diff suppressed because it is too large Load diff

View file

@ -17,7 +17,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<!-- Sidebar - Brand -->
<a class="sidebar-brand d-flex align-items-center justify-content-center" href="remotes.html">
<a class="sidebar-brand d-flex align-items-center justify-content-center" href="remotes.php">
<div class="sidebar-brand-icon rotate-n-0">
<img src="assets/images/logo-dark.svg" style="width: 2rem;"></img>
<!-- <i class="fas fa-cube" style="width: 2rem;"></i> -->
@ -31,7 +31,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<div id="hosts">
<!-- Nav Item - Hosts -->
<li class="nav-item">
<a class="nav-link" href="remotes.html">
<a class="nav-link" href="remotes.php">
<i class="fas fa-fw fa-server"></i>
<span>Hosts</span></a>
</li>
@ -41,11 +41,18 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<hr class="sidebar-divider">
<div id="main">
<!-- Nav Item - Instances -->
<!-- Nav Item - Containers -->
<li class="nav-item">
<a class="nav-link" id="instancesLinkSidebar" href="#">
<i id="instancesIcon" class="fas fa-fw fa-cube"></i>
<span id="instancesSpan">Instances</span></a>
<a class="nav-link" id="containersLinkSidebar" href="#">
<i id="containersIcon" class="fas fa-fw fa-cube"></i>
<span id="containersSpan">Containers</span></a>
</li>
<!-- Nav Item - Containers -->
<li class="nav-item">
<a class="nav-link" id="virtualMachinesLinkSidebar" href="#">
<i id="virtualMachinesIcon" class="fas fa-fw fa-cube"></i>
<span id="virtualMachinesSpan">Virtual Machines</span></a>
</li>
<!-- Nav Item - Images -->
@ -136,71 +143,77 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<script>
$("#instancesLinkSidebar").attr("href", "instances.html?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$("#imagesLinkSidebar").attr("href", "images.html?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$("#profilesLinkSidebar").attr("href", "profiles.html?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$("#networksLinkSidebar").attr("href", "networks.html?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$("#storagePoolsLinkSidebar").attr("href", "storage-pools.html?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$("#containersLinkSidebar").attr("href", "containers.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$("#virtualMachinesLinkSidebar").attr("href", "virtual-machines.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$("#imagesLinkSidebar").attr("href", "images.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$("#profilesLinkSidebar").attr("href", "profiles.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$("#networksLinkSidebar").attr("href", "networks.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$("#storagePoolsLinkSidebar").attr("href", "storage-pools.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$("#clusterLinkSidebar").attr("href", "cluster-members.html?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$("#projectsLinkSidebar").attr("href", "projects.html?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$("#networkAclsLinkSidebar").attr("href", "network-acls.html?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$("#operationsLinkSidebar").attr("href", "operations.html?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$("#certificatesLinkSidebar").attr("href", "certificates.html?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$("#clusterLinkSidebar").attr("href", "cluster-members.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$("#projectsLinkSidebar").attr("href", "projects.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$("#networkAclsLinkSidebar").attr("href", "network-acls.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$("#operationsLinkSidebar").attr("href", "operations.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$("#certificatesLinkSidebar").attr("href", "certificates.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$("#simplestreamsLinkSidebar").attr("href", "simplestreams.html?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$("#simplestreamsLinkSidebar").attr("href", "simplestreams.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
if (location.pathname == "/instances.html" || location.pathname == "/instance.html"){
$('#instancesSpan').css('color','#fff');
$('#instancesIcon').css('color','#fff');
if (location.pathname == "/containers.php" || location.pathname == "/containers-single.php"){
$('#containersSpan').css('color','#fff');
$('#containersIcon').css('color','#fff');
}
if (location.pathname == "/images.html"){
if (location.pathname == "/virtual-machines.php" || location.pathname == "/virtual-machines-single.php"){
$('#virtualMachinesSpan').css('color','#fff');
$('#virtualMachinesIcon').css('color','#fff');
}
if (location.pathname == "/images.php"){
$('#imagesSpan').css('color','#fff');
$('#imagesIcon').css('color','#fff');
}
if (location.pathname == "/profiles.html"){
if (location.pathname == "/profiles.php"){
$('#profilesSpan').css('color','#fff');
$('#profilesIcon').css('color','#fff');
}
if (location.pathname == "/networks.html"){
if (location.pathname == "/networks.php"){
$('#networksSpan').css('color','#fff');
$('#networksIcon').css('color','#fff');
}
if (location.pathname == "/storage-pools.html" || location.pathname == "/storage-volumes.html"){
if (location.pathname == "/storage-pools.php" || location.pathname == "/storage-volumes.php"){
$('#storagePoolsSpan').css('color','#fff');
$('#storagePoolsIcon').css('color','#fff');
}
if (location.pathname == "/cluster-members.html"){
if (location.pathname == "/cluster-members.php"){
$('#cluterSpan').css('color','#fff');
$('#clusterIcon').css('color','#fff');
}
if (location.pathname == "/projects.html"){
if (location.pathname == "/projects.php"){
$('#projectsSpan').css('color','#fff');
$('#projectsIcon').css('color','#fff');
}
if (location.pathname == "/network-acls.html" || location.pathname == "/network-acls-egress.html" || location.pathname == "/network-acls-ingress.html"){
if (location.pathname == "/network-acls.php" || location.pathname == "/network-acls-egress.php" || location.pathname == "/network-acls-ingress.php"){
$('#networkAclsSpan').css('color','#fff');
$('#networkAclsIcon').css('color','#fff');
}
if (location.pathname == "/operations.html"){
if (location.pathname == "/operations.php"){
$('#operationsSpan').css('color','#fff');
$('#operationsIcon').css('color','#fff');
}
if (location.pathname == "/certificates.html"){
if (location.pathname == "/certificates.php"){
$('#certificatesSpan').css('color','#fff');
$('#certificatesIcon').css('color','#fff');
}
if (location.pathname == "/simplestreams.html"){
if (location.pathname == "/simplestreams.php"){
$('#simplestreamsSpan').css('color','#fff');
$('#simplestreamsIcon').css('color','#fff');
}

View file

@ -37,7 +37,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Custom styles for this template-->
<link href="vendor/sb-admin-2/css/sb-admin-2.css" rel="stylesheet">
<link href="assets/css/style.css" rel="stylesheet">
<link href="assets/css/style.css?version=3.0" rel="stylesheet">
<!-- Custom styles for this page -->
<link href="vendor/datatables/dataTables.bootstrap4.min.css" rel="stylesheet">
@ -50,7 +50,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<div id="wrapper">
<!-- Sidebar -->
<ul class="navbar-nav bg-dark sidebar sidebar-dark accordion" id="accordionSidebar">
<ul class="navbar-nav bg-dark sidebar sidebar-dark accordion sidebar-divider-right" id="accordionSidebar">
<div id="sidebarLinks"></div>
@ -59,12 +59,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Sidebar Toggler (Sidebar) -->
<div class="text-center d-none d-md-inline">
<button class="rounded-circle border-0" id="sidebarToggle"></button>
<button class="rounded-circle border-0" id="sidebarToggle" onclick="setSidebarToggleValue()"></button>
</div>
</ul>
<!-- End of Sidebar -->
<!-- Content Wrapper -->
<div id="content-wrapper" class="d-flex flex-column">
@ -79,36 +78,43 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<i class="fa fa-bars"></i>
</button>
<!-- Topbar Notification -->
<div class="d-none d-sm-inline-block form-inline mr-auto ml-md-3 my-2 my-md-0 mw-100 navbar-search">
<ul class="navbar-nav ml-auto">
<li>
<div class="nav-item spinner-border m-3" role="status" style="display:none;" id="spinner">
<span class="nav-item sr-only">Loading...</span>
</div>
</li>
<li class="nav-item dropdown no-arrow" id="notificationArea" style="display: none;">
<div class="nav-link dropdown-toggle">
<span id="notification" class="mr-2 d-none d-lg-inline text-gray-600">Notification</span>
<span id="notification" class="mr-2 d-none d-lg-inline text-danger">Notification</span>
</div>
</li>
</ul>
</div>
<!-- Topbar Navbar -->
<ul class="navbar-nav ml-auto">
<li class="nav-item dropdown" id="remoteListNav">
<li class="nav-item dropdown">
<label class="h6 mt-4 mr-2 ml-4">Host: </label>
</li>
<li class="nav-item dropdown">
<div class="input-group mt-3">
<select class="form-control" id="remoteListNav" style="width:150px;" onchange="location = this.value;">
</select>
</div>
</li>
<li class="nav-item dropdown" id="projectListNav">
<li class="nav-item dropdown">
<label class="h6 mt-4 mr-2 ml-4">Project: </label>
</li>
<li class="nav-item dropdown">
<div class="input-group mt-3">
<select class="form-control" id="projectListNav" style="width:150px;" onchange="location = this.value;">
</select>
</div>
</li>
<!-- Nav Divider -->
<div class="topbar-divider d-none d-sm-block"></div>
<!-- Nav Item - User Information -->
@ -119,14 +125,18 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</a>
<!-- Dropdown - User Information -->
<div class="dropdown-menu dropdown-menu-right shadow animated--grow-in" aria-labelledby="userDropdown">
<a class="dropdown-item" href="user-profile.html">
<a class="dropdown-item" href="user-profile.php">
<i class="fas fa-user fa-sm fa-fw mr-2 text-gray-400"></i>
Profile
</a>
<a class="dropdown-item" href="settings.html">
<a class="dropdown-item" href="settings.php">
<i class="fas fa-cog fa-sm fa-fw mr-2 text-gray-400"></i>
Settings
</a>
<a class="dropdown-item" href="logs.php">
<i class="fas fa-history fa-sm fa-fw mr-2 text-gray-400"></i>
Logs
</a>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#aboutModal">
<i class="fas fa-info-circle fa-sm fa-fw mr-2 text-gray-400"></i>
About
@ -147,25 +157,48 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Begin Page Content -->
<div class="container-fluid">
<!-- BreadCrumb -->
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="#" id="remoteBreadCrumb"></a></li>
<li class="breadcrumb-item active" aria-current="page" id="simplestreamsBreadCrumb"></li>
</ol>
</nav>
<header class="page-header page-header-dark bg-gradient-primary-to-secondary">
<div class="container-xl px-4">
<div class="page-header-content pt-4">
<div class="row align-items-center justify-content-between mt-n5 ml-n5 mr-n5 bg-dark pb-6">
<div class="col-auto mt-4 ml-3">
<div class="page-header-subtitle">
<a href="#" id="remoteBreadCrumb"></a>
</div>
<h2 class="page-header-title mt-2">
SIMPLESTREAMS
</h2>
<div class="page-header-subtitle">
Add and manage simplestreams image repositories
</div>
</div>
<div class="col-12 col-xl-auto mt-4">
<div class="input-group input-group-joined border-0" style="width: 14rem">
<span class="input-group-text bg-transparent border-0">
<a class="btn btn-outline-primary" href="#" data-toggle="modal" data-target="#addSimplestreamsModal" title="New Simplestreams Host" aria-hidden="true">
<i class="fas fa-plus fa-sm fa-fw"></i> Simplestreams Host
</a>
</span>
</div>
</div>
</div>
</div>
</div>
</header>
<div class="row">
<div class="row mt-n5 ml-2 mr-2">
<div class="col-12">
<div class="col-12 mt-n3">
<!-- Simplestreams List -->
<div class="card shadow mb-4">
<!-- Card Header - Dropdown -->
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">Simplestreams</h6>
<h6 class="m-0 font-weight-bold">
<span class="ml-1">Simplestreams</span>
</h6>
<div class="dropdown no-arrow">
<a class="dropdown-toggle mr-2" href="#" data-toggle="modal" data-target="#addSimplestreamsModal" title="New Simplestreams Host" aria-hidden="true">
<i class="fas fa-plus fa-sm fa-fw"></i> Simplestreams Host</a>
<a class="dropdown-toggle mr-2" href="#" onclick="reloadPageContent()" title="Refresh" aria-hidden="true">
<i class="fa fa-sync fa-1x fa-fw"></i></a>
</div>
</div>
<!-- Card Body -->
@ -191,7 +224,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<footer class="sticky-footer bg-white">
<div class="container my-auto">
<div class="copyright text-center my-auto">
<span>Copyright &copy; lxdware.com 2021</span>
<span>Copyright &copy; LXDWARE 2020 - Present</span>
</div>
</div>
</footer>
@ -221,14 +254,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<div class="modal-body">
<div class="row">
<label class="col-3 col-form-label text-right">URL: </label>
<label class="col-3 col-form-label text-right">URL: <span class="text-danger">*</span></label>
<div class="col-7">
<div class="form-group">
<input type="text" class="form-control" id="hostInput" required="required" placeholder="" name="host">
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle text-danger" title='(Required) - Enter in the URL of the simplestreams server. For example, https://images.linuxcontainers.org'></i>
<i class="far fa-sm fa-question-circle" title='(Required) - Enter in the URL of the simplestreams server. For example, https://images.linuxcontainers.org'></i>
</div>
</div>
@ -298,61 +331,66 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
const urlParams = new URLSearchParams(queryString);
const remoteId = urlParams.get('remote');
const projectName = urlParams.get('project');
var reloadTime = 5000;
function logout(){
$.get("./php/aaa/authentication.php?action=deauthenticateUser", function (data) {
$.get("./backend/aaa/authentication.php?action=deauthenticateUser", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code == 200) {
window.location = './index.html'
window.location.href = './index.php'
}
});
}
function operationStatusCheck(){
clearTimeout(operationTimeout);
//check to see if there are any running operations
$.get("./php/lxd/operations.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayOperationStatus", function (data) {
$.get("./backend/lxd/operations.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayOperationStatus", function (data) {
//Check to see if we have running operations
if (data){
//Display spinner and notification area if there are running tasks
$('#spinner').show();
if (data) {
//Display notification area if there are running tasks
$('#notificationArea').show();
$('#notification').text(data);
//Set the page to check operations again in 1 second
setTimeout(() => { operationStatusCheck(); }, 1000);
$('#notification').text("Notice: " + data);
//Set the page to check operations again in 2 seconds
operationTimeout = setTimeout(() => { operationStatusCheck(); }, 2000);
}
else {
//Hide spinner and notification area if no running tasks
$('#spinner').hide();
//Hide notification area if no running tasks
$('#notificationArea').hide();
$('#notification').text("");
//Set the page to check operations again in 3 seconds
setTimeout(() => { operationStatusCheck(); }, 3000);
//Set the page to check operations again in 4 seconds
operationTimeout = setTimeout(() => { operationStatusCheck(); }, 4000);
}
});
}
function reloadPageContent() {
clearTimeout(pageReloadTimeout);
//Check Authorization
$.get("./php/aaa/authentication.php?action=validateAuthentication", function (data) {
$.get("./backend/aaa/authentication.php?action=validateAuthentication", function (data) {
operationData = JSON.parse(data);
if (operationData.status_code != 200) {
console.log(operationData);
window.location = './index.html'
window.location.href = './index.php'
}
});
$('#simplestreamsListTable').DataTable().ajax.reload(null, false);
//Set reload page content
pageReloadTimeout = setTimeout(() => { reloadPageContent(); }, reloadTime);
}
function loadPageContent(){
//Display current logged in username
$("#username").load("./php/admin/settings.php?action=displayUsername");
$("#username").load("./backend/admin/settings.php?action=displayUsername");
$('#simplestreamsListTable').DataTable( {
ajax: "./php/lxd/simplestreams.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listSimplestreams",
ajax: "./backend/lxd/simplestreams.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listSimplestreams",
columns: [
{},
{ title: "Host" },
@ -367,17 +405,23 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
});
//Check for any running operations
operationStatusCheck();
operationTimeout = setTimeout(() => { operationStatusCheck(); }, 1000);
//Set reload page content
$.get("./backend/admin/settings.php?action=retrievePageRefreshRateValues", function (data) {
operationData = JSON.parse(data);
if (operationData.simplestreams_page_rate >= 1)
reloadTime = operationData.simplestreams_page_rate * 1000;
pageReloadTimeout = setTimeout(() => { reloadPageContent(); }, reloadTime);
});
//Set the page content to reload in 5 seconds
setInterval(() => { reloadPageContent(); }, 5000);
}
function addSimplestreams(){
var hostName = $("#hostInput").val();
var aliasName = $("#aliasInput").val();
console.log("Info: adding simplestreams host " + hostName);
$.get("./php/lxd/simplestreams.php?host=" + encodeURI(hostName) + "&alias=" + encodeURI(aliasName) + "&action=addSimplestreams", function (data) {
$.get("./backend/lxd/simplestreams.php?host=" + encodeURI(hostName) + "&alias=" + encodeURI(aliasName) + "&action=addSimplestreams", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code >= 400){
@ -389,7 +433,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
function deleteSimplestreams(simplestreamsID){
console.log("Info: removing simplesteams host, id " + simplestreamsID);
$.get("./php/lxd/simplestreams.php?id=" + encodeURI(simplestreamsID) + "&action=deleteSimplestreams", function (data) {
$.get("./backend/lxd/simplestreams.php?id=" + encodeURI(simplestreamsID) + "&action=deleteSimplestreams", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code >= 400){
@ -399,34 +443,64 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
});
}
function setSidebarToggleValue(){
sidebarState = localStorage.getItem('sidebarState');
if (sidebarState == "collapsed"){
localStorage.setItem('sidebarState','expanded');
}
else {
localStorage.setItem('sidebarState','collapsed');
}
}
function applySidebarToggleValue() {
sidebarState = localStorage.getItem('sidebarState');
if (sidebarState == "collapsed"){
$("body").toggleClass("sidebar-toggled"),
$(".sidebar").toggleClass("toggled"),
$(".sidebar").hasClass("toggled") && $(".sidebar .collapse").collapse("hide")
}
}
applySidebarToggleValue();
$(document).ready(function(){
//Check Authorization
$.get("./php/aaa/authentication.php?action=validateAuthentication", function (data) {
$.get("./backend/aaa/authentication.php?action=validateAuthentication", function (data) {
operationData = JSON.parse(data);
if (operationData.status_code != 200) {
console.log(operationData);
window.location = './index.html'
window.location.href = './index.php'
}
});
//Load in the sidebar
$("#sidebarLinks").load("./sidebar.html");
$("#sidebarLinks").load("./sidebar.php?version=3.0");
//Setup Page Breadcrumb Links/Information
$('#remoteBreadCrumb').load("./php/lxd/remote-breadcrumb.php?remote=" + encodeURI(remoteId));
$('#remoteBreadCrumb').attr("href", "remotes-single.html?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$('#simplestreamsBreadCrumb').text("simplestreams");
$('#remoteBreadCrumb').load("./backend/lxd/remote-breadcrumb.php?remote=" + encodeURI(remoteId));
$('#remoteBreadCrumb').attr("href", "remotes-single.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
//Load the card contents
loadPageContent();
//Validate remote host connection returns 200 status
$.get("./backend/lxd/remotes-single.php?remote=" + encodeURI(remoteId) + "&action=validateRemoteConnection", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code == 200) {
//Set top navbar dropdowns
$("#remoteListNav").load("./backend/lxd/remotes.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listRemotesForSelectOption");
$("#projectListNav").load("./backend/lxd/projects.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listProjectsForSelectOption");
$("#remoteListNav").load("./php/lxd/remotes.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listRemotesForTopNavigation");
$("#projectListNav").load("./php/lxd/projects.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listProjectsForTopNavigation");
//Load Page Content
loadPageContent();
}
else {
alert("Unable to connect to remote host. HTTP status code: " + operationData.status_code);
}
});
//Load the about info for the about modal
$.get("./about.html", function (data) {
$.get("./backend/config/about.php", function (data) {
$("#about").html(data);
});

View file

@ -37,7 +37,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Custom styles for this template-->
<link href="vendor/sb-admin-2/css/sb-admin-2.css" rel="stylesheet">
<link href="assets/css/style.css" rel="stylesheet">
<link href="assets/css/style.css?version=3.0" rel="stylesheet">
<!-- Custom styles for this page -->
<link href="vendor/datatables/dataTables.bootstrap4.min.css" rel="stylesheet">
@ -50,7 +50,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<div id="wrapper">
<!-- Sidebar -->
<ul class="navbar-nav bg-dark sidebar sidebar-dark accordion" id="accordionSidebar">
<ul class="navbar-nav bg-dark sidebar sidebar-dark accordion sidebar-divider-right" id="accordionSidebar">
<div id="sidebarLinks"></div>
@ -59,12 +59,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Sidebar Toggler (Sidebar) -->
<div class="text-center d-none d-md-inline">
<button class="rounded-circle border-0" id="sidebarToggle"></button>
<button class="rounded-circle border-0" id="sidebarToggle" onclick="setSidebarToggleValue()"></button>
</div>
</ul>
<!-- End of Sidebar -->
<!-- Content Wrapper -->
<div id="content-wrapper" class="d-flex flex-column">
@ -79,36 +78,43 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<i class="fa fa-bars"></i>
</button>
<!-- Topbar Notification -->
<div class="d-none d-sm-inline-block form-inline mr-auto ml-md-3 my-2 my-md-0 mw-100 navbar-search">
<ul class="navbar-nav ml-auto">
<li>
<div class="nav-item spinner-border m-3" role="status" style="display:none;" id="spinner">
<span class="nav-item sr-only">Loading...</span>
</div>
</li>
<li class="nav-item dropdown no-arrow" id="notificationArea" style="display: none;">
<div class="nav-link dropdown-toggle">
<span id="notification" class="mr-2 d-none d-lg-inline text-gray-600">Notification</span>
<span id="notification" class="mr-2 d-none d-lg-inline text-danger">Notification</span>
</div>
</li>
</ul>
</div>
<!-- Topbar Navbar -->
<ul class="navbar-nav ml-auto">
<li class="nav-item dropdown" id="remoteListNav">
<li class="nav-item dropdown">
<label class="h6 mt-4 mr-2 ml-4">Host: </label>
</li>
<li class="nav-item dropdown">
<div class="input-group mt-3">
<select class="form-control" id="remoteListNav" style="width:150px;" onchange="location = this.value;">
</select>
</div>
</li>
<li class="nav-item dropdown" id="projectListNav">
<li class="nav-item dropdown">
<label class="h6 mt-4 mr-2 ml-4">Project: </label>
</li>
<li class="nav-item dropdown">
<div class="input-group mt-3">
<select class="form-control" id="projectListNav" style="width:150px;" onchange="location = this.value;">
</select>
</div>
</li>
<!-- Nav Divider -->
<div class="topbar-divider d-none d-sm-block"></div>
<!-- Nav Item - User Information -->
@ -119,14 +125,18 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</a>
<!-- Dropdown - User Information -->
<div class="dropdown-menu dropdown-menu-right shadow animated--grow-in" aria-labelledby="userDropdown">
<a class="dropdown-item" href="user-profile.html">
<a class="dropdown-item" href="user-profile.php">
<i class="fas fa-user fa-sm fa-fw mr-2 text-gray-400"></i>
Profile
</a>
<a class="dropdown-item" href="settings.html">
<a class="dropdown-item" href="settings.php">
<i class="fas fa-cog fa-sm fa-fw mr-2 text-gray-400"></i>
Settings
</a>
<a class="dropdown-item" href="logs.php">
<i class="fas fa-history fa-sm fa-fw mr-2 text-gray-400"></i>
Logs
</a>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#aboutModal">
<i class="fas fa-info-circle fa-sm fa-fw mr-2 text-gray-400"></i>
About
@ -147,25 +157,48 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Begin Page Content -->
<div class="container-fluid">
<!-- BreadCrumb -->
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="#" id="remoteBreadCrumb"></a></li>
<li class="breadcrumb-item active" aria-current="page" id="storagePoolsBreadCrumb"></li>
</ol>
</nav>
<header class="page-header page-header-dark bg-gradient-primary-to-secondary">
<div class="container-xl px-4">
<div class="page-header-content pt-4">
<div class="row align-items-center justify-content-between mt-n5 ml-n5 mr-n5 bg-dark pb-6">
<div class="col-auto mt-4 ml-3">
<div class="page-header-subtitle">
<a href="#" id="remoteBreadCrumb"></a>
</div>
<h2 class="page-header-title mt-2">
STORAGE POOLS
</h2>
<div class="page-header-subtitle">
Create and manage LXD storage pools
</div>
</div>
<div class="col-12 col-xl-auto mt-4">
<div class="input-group input-group-joined border-0" style="width: 14rem">
<span class="input-group-text bg-transparent border-0">
<a class="btn btn-outline-primary" href="#" onclick="loadCreateStoragePoolModal()" title="New Storage Pool" aria-hidden="true">
<i class="fas fa-plus fa-sm fa-fw"></i> Storge Pool
</a>
</span>
</div>
</div>
</div>
</div>
</div>
</header>
<div class="row">
<div class="row mt-n5 ml-2 mr-2">
<div class="col-12">
<div class="col-12 mt-n3">
<!-- Storage Pool List -->
<div class="card shadow mb-4">
<!-- Card Header - Dropdown -->
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">Storage Pools</h6>
<h6 class="m-0 font-weight-bold">
<span class="ml-1">Storage Pools</span>
</h6>
<div class="dropdown no-arrow">
<a class="dropdown-toggle mr-2" href="#" onclick="loadCreateStoragePoolModal()" title="New Storage Pool" aria-hidden="true">
<i class="fas fa-plus fa-sm fa-fw"></i> Storage Pool</a>
<a class="dropdown-toggle mr-2" href="#" onclick="reloadPageContent()" title="Refresh" aria-hidden="true">
<i class="fa fa-sync fa-1x fa-fw"></i></a>
</div>
</div>
<!-- Card Body -->
@ -191,7 +224,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<footer class="sticky-footer bg-white">
<div class="container my-auto">
<div class="copyright text-center my-auto">
<span>Copyright &copy; lxdware.com 2021</span>
<span>Copyright &copy; LXDWARE 2020 - Present</span>
</div>
</div>
</footer>
@ -231,14 +264,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<div class="tab-pane fade show active" id="form" role="tabpanel" aria-labelledby="form-tab">
<br />
<div class="row">
<label class="col-3 col-form-label text-right">Name: </label>
<label class="col-3 col-form-label text-right">Name: <span class="text-danger">*</span></label>
<div class="col-7">
<div class="form-group">
<input type="text" id="storagePoolNameInput" class="form-control" placeholder="" name="storage_pool_name">
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle text-danger" title='(Required) - Enter in the name of the storage pool.'></i>
<i class="far fa-sm fa-question-circle" title='(Required) - Enter in the name of the storage pool.'></i>
</div>
</div>
@ -255,7 +288,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</div>
<div class="row">
<label class="col-3 col-form-label text-right">Driver: </label>
<label class="col-3 col-form-label text-right">Driver: <span class="text-danger">*</span></label>
<div class="col-7">
<div class="form-group">
<select id="storagePoolDriverInput" class="form-control" onclick="changeStoragePoolDriverInput()"name="storage_pool_driver">
@ -269,7 +302,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle text-danger" title='(Required) - Select the storage pool driver.'></i>
<i class="far fa-sm fa-question-circle" title='(Required) - Select the storage pool driver.'></i>
</div>
</div>
@ -798,61 +831,66 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
const remoteId = urlParams.get('remote');
const projectName = urlParams.get('project');
var storagePoolToUpdate = "";
var reloadTime = 5000;
function logout(){
$.get("./php/aaa/authentication.php?action=deauthenticateUser", function (data) {
$.get("./backend/aaa/authentication.php?action=deauthenticateUser", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code == 200) {
window.location = './index.html'
window.location.href = './index.php'
}
});
}
function operationStatusCheck(){
clearTimeout(operationTimeout);
//check to see if there are any running operations
$.get("./php/lxd/operations.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayOperationStatus", function (data) {
$.get("./backend/lxd/operations.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayOperationStatus", function (data) {
//Check to see if we have running operations
if (data){
//Display spinner and notification area if there are running tasks
$('#spinner').show();
if (data) {
//Display notification area if there are running tasks
$('#notificationArea').show();
$('#notification').text(data);
//Set the page to check operations again in 1 second
setTimeout(() => { operationStatusCheck(); }, 1000);
$('#notification').text("Notice: " + data);
//Set the page to check operations again in 2 seconds
operationTimeout = setTimeout(() => { operationStatusCheck(); }, 2000);
}
else {
//Hide spinner and notification area if no running tasks
$('#spinner').hide();
//Hide notification area if no running tasks
$('#notificationArea').hide();
$('#notification').text("");
//Set the page to check operations again in 3 seconds
setTimeout(() => { operationStatusCheck(); }, 3000);
//Set the page to check operations again in 4 seconds
operationTimeout = setTimeout(() => { operationStatusCheck(); }, 4000);
}
});
}
function reloadPageContent() {
clearTimeout(pageReloadTimeout);
//Check Authorization
$.get("./php/aaa/authentication.php?action=validateAuthentication", function (data) {
$.get("./backend/aaa/authentication.php?action=validateAuthentication", function (data) {
operationData = JSON.parse(data);
if (operationData.status_code != 200) {
console.log(operationData);
window.location = './index.html'
window.location.href = './index.php'
}
});
$('#storagePoolListTable').DataTable().ajax.reload(null, false);
//Set reload page content
pageReloadTimeout = setTimeout(() => { reloadPageContent(); }, reloadTime);
}
function loadPageContent(){
//Display current logged in username
$("#username").load("./php/admin/settings.php?action=displayUsername");
$("#username").load("./backend/admin/settings.php?action=displayUsername");
$('#storagePoolListTable').DataTable( {
ajax: "./php/lxd/storage-pools.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listStoragePools",
ajax: "./backend/lxd/storage-pools.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listStoragePools",
columns: [
{},
{ title: "Name" },
@ -870,16 +908,22 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
});
//Check for any running operations
operationStatusCheck();
operationTimeout = setTimeout(() => { operationStatusCheck(); }, 1000);
//Set reload page content
$.get("./backend/admin/settings.php?action=retrievePageRefreshRateValues", function (data) {
operationData = JSON.parse(data);
if (operationData.storage_pools_page_rate >= 1)
reloadTime = operationData.storage_pools_page_rate * 1000;
pageReloadTimeout = setTimeout(() => { reloadPageContent(); }, reloadTime);
});
//Set the page content to reload in 5 seconds
setInterval(() => { reloadPageContent(); }, 5000);
}
function createStoragePoolUsingJSON(){
var storagePoolCreateJSON = $("#jsonCreateInput").val();
console.log("Info: creating storage pool");
$.post("./php/lxd/storage-pools.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=createStoragePoolUsingJSON", {json: storagePoolCreateJSON}, function (data) {
$.post("./backend/lxd/storage-pools.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=createStoragePoolUsingJSON", {json: storagePoolCreateJSON}, function (data) {
//Sync operation type
var operationData = JSON.parse(data);
console.log(operationData);
@ -928,7 +972,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
var storagePoolZfsPoolNameInput = $("#storagePoolZfsPoolNameInput").val();
console.log("Info: creating storage pool");
$.get("./php/lxd/storage-pools.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) +
$.get("./backend/lxd/storage-pools.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) +
"&name=" + encodeURI(storagePoolNameInput) +
"&description=" + encodeURI(storagePoolDescriptionInput) +
"&size=" + encodeURI(storagePoolSizeInput) +
@ -979,7 +1023,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
function loadStoragePoolJson(storagePoolToLoad){
console.log("Info: loading storage pool " + storagePoolToLoad);
storagePoolToUpdate = storagePoolToLoad;
$.get("./php/lxd/storage-pools.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&storage_pool=" + encodeURI(storagePoolToLoad) + "&action=loadStoragePool", function (data) {
$.get("./backend/lxd/storage-pools.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&storage_pool=" + encodeURI(storagePoolToLoad) + "&action=loadStoragePool", function (data) {
//Sync operation type
var operationData = JSON.parse(data);
console.log(operationData);
@ -995,7 +1039,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
function updateStoragePool(){
var storagePoolUpdateJSON = $("#jsonEditInput").val();
console.log("Info: updating storage pool " + storagePoolToUpdate);
$.post("./php/lxd/storage-pools.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&storage_pool=" + encodeURI(storagePoolToUpdate) + "&action=updateStoragePool", {json: storagePoolUpdateJSON}, function (data) {
$.post("./backend/lxd/storage-pools.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&storage_pool=" + encodeURI(storagePoolToUpdate) + "&action=updateStoragePool", {json: storagePoolUpdateJSON}, function (data) {
//Sync operation type
var operationData = JSON.parse(data);
console.log(operationData);
@ -1008,7 +1052,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
function deleteStoragePool(storagePoolToDelete){
console.log("Info: deleting storage pool " + storagePoolToDelete);
$.get("./php/lxd/storage-pools.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&storage_pool=" + encodeURI(storagePoolToDelete) + "&action=deleteStoragePool", function (data) {
$.get("./backend/lxd/storage-pools.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&storage_pool=" + encodeURI(storagePoolToDelete) + "&action=deleteStoragePool", function (data) {
//Sync operation type
var operationData = JSON.parse(data);
console.log(operationData);
@ -1233,33 +1277,64 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
}
}
function setSidebarToggleValue(){
sidebarState = localStorage.getItem('sidebarState');
if (sidebarState == "collapsed"){
localStorage.setItem('sidebarState','expanded');
}
else {
localStorage.setItem('sidebarState','collapsed');
}
}
function applySidebarToggleValue() {
sidebarState = localStorage.getItem('sidebarState');
if (sidebarState == "collapsed"){
$("body").toggleClass("sidebar-toggled"),
$(".sidebar").toggleClass("toggled"),
$(".sidebar").hasClass("toggled") && $(".sidebar .collapse").collapse("hide")
}
}
applySidebarToggleValue();
$(document).ready(function(){
//Check Authorization
$.get("./php/aaa/authentication.php?action=validateAuthentication", function (data) {
$.get("./backend/aaa/authentication.php?action=validateAuthentication", function (data) {
operationData = JSON.parse(data);
if (operationData.status_code != 200) {
console.log(operationData);
window.location = './index.html'
window.location.href = './index.php'
}
});
//Load in the sidebar
$("#sidebarLinks").load("./sidebar.html");
//Load in the sidebar
$("#sidebarLinks").load("./sidebar.php?version=3.0");
//Setup Page Breadcrumb Links/Information
$('#remoteBreadCrumb').load("./php/lxd/remote-breadcrumb.php?remote=" + encodeURI(remoteId));
$('#remoteBreadCrumb').attr("href", "remotes-single.html?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$('#storagePoolsBreadCrumb').text("storage-pools");
//Load the card contents
loadPageContent();
$("#remoteListNav").load("./php/lxd/remotes.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listRemotesForTopNavigation");
$("#projectListNav").load("./php/lxd/projects.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listProjectsForTopNavigation");
$('#remoteBreadCrumb').load("./backend/lxd/remote-breadcrumb.php?remote=" + encodeURI(remoteId));
$('#remoteBreadCrumb').attr("href", "remotes-single.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
//Validate remote host connection returns 200 status
$.get("./backend/lxd/remotes-single.php?remote=" + encodeURI(remoteId) + "&action=validateRemoteConnection", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code == 200) {
//Set top navbar dropdowns
$("#remoteListNav").load("./backend/lxd/remotes.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listRemotesForSelectOption");
$("#projectListNav").load("./backend/lxd/projects.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listProjectsForSelectOption");
//Load Page Content
loadPageContent();
}
else {
alert("Unable to connect to remote host. HTTP status code: " + operationData.status_code);
}
});
//Load the about info for the about modal
$.get("./about.html", function (data) {
$.get("./backend/config/about.php", function (data) {
$("#about").html(data);
});

View file

@ -37,7 +37,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Custom styles for this template-->
<link href="vendor/sb-admin-2/css/sb-admin-2.css" rel="stylesheet">
<link href="assets/css/style.css" rel="stylesheet">
<link href="assets/css/style.css?version=3.0" rel="stylesheet">
<!-- Custom styles for this page -->
<link href="vendor/datatables/dataTables.bootstrap4.min.css" rel="stylesheet">
@ -50,7 +50,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<div id="wrapper">
<!-- Sidebar -->
<ul class="navbar-nav bg-dark sidebar sidebar-dark accordion" id="accordionSidebar">
<ul class="navbar-nav bg-dark sidebar sidebar-dark accordion sidebar-divider-right" id="accordionSidebar">
<div id="sidebarLinks"></div>
@ -59,12 +59,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Sidebar Toggler (Sidebar) -->
<div class="text-center d-none d-md-inline">
<button class="rounded-circle border-0" id="sidebarToggle"></button>
<button class="rounded-circle border-0" id="sidebarToggle" onclick="setSidebarToggleValue()"></button>
</div>
</ul>
<!-- End of Sidebar -->
<!-- Content Wrapper -->
<div id="content-wrapper" class="d-flex flex-column">
@ -79,36 +78,43 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<i class="fa fa-bars"></i>
</button>
<!-- Topbar Notification -->
<div class="d-none d-sm-inline-block form-inline mr-auto ml-md-3 my-2 my-md-0 mw-100 navbar-search">
<!-- Topbar Notification -->
<div class="d-none d-sm-inline-block form-inline mr-auto ml-md-3 my-2 my-md-0 mw-100 navbar-search">
<ul class="navbar-nav ml-auto">
<li>
<div class="nav-item spinner-border m-3" role="status" style="display:none;" id="spinner">
<span class="nav-item sr-only">Loading...</span>
</div>
</li>
<li class="nav-item dropdown no-arrow" id="notificationArea" style="display: none;">
<div class="nav-link dropdown-toggle">
<span id="notification" class="mr-2 d-none d-lg-inline text-gray-600">Notification</span>
<span id="notification" class="mr-2 d-none d-lg-inline text-danger">Notification</span>
</div>
</li>
</ul>
</div>
<!-- Topbar Navbar -->
<ul class="navbar-nav ml-auto">
<li class="nav-item dropdown" id="remoteListNav">
<li class="nav-item dropdown">
<label class="h6 mt-4 mr-2 ml-4">Host: </label>
</li>
<li class="nav-item dropdown">
<div class="input-group mt-3">
<select class="form-control" id="remoteListNav" style="width:150px;" onchange="location = this.value;">
</select>
</div>
</li>
<li class="nav-item dropdown" id="projectListNav">
<li class="nav-item dropdown">
<label class="h6 mt-4 mr-2 ml-4">Project: </label>
</li>
<li class="nav-item dropdown">
<div class="input-group mt-3">
<select class="form-control" id="projectListNav" style="width:150px;" onchange="location = this.value;">
</select>
</div>
</li>
<!-- Nav Divider -->
<div class="topbar-divider d-none d-sm-block"></div>
<!-- Nav Item - User Information -->
@ -119,14 +125,18 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</a>
<!-- Dropdown - User Information -->
<div class="dropdown-menu dropdown-menu-right shadow animated--grow-in" aria-labelledby="userDropdown">
<a class="dropdown-item" href="user-profile.html">
<a class="dropdown-item" href="user-profile.php">
<i class="fas fa-user fa-sm fa-fw mr-2 text-gray-400"></i>
Profile
</a>
<a class="dropdown-item" href="settings.html">
<a class="dropdown-item" href="settings.php">
<i class="fas fa-cog fa-sm fa-fw mr-2 text-gray-400"></i>
Settings
</a>
<a class="dropdown-item" href="logs.php">
<i class="fas fa-history fa-sm fa-fw mr-2 text-gray-400"></i>
Logs
</a>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#aboutModal">
<i class="fas fa-info-circle fa-sm fa-fw mr-2 text-gray-400"></i>
About
@ -147,26 +157,50 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Begin Page Content -->
<div class="container-fluid">
<!-- BreadCrumb -->
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="#" id="remoteBreadCrumb"></a></li>
<li class="breadcrumb-item"><a href="#" id="storagePoolsBreadCrumb"></a></li>
<li class="breadcrumb-item active" aria-current="page" id="storageVolumesBreadCrumb"></li>
</ol>
</nav>
<header class="page-header page-header-dark bg-gradient-primary-to-secondary">
<div class="container-xl px-4">
<div class="page-header-content pt-4">
<div class="row align-items-center justify-content-between mt-n5 ml-n5 mr-n5 bg-dark pb-6">
<div class="col-auto mt-4 ml-3">
<div class="page-header-subtitle">
<a href="#" id="remoteBreadCrumb"></a>
/
<a href="#" id="storagePoolsBreadCrumb"></a>
</div>
<h2 class="page-header-title mt-2">
STORAGE VOLUMES
</h2>
<div class="page-header-subtitle">
Create and manage LXD storage volumes
</div>
</div>
<div class="col-12 col-xl-auto mt-4">
<div class="input-group input-group-joined border-0" style="width: 14rem">
<span class="input-group-text bg-transparent border-0">
<a class="btn btn-outline-primary" href="#" data-toggle="modal" data-target="#createStorageVolumeModal" title="New Storage Volume" aria-hidden="true">
<i class="fas fa-plus fa-sm fa-fw"></i> Storage Volume
</a>
</span>
</div>
</div>
</div>
</div>
</div>
</header>
<div class="row">
<div class="row mt-n5 ml-2 mr-2">
<div class="col-12">
<div class="col-12 mt-n3">
<!-- Storage Volume List -->
<div class="card shadow mb-4">
<!-- Card Header - Dropdown -->
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">Storage Volumes</h6>
<h6 class="m-0 font-weight-bold">
<span class="ml-1">Storage Volumes</span>
</h6>
<div class="dropdown no-arrow">
<a class="dropdown-toggle mr-2" href="#" data-toggle="modal" data-target="#createStorageVolumeModal" title="New Storage Volume" aria-hidden="true">
<i class="fas fa-plus fa-sm fa-fw"></i> Storage Volume</a>
<a class="dropdown-toggle mr-2" href="#" onclick="reloadPageContent()" title="Refresh" aria-hidden="true">
<i class="fa fa-sync fa-1x fa-fw"></i></a>
</div>
</div>
<!-- Card Body -->
@ -180,7 +214,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</div>
</div>
</div>
<!-- End Storage Volume List -->
<!-- End Storeage Volume List -->
</div>
</div>
@ -195,7 +229,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<footer class="sticky-footer bg-white">
<div class="container my-auto">
<div class="copyright text-center my-auto">
<span>Copyright &copy; lxdware.com 2021</span>
<span>Copyright &copy; LXDWARE 2020 - Present</span>
</div>
</div>
</footer>
@ -235,18 +269,18 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<div class="tab-pane fade show active" id="form" role="tabpanel" aria-labelledby="form-tab">
<br />
<div class="row">
<label class="col-3 col-form-label text-right">Name: </label>
<label class="col-3 col-form-label text-right">Name: <span class="text-danger">*</span></label>
<div class="col-7">
<div class="form-group">
<input type="text" id="storageVolumeNameInput" class="form-control" placeholder="" name="storage_volume_name">
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle text-danger" title='(Required) - Enter in the name of the storage volume.'></i>
<i class="far fa-sm fa-question-circle" title='(Required) - Enter in the name of the storage volume.'></i>
</div>
</div>
<div class="row">
<label class="col-3 col-form-label text-right">Content Type: </label>
<label class="col-3 col-form-label text-right">Content Type: <span class="text-danger">*</span></label>
<div class="col-7">
<div class="form-group">
<select id="storageVolumeContentTypeInput" class="form-control" name="content_type">
@ -256,7 +290,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle text-danger" title='(Required) - Select the content type.'></i>
<i class="far fa-sm fa-question-circle" title='(Required) - Select the content type.'></i>
</div>
</div>
<div class="row">
@ -536,62 +570,67 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
const projectName = urlParams.get('project');
const storagePoolName = urlParams.get('pool');
var storageVolumeToUpdate = "";
var volumeType = urlParams.get('type');
var volumeType = urlParams.get('type');
var reloadTime = 5000;
function logout(){
$.get("./php/aaa/authentication.php?action=deauthenticateUser", function (data) {
$.get("./backend/aaa/authentication.php?action=deauthenticateUser", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code == 200) {
window.location = './index.html'
window.location.href = './index.php'
}
});
}
function operationStatusCheck(){
clearTimeout(operationTimeout);
//check to see if there are any running operations
$.get("./php/lxd/operations.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayOperationStatus", function (data) {
$.get("./backend/lxd/operations.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=displayOperationStatus", function (data) {
//Check to see if we have running operations
if (data){
//Display spinner and notification area if there are running tasks
$('#spinner').show();
if (data) {
//Display notification area if there are running tasks
$('#notificationArea').show();
$('#notification').text(data);
//Set the page to check operations again in 1 second
setTimeout(() => { operationStatusCheck(); }, 1000);
$('#notification').text("Notice: " + data);
//Set the page to check operations again in 2 seconds
operationTimeout = setTimeout(() => { operationStatusCheck(); }, 2000);
}
else {
//Hide spinner and notification area if no running tasks
$('#spinner').hide();
//Hide notification area if no running tasks
$('#notificationArea').hide();
$('#notification').text("");
//Set the page to check operations again in 3 seconds
setTimeout(() => { operationStatusCheck(); }, 3000);
//Set the page to check operations again in 4 seconds
operationTimeout = setTimeout(() => { operationStatusCheck(); }, 4000);
}
});
}
function reloadPageContent(){
clearTimeout(pageReloadTimeout);
//Check Authorization
$.get("./php/aaa/authentication.php?action=validateAuthentication", function (data) {
$.get("./backend/aaa/authentication.php?action=validateAuthentication", function (data) {
operationData = JSON.parse(data);
if (operationData.status_code != 200) {
console.log(operationData);
window.location = './index.html'
window.location.href = './index.php'
}
});
$('#storageVolumeListTable').DataTable().ajax.reload(null, false);
//Set reload page content
pageReloadTimeout = setTimeout(() => { reloadPageContent(); }, reloadTime);
}
function loadPageContent(){
//Display current logged in username
$("#username").load("./php/admin/settings.php?action=displayUsername");
$("#username").load("./backend/admin/settings.php?action=displayUsername");
$('#storageVolumeListTable').DataTable( {
ajax: "./php/lxd/storage-volumes.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&pool=" + encodeURI(storagePoolName) + "&type=" + encodeURI(volumeType) + "&action=listStorageVolumes",
ajax: "./backend/lxd/storage-volumes.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&pool=" + encodeURI(storagePoolName) + "&type=" + encodeURI(volumeType) + "&action=listStorageVolumes",
columns: [
{},
{ title: "Name" },
@ -608,10 +647,16 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
});
//Check for any running operations
operationStatusCheck();
operationTimeout = setTimeout(() => { operationStatusCheck(); }, 1000);
//Set reload page content
$.get("./backend/admin/settings.php?action=retrievePageRefreshRateValues", function (data) {
operationData = JSON.parse(data);
if (operationData.storage_volumes_page_rate >= 1)
reloadTime = operationData.storage_volumes_page_rate * 1000;
pageReloadTimeout = setTimeout(() => { reloadPageContent(); }, reloadTime);
});
//Set the page content to reload in 5 seconds
setInterval(() => { reloadPageContent(); }, 5000);
}
function createStorageVolumeUsingForm(){
@ -632,7 +677,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
var storageVolumeZfsUseRefquotaInput = $("#storageVolumeZfsUseRefquotaInput").val();
console.log("Info: creating storage volume " + storageVolumeNameInput + " in " + storagePoolName);
$.get("./php/lxd/storage-volumes.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) +
$.get("./backend/lxd/storage-volumes.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) +
"&name=" + encodeURI(storageVolumeNameInput) +
"&content_type=" + encodeURI(storageVolumeContentTypeInput) +
"&size=" + encodeURI(storageVolumeSizeInput) +
@ -665,7 +710,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
function createStorageVolumeUsingJSON(){
var storageVolumeCreateJSON = $("#jsonCreateInput").val();
console.log("Info: creating storage volume");
$.post("./php/lxd/storage-volumes.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&storage_pool=" + encodeURI(storagePoolName) + "&action=createStorageVolumeUsingJSON", {json: storageVolumeCreateJSON}, function (data) {
$.post("./backend/lxd/storage-volumes.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&storage_pool=" + encodeURI(storagePoolName) + "&action=createStorageVolumeUsingJSON", {json: storageVolumeCreateJSON}, function (data) {
//Sync operation type
var operationData = JSON.parse(data);
console.log(operationData);
@ -679,7 +724,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
function loadStorageVolumeJson(storageVolumeToLoad){
console.log("Info: loading storage volume " + storageVolumeToLoad);
storageVolumeToUpdate = storageVolumeToLoad;
$.get("./php/lxd/storage-volumes.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&name=" + encodeURI(storageVolumeToLoad) + "&storage_pool=" + encodeURI(storagePoolName) + "&action=loadStorageVolume", function (data) {
$.get("./backend/lxd/storage-volumes.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&name=" + encodeURI(storageVolumeToLoad) + "&storage_pool=" + encodeURI(storagePoolName) + "&action=loadStorageVolume", function (data) {
//Sync operation type
var operationData = JSON.parse(data);
console.log(operationData);
@ -695,7 +740,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
function updateStorageVolume(){
var storageVolumeUpdateJSON = $("#jsonEditInput").val();
console.log("Info: updating storage volume " + storageVolumeToUpdate);
$.post("./php/lxd/storage-volumes.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&name=" + encodeURI(storageVolumeToUpdate) + "&storage_pool=" + encodeURI(storagePoolName) + "&action=updateStorageVolume", {json: storageVolumeUpdateJSON}, function (data) {
$.post("./backend/lxd/storage-volumes.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&name=" + encodeURI(storageVolumeToUpdate) + "&storage_pool=" + encodeURI(storagePoolName) + "&action=updateStorageVolume", {json: storageVolumeUpdateJSON}, function (data) {
//Sync operation type
var operationData = JSON.parse(data);
console.log(operationData);
@ -708,7 +753,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
function deleteStorageVolume(storageVolumeToDelete){
console.log("Info: deleting storage volume " + storageVolumeToDelete);
$.get("./php/lxd/storage-volumes.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&name=" + encodeURI(storageVolumeToDelete) + "&storage_pool=" + encodeURI(storagePoolName) + "&action=deleteStorageVolume", function (data) {
$.get("./backend/lxd/storage-volumes.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&name=" + encodeURI(storageVolumeToDelete) + "&storage_pool=" + encodeURI(storagePoolName) + "&action=deleteStorageVolume", function (data) {
//Sync operation type
var operationData = JSON.parse(data);
console.log(operationData);
@ -719,35 +764,66 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
});
}
function setSidebarToggleValue(){
sidebarState = localStorage.getItem('sidebarState');
if (sidebarState == "collapsed"){
localStorage.setItem('sidebarState','expanded');
}
else {
localStorage.setItem('sidebarState','collapsed');
}
}
function applySidebarToggleValue() {
sidebarState = localStorage.getItem('sidebarState');
if (sidebarState == "collapsed"){
$("body").toggleClass("sidebar-toggled"),
$(".sidebar").toggleClass("toggled"),
$(".sidebar").hasClass("toggled") && $(".sidebar .collapse").collapse("hide")
}
}
applySidebarToggleValue();
$(document).ready(function(){
//Check Authorization
$.get("./php/aaa/authentication.php?action=validateAuthentication", function (data) {
$.get("./backend/aaa/authentication.php?action=validateAuthentication", function (data) {
operationData = JSON.parse(data);
if (operationData.status_code != 200) {
console.log(operationData);
window.location = './index.html'
window.location.href = './index.php'
}
});
//Load in the sidebar
$("#sidebarLinks").load("./sidebar.html");
$("#sidebarLinks").load("./sidebar.php?version=3.0");
//Setup Page Breadcrumb Links/Information
$('#remoteBreadCrumb').load("./php/lxd/remote-breadcrumb.php?remote=" + encodeURI(remoteId));
$('#remoteBreadCrumb').attr("href", "remotes-single.html?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$('#storagePoolsBreadCrumb').text("storage-pools");
$('#storagePoolsBreadCrumb').attr("href", "storage-pools.html?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$('#storageVolumesBreadCrumb').text(storagePoolName);
$('#remoteBreadCrumb').load("./backend/lxd/remote-breadcrumb.php?remote=" + encodeURI(remoteId));
$('#remoteBreadCrumb').attr("href", "remotes-single.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$('#storagePoolsBreadCrumb').text("Storage Pools");
$('#storagePoolsBreadCrumb').attr("href", "storage-pools.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
//Load the card contents
loadPageContent();
//Validate remote host connection returns 200 status
$.get("./backend/lxd/remotes-single.php?remote=" + encodeURI(remoteId) + "&action=validateRemoteConnection", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code == 200) {
//Set top navbar dropdowns
$("#remoteListNav").load("./backend/lxd/remotes.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listRemotesForSelectOption");
$("#projectListNav").load("./backend/lxd/projects.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listProjectsForSelectOption");
$("#remoteListNav").load("./php/lxd/remotes.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listRemotesForTopNavigation");
$("#projectListNav").load("./php/lxd/projects.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) + "&action=listProjectsForTopNavigation");
//Load Page Content
loadPageContent();
}
else {
alert("Unable to connect to remote host. HTTP status code: " + operationData.status_code);
}
});
//Load the about info for the about modal
$.get("./about.html", function (data) {
$.get("./backend/config/about.php", function (data) {
$("#about").html(data);
});
@ -756,7 +832,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
$('#allVolumeTypesLink').hide()
}
else{
$('#allVolumeTypesLink').attr("href", "storage-volumes.html?pool=" + encodeURI(storagePoolName) + "&remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$('#allVolumeTypesLink').attr("href", "storage-volumes.php?pool=" + encodeURI(storagePoolName) + "&remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName));
$('#allVolumeTypesLink').show()
}

View file

@ -37,7 +37,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Custom styles for this template-->
<link href="vendor/sb-admin-2/css/sb-admin-2.css" rel="stylesheet">
<link href="assets/css/style.css" rel="stylesheet">
<link href="assets/css/style.css?version=3.0" rel="stylesheet">
</head>
@ -47,10 +47,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<div id="wrapper">
<!-- Sidebar -->
<ul class="navbar-nav bg-dark sidebar sidebar-dark accordion" id="accordionSidebar">
<ul class="navbar-nav bg-dark sidebar sidebar-dark accordion sidebar-divider-right" id="accordionSidebar">
<!-- Sidebar - Brand -->
<a class="sidebar-brand d-flex align-items-center justify-content-center" href="index.html">
<a class="sidebar-brand d-flex align-items-center justify-content-center" href="index.php">
<div class="sidebar-brand-icon rotate-n-0">
<img src="assets/images/logo-dark.svg" style="width: 2rem;"></img>
<!-- <i class="fas fa-cube" style="width: 2rem;"></i> -->
@ -63,7 +63,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Nav Item - Dashboard -->
<li class="nav-item">
<a class="nav-link" href="remotes.html">
<a class="nav-link" href="remotes.php">
<i class="fas fa-fw fa-server"></i>
<span>Hosts</span></a>
</li>
@ -73,7 +73,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Sidebar Toggler (Sidebar) -->
<div class="text-center d-none d-md-inline">
<button class="rounded-circle border-0" id="sidebarToggle"></button>
<button class="rounded-circle border-0" id="sidebarToggle" onclick="setSidebarToggleValue()"></button>
</div>
</ul>
<!-- End of Sidebar -->
@ -106,14 +106,18 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</a>
<!-- Dropdown - User Information -->
<div class="dropdown-menu dropdown-menu-right shadow animated--grow-in" aria-labelledby="userDropdown">
<a class="dropdown-item" href="user-profile.html">
<a class="dropdown-item" href="user-profile.php">
<i class="fas fa-user fa-sm fa-fw mr-2 text-gray-400"></i>
Profile
</a>
<a class="dropdown-item" href="settings.html">
<a class="dropdown-item" href="settings.php">
<i class="fas fa-cog fa-sm fa-fw mr-2 text-gray-400"></i>
Settings
</a>
<a class="dropdown-item" href="logs.php">
<i class="fas fa-history fa-sm fa-fw mr-2 text-gray-400"></i>
Logs
</a>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#aboutModal">
<i class="fas fa-info-circle fa-sm fa-fw mr-2 text-gray-400"></i>
About
@ -134,33 +138,54 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Begin Page Content -->
<div class="container-fluid">
<!-- Page Heading -->
<div class="d-sm-flex align-items-center justify-content-between">
<h1 class="h5 mb-0 text-gray-800">USER PROFILE</h1>
</div>
<div class="col-12">
<div class="row">
<div class="col-2 border-right mt-5">
<div class="nav flex-column nav-pills" id="v-pills-tab" role="tablist" aria-orientation="vertical">
<a class="nav-link active" id="v-pills-account-tab" data-toggle="pill" href="#v-pills-account" role="tab" aria-controls="v-pills-account" aria-selected="false">Account</a>
<a class="nav-link" id="v-pills-password-tab" data-toggle="pill" href="#v-pills-password" role="tab" aria-controls="v-pills-password" aria-selected="false">Password</a>
<header class="page-header page-header-dark bg-gradient-primary-to-secondary">
<div class="container-xl px-4">
<div class="page-header-content pt-4">
<div class="row align-items-center justify-content-between mt-n5 ml-n5 mr-n5 bg-dark pb-6">
<div class="col-auto mt-4 ml-3">
<div class="page-header-subtitle">
<span id="remoteBreadCrumb">LXD Dashboard</span>
</div>
<h2 class="page-header-title mt-2">
USER PROFILE
</h2>
<div class="page-header-subtitle">
Edit user profile
</div>
</div>
<div class="col-12 col-xl-auto mt-4">
<div class="input-group input-group-joined border-0" style="width: 14rem">
<span class="input-group-text bg-transparent border-0">
</span>
</div>
</div>
</div>
</div>
</div>
</header>
<div class="col-10">
<div class="tab-content" id="v-pills-tabContent">
<div class="tab-pane fade show active" id="v-pills-account" role="tabpanel" aria-labelledby="v-pills-account-tab">
<!-- Account Information -->
<div class="card border-light mb-4">
<!-- Card Header - Dropdown -->
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">Account Information</h6>
</div>
<!-- Card Body -->
<div class="card-body">
<div class="row mt-n5 ml-2 mr-2">
<div class="col-12 mt-n3">
<div class="card shadow mb-4">
<!-- Card Header - Dropdown -->
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">
<ul class="nav nav-pills card-header-pills" id="cardPill" role="tablist">
<li class="nav-item"><a class="nav-link active" id="nav-account-tab" href="#nav-account" data-toggle="pill" role="tab" aria-controls="nav-account" aria-selected="true">Account</a></li>
<li class="nav-item"><a class="nav-link" id="nav-password-tab" href="#nav-password" data-toggle="pill" role="tab" aria-controls="nav-password" aria-selected="false">Password</a></li>
</ul>
</h6>
</div>
<!-- Card Body -->
<div class="card-body">
<div class="col-12">
<div class="tab-content" id="nav-tabContent">
<div class="tab-pane fade show active" id="nav-account" role="tabpanel" aria-labelledby="nav-account-tab">
<!-- Profile Form -->
<div class="row">
<label class="col-2 col-form-label text-right">Username:</label>
<div class="col-4">
@ -213,21 +238,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</div>
</div>
</div>
<!-- End Profile Form-->
</div>
</div>
<!-- End Account Information -->
</div>
<div class="tab-pane fade" id="v-pills-password" role="tabpanel" aria-labelledby="v-pills-password-tab">
<!-- Password Reset -->
<div class="card border-light mb-4">
<!-- Card Header - Dropdown -->
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">Password Reset</h6>
</div>
<!-- Card Body -->
<div class="card-body">
<div class="tab-pane fade" id="nav-password" role="tabpanel" aria-labelledby="nav-password-tab">
<!-- Password Reset Form -->
<div class="row">
<label class="col-2 col-form-label text-right">New Password:</label>
<div class="col-4">
@ -253,10 +267,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</div>
</div>
</div>
<!-- End Password Reset Form -->
</div>
</div>
<!-- End Password Reset -->
</div>
</div>
</div>
@ -275,7 +290,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<footer class="sticky-footer bg-white">
<div class="container my-auto">
<div class="copyright text-center my-auto">
<span>Copyright &copy; lxdware.com 2021</span>
<span>Copyright &copy; LXDWARE 2020 - Present</span>
</div>
</div>
</footer>
@ -334,11 +349,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
var userId = urlParams.get('user');
function logout(){
$.get("./php/aaa/authentication.php?action=deauthenticateUser", function (data) {
$.get("./backend/aaa/authentication.php?action=deauthenticateUser", function (data) {
operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code == 200) {
window.location = './index.html'
window.location.href = './index.php'
}
});
}
@ -346,10 +361,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
function loadPageContent(){
//Display current logged in username
$("#username").load("./php/admin/settings.php?action=displayUsername");
$("#username").load("./backend/admin/settings.php?action=displayUsername");
if (userId) {
$.get("./php/admin/user-profile.php?id=" + userId + "&action=retrieveUserDetails", function (data) {
$.get("./backend/admin/user-profile.php?id=" + userId + "&action=retrieveUserDetails", function (data) {
operationData = JSON.parse(data);
$("#usernameInput").val(operationData.username);
$("#firstNameInput").val(operationData.firstName);
@ -359,10 +374,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
});
}
else {
$.get("./php/admin/user-profile.php?action=retrieveUserId", function (data) {
$.get("./backend/admin/user-profile.php?action=retrieveUserId", function (data) {
operationData = JSON.parse(data);
userId = operationData.id
$.get("./php/admin/user-profile.php?id=" + userId + "&action=retrieveUserDetails", function (data) {
$.get("./backend/admin/user-profile.php?id=" + userId + "&action=retrieveUserDetails", function (data) {
operationData = JSON.parse(data);
$("#usernameInput").val(operationData.username);
$("#firstNameInput").val(operationData.firstName);
@ -380,7 +395,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
var lastNameInput = $("#lastNameInput").val();
var emailInput = $("#emailInput").val();
console.log("Info: updating user account for " + usernameInput);
$.get("./php/admin/user-profile.php?id=" + userId + "&first_name=" + firstNameInput + "&last_name=" + lastNameInput + "&email=" + emailInput + "&action=updateUserAccount", function (data) {
$.get("./backend/admin/user-profile.php?id=" + userId + "&first_name=" + firstNameInput + "&last_name=" + lastNameInput + "&email=" + emailInput + "&action=updateUserAccount", function (data) {
var operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code >= 400) {
@ -397,7 +412,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
var confirmPasswordInput = $("#confirmPasswordInput").val();
if (newPasswordInput == confirmPasswordInput){
console.log("Info: updating user password for user id " + userId );
$.post("./php/admin/user-profile.php?id=" + userId + "&action=updateUserPassword", {password: newPasswordInput}, function (data) {
$.post("./backend/admin/user-profile.php?id=" + userId + "&action=updateUserPassword", {password: newPasswordInput}, function (data) {
var operationData = JSON.parse(data);
console.log(operationData);
if (operationData.status_code >= 400) {
@ -414,17 +429,37 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
alert("Your passwords did not match, try again");
}
}
function setSidebarToggleValue(){
sidebarState = localStorage.getItem('sidebarState');
if (sidebarState == "collapsed"){
localStorage.setItem('sidebarState','expanded');
}
else {
localStorage.setItem('sidebarState','collapsed');
}
}
function applySidebarToggleValue() {
sidebarState = localStorage.getItem('sidebarState');
if (sidebarState == "collapsed"){
$("body").toggleClass("sidebar-toggled"),
$(".sidebar").toggleClass("toggled"),
$(".sidebar").hasClass("toggled") && $(".sidebar .collapse").collapse("hide")
}
}
applySidebarToggleValue();
$(document).ready(function(){
//Check Authorization
$.get("./php/aaa/authentication.php?action=validateAuthentication", function (data) {
$.get("./backend/aaa/authentication.php?action=validateAuthentication", function (data) {
operationData = JSON.parse(data);
if (operationData.status_code != 200) {
console.log(operationData);
window.location = './index.html'
window.location.href = './index.php'
}
});
@ -432,7 +467,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
loadPageContent();
//Load the about info for the about modal
$.get("./about.html", function (data) {
$.get("./backend/config/about.php", function (data) {
$("#about").html(data);
});

BIN
lxd-dashboard/vendor/images/alpine.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
lxd-dashboard/vendor/images/centos.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
lxd-dashboard/vendor/images/debian.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
lxd-dashboard/vendor/images/fedora.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
lxd-dashboard/vendor/images/gentoo.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

BIN
lxd-dashboard/vendor/images/kali.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

BIN
lxd-dashboard/vendor/images/opensuse.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
lxd-dashboard/vendor/images/openwrt.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
lxd-dashboard/vendor/images/ubuntu.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

File diff suppressed because it is too large Load diff