Compare commits

...

4 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
12 changed files with 93 additions and 22 deletions

View file

@ -1,3 +1,15 @@
# v3.8.0
- Added a check for a null config in storage pools
- Added image token cleanup with downloading images while in a cluster
# 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
# 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

View file

@ -43,7 +43,7 @@ if (isset($_SESSION['username'])) {
<body class="">
<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">v3.6.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>

View file

@ -650,10 +650,10 @@ if (isset($_SESSION['username'])) {
case "establishInstanceWebSocketExecConnection":
$url = $base_url . "/1.0/containers/".$instance."/exec?project=" . $project;
if ($shell == "sh"){
$data = '{ "command": ["/bin/sh"], "wait-for-websocket": true, "environment":{"HOME": "/root", "TERM": "xterm", "USER": "root"}, "interactive": true}';
$data = '{ "command": ["/bin/sh"], "wait-for-websocket": true, "environment":{"HOME": "/root", "TERM": "xterm", "USER": "root"}, "interactive": true, "width": 80, "height": 25}';
}
else {
$data = '{ "command": ["/bin/bash"], "wait-for-websocket": true, "environment":{"HOME": "/root", "TERM": "xterm", "USER": "root"}, "interactive": true}';
$data = '{ "command": ["/bin/bash"], "wait-for-websocket": true, "environment":{"HOME": "/root", "TERM": "xterm", "USER": "root"}, "interactive": true, "width": 80, "height": 25}';
}
$results = sendCurlRequest($action, "POST", $url, $data);

View file

@ -52,7 +52,6 @@ if (isset($_SESSION['username'])) {
$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) : "";
$cloud_init_user_data = (isset($_GET['cloud_init_user_data'])) ? filter_var(urldecode($_GET['cloud_init_user_data']), FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES) : "";
$limits_cpu = (isset($_GET['limits_cpu'])) ? filter_var(urldecode($_GET['limits_cpu']), FILTER_SANITIZE_STRING) : "";
$limits_cpu_allowance = (isset($_GET['limits_cpu_allowance'])) ? filter_var(urldecode($_GET['limits_cpu_allowance']), FILTER_SANITIZE_STRING) : "";
$limits_cpu_priority = (isset($_GET['limits_cpu_priority'])) ? filter_var(urldecode($_GET['limits_cpu_priority']), FILTER_SANITIZE_STRING) : "";
@ -108,6 +107,7 @@ if (isset($_SESSION['username'])) {
//Declare and instantiate POST variables
$json = (isset($_POST['json'])) ? $_POST['json'] : "";
$cloud_init_user_data = (isset($_POST['cloud_init_user_data'])) ? $_POST['cloud_init_user_data'] : "";
//Require code from lxd-dashboard/backend/config/curl.php
require_once('../config/curl.php');

View file

@ -144,6 +144,13 @@ 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;
}
}
}

View file

@ -452,7 +452,12 @@ if (isset($_SESSION['username'])) {
echo '"' . htmlentities($storage_pool['description']) . '",';
echo '"' . htmlentities($storage_pool['driver']) . '",';
echo '"' . htmlentities($storage_pool['status']) . '",';
echo '"' . htmlentities($storage_pool['config']['source']) . '",';
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) . '",';

View file

