mirror of
https://github.com/unraid/webgui.git
synced 2026-01-04 08:29:51 -06:00
MAC Address option and ZFS ref link
This commit is contained in:
@@ -234,7 +234,8 @@ function VMClone(uuid, name){
|
||||
var edit = box.find('#Edit').prop('checked') ? 'yes' : 'no';
|
||||
var overwrite = box.find('#Overwrite').prop('checked') ? 'yes' : 'no';
|
||||
var free = box.find('#Free').prop('checked') ? 'yes' : 'no';
|
||||
scripturl = "VMClone.php " + encodeURIComponent("/usr/local/emhttp/plugins/dynamix.vm.manager/include/VMClone.php&" + $.param({action:"clone", name:name, clone:clone, overwrite:overwrite, edit:edit, start:start, free:free}));
|
||||
var regenmac = box.find('#Regenmac').prop('checked') ? 'yes' : 'no';
|
||||
scripturl = "VMClone.php " + encodeURIComponent("/usr/local/emhttp/plugins/dynamix.vm.manager/include/VMClone.php&" + $.param({action:"clone", name:name, clone:clone, overwrite:overwrite, edit:edit, start:start, free:free, regenmac:regenmac}));
|
||||
openVMAction((scripturl),"VM Clone", "dynamix.vm.manager", "loadlist");
|
||||
box.dialog('close');
|
||||
},
|
||||
@@ -572,6 +573,7 @@ _(Snapshot Name)_: <input type="text" id="targetsnap" hidden><label id="targetsn
|
||||
<tr><td>_(Overwrite)_:</td><td><input type="checkbox" id="Overwrite" value="" checked></td></tr>
|
||||
<tr hidden><td>_(Start Cloned VM)_:</td><td><input type="checkbox" id="Start" value="" ></td></tr>
|
||||
<tr hidden><td>_(Edit VM after clone)_:</td><td><input type="checkbox" id="Edit" value="" ></td></tr>
|
||||
<tr><td>_(Regenerate MAC addresses)_:</td><td><input type="checkbox" id="Regenmac" value="" checked ></td></tr>
|
||||
<tr><td>_(Check free space)_:</td><td><input type="checkbox" id="Free" value="" checked></td></tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@@ -1727,7 +1727,7 @@ class Array2XML {
|
||||
return $copypaste;
|
||||
}
|
||||
|
||||
function vm_clone($vm, $clone ,$overwrite,$start,$edit, $free, $waitID) {
|
||||
function vm_clone($vm, $clone ,$overwrite,$start,$edit, $free, $waitID, $regenmac) {
|
||||
global $lv,$domain_cfg,$arrDisplayOptions;
|
||||
/*
|
||||
Clone.
|
||||
@@ -1800,9 +1800,12 @@ class Array2XML {
|
||||
|
||||
$config["domain"]["name"] = $clone;
|
||||
$config["domain"]["uuid"] = $lv->domain_generate_uuid();
|
||||
foreach($config["nic"] as $index => $detail) {
|
||||
$config["nic"][$index]["mac"] = $lv->generate_random_mac_addr();
|
||||
}
|
||||
if ($regenmac == "yes") {
|
||||
write("addLog\0".htmlspecialchars(_("Regenerate MACs")));
|
||||
foreach($config["nic"] as $index => $detail) {
|
||||
$config["nic"][$index]["mac"] = $lv->generate_random_mac_addr();
|
||||
}
|
||||
} else write("addLog\0".htmlspecialchars(_("Retain existing MACs")));
|
||||
$config["domain"]["type"] = "kvm";
|
||||
|
||||
$usbs = getVMUSBs($vmxml);
|
||||
@@ -1831,7 +1834,7 @@ class Array2XML {
|
||||
if (!is_dir($clonedir)) {
|
||||
my_mkdir($clonedir,0777,true);
|
||||
}
|
||||
write("addLog\0".htmlspecialchars("Checking for image files"));
|
||||
write("addLog\0".htmlspecialchars(_("Checking for image files")));
|
||||
if ($file_exists && $overwrite != "yes") { write("addLog\0".htmlspecialchars(_("New image file names exist and Overwrite is not allowed"))); return( false); }
|
||||
|
||||
#Create duplicate files.
|
||||
@@ -1844,8 +1847,18 @@ class Array2XML {
|
||||
$reptgt = str_replace('/mnt/user/', "/mnt/$sourcerealdisk/", $target);
|
||||
$repsrc = str_replace('/mnt/user/', "/mnt/$sourcerealdisk/", $source);
|
||||
}
|
||||
$cmdstr = "cp --reflink=always '$repsrc' '$reptgt'";
|
||||
if ($reflink == true) { $refcmd = $cmdstr; } else {$refcmd = false; }
|
||||
|
||||
$refresult = getFilesystemAndReflinkMode($repsrc);
|
||||
$refcmdaction = $refresult['reflink_mode'];
|
||||
$refcmdfs = $refresult['filesystem'];
|
||||
$cmdstr = "cp --reflink=$refcmdaction '$repsrc' '$reptgt'";
|
||||
write("addLog\0".htmlspecialchars(_("Reflink Action")." ".$refcmdaction." "._("for filesystem")." ".$refcmdfs));
|
||||
if ($reflink == true) { $refcmd = $cmdstr; } else {$refcmd = false; }
|
||||
if ($refresult['filesystem'] == "zfs" && $refresult['reflink_mode'] == "skip") {
|
||||
write("addLog\0".htmlspecialchars(_("Reflink copy not supported on ZFS skipping")));
|
||||
$refcmd = false;
|
||||
}
|
||||
|
||||
$cmdstr = "rsync -ahPIXS --out-format=%f --info=flist0,misc0,stats0,name1,progress2 '$repsrc' '$reptgt'";
|
||||
$error = execCommand_nchan_clone($cmdstr,$target,$refcmd);
|
||||
if (!$error) { write("addLog\0".htmlspecialchars("Image copied failed.")); return( false); }
|
||||
@@ -2936,4 +2949,71 @@ function get_storage_fstype($storage="default") {
|
||||
$fstype = trim(shell_exec(" stat -f -c '%T' $storage"));
|
||||
return $fstype;
|
||||
}
|
||||
|
||||
function getFilesystemAndReflinkMode(string $filePath): array {
|
||||
// Default return values
|
||||
$result = [
|
||||
'filesystem' => 'unknown',
|
||||
'reflink_mode' => 'always' // safest fallback if unsupported
|
||||
];
|
||||
|
||||
$realPath = realpath($filePath);
|
||||
if ($realPath === false || !file_exists($realPath)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$dirname = dirname($realPath);
|
||||
|
||||
// Handle Unraid-style virtual paths
|
||||
if (strpos($dirname, '/mnt/user/') === 0) {
|
||||
error_log("Getting real disks\n");
|
||||
$realdisk = trim(shell_exec("getfattr --absolute-names --only-values -n system.LOCATION " . escapeshellarg($dirname) . " 2>/dev/null"));
|
||||
if (!empty($realdisk)) {
|
||||
$dirname = str_replace('/mnt/user/', "/mnt/$realdisk/", $dirname);
|
||||
}
|
||||
}
|
||||
|
||||
// Get filesystem type
|
||||
$fstype = trim(shell_exec("stat -f -c '%T' " . escapeshellarg($dirname)));
|
||||
$result['filesystem'] = $fstype;
|
||||
|
||||
// If not ZFS, return early
|
||||
if ($fstype !== 'zfs') {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$result['reflink_mode'] = 'skip';
|
||||
|
||||
// Get dataset from the file
|
||||
$dataset = trim(shell_exec("zfs list -H -o name " . escapeshellarg($dirname) . " 2>/dev/null"));
|
||||
if (empty($dataset)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Get pool from dataset
|
||||
$parts = explode('/', $dataset);
|
||||
$pool = $parts[0] ?? '';
|
||||
if (empty($pool)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Check ZFS block_cloning feature
|
||||
$output = [];
|
||||
$resultCode = 0;
|
||||
exec("zpool get -H -o value feature@block_cloning " . escapeshellarg($pool) . " 2>/dev/null", $output, $resultCode);
|
||||
if ($resultCode !== 0 || empty($output) || (trim($output[0]) !== 'enabled' && trim($output[0]) !== 'active')) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Check if bclone is enabled at runtime
|
||||
$bcloneValue = @file_get_contents("/sys/module/zfs/parameters/zfs_bclone_enabled");
|
||||
if ($bcloneValue === false || trim($bcloneValue) !== '1') {
|
||||
return $result;
|
||||
}
|
||||
|
||||
// If both checks passed, block cloning is supported
|
||||
$result['reflink_mode'] = 'auto';
|
||||
return $result;
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -99,7 +99,7 @@ write("addLog\0".htmlspecialchars("Cloning $name to $clone"));
|
||||
|
||||
switch ($action) {
|
||||
case "clone":
|
||||
$rtn = vm_clone($name,$clone,$overwrite,$start,$edit,$free,$waitID) ;
|
||||
$rtn = vm_clone($name,$clone,$overwrite,$start,$edit,$free,$waitID,$regenmac) ;
|
||||
break ;
|
||||
}
|
||||
write("stop_Wait\0$waitID") ;
|
||||
|
||||
@@ -698,6 +698,7 @@ function hideShow() {
|
||||
<tr><td>_(Overwrite)_:</td><td><input type="checkbox" id="Overwrite" value="" ></td></tr>
|
||||
<tr hidden><td>_(Start Cloned VM)_:</td><td><input type="checkbox" id="Start" value="" ></td></tr>
|
||||
<tr hidden><td>_(Edit VM after clone)_:</td><td><input type="checkbox" id="Edit" value="" ></td></tr>
|
||||
<tr><td>_(Regenerate MAC addresses)_:</td><td><input type="checkbox" id="Edit" value="" checked ></td></tr>
|
||||
<tr><td>_(Check free space)_:</td><td><input type="checkbox" id="Free" value="" ></td></tr>
|
||||
</table>
|
||||
</div>
|
||||
@@ -1464,7 +1465,8 @@ function VMClone(uuid, name){
|
||||
var edit = box.find('#Edit').prop('checked') ? 'yes' : 'no';
|
||||
var overwrite = box.find('#Overwrite').prop('checked') ? 'yes' : 'no';
|
||||
var free = box.find('#Free').prop('checked') ? 'yes' : 'no';
|
||||
var scripturl = "VMClone.php " + encodeURIComponent("/usr/local/emhttp/plugins/dynamix.vm.manager/include/VMClone.php&" + $.param({action:"clone", name:name, clone:clone, overwrite:overwrite, edit:edit, start:start, free:free}));
|
||||
var regenmac = box.find('#Regenmac').prop('checked') ? 'yes' : 'no';
|
||||
var scripturl = "VMClone.php " + encodeURIComponent("/usr/local/emhttp/plugins/dynamix.vm.manager/include/VMClone.php&" + $.param({action:"clone", name:name, clone:clone, overwrite:overwrite, edit:edit, start:start, free:free, regenmac:regenmac}));
|
||||
openVMAction((scripturl),"VM Clone", "dynamix.vm.manager", "loadlist");
|
||||
box.dialog('close');
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user