diff --git a/emhttp/plugins/dynamix.vm.manager/VMMachines.page b/emhttp/plugins/dynamix.vm.manager/VMMachines.page index 53eb2d069..5022d0a23 100644 --- a/emhttp/plugins/dynamix.vm.manager/VMMachines.page +++ b/emhttp/plugins/dynamix.vm.manager/VMMachines.page @@ -243,9 +243,9 @@ function selectsnapshot(uuid, name ,snaps, opt, getlist,state ,fstype){ box.html($("#templatesnapshot"+opt).html()); const capopt = opt.charAt(0).toUpperCase() + opt.slice(1); var optiontext = capopt + " _(Snapshot)_"; - //var fstype = "ZFS"; 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) { @@ -496,7 +496,7 @@ $(function() { _(VM Name)_: _(Snapshot Name)_:_(Check free space)_: _(Description )_: -_(FS Native Snapshot )_:_(Unchecked will use QEMU External Snapshot)_ +_(FS Native Snapshot )_:_(Unchecked will use QEMU External Snapshot)_ diff --git a/emhttp/plugins/dynamix.vm.manager/include/VMMachines.php b/emhttp/plugins/dynamix.vm.manager/include/VMMachines.php index 4ba424c2d..c559978b7 100644 --- a/emhttp/plugins/dynamix.vm.manager/include/VMMachines.php +++ b/emhttp/plugins/dynamix.vm.manager/include/VMMachines.php @@ -66,8 +66,10 @@ foreach ($vms as $vm) { $log = (is_file("/var/log/libvirt/qemu/$vm.log") ? "libvirt/qemu/$vm.log" : ''); $disks = '-'; $diskdesc = ''; + $fstype ="QEMU"; if (($diskcnt = $lv->get_disk_count($res)) > 0) { $disks = $diskcnt.' / '.$lv->get_disk_capacity($res); + $fstype = $lv->get_disk_fstype($res); $diskdesc = 'Current physical size: '.$lv->get_disk_capacity($res, true)."\nDefault snapshot type:$fstype"; } $arrValidDiskBuses = getValidDiskBuses(); @@ -108,8 +110,6 @@ foreach ($vms as $vm) { } unset($dom); if (!isset($domain_cfg["CONSOLE"])) $vmrcconsole = "web" ; else $vmrcconsole = $domain_cfg["CONSOLE"] ; - if ($diskcnt > 0) $fstype = $lv->get_disk_fstype($res); else $fstype="QEMU"; - #$fstype = "ZFS"; $menu = sprintf("onclick=\"addVMContext('%s','%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,$vmpreview); $kvm[] = "kvm.push({id:'$uuid',state:'$state'});"; switch ($state) { diff --git a/emhttp/plugins/dynamix.vm.manager/include/libvirt_helpers.php b/emhttp/plugins/dynamix.vm.manager/include/libvirt_helpers.php index d06b92576..eae0598b5 100644 --- a/emhttp/plugins/dynamix.vm.manager/include/libvirt_helpers.php +++ b/emhttp/plugins/dynamix.vm.manager/include/libvirt_helpers.php @@ -1726,7 +1726,7 @@ private static $encoding = 'UTF-8'; function getvmsnapshots($vm) { $snaps=array() ; - $dbpath = "/etc/libvirt/qemu/snapshot/$vm" ; + $dbpath = "/etc/libvirt/qemu/snapshotdb/$vm" ; $snaps_json = file_get_contents($dbpath."/snapshots.db") ; $snaps = json_decode($snaps_json,true) ; if (is_array($snaps)) uasort($snaps,'compare_creationtime') ; @@ -1735,7 +1735,7 @@ private static $encoding = 'UTF-8'; function write_snapshots_database($vm,$name,$state,$desc,$method="QEMU") { global $lv ; - $dbpath = "/etc/libvirt/qemu/snapshot/$vm" ; + $dbpath = "/etc/libvirt/qemu/snapshotdb/$vm" ; if (!is_dir($dbpath)) mkdir($dbpath) ; $noxml = ""; $snaps_json = file_get_contents($dbpath."/snapshots.db") ; @@ -1747,12 +1747,13 @@ private static $encoding = 'UTF-8'; # Create Snapshot info $vmsnap = $name; $snaps[$vmsnap]["name"]= $name; - $snaps[$vmsnap]["parent"]= "Base" ; + $snaps[$vmsnap]["parent"]= "None" ; $snaps[$vmsnap]["state"]= "shutoff"; $snaps[$vmsnap]["desc"]= $desc; $snaps[$vmsnap]["memory"]= ['@attributes' => ['snapshot' => 'no']]; $snaps[$vmsnap]["creationtime"]= date("U"); $snaps[$vmsnap]["method"]= $method; + $snaps[$vmsnap]['xml'] = $lv->domain_get_xml($vm); $noxml = "noxml"; } } else { @@ -1773,7 +1774,7 @@ private static $encoding = 'UTF-8'; $disks =$lv->get_disk_stats($vm) ; foreach($disks as $disk) { $file = $disk["file"] ; - if ($disk['device'] == "hdc" ) $primarypath = dirname($file); + if ($disk['device'] == "hdc" ) $primarypath = dirname(transpose_user_path($file)); $output = array() ; exec("qemu-img info --backing-chain -U '$file' | grep image:",$output) ; foreach($output as $key => $line) { @@ -1803,7 +1804,7 @@ private static $encoding = 'UTF-8'; function refresh_snapshots_database($vm) { global $lv ; - $dbpath = "/etc/libvirt/qemu/snapshot/$vm" ; + $dbpath = "/etc/libvirt/qemu/snapshotdb/$vm" ; if (!is_dir($dbpath)) mkdir($dbpath) ; $snaps_json = file_get_contents($dbpath."/snapshots.db") ; $snaps = json_decode($snaps_json,true) ; @@ -1839,7 +1840,6 @@ private static $encoding = 'UTF-8'; # Get uuid $vmuuid = $lv->domain_get_uuid($vm) ; #Get list of files - #$filepath = "/etc/libvirt/qemu/nvram/'.$uuid*" ; #$snapshotname" $filepath = "/etc/libvirt/qemu/nvram/$vmuuid*" ; #$snapshotname" $nvram_files=glob($filepath) ; foreach($nvram_files as $key => $nvram_file) { @@ -1859,7 +1859,7 @@ private static $encoding = 'UTF-8'; function delete_snapshots_database($vm,$name) { global $lv ; - $dbpath = "/etc/libvirt/qemu/snapshot/$vm" ; + $dbpath = "/etc/libvirt/qemu/snapshotdb/$vm" ; $snaps_json = file_get_contents($dbpath."/snapshots.db") ; $snaps = json_decode($snaps_json,true) ; unset($snaps[$name]) ; @@ -1938,14 +1938,10 @@ private static $encoding = 'UTF-8'; if ($state == "running") exec("virsh dumpxml '$vm' > ".escapeshellarg($xmlfile),$outxml,$rtnxml) ; $output= [] ; - #$test = false ; - #if ($test) exec($cmdstr." --print-xml 2>&1",$output,$return) ; else exec($cmdstr." 2>&1",$output,$return) ; switch ($method) { case "ZFS": # Create ZFS Snapshot - #$zfsdataset = "vmpoolzfs/domains3/Arch3"; - #stat -f -c '%T' /mnt/vmpoolzfs/domains2/Arch3 if ($state == "running") exec($cmdstr." 2>&1",$output,$return); $zfsdataset = trim(shell_exec("zfs list -H -o name -r $dirpath")) ; $fssnapcmd = " zfs snapshot $zfsdataset@$name"; @@ -1973,115 +1969,6 @@ private static $encoding = 'UTF-8'; } - function vm_revert_old($vm, $snap="--current",$action="no",$actionmeta = 'yes') { - global $lv ; - $snapslist= getvmsnapshots($vm) ; - $disks =$lv->get_disk_stats($vm) ; - - switch ($snapslist[$snap]['state']) { - case "shutoff": - case "running": - #VM must be shutdown. - $res = $lv->get_domain_by_name($vm); - $dom = $lv->domain_get_info($res); - $state = $lv->domain_state_translate($dom['state']); - # if VM running shutdown. Record was running. - if ($state != 'shutdown') $arrResponse = $lv->domain_destroy($vm) ; - # Wait for shutdown? - # GetXML - $strXML= $lv->domain_get_xml($res) ; - $xmlobj = custom::createArray('domain',$strXML) ; - - # Process disks and update path. - $disks=($snapslist[$snap]['disks']) ; - foreach ($disks as $disk) { - $diskname = $disk["@attributes"]["name"] ; - if ($diskname == "hda" || $diskname == "hdb") continue ; - $path = $disk["source"]["@attributes"]["file"] ; - if ($diskname == "hdc") { - $primarypathinfo = pathinfo($path) ; - $primarypath = $primarypathinfo['dirname'] ; - } - $item = array_search($path,$snapslist[$snap]['backing'][$diskname]) ; - $newpath = $snapslist[$snap]['backing'][$diskname][$item + 1]; - $json_info = getDiskImageInfo($newpath) ; - foreach($xmlobj['devices']['disk'] as $ddk => $dd){ - if ($dd['target']["@attributes"]['dev'] == $diskname) { - $xmlobj['devices']['disk'][$ddk]['source']["@attributes"]['file'] = "$newpath" ; - $xmlobj['devices']['disk'][$ddk]['driver']["@attributes"]['type'] = $json_info["format"] ; - } - } - } - $xml = custom::createXML('domain',$xmlobj)->saveXML(); - if (!strpos($xml,'domain_define($xml); - file_put_contents("/tmp/xmlrevert", "$xml" ) ;## Remove before stable. - if ($new) - $arrResponse = ['success' => true] ; else - $arrResponse = ['error' => $lv->get_last_error()] ; - - # remove snapshot meta data and images for all snpahots. - - foreach ($disks as $disk) { - $diskname = $disk["@attributes"]["name"] ; - if ($diskname == "hda" || $diskname == "hdb") continue ; - $path = $disk["source"]["@attributes"]["file"] ; - if (is_file($path) && $action == "yes") unlink("$path") ; - file_put_contents("/tmp/rmvsnaps",$path,FILE_APPEND); - $item = array_search($path,$snapslist[$snap]['backing']["r".$diskname]) ; - $item++ ; - while($item > 0) - { - if (!isset($snapslist[$snap]['backing']["r".$diskname][$item])) break ; - $newpath = $snapslist[$snap]['backing']["r".$diskname][$item] ; - file_put_contents("/tmp/rmvsnaps",$newpath,FILE_APPEND); - if (is_file($newpath) && $action == "yes") unlink("$newpath") ; - $item++ ; - } - } - - uasort($snapslist,'compare_creationtimelt') ; - foreach($snapslist as $s) { - $name = $s['name'] ; - - $xmlfile = $primarypath."/$name.running" ; - $memoryfile = $primarypath."/memory$name.mem" ; - - if ($snapslist[$snap]['state'] == "running") { - # Set XML to saved XML - $xml = file_get_contents($xmlfile) ; - $xmlobj = custom::createArray('domain',$xml) ; - $xml = custom::createXML('domain',$xmlobj)->saveXML(); - if (!strpos($xml,'domain_define($xml) ; - - # Restore Memory. - - $makerun = true ; - if ($makerun == true) exec("virsh restore ".escapeshellarg($memoryfile)) ; - } - #Delete Metadata only. - if ($actionmeta == "yes") { - $ret = delete_snapshots_database("$vm","$name") ; - } - if (is_file($memoryfile) && $action == "yes") unlink($memoryfile) ; - if (is_file($xmlfile) && $action == "yes") unlink($xmlfile) ; - if ($s['name'] == $snap) break ; - } - #if VM was started restart. - if ($state == 'running' && $snapslist[$snap]['state'] != "running") { - $arrResponse = $lv->domain_start($vm) ; - } - - if (!empty($lv->domain_get_ovmf($res))) $nvram = $lv->nvram_revert_snapshot($lv->domain_get_uuid($vm),$name) ; - break ; - - } - $arrResponse = ['success' => true] ; - return($arrResponse) ; - } - function vm_revert($vm, $snap="--current",$action="no",$actionmeta = 'yes',$dryrun = false) { global $lv ; $snapslist= getvmsnapshots($vm) ; @@ -2127,7 +2014,7 @@ private static $encoding = 'UTF-8'; # If Snapstate not running create new XML. if ($snapstate != "running") { - $xml = custom::createXML('domain',$xmlobj)->saveXML(); + if ($method == "ZFS") $xml = $snapslist[$snap]['xml']; else $xml = custom::createXML('domain',$xmlobj)->saveXML(); if (!strpos($xml,'domain_define($xml); file_put_contents("/tmp/xmlrevert", "$xml" ) ;## Remove before stable. @@ -2155,14 +2042,13 @@ private static $encoding = 'UTF-8'; } # Remove later snapshots - uasort($snapslist,'compare_creationtimelt') ; - #var_dump($snapslist); + if (!is_null($snapslist)) uasort($snapslist,'compare_creationtimelt') ; foreach($snapslist as $s) { if ($s['name'] == $snap) break ; $name = $s['name'] ; $oldmethod = $s['method']; - if (!$dryrun) echo "$name $oldmethod\n"; + if ($dryrun) echo "$name $oldmethod\n"; if (!isset($primarypath)) $primarypath = $s['primarypath']; $xmlfile = $primarypath."/$name.running" ; $memoryfile = $primarypath."/memory$name.mem" ; @@ -2177,10 +2063,7 @@ private static $encoding = 'UTF-8'; } } if ($oldmethod == "ZFS") { - # Create ZFS Snapshot - #$zfsdataset = "vmpoolzfs/domains3/Arch3"; - #stat -f -c '%T' /mnt/vmpoolzfs/domains2/Arch3 - #if ($state == "running") exec($cmdstr." 2>&1",$output,$return); + # Rollback ZFS Snapshot $zfsdataset = trim(shell_exec("zfs list -H -o name -r ".transpose_user_path($primarypath))) ; $fssnapcmd = " zfs destroy $zfsdataset@$name"; if (!$dryrun) shell_exec($fssnapcmd); else echo "old $fssnapcmd\n"; @@ -2194,13 +2077,17 @@ private static $encoding = 'UTF-8'; # Delete NVRAM if (!empty($lv->domain_get_ovmf($res)) && $action == "yes") if (!$dryrun) if (!empty($lv->domain_get_ovmf($res))) $nvram = $lv->nvram_revert_snapshot($lv->domain_get_uuid($vm),$name) ; else echo "Remove old NV\n"; if ($actionmeta == "yes") { - if (!$dryrun) $ret = delete_snapshots_database("$vm","$name") ; echo "Old Delete snapshot meta\n"; + if (!$dryrun) $ret = delete_snapshots_database("$vm","$name"); else echo "Old Delete snapshot meta\n"; } } if ($method == "ZFS") { if (!isset($primarypath)) $primarypath = $snapslist[$snap]['primarypath']; + $zfsdataset = trim(shell_exec("zfs list -H -o name -r ".transpose_user_path($primarypath))) ; + if ($dryrun) { + var_dump(transpose_user_path($primarypath)); + } $fssnapcmd = " zfs rollback $zfsdataset@$snap"; if (!$dryrun) shell_exec($fssnapcmd); else echo "$fssnapcmd\n"; $fssnapcmd = " zfs destroy $zfsdataset@$snap"; @@ -2220,7 +2107,9 @@ private static $encoding = 'UTF-8'; # Restore Memory. - if (!$dryrun) exec("virsh restore ".escapeshellarg($memoryfile)) ; + if (!$dryrun) $cmdrtn = exec("virsh restore --running ".escapeshellarg($memoryfile)) ; + if (!$dryrun && !$cmdrtn) unlink($xmlfile); + if (!$dryrun && !$cmdrtn) unlink($memoryfile); } diff --git a/emhttp/plugins/dynamix/DashStats.page b/emhttp/plugins/dynamix/DashStats.page index 32ea824dc..cad9516f9 100644 --- a/emhttp/plugins/dynamix/DashStats.page +++ b/emhttp/plugins/dynamix/DashStats.page @@ -685,6 +685,7 @@ function hideShow() { _(VM Name)_: _(Snapshot Name)_:_(Check free space)_: _(Description)_: +_(FS Native Snapshot )_:_(Unchecked will use QEMU External Snapshot)_ @@ -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(){ diff --git a/emhttp/plugins/dynamix/include/DashboardApps.php b/emhttp/plugins/dynamix/include/DashboardApps.php index e52517179..8baaee591 100644 --- a/emhttp/plugins/dynamix/include/DashboardApps.php +++ b/emhttp/plugins/dynamix/include/DashboardApps.php @@ -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': diff --git a/etc/rc.d/rc.libvirt b/etc/rc.d/rc.libvirt index 6a7b3d8de..ee225c436 100755 --- a/etc/rc.d/rc.libvirt +++ b/etc/rc.d/rc.libvirt @@ -229,6 +229,7 @@ libvirtd_start(){ mkdir -p /etc/libvirt/qemu/swtpm/tpm-states # setup snapshot persistance. mkdir -p /etc/libvirt/qemu/snapshot + mkdir -p /etc/libvirt/qemu/snapshotdb rm -rf /var/lib/libvirt/qemu/snapshot ln -sf /etc/libvirt/qemu/snapshot /var/lib/libvirt/qemu/snapshot # create directory for pid file