@ -599,10 +599,10 @@ if (isset($_SESSION['username'])) {
case "establishInstanceWebSocketExecConnection":
$url = $base_url . "/1.0/instances/".$instance."/exec?project=" . $project;
if ($shell == "sh"){
$data = '{ "command": ["/bin/sh"], "wait-for-websocket": true, "environment":{"HOME": "/root", "TERM": "xterm", "USER": "root"}, "interactive": true}';
$data = '{ "command": ["/bin/sh"], "wait-for-websocket": true, "environment":{"HOME": "/root", "TERM": "xterm", "USER": "root"}, "interactive": true, "width": 80, "height": 25}';
}
else {
$data = '{ "command": ["/bin/bash"], "wait-for-websocket": true, "environment":{"HOME": "/root", "TERM": "xterm", "USER": "root"}, "interactive": true}';
$data = '{ "command": ["/bin/bash"], "wait-for-websocket": true, "environment":{"HOME": "/root", "TERM": "xterm", "USER": "root"}, "interactive": true, "width": 80, "height": 25}';
}
$results = sendCurlRequest($action, "POST", $url, $data);

View file

@ -61,6 +61,7 @@ if (isset($_SESSION['username'])) {
$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) : "";
@ -257,6 +258,7 @@ if (isset($_SESSION['username'])) {
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;}
@ -899,6 +901,7 @@ if (isset($_SESSION['username'])) {
$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;

View file

@ -5813,9 +5813,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
//Listen for "data" websocket messages
execDataSocket.onmessage = function (e) {
if (e.data instanceof ArrayBuffer) {
if (convertArrayBuffer2String(e.data) != null){
execTerminal.write(convertArrayBuffer2String(e.data));
if (e.data.length == 0) {
execControlSocket.close();
execDataSocket.close();
} else {
if (e.data instanceof ArrayBuffer) {
if (convertArrayBuffer2String(e.data) != null){
execTerminal.write(convertArrayBuffer2String(e.data));
}
}
}
};
@ -5948,7 +5953,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
//Initialize xterm for Console
consoleTerminal = new Terminal({
cursorBlink: "block"
cursorBlink: "block",
rows: 25
});
//Setup listener for Console terminal
@ -5960,7 +5966,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
//Initialize xterm for Exec
execTerminal = new Terminal({
cursorBlink: "block"
cursorBlink: "block",
rows: 25
});
//Setup listener for Exec terminal

View file

@ -923,7 +923,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<label class="col-4 col-form-label text-right">User-Data: </label>
<div class="col-6">
<div class="form-group">
<textarea id="containerCloudInitUserDataInput" class="form-control" name="containerCloudInitUserDataInput"></textarea>
<textarea id="containerCloudInitUserDataInput" class="form-control" name="containerCloudInitUserDataInput"></textarea>
</div>
</div>
<div class="col-1">
@ -1517,7 +1517,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
var snapshotsExpiry = $("#containerSnapshotsExpiryInput").val();
console.log("Info: creating container " + instanceName);
$.get("./backend/lxd/containers.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) +
$.post("./backend/lxd/containers.php?remote=" + encodeURI(remoteId) + "&project=" + encodeURI(projectName) +
"&name=" + encodeURI(instanceName) +
"&description=" + encodeURI(instanceDescription) +
"&fingerprint=" + encodeURI(fingerprint) +
@ -1532,8 +1532,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
"&boot_host_shutdown_timeout=" + encodeURI(bootHostShutdownTimeout) +
"&boot_stop_priority=" + encodeURI(bootStopPriority) +
"&cloud_init_user_data=" + encodeURIComponent(cloudInitUserData) +
"&limits_cpu=" + encodeURI(limitsCpu) +
"&limits_cpu_allowance=" + encodeURI(limitsCpuAllowance) +
"&limits_cpu_priority=" + encodeURI(limitsCpuPriority) +
@ -1591,7 +1589,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
"&snapshots_pattern=" + encodeURI(snapshotsPattern) +
"&snapshots_expiry=" + encodeURI(snapshotsExpiry) +
"&action=createInstanceUsingForm", function (data) {
"&action=createInstanceUsingForm", {
//Sending cloud_init_user_data over POST due to encoding. Shoul work to convert all variables to POST as well in future release.
cloud_init_user_data: cloudInitUserData
}, function (data) {
//Sync type
var operationData = JSON.parse(data);
console.log(operationData);

View file

@ -472,6 +472,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<table class="table table-sm">
<tr><td class="pr-3 font-weight-bold">Apparmor:</td> <td><span id="rawApparmor"></span></td></tr>
<tr><td class="pr-3 font-weight-bold">Qemu:</td> <td><span id="rawQemu"></span></td></tr>
<tr><td class="pr-3 font-weight-bold">Qemu.conf:</td> <td><span id="rawQemuConf"></span></td></tr>
</table>
</div>
</div>
@ -2583,6 +2584,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<i class="far fa-sm fa-question-circle" title="Enter in qemu configuration to be appended to the profile. Default: (not set)."></i>
</div>
</div>
<div class="row">
<label class="col-4 col-form-label text-right">Qemu.conf: </label>
<div class="col-6">
<div class="form-group">
<input type="text" id="instanceRawQemuConfInput" class="form-control" placeholder="" name="instanceRawQemuConfInput">
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle" title="Enter in qemu.conf configuration to override the generated qemu.conf file. Default: (not set)."></i>
</div>
</div>
</div>
<div class="tab-pane fade" id="nav-security" role="tabpanel" aria-labelledby="nav-security-tab">
@ -2985,6 +2997,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
if (dataConfig.hasOwnProperty('raw.apparmor')) { $("#rawApparmor").text(dataConfig['raw.apparmor']); } else { $("#rawApparmor").text(""); }
if (dataConfig.hasOwnProperty('raw.qemu')) { $("#rawQemu").text(dataConfig['raw.qemu']); } else { $("#rawQemu").text(""); }
if (dataConfig.hasOwnProperty('raw.qemu.conf')) { $("#rawQemuConf").text(dataConfig['raw.qemu.conf']); } else { $("#rawQemuConf").text(""); }
if (dataConfig.hasOwnProperty('security.devlxd')) { $("#securityDevLxd").text(dataConfig['security.devlxd']); } else { $("#securityDevLxd").text(""); }
if (dataConfig.hasOwnProperty('security.protection.delete')) { $("#securityProtectionDelete").text(dataConfig['security.protection.delete']); } else { $("#securityProtectionDelete").text(""); }
@ -3092,6 +3105,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
if (dataConfig.hasOwnProperty('raw.apparmor')) { $("#rawApparmor").text(dataConfig['raw.apparmor']); }
if (dataConfig.hasOwnProperty('raw.qemu')) { $("#rawQemu").text(dataConfig['raw.qemu']); }
if (dataConfig.hasOwnProperty('raw.qemu.conf')) { $("#rawQemuConf").text(dataConfig['raw.qemu.conf']); }
if (dataConfig.hasOwnProperty('security.devlxd')) { $("#securityDevLxd").text(dataConfig['security.devlxd']); }
if (dataConfig.hasOwnProperty('security.protection.delete')) { $("#securityProtectionDelete").text(dataConfig['security.protection.delete']); }
@ -4499,6 +4513,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
if (dataConfig.hasOwnProperty('migration.stateful')) { $("#instanceMigrationStatefulInput").val(dataConfig['migration.stateful']); }
if (dataConfig.hasOwnProperty('raw.apparmor')) { $("#instanceRawApparmorInput").val(dataConfig['raw.apparmor']); }
if (dataConfig.hasOwnProperty('raw.qemu')) { $("#instanceRawQemuInput").val(dataConfig['raw.qemu']); }
if (dataConfig.hasOwnProperty('raw.qemu.conf')) { $("#instanceRawQemuConfInput").val(dataConfig['raw.qemu.conf']); }
if (dataConfig.hasOwnProperty('security.devlxd')) { $("#instanceSecurityDevLxdInput").val(dataConfig['security.devlxd']); }
if (dataConfig.hasOwnProperty('security.protection.delete')) { $("#instanceSecurityProtectionDeleteInput").val(dataConfig['security.protection.delete']); }
if (dataConfig.hasOwnProperty('security.secureboot')) { $("#instanceSecuritySecurebootInput").val(dataConfig['security.secureboot']); }
@ -4531,6 +4546,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
"&migration_stateful=" + encodeURI($("#instanceMigrationStatefulInput").val()) +
"&raw_apparmor=" + encodeURI($("#instanceRawApparmorInput").val()) +
"&raw_qemu=" + encodeURI($("#instanceRawQemuInput").val()) +
"&raw_qemu_conf=" + encodeURI($("#instanceRawQemuConfInput").val()) +
"&security_devlxd=" + encodeURI($("#instanceSecurityDevLxdInput").val()) +
"&security_protection_delete=" + encodeURI($("#instanceSecurityProtectionDeleteInput").val()) +
"&security_secureboot=" + encodeURI($("#instanceSecuritySecurebootInput").val()) +
@ -4759,9 +4775,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
//Listen for "data" websocket messages
execDataSocket.onmessage = function (e) {
if (e.data instanceof ArrayBuffer) {
if (convertArrayBuffer2String(e.data) != null){
execTerminal.write(convertArrayBuffer2String(e.data));
if (e.data.length == 0) {
execControlSocket.close();
execDataSocket.close();
} else {
if (e.data instanceof ArrayBuffer) {
if (convertArrayBuffer2String(e.data) != null){
execTerminal.write(convertArrayBuffer2String(e.data));
}
}
}
};
@ -4896,7 +4917,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
//Initialize xterm for Console
consoleTerminal = new Terminal({
cursorBlink: "block"
cursorBlink: "block",
rows: 25
});
//Setup listener for Console terminal
@ -4908,7 +4930,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
//Initialize xterm for Exec
execTerminal = new Terminal({
cursorBlink: "block"
cursorBlink: "block",
rows: 25
});
//Setup listener for Exec terminal

View file

@ -705,6 +705,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<i class="far fa-sm fa-question-circle" title="Enter in qemu configuration to be appended to the profile. Default: (not set)."></i>
</div>
</div>
<div class="row">
<label class="col-4 col-form-label text-right">Qemu.conf: </label>
<div class="col-6">
<div class="form-group">
<input type="text" id="instanceRawQemuConfInput" class="form-control" placeholder="" name="instanceRawQemuConfInput">
</div>
</div>
<div class="col-1">
<i class="far fa-sm fa-question-circle" title="Enter in qemu.conf configuration to override the generated qemu.conf file. Default: (not set)."></i>
</div>
</div>
</div>
<div class="tab-pane fade" id="nav-security" role="tabpanel" aria-labelledby="nav-security-tab">
@ -995,6 +1006,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
var migrationStateful = $("#instanceMigrationStatefulInput").val();
var rawApparmor = $("#instanceRawApparmorInput").val();
var rawQemu = $("#instanceRawQemuInput").val();
var rawQemuConf = $("#instanceRawQemuConfInput").val();
var securityDevLxd = $("#instanceSecurityDevLxdInput").val();
var securityProtectionDelete = $("#instanceSecurityProtectionDeleteInput").val();
var securitySecureboot = $("#instanceSecuritySecurebootInput").val();
@ -1026,6 +1038,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
"&migration_stateful=" + encodeURI(migrationStateful) +
"&raw_apparmor=" + encodeURI(rawApparmor) +
"&raw_qemu=" + encodeURI(rawQemu) +
"&raw_qemu_conf=" + encodeURI(rawQemuConf) +
"&security_devlxd=" + encodeURI(securityDevLxd) +
"&security_protection_delete=" + encodeURI(securityProtectionDelete) +
"&security_secureboot=" + encodeURI(securitySecureboot) +