diff --git a/plugins/dynamix.vm.manager/include/libvirt_helpers.php b/plugins/dynamix.vm.manager/include/libvirt_helpers.php
index 7de62180c..0dbba5ee2 100644
--- a/plugins/dynamix.vm.manager/include/libvirt_helpers.php
+++ b/plugins/dynamix.vm.manager/include/libvirt_helpers.php
@@ -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';
}
diff --git a/plugins/dynamix.vm.manager/templates/Custom.form.php b/plugins/dynamix.vm.manager/templates/Custom.form.php
index 223035a08..523d72c85 100644
--- a/plugins/dynamix.vm.manager/templates/Custom.form.php
+++ b/plugins/dynamix.vm.manager/templates/Custom.form.php
@@ -201,11 +201,16 @@ $hdrXML = "\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 = "\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() {
// 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('');
+ if (gpu != 'vnc' && !gpus.includes(gpu)) form.append('');
+ });
+ // 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('');
});
var postdata = $button.closest('form').find('input,select').serialize().replace(/'/g,"%27");
// 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);
});
diff --git a/plugins/dynamix.vm.manager/templates/LibreELEC.form.php b/plugins/dynamix.vm.manager/templates/LibreELEC.form.php
index c61639a25..a3cc2f8a0 100644
--- a/plugins/dynamix.vm.manager/templates/LibreELEC.form.php
+++ b/plugins/dynamix.vm.manager/templates/LibreELEC.form.php
@@ -392,7 +392,7 @@ $hdrXML = "\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
// 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('');
+ if (gpu != 'vnc' && !gpus.includes(gpu)) form.append('');
+ });
+ // 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('');
});
- var postdata = $button.closest('form').find('input,select').serialize().replace(/'/g,"%27");
+ var postdata = form.find('input,select').serialize().replace(/'/g,"%27");
// 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);
});
diff --git a/plugins/dynamix.vm.manager/templates/OpenELEC.form.php b/plugins/dynamix.vm.manager/templates/OpenELEC.form.php
index c43e93c40..0a1bedfd0 100644
--- a/plugins/dynamix.vm.manager/templates/OpenELEC.form.php
+++ b/plugins/dynamix.vm.manager/templates/OpenELEC.form.php
@@ -394,7 +394,7 @@ $hdrXML = "\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
// 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('');
+ if (gpu != 'vnc' && !gpus.includes(gpu)) form.append('');
+ });
+ // 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('');
});
- var postdata = $button.closest('form').find('input,select').serialize().replace(/'/g,"%27");
+ var postdata = form.find('input,select').serialize().replace(/'/g,"%27");
// 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);
});
diff --git a/plugins/dynamix/include/Custom.php b/plugins/dynamix/include/Custom.php
index de58bc6df..0cedf51e6 100644
--- a/plugins/dynamix/include/Custom.php
+++ b/plugins/dynamix/include/Custom.php
@@ -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 = [];