Merge pull request #1566 from SimonFair/File-System-Snapshots

Add Support for File system level snapshots for VMs.
This commit is contained in:
tom mortensen
2024-01-03 21:36:31 -08:00
committed by GitHub
11 changed files with 277 additions and 145 deletions
+7 -2
View File
@@ -685,6 +685,7 @@ function hideShow() {
<tr><td>_(VM Name)_:</td><td><label id="VMName"></label></td></tr>
<tr><td>_(Snapshot Name)_:</td><td><input type="text" id="targetsnap" autocomplete="off" spellcheck="false" value="--generate" onclick="this.select()">_(Check free space)_:<input type="checkbox" id="targetsnapfspc" checked></td></tr>
<tr><td>_(Description)_:</td><td><input type="text" id="targetsnapdesc" autocomplete="off" spellcheck="false" value="" onclick="this.select()"></td></tr>
<tr id="fstypeline"><td>_(FS Native Snapshot )_:</td><td><label id="fstype"></label><input type="checkbox" id="targetsnapfstype" checked>_(Unchecked will use QEMU External Snapshot)_</td></tr>
</table>
</div>
@@ -1379,12 +1380,14 @@ function VMClone(uuid, name){
});
dialogStyle();
}
function selectsnapshot(uuid, name ,snaps, opt, getlist){
function selectsnapshot(uuid, name ,snaps, opt, getlist, status,fstype){
box = $("#iframe-popup");
box.html($("#templatesnapshot"+opt).html());
const capopt = opt.charAt(0).toUpperCase() + opt.slice(1);
var optiontext = capopt + " _(Snapshot)_";
box.find('#VMName').html(name);
box.find('#fstype').html(fstype);
if (fstype == "QEMU") box.find('#fstypeline').prop('hidden',true);
box.find('#targetsnap').val(snaps);
box.find('#targetsnapl').html(snaps);
if (getlist) {
@@ -1419,8 +1422,10 @@ function selectsnapshot(uuid, name ,snaps, opt, getlist){
if (opt == "create") {
free = box.find('#targetsnapfspc').prop('checked') ? 'yes' : 'no';
desc = box.find("#targetsnapdesc").prop('value');
fstypeuse = box.find('#targetsnapfstype').prop('checked') ? 'yes' : 'no';
if (fstypeuse == "no") fstype ="QEMU";
}
ajaxVMDispatch({action:"snap-" + opt +'-external', uuid:uuid, snapshotname:target, remove:remove, free:free, desc:desc}, "loadlist");
ajaxVMDispatch({action:"snap-" + opt +'-external', uuid:uuid, snapshotname:target, remove:remove, free:free, desc:desc, fstype:fstype}, "loadlist");
box.dialog('close');
},
"_(Cancel)_": function(){
@@ -83,6 +83,8 @@ if ($_POST['vms']) {
$uuid = libvirt_domain_get_uuid_string($res);
$dom = $lv->domain_get_info($res);
$id = $lv->domain_get_id($res);
$fstype ="QEMU";
if (($diskcnt = $lv->get_disk_count($res)) > 0) $fstype = $lv->get_disk_fstype($res);
$state = $lv->domain_state_translate($dom['state']);
$vmrcport = $lv->domain_get_vnc_port($res);
$autoport = $lv->domain_get_vmrc_autoport($res);
@@ -114,7 +116,7 @@ if ($_POST['vms']) {
if (empty($template)) $template = 'Custom';
$log = (is_file("/var/log/libvirt/qemu/$vm.log") ? "libvirt/qemu/$vm.log" : '');
if (!isset($domain_cfg["CONSOLE"])) $vmrcconsole = "web" ; else $vmrcconsole = $domain_cfg["CONSOLE"] ;
$menu = sprintf("onclick=\"addVMContext('%s','%s','%s','%s','%s','%s','%s','%s')\"", addslashes($vm), addslashes($uuid), addslashes($template), $state, addslashes($vmrcurl), strtoupper($vmrcprotocol), addslashes($log), $vmrcconsole);
$menu = sprintf("onclick=\"addVMContext('%s','%s','%s','%s','%s','%s','%s','%s','%s')\"", addslashes($vm), addslashes($uuid), addslashes($template), $state, addslashes($vmrcurl), strtoupper($vmrcprotocol), addslashes($log),addslashes($fstype), $vmrcconsole);
$icon = $lv->domain_get_icon_url($res);
switch ($state) {
case 'running':
+13 -16
View File
@@ -270,28 +270,25 @@ function my_preg_split($split, $text, $count=2) {
function delete_file(...$file) {
array_map('unlink',array_filter($file,'file_exists'));
}
function my_mkdir($dirname) {
function my_mkdir($dirname,$permissions = 0777,$recursive = false) {
$dirname = transpose_user_path($dirname);
$pathinfo = pathinfo($dirname);
$parent = $pathinfo["dirname"];
$userPathFound = strpos($dirname,"/mnt/user");
$realdir = $dirname;
if ($userPathFound !== false) {
$realLocation = trim(shell_exec("getfattr --absolute-names --only-values -n system.LOCATION ".escapeshellarg("$parent")));
$realdir = str_replace("/mnt/user","/mnt/$realLocation",$dirname);
$parent = dirname($realdir);
}
$fstype = trim(shell_exec(" stat -f -c '%T' $parent"));
$rtncode = false;
switch ($fstype) {
case "zfs":
$zfsdataset = trim(shell_exec("zfs list -H -o name $parent")) ;
shell_exec("zfs create $zfsdataset/{$pathinfo['filename']}");
break;
case "btrfs":
shell_exec("btrfs subvolume create $realdir");
break;
default:
mkdir($realdir, 0777, true);
$zfsdataset = trim(shell_exec("zfs list -H -o name $parent")) ;
$rtncode=exec("zfs create $zfsdataset/{$pathinfo['filename']}");
if (!$rtncode) mkdir($dirname, $permissions, $recursive);
break;
case "btrfs":
$rtncode=exec("btrfs subvolume create $dirname");
if (!$rtncode) mkdir($dirname, $permissions, $recursive);
break;
default:
mkdir($dirname, $permissions, $recursive);
break;
}
}
?>
+7 -2
View File
@@ -21,8 +21,9 @@ require_once "$docroot/plugins/dynamix.vm.manager/include/libvirt_helpers.php";
$_SERVER['REQUEST_URI'] = 'tools';
require_once "$docroot/webGui/include/Translations.php";
require_once "$docroot/plugins/dynamix.docker.manager/include/DockerClient.php";
require_once "/usr/local/emhttp/plugins/dynamix.vm.manager/include/libvirt.php";
$vms = $lv->get_domains();
require_once "$docroot/plugins/dynamix.vm.manager/include/libvirt.php";
$arrEntries = [];
$vms = $lv->get_domains() ?:[];
sort($vms,SORT_NATURAL);
foreach($vms as $vm){
$arrEntries['VM'][$vm]['interfaces'] = $lv->get_nic_info($vm);
@@ -94,6 +95,10 @@ case 't1load':
$text = "";
}
}
if (count($arrMacs) < 1) {
$html .= "<tr id='row'>";
$html .= "<td></td><td></td><td>"._("No Entries")."</td><td></td><td></td></tr>";
}
$html .= "</tbody>";
$rtn = array();