VM edit corrections

- create image when new vdisk is added
- keep sound card selection included
- fix add/remove of network interfaces
This commit is contained in:
bergware
2018-09-15 13:24:00 +02:00
parent 869d04306f
commit 968df19f40
5 changed files with 83 additions and 30 deletions
@@ -1085,6 +1085,20 @@
];
}
function create_vdisk(&$new) {
global $lv;
$index = 0;
foreach ($new['disk'] as $i => $disk) {
$index++;
if ($disk['new']) {
$disk = $lv->create_disk_image($disk, $new['domain']['name'], $index);
if ($disk['error']) return $disk['error'];
$new['disk'][$i] = $disk;
}
}
return false;
}
function array_update_recursive(&$old, &$new) {
$hostold = $old['devices']['hostdev']; // existing devices including custom settings
$hostnew = $new['devices']['hostdev']; // GUI generated devices
@@ -1115,7 +1129,8 @@
// update parent arrays
if (!$old['devices']['hostdev']) unset($old['devices']['hostdev']);
if (!$new['devices']['hostdev']) unset($new['devices']['hostdev']);
unset($old['cputune']['vcpupin'],$old['devices']['graphics'],$old['devices']['video'],$old['devices']['disk']);
// remove existing auto-generated settings
unset($old['cputune']['vcpupin'],$old['devices']['graphics'],$old['devices']['video'],$old['devices']['disk'],$old['devices']['interface']);
// set namespace
$new['metadata']['vmtemplate']['@attributes']['xmlns'] = 'unraid';
}
@@ -201,11 +201,16 @@ $hdrXML = "<?xml version='1.0' encoding='UTF-8'?>\n"; // XML encoding declaratio
$xml = $_POST['xmldesc'];
} else {
// form view
$arrExistingConfig = custom::createArray('domain',$strXML);
$arrUpdatedConfig = custom::createArray('domain',$lv->config_to_xml($_POST));
array_update_recursive($arrExistingConfig, $arrUpdatedConfig);
$arrConfig = array_replace_recursive($arrExistingConfig, $arrUpdatedConfig);
$xml = custom::createXML('domain',$arrConfig)->saveXML();
if ($error = create_vdisk($_POST) === false) {
$arrExistingConfig = custom::createArray('domain',$strXML);
$arrUpdatedConfig = custom::createArray('domain',$lv->config_to_xml($_POST));
array_update_recursive($arrExistingConfig, $arrUpdatedConfig);
$arrConfig = array_replace_recursive($arrExistingConfig, $arrUpdatedConfig);
$xml = custom::createXML('domain',$arrConfig)->saveXML();
} else {
echo json_encode(['error' => $error]);
exit;
}
}
// delete and create the VM
$lv->nvram_backup($uuid);
@@ -232,7 +237,7 @@ $hdrXML = "<?xml version='1.0' encoding='UTF-8'?>\n"; // XML encoding declaratio
$boolRunning = $lv->domain_get_state($dom)=='running';
$strXML = $lv->domain_get_xml($dom);
$boolNew = false;
$arrConfig = domain_to_config($uuid);
$arrConfig = array_replace_recursive($arrConfigDefaults, domain_to_config($uuid));
} else {
// edit new VM
$boolRunning = false;
@@ -1418,6 +1423,7 @@ $(function() {
$("#vmform .formview #btnSubmit").click(function frmSubmit() {
var $button = $(this);
var $panel = $('.formview');
var form = $button.closest('form');
$("#vmform .disk_select option:selected").not("[value='manual']").closest('table').each(function () {
var v = $(this).find('.disk_preview').html();
@@ -1428,24 +1434,34 @@ $(function() {
<?if (!$boolNew):?>
// signal devices to be added or removed
$button.closest('form').find('input[name="usb[]"],input[name="pci[]"]').each(function(){
form.find('input[name="usb[]"],input[name="pci[]"]').each(function(){
if (!$(this).prop('checked')) $(this).prop('checked',true).val($(this).val()+'#remove');
});
// remove unused graphic cards
var gpus = [], i = 0;
do {
var gpu = $button.closest('form').find('select[name="gpu['+(i++)+'][id]"] option:selected').val();
var gpu = form.find('select[name="gpu['+(i++)+'][id]"] option:selected').val();
if (gpu) gpus.push(gpu);
} while (gpu);
$button.closest('form').find('select[name="gpu[0][id]"] option').each(function(){
form.find('select[name="gpu[0][id]"] option').each(function(){
var gpu = $(this).val();
if (gpu != 'vnc' && !gpus.includes(gpu)) $('form#vmform').append('<input type="hidden" name="pci[]" value="'+gpu+'#remove">');
if (gpu != 'vnc' && !gpus.includes(gpu)) form.append('<input type="hidden" name="pci[]" value="'+gpu+'#remove">');
});
// remove unused sound cards
var sound = [], i = 0;
do {
var audio = form.find('select[name="audio['+(i++)+'][id]"] option:selected').val();
if (audio) sound.push(audio);
} while (audio);
form.find('select[name="audio[0][id]"] option').each(function(){
var audio = $(this).val();
if (audio && !sound.includes(audio)) form.append('<input type="hidden" name="pci[]" value="'+audio+'#remove">');
});
<?endif?>
var postdata = $button.closest('form').find('input,select').serialize().replace(/'/g,"%27");
<?if (!$boolNew):?>
// keep checkbox visually unchecked
$button.closest('form').find('input[name="usb[]"],input[name="pci[]"]').each(function(){
form.find('input[name="usb[]"],input[name="pci[]"]').each(function(){
if ($(this).val().indexOf('#remove')>0) $(this).prop('checked',false);
});
<?endif?>
@@ -392,7 +392,7 @@ $hdrXML = "<?xml version='1.0' encoding='UTF-8'?>\n"; // XML encoding declaratio
$boolRunning = $lv->domain_get_state($dom)=='running';
$strXML = $lv->domain_get_xml($dom);
$boolNew = false;
$arrConfig = domain_to_config($uuid);
$arrConfig = array_replace_recursive($arrConfigDefaults, domain_to_config($uuid));
} else {
// edit new VM
$boolRunning = false;
@@ -1116,29 +1116,40 @@ $(function() {
$("#vmform .formview #btnSubmit").click(function frmSubmit() {
var $button = $(this);
var $panel = $('.formview');
var form = $button.closest('form');
$panel.find('input').prop('disabled', false); // enable all inputs otherwise they wont post
<?if (!$boolNew):?>
// signal devices to be added or removed
$button.closest('form').find('input[name="usb[]"],input[name="pci[]"]').each(function(){
form.find('input[name="usb[]"],input[name="pci[]"]').each(function(){
if (!$(this).prop('checked')) $(this).prop('checked',true).val($(this).val()+'#remove');
});
// remove unused graphic cards
var gpus = [], i = 0;
do {
var gpu = $button.closest('form').find('select[name="gpu['+(i++)+'][id]"] option:selected').val();
var gpu = form.find('select[name="gpu['+(i++)+'][id]"] option:selected').val();
if (gpu) gpus.push(gpu);
} while (gpu);
$button.closest('form').find('select[name="gpu[0][id]"] option').each(function(){
form.find('select[name="gpu[0][id]"] option').each(function(){
var gpu = $(this).val();
if (gpu != 'vnc' && !gpus.includes(gpu)) $('form#vmform').append('<input type="hidden" name="pci[]" value="'+gpu+'#remove">');
if (gpu != 'vnc' && !gpus.includes(gpu)) form.append('<input type="hidden" name="pci[]" value="'+gpu+'#remove">');
});
// remove unused sound cards
var sound = [], i = 0;
do {
var audio = form.find('select[name="audio['+(i++)+'][id]"] option:selected').val();
if (audio) sound.push(audio);
} while (audio);
form.find('select[name="audio[0][id]"] option').each(function(){
var audio = $(this).val();
if (audio && !sound.includes(audio)) form.append('<input type="hidden" name="pci[]" value="'+audio+'#remove">');
});
<?endif?>
var postdata = $button.closest('form').find('input,select').serialize().replace(/'/g,"%27");
var postdata = form.find('input,select').serialize().replace(/'/g,"%27");
<?if (!$boolNew):?>
// keep checkbox visually unchecked
$button.closest('form').find('input[name="usb[]"],input[name="pci[]"]').each(function(){
form.find('input[name="usb[]"],input[name="pci[]"]').each(function(){
if ($(this).val().indexOf('#remove')>0) $(this).prop('checked',false);
});
<?endif?>
@@ -394,7 +394,7 @@ $hdrXML = "<?xml version='1.0' encoding='UTF-8'?>\n"; // XML encoding declaratio
$boolRunning = $lv->domain_get_state($dom)=='running';
$strXML = $lv->domain_get_xml($dom);
$boolNew = false;
$arrConfig = domain_to_config($uuid);
$arrConfig = array_replace_recursive($arrConfigDefaults, domain_to_config($uuid));
} else {
// edit new VM
$boolRunning = false;
@@ -1118,29 +1118,40 @@ $(function() {
$("#vmform .formview #btnSubmit").click(function frmSubmit() {
var $button = $(this);
var $panel = $('.formview');
var form = $button.closest('form');
$panel.find('input').prop('disabled', false); // enable all inputs otherwise they wont post
<?if (!$boolNew):?>
// signal devices to be added or removed
$button.closest('form').find('input[name="usb[]"],input[name="pci[]"]').each(function(){
form.find('input[name="usb[]"],input[name="pci[]"]').each(function(){
if (!$(this).prop('checked')) $(this).prop('checked',true).val($(this).val()+'#remove');
});
// remove unused graphic cards
var gpus = [], i = 0;
do {
var gpu = $button.closest('form').find('select[name="gpu['+(i++)+'][id]"] option:selected').val();
var gpu = form.find('select[name="gpu['+(i++)+'][id]"] option:selected').val();
if (gpu) gpus.push(gpu);
} while (gpu);
$button.closest('form').find('select[name="gpu[0][id]"] option').each(function(){
form.find('select[name="gpu[0][id]"] option').each(function(){
var gpu = $(this).val();
if (gpu != 'vnc' && !gpus.includes(gpu)) $('form#vmform').append('<input type="hidden" name="pci[]" value="'+gpu+'#remove">');
if (gpu != 'vnc' && !gpus.includes(gpu)) form.append('<input type="hidden" name="pci[]" value="'+gpu+'#remove">');
});
// remove unused sound cards
var sound = [], i = 0;
do {
var audio = form.find('select[name="audio['+(i++)+'][id]"] option:selected').val();
if (audio) sound.push(audio);
} while (audio);
form.find('select[name="audio[0][id]"] option').each(function(){
var audio = $(this).val();
if (audio && !sound.includes(audio)) form.append('<input type="hidden" name="pci[]" value="'+audio+'#remove">');
});
<?endif?>
var postdata = $button.closest('form').find('input,select').serialize().replace(/'/g,"%27");
var postdata = form.find('input,select').serialize().replace(/'/g,"%27");
<?if (!$boolNew):?>
// keep checkbox visually unchecked
$button.closest('form').find('input[name="usb[]"],input[name="pci[]"]').each(function(){
form.find('input[name="usb[]"],input[name="pci[]"]').each(function(){
if ($(this).val().indexOf('#remove')>0) $(this).prop('checked',false);
});
<?endif?>
+4 -4
View File
@@ -34,7 +34,7 @@ class custom {
* @param array $arr - array object to be converterd
* @return XML object
*/
public static function &createXML($root, $arr=array()) {
public static function &createXML($root, $arr) {
$xml = self::getXMLRoot();
$xml->appendChild(self::Array2XML($root, $arr));
self::$xml = null; // clear the xml node in the class for 2nd time use
@@ -55,7 +55,7 @@ class custom {
/*
* Recursive conversion Array to XML
*/
private static function &Array2XML($node_name, $arr=array()) {
private static function &Array2XML($node_name, $arr) {
$xml = self::getXMLRoot();
$node = $xml->createElement($node_name);
if (is_array($arr)) {
@@ -130,11 +130,11 @@ class custom {
// store as single or multi array
if (!isset($tags[$node])) {
// specific for Unraid
if (in_array($node,['hostdev','controller','disk'])) $tags[$node][] = $data; else $tags[$node] = $data;
if (in_array($node,['hostdev','controller','disk','interface'])) $tags[$node][] = $data; else $tags[$node] = $data;
} elseif (is_array($tags[$node]) && array_keys($tags[$node])===range(0, count($tags[$node])-1)) {
$tags[$node][] = $data;
} else {
$tags[$node] = array($tags[$node], $data);
$tags[$node] = [$tags[$node], $data];
}
}
$textContent = [];