[PATCH v3] [Kimchi 0/8] CPU topology setup enhancements

From: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com> * NOTE: THIS PATCH SET ISN'T COMPATIBLE WITH STABLE-2.3.X BRANCH * v3: - added an extra patch to handle a problem with the 'Save' button in the Edit Guest window - fixed a bug in the patch that turned 'threads' in a number field v2: - added an extra patch to handle the 'threads' field problem * NOTE: THIS PATCH SET IS NOT APPLICABLE IN THE STABLE-2.3.X BRANCH * This patch set contains several patches that enhances the user experience when configuring existing templates and offline guests, allowing current CPU, maximum CPU and CPU topology to be defined at all times. Daniel Henrique Barboza (8): Bug fix #1072 - changing vpus verification Adding 'sockets' field in the topology of Templates template_edit_main.js: initProcessor now a global function Adding 'Processor' tab in Edit Guest dialog CPU configuration UI: several improvements Adding CPU setup help text in Edit Guest/Template Edit Guest dialog: fixing 'Save' button on Processor tab Changing 'threads' to be a free number field i18n.py | 3 +- model/cpuinfo.py | 4 +- tests/test_model.py | 12 +-- ui/css/kimchi.css | 36 +++++-- ui/css/src/modules/_edit-guests.scss | 28 ++++- ui/css/src/modules/_templates.scss | 3 - ui/js/src/kimchi.guest_edit_main.js | 94 ++++++++--------- ui/js/src/kimchi.template_edit_main.js | 187 ++++++++++++++++++++++----------- ui/pages/guest-edit.html.tmpl | 54 ++++++++-- ui/pages/i18n.json.tmpl | 2 +- ui/pages/template-edit.html.tmpl | 27 +++-- 11 files changed, 296 insertions(+), 154 deletions(-) -- 2.7.4

From: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com> This patch changes the vcpu verification when editing a turned off VM, if the VM has a topology set, to comply with the current libvirt schema: vcpus must be a multiple of the 'threads' value. Unit tests were adapted to reflect these changes. Signed-off-by: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com> --- i18n.py | 2 +- model/cpuinfo.py | 2 +- tests/test_model.py | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/i18n.py b/i18n.py index 03929e5..9d0abee 100644 --- a/i18n.py +++ b/i18n.py @@ -357,7 +357,7 @@ messages = { "KCHCPUINF0002E": _("When CPU topology is defined, maximum number of vCPUs must be a product of sockets, cores, and threads."), "KCHCPUINF0003E": _("This host (or current configuration) does not allow CPU topology."), "KCHCPUINF0004E": _("The maximum number of vCPUs is too large for this system."), - "KCHCPUINF0005E": _("When CPU topology is defined, vCPUs must be a multiple of a product of cores and threads."), + "KCHCPUINF0005E": _("When CPU topology is defined, CPUs must be a multiple of the 'threads' number defined."), "KCHCPUINF0006E": _("The number of threads is too large for this system."), "KCHCPUINF0007E": _("When CPU topology is specified, sockets, cores and threads are required paramaters."), "KCHCPUINF0008E": _("Parameter 'cpu_info' expects an object with fields among: 'vcpus', 'maxvcpus', 'topology'."), diff --git a/model/cpuinfo.py b/model/cpuinfo.py index 3707a02..5f82320 100644 --- a/model/cpuinfo.py +++ b/model/cpuinfo.py @@ -138,7 +138,7 @@ class CPUInfoModel(object): raise InvalidParameter("KCHCPUINF0006E") if maxvcpus != sockets * cores * threads: raise InvalidParameter("KCHCPUINF0002E") - if vcpus % (cores * threads) != 0: + if vcpus % threads != 0: raise InvalidParameter("KCHCPUINF0005E") if maxvcpus > self.get_host_max_vcpus(): diff --git a/tests/test_model.py b/tests/test_model.py index 1eaad6a..4bc82ad 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -1316,23 +1316,23 @@ class ModelTests(unittest.TestCase): # define CPU topology inst.vm_update(u'kimchi-vm1', {'cpu_info': {'topology': { - 'sockets': 4, 'cores': 2, 'threads': 1}}}) + 'sockets': 2, 'cores': 2, 'threads': 2}}}) vm_info = inst.vm_lookup(u'kimchi-vm1') - self.assertEquals({'sockets': 4, 'cores': 2, 'threads': 1}, + self.assertEquals({'sockets': 2, 'cores': 2, 'threads': 2}, vm_info['cpu_info']['topology']) - # vcpus not a multiple of (cores * threads) + # vcpus not a multiple of threads self.assertRaises(InvalidParameter, inst.vm_update, u'kimchi-vm1', - {'cpu_info': {'vcpus': 1}}) + {'cpu_info': {'vcpus': 5}}) # maxvcpus different of (sockets * cores * threads) self.assertRaises(InvalidParameter, inst.vm_update, u'kimchi-vm1', {'cpu_info': {'maxvcpus': 4}}) - # topology does not match maxvcpus (8 != 2 * 2 * 1) + # topology does not match maxvcpus (8 != 3 * 2 * 2) self.assertRaises(InvalidParameter, inst.vm_update, u'kimchi-vm1', {'cpu_info': {'topology': { - 'sockets': 2, 'cores': 2, 'threads': 1}}}) + 'sockets': 3, 'cores': 2, 'threads': 2}}}) # undefine CPU topology inst.vm_update(u'kimchi-vm1', {'cpu_info': {'topology': {}}}) -- 2.7.4

From: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com> Following the changes of bug fix #1072, this patch adds the 'sockets' values to be editable in the CPU topology. Since sockets is now a component of the calculation of Max CPUs of a VM, it makes sense to allow user control of it. As with cores and threads, the defautl value of sockets is returned by the cpu_info API. Signed-off-by: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com> --- ui/js/src/kimchi.template_edit_main.js | 21 +++++++++++++++++---- ui/pages/template-edit.html.tmpl | 12 +++++++----- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/ui/js/src/kimchi.template_edit_main.js b/ui/js/src/kimchi.template_edit_main.js index 9b9828d..457246e 100644 --- a/ui/js/src/kimchi.template_edit_main.js +++ b/ui/js/src/kimchi.template_edit_main.js @@ -641,8 +641,15 @@ kimchi.template_edit_main = function() { var initProcessor = function(){ var setCPUValue = function(){ - if(!$('#cores').hasClass("invalid-field")&&$('#cores').val()!=""){ - var computedCpu = parseInt($("#cores").val())*parseInt($("#threads").val()); + if(!$('#sockets').hasClass("invalid-field") && + !$('#cores').hasClass("invalid-field") && + $('#sockets').val()!="" && $('#cores').val()!=""){ + + var sockets = parseInt($("#sockets").val()); + var cores = parseInt($("#cores").val()); + var threads = parseInt($("#threads").val()); + + var computedCpu = sockets * cores * threads; $("#vcpus").val(computedCpu); if ($("#cpus-check").prop("checked")) { //If topology is checked, set maxcpu to be the same as # of cpu otherwise, backend gives error @@ -654,7 +661,10 @@ kimchi.template_edit_main = function() { }; $("input:text", "#form-template-processor").on('keyup', function() { $(this).toggleClass("invalid-field", !$(this).val().match('^[0-9]*$')); - if ($(this).prop('id') == 'cores') setCPUValue(); + if ($(this).prop('id') == 'sockets' || + $(this).prop('id') == 'cores') { + setCPUValue(); + } }); $("input:checkbox", "#form-template-processor").click(function() { $('#threads').selectpicker(); @@ -680,6 +690,9 @@ kimchi.template_edit_main = function() { if (template.cpu_info.maxvcpus) { $("#guest-edit-max-processor-textbox").val(template.cpu_info.maxvcpus); } + if (topo && topo.sockets) { + $("#sockets").val(topo.sockets); + } if (topo && topo.cores) { $("#cores").val(topo.cores); } @@ -815,7 +828,7 @@ kimchi.template_edit_main = function() { vcpus: cpu, maxvcpus: maxCpuFinal, topology: { - sockets: 1, + sockets: parseInt($("#sockets").val()), cores: parseInt($("#cores").val()), threads: parseInt($("#threads").val()) } diff --git a/ui/pages/template-edit.html.tmpl b/ui/pages/template-edit.html.tmpl index e9a479e..0ba4c4b 100644 --- a/ui/pages/template-edit.html.tmpl +++ b/ui/pages/template-edit.html.tmpl @@ -169,14 +169,16 @@ </div> <div class="topology"> <div class="form-group"> + <label for="sockets">$_("Sockets")</label> + <input type="text" class="form-control" value="1" id="sockets" /> + </div> + <div class="form-group"> <label for="cores">$_("Cores")</label> <input type="text" class="form-control" value="1" id="cores" /> </div> - <div> - <div class="form-group"> - <label for="threads">$_("Threads")</label> - <select id="threads" class="selectpicker col-md-12 col-lg-12"></select> - </div> + <div class="form-group"> + <label for="threads">$_("Threads")</label> + <select id="threads" class="selectpicker col-md-12 col-lg-12"></select> </div> </div> </form> -- 2.7.4

From: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com> This patch makes the initProcessor function declared inside template_edit_main.js a global function called kimchi.init_processor_tab. The idea is to avoid code repetition when the same tab is used by other modals (Guest Edit, for example). To make the function generic, references of 'template' inside ids of init_processor_tab were removed. Changes in template-edit.html.tmpl were required to make the tab work with this new function. Signed-off-by: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com> --- ui/js/src/kimchi.template_edit_main.js | 158 ++++++++++++++++++--------------- ui/pages/template-edit.html.tmpl | 2 +- 2 files changed, 85 insertions(+), 75 deletions(-) diff --git a/ui/js/src/kimchi.template_edit_main.js b/ui/js/src/kimchi.template_edit_main.js index 457246e..36e6911 100644 --- a/ui/js/src/kimchi.template_edit_main.js +++ b/ui/js/src/kimchi.template_edit_main.js @@ -15,6 +15,88 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +kimchi.init_processor_tab = function(cpu_info) { + var setCPUValue = function(){ + if (!$('#sockets').hasClass("invalid-field") && + !$('#cores').hasClass("invalid-field") && + $('#sockets').val()!="" && $('#cores').val()!="") { + + var sockets = parseInt($("#sockets").val()); + var cores = parseInt($("#cores").val()); + var threads = parseInt($("#threads").val()); + + var computedCpu = sockets * cores * threads; + $("#vcpus").val(computedCpu); + if ($("#cpus-check").prop("checked")) { + //If topology is checked, set maxcpu to be the same as # of cpu otherwise, backend gives error + $("#guest-edit-max-processor-textbox").val(computedCpu); + } + } else { + $("#vcpus").val(''); + } + }; + + $("input:text", "#form-edit-processor").on('keyup', function() { + $(this).toggleClass("invalid-field", !$(this).val().match('^[0-9]*$')); + if ($(this).prop('id') == 'sockets' || + $(this).prop('id') == 'cores') { + setCPUValue(); + } + }); + + $("input:checkbox", "#form-edit-processor").click(function() { + $('#threads').selectpicker(); + $(".topology", "#form-edit-processor").slideToggle(); + $("#vcpus").attr("disabled", $(this).prop("checked")); + $("#guest-edit-max-processor-textbox").attr("disabled", $(this).prop("checked")); + setCPUValue(); + }); + + $('#threads').change(function() { + setCPUValue(); + }); + + kimchi.getCPUInfo(function(data) { + var options = ""; + var topo = cpu_info.topology; + + for (var i = 0; Math.pow(2, i) <= data.threads_per_core; i++) { + var lastOne = Math.pow(2, i + 1) > data.threads_per_core ? " selected" : ""; + options += "<option" + lastOne + ">" + Math.pow(2, i) + "</option>"; + } + + $('#threads').append(options); + + if (cpu_info.vcpus) { + $("#vcpus").val(cpu_info.vcpus); + } + if (cpu_info.maxvcpus) { + $("#guest-edit-max-processor-textbox").val(cpu_info.maxvcpus); + } + if (topo && topo.sockets) { + $("#sockets").val(topo.sockets); + } + if (topo && topo.cores) { + $("#cores").val(topo.cores); + } + if (topo && topo.threads) { + $('#threads').val(topo.threads); + $('#threads').selectpicker(); + $("input:checkbox", "#form-edit-processor").trigger('click'); + } + }); + + $('#guest-show-max-processor').on('click', function(e) { + e.preventDefault; + $('#guest-max-processor-panel').slideToggle(); + var text = $('#guest-show-max-processor span.text').text(); + $('#guest-show-max-processor span.text').text(text == i18n['KCHVMED6008M'] ? i18n['KCHVMED6009M'] : i18n['KCHVMED6008M']); + $('#guest-show-max-processor i.fa').toggleClass('fa-plus-circle fa-minus-circle'); + }); +}; + + kimchi.template_edit_main = function() { var templateEditMain = $('#edit-template-tabs'); var origDisks; @@ -639,78 +721,6 @@ kimchi.template_edit_main = function() { }); }; - var initProcessor = function(){ - var setCPUValue = function(){ - if(!$('#sockets').hasClass("invalid-field") && - !$('#cores').hasClass("invalid-field") && - $('#sockets').val()!="" && $('#cores').val()!=""){ - - var sockets = parseInt($("#sockets").val()); - var cores = parseInt($("#cores").val()); - var threads = parseInt($("#threads").val()); - - var computedCpu = sockets * cores * threads; - $("#vcpus").val(computedCpu); - if ($("#cpus-check").prop("checked")) { - //If topology is checked, set maxcpu to be the same as # of cpu otherwise, backend gives error - $("#guest-edit-max-processor-textbox").val(computedCpu); - } - } else { - $("#vcpus").val(''); - } - }; - $("input:text", "#form-template-processor").on('keyup', function() { - $(this).toggleClass("invalid-field", !$(this).val().match('^[0-9]*$')); - if ($(this).prop('id') == 'sockets' || - $(this).prop('id') == 'cores') { - setCPUValue(); - } - }); - $("input:checkbox", "#form-template-processor").click(function() { - $('#threads').selectpicker(); - $(".topology", "#form-template-processor").slideToggle(); - $("#vcpus").attr("disabled", $(this).prop("checked")); - $("#guest-edit-max-processor-textbox").attr("disabled", $(this).prop("checked")); - setCPUValue(); - }); - $('#threads').change(function() { - setCPUValue(); - }); - kimchi.getCPUInfo(function(data) { - var options = ""; - var topo = template.cpu_info.topology; - for (var i = 0; Math.pow(2, i) <= data.threads_per_core; i++) { - var lastOne = Math.pow(2, i + 1) > data.threads_per_core ? " selected" : ""; - options += "<option" + lastOne + ">" + Math.pow(2, i) + "</option>"; - } - $('#threads').append(options); - if (template.cpu_info.vcpus) { - $("#vcpus").val(template.cpu_info.vcpus); - } - if (template.cpu_info.maxvcpus) { - $("#guest-edit-max-processor-textbox").val(template.cpu_info.maxvcpus); - } - if (topo && topo.sockets) { - $("#sockets").val(topo.sockets); - } - if (topo && topo.cores) { - $("#cores").val(topo.cores); - } - if (topo && topo.threads) { - $('#threads').val(topo.threads); - $('#threads').selectpicker(); - $("input:checkbox", "#form-template-processor").trigger('click'); - } - }); - $('#guest-show-max-processor').on('click', function(e) { - e.preventDefault; - $('#guest-max-processor-panel').slideToggle(); - var text = $('#guest-show-max-processor span.text').text(); - $('#guest-show-max-processor span.text').text(text == i18n['KCHVMED6008M'] ? i18n['KCHVMED6009M'] : i18n['KCHVMED6008M']); - $('#guest-show-max-processor i.fa').toggleClass('fa-plus-circle fa-minus-circle'); - }); - }; - var checkInvalids = function() { $.each(template.invalid, function(key, value) { if (key === 'cdrom' || key === 'vm-image') { @@ -738,7 +748,7 @@ kimchi.template_edit_main = function() { kimchi.listStoragePools(initStorage); } - initProcessor(); + kimchi.init_processor_tab(template.cpu_info); checkInvalids(); }; kimchi.retrieveTemplate(kimchi.selectedTemplate, initTemplate); @@ -822,7 +832,7 @@ kimchi.template_edit_main = function() { data['cdrom'] = $('.tab-content input[name="cdrom"]').val(); } - if ($("input:checkbox", "#form-template-processor").prop("checked")) { + if ($("input:checkbox", "#form-edit-processor").prop("checked")) { //Check if maxCpu field has a value data['cpu_info'] = { vcpus: cpu, diff --git a/ui/pages/template-edit.html.tmpl b/ui/pages/template-edit.html.tmpl index 0ba4c4b..90e06e4 100644 --- a/ui/pages/template-edit.html.tmpl +++ b/ui/pages/template-edit.html.tmpl @@ -151,7 +151,7 @@ </form> </div> <div role="tabpanel" class="tab-pane" id="processor"> - <form id="form-template-processor"> + <form id="form-edit-processor"> <div class="form-group"> <div id="guest-processor"> <label for="vcpus">$_("Current CPU Number")</label> -- 2.7.4

From: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com> This patch adds the 'Processor' tab in the Edit Guest dialog, allowing full control of the CPU configuration of an existing guest in the same way it is done in the Edit Template dialog. Signed-off-by: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com> --- ui/css/kimchi.css | 32 +++++++++++++-- ui/css/src/modules/_edit-guests.scss | 28 ++++++++++++-- ui/js/src/kimchi.guest_edit_main.js | 75 +++++++++++++++++------------------- ui/pages/guest-edit.html.tmpl | 42 ++++++++++++++------ 4 files changed, 120 insertions(+), 57 deletions(-) diff --git a/ui/css/kimchi.css b/ui/css/kimchi.css index de23053..61d8dc0 100644 --- a/ui/css/kimchi.css +++ b/ui/css/kimchi.css @@ -1090,9 +1090,7 @@ body.wok-gallery { } #guest-edit-window #form-guest-edit-general #guest-edit-memory-textbox, -#guest-edit-window #form-guest-edit-general #guest-show-max-memory, -#guest-edit-window #form-guest-edit-general #guest-edit-cores-textbox, -#guest-edit-window #form-guest-edit-general #guest-show-max-processor { +#guest-edit-window #form-guest-edit-general #guest-show-max-memory { display: inline-block; } @@ -1117,6 +1115,34 @@ body.wok-gallery { width: 4.47%; } +#guest-edit-window #form-edit-processor #guest-processor label { + display: block; +} + +#guest-edit-window #form-edit-processor #guest-max-processor-panel label { + display: block; +} + +#guest-edit-window #form-edit-processor #guest-max-processor-panel .form-control, +#guest-edit-window #form-edit-processor #guest-processor .form-control { + display: inline-block; + width: 184px; +} + +#guest-edit-window #form-edit-processor .manual { + margin-top: 5px; + margin-bottom: 10px; +} + +#guest-edit-window #form-edit-processor .topology { + display: none; + margin: 0 24px; +} + +#guest-edit-window #form-edit-processor .topology label { + display: block; +} + #guest-edit-window form { margin: 15px 0 0; } diff --git a/ui/css/src/modules/_edit-guests.scss b/ui/css/src/modules/_edit-guests.scss index fb7a91c..6caa720 100644 --- a/ui/css/src/modules/_edit-guests.scss +++ b/ui/css/src/modules/_edit-guests.scss @@ -39,9 +39,7 @@ } #guest-edit-memory-textbox, - #guest-show-max-memory, - #guest-edit-cores-textbox, - #guest-show-max-processor { + #guest-show-max-memory { display: inline-block; } @@ -70,6 +68,30 @@ width: 4.47%; } } + #form-edit-processor { + #guest-processor label { + display: block; + } + #guest-max-processor-panel label { + display: block; + } + #guest-max-processor-panel .form-control, + #guest-processor .form-control { + display: inline-block; + width: 184px; + } + .manual { + margin-top: 5px; + margin-bottom: 10px; + } + .topology { + display: none; + margin: 0 24px; + } + .topology label { + display: block; + } + } form { margin: 15px 0 0; .header, diff --git a/ui/js/src/kimchi.guest_edit_main.js b/ui/js/src/kimchi.guest_edit_main.js index 3261075..0ee0e87 100644 --- a/ui/js/src/kimchi.guest_edit_main.js +++ b/ui/js/src/kimchi.guest_edit_main.js @@ -968,8 +968,6 @@ kimchi.guest_edit_main = function() { }; var initContent = function(guest) { - guest['vcpus'] = guest.cpu_info['vcpus']; - guest['max-processor'] = guest.cpu_info['maxvcpus']; guest['icon'] = guest['icon'] || 'plugins/kimchi/images/icon-vm.png'; $('#form-guest-edit-general').fillWithObject(guest); $('#guest-edit-memory-textbox').val(parseInt(guest.memory.current)); @@ -1000,14 +998,6 @@ kimchi.guest_edit_main = function() { $('#guest-show-max-memory i.fa').toggleClass('fa-plus-circle fa-minus-circle'); }); - $('#guest-show-max-processor').on('click', function(e) { - e.preventDefault; - $('#guest-max-processor-panel').slideToggle(); - var cputext = $('#guest-show-max-processor span.cputext').text(); - $('#guest-show-max-processor span.cputext').text(cputext == i18n['KCHVMED6008M'] ? i18n['KCHVMED6009M'] : i18n['KCHVMED6008M']); - $('#guest-show-max-processor i.fa').toggleClass('fa-plus-circle fa-minus-circle'); - }); - if ((kimchi.thisVMState !== "running") && (kimchi.thisVMState !== "paused")) { $("#guest-edit-memory-textbox").bind('keyup blur', function(e) { $('#guest-edit-max-memory-textbox').val($(this).val()); @@ -1042,6 +1032,7 @@ kimchi.guest_edit_main = function() { setupPermission(); setupPCIDevice(); setupSnapshot(); + kimchi.init_processor_tab(guest.cpu_info); wok.topic('kimchi/vmCDROMAttached').subscribe(onAttached); wok.topic('kimchi/vmCDROMReplaced').subscribe(onReplaced); @@ -1061,7 +1052,31 @@ kimchi.guest_edit_main = function() { $(saveButton).prop('disabled', true); var data = $('#form-guest-edit-general').serializeObject(); data['memory'] = {current: Number(data['memory-ui']), maxmemory: Number(data['max-memory'])}; - data['cpu_info'] = {maxvcpus: Number(data['max-processor']), vcpus: Number(data['vcpus']), topology: org['cpu_info']['topology']}; + + var cpu = parseInt($('#vcpus').val()); + var maxCpu = parseInt($('#guest-edit-max-processor-textbox').val()); + var maxCpuFinal = cpu; + if (maxCpu >= cpu) { + maxCpuFinal = maxCpu; + } + if ($("input:checkbox", "#form-edit-processor").prop("checked")) { + data['cpu_info'] = { + vcpus: cpu, + maxvcpus: maxCpuFinal, + topology: { + sockets: parseInt($("#sockets").val()), + cores: parseInt($("#cores").val()), + threads: parseInt($("#threads").val()) + } + }; + } else { + data['cpu_info'] = { + vcpus: cpu, + maxvcpus: maxCpuFinal, + topology: {} + }; + } + var changedFields = {}; for (var key in data) { valueFromUI = data[key]; @@ -1092,12 +1107,8 @@ kimchi.guest_edit_main = function() { } var origMem = Number(org.memory.current); var origMaxMem = Number(org.memory.maxmemory); - var origCpu = Number(org.cpu_info.vcpus); - var origMaxCpu = Number(org.cpu_info.maxvcpus); var currentMem = data['memory-ui']; var currentMaxMem = data['max-memory']; - var currentCpu = data['vcpus']; - var currentMaxCpu = data['max-processor']; if ('memory' in changedFields) { if (currentMaxMem !== undefined) { @@ -1125,34 +1136,18 @@ kimchi.guest_edit_main = function() { delete changedFields.memory.current; } } + if ('cpu_info' in changedFields) { - if (currentMaxCpu !== undefined) { - currentMaxCpu = Number(currentMaxCpu); - if (currentMaxCpu === origMaxCpu) { - delete changedFields.cpu_info.maxvcpus; - } - } else { - delete changedFields.cpu_info.maxvcpus; - } - if (currentCpu !== undefined) { - currentCpu = Number(currentCpu); - if (currentMaxCpu !== undefined && currentCpu > currentMaxCpu) { - wok.message.error(i18n['KCHVM0003E'], '#alert-modal-container'); - $(saveButton).prop('disabled', false); - return; - } - if (currentCpu === origCpu) { - delete changedFields.cpu_info.vcpus; - } - if (currentMaxCpu === origMaxCpu) { - delete changedFields.cpu_info.maxvcpus; - } - } else { - delete changedFields.cpu_info.vcpus; + var currentCpu = data['cpu_info'].vcpus; + var currentMaxCpu = data['cpu_info'].maxvcpus; + + if (currentCpu > currentMaxCpu) { + wok.message.error(i18n['KCHVM0003E'], '#alert-modal-container'); + $(saveButton).prop('disabled', false); + return; } - // Delete this as it is not applicable regardless - delete changedFields.cpu_info.topology; } + kimchi.updateVM(kimchi.selectedGuest, changedFields, function() { kimchi.listVmsAuto(); wok.window.close(); diff --git a/ui/pages/guest-edit.html.tmpl b/ui/pages/guest-edit.html.tmpl index 7e0e3d3..66e82ab 100644 --- a/ui/pages/guest-edit.html.tmpl +++ b/ui/pages/guest-edit.html.tmpl @@ -37,6 +37,7 @@ <li role="presentation"><a href="#form-guest-edit-permission" aria-controls="form-guest-edit-permission" role="tab" data-id="form-guest-edit-permission" data-toggle="tab">$_("Permission")</a></li> <li role="presentation"><a href="#form-guest-edit-pci" aria-controls="form-guest-edit-pci" role="form-guest-edit-pci" data-id="form-guest-edit-pci" data-toggle="tab">$_("Pci")</a></li> <li role="presentation"><a href="#form-guest-edit-snapshot" aria-controls="form-guest-edit-snapshot" role="tab" data-id="form-guest-edit-snapshot" data-toggle="tab">$_("Snapshot")</a></li> + <li role="presentation"><a href="#form-edit-processor" aria-controls="form-edit-processor" role="tab" data-id="form-edit-processor" data-toggle="tab">$_("Processor")</a></li> </ul> <div class="tab-content" id="guest-edit-tabs"> <form role="tabpanel" class="tab-pane active" id="form-guest-edit-general"> @@ -45,17 +46,6 @@ <input id="guest-edit-id-textbox" class="form-control" name="name" type="text" /> </div> <div class="form-group"> - <label for="guest-edit-cores-textbox">$_("Current CPUs")</label> - <div id="guest-processor"> - <input id="guest-edit-cores-textbox" class="form-control" name="vcpus" type="number" min="1" /> - <button id="guest-show-max-processor" class="btn btn-primary" type="button"><i class="fa fa-plus-circle"></i> <span class="cputext">$_("More")</span></button> - </div> - </div> - <div id="guest-max-processor-panel" class="form-group"> - <label for="guest-edit-max-processor-textbox">$_("Max CPU")</label> - <input id="guest-edit-max-processor-textbox" class="form-control" name="max-processor" type="number" min="1" /> - </div> - <div class="form-group"> <label for="guest-edit-memory-textbox">$_("Memory (MB)")</label> <div id="guest-memory"> <input id="guest-edit-memory-textbox" class="form-control" name="memory-ui" type="number" min="1024" step="1024" /> @@ -197,6 +187,36 @@ <div class="task"></div> <div class="body"></div> </form> + <form role="tabpanel" class="tab-pane" id="form-edit-processor"> + <div class="form-group"> + <div id="guest-processor"> + <label for="vcpus">$_("Current CPU Number")</label> + <input id="vcpus" class="form-control" name="processor" type="number" min="1" /> + </div> + <div id="guest-max-processor-panel" class="form-group"> + <label for="guest-edit-max-processor-textbox">$_("Max CPU")</label> + <input id="guest-edit-max-processor-textbox" class="form-control" name="max-processor" type="number" min="1" /> + </div> + </div> + <div class="manual form-group"> + <input type="checkbox" class="wok-checkbox" id="cpus-check" /> + <label for="cpus-check">$_("Manually set CPU topology")</label> + </div> + <div class="topology"> + <div class="form-group"> + <label for="sockets">$_("Sockets")</label> + <input type="text" class="form-control" value="1" id="sockets" /> + </div> + <div class="form-group"> + <label for="cores">$_("Cores")</label> + <input type="text" class="form-control" value="1" id="cores" /> + </div> + <div class="form-group"> + <label for="threads">$_("Threads")</label> + <select id="threads" class="selectpicker col-md-12 col-lg-12"></select> + </div> + </div> + </form> </div> </div> <div class="modal-footer"> -- 2.7.4

From: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com> - Removed 'More' button from the Processor tab in Edit Template. This was done to be standardized with the Edit Guest tab that does not have this button to show/hide the max processor value. - Save button state is now being controlled by the init_processor_tab function (at least inside the Processor tab). - 'Current CPU' is now editable at all times, in both Edit Guest and Edit Template dialogs, even when defining a topology. Inserting a wrong value in the field will invalidate the save state, disabling the button. When defining a topology and Current CPU has an inconsistent value, it will be automatically adjusted to be (1) a multiple of threads or (2) equal to new Max CPU value, in that order. - When not defining a topology, setting any Current CPU value greater than Max CPU will force the field back to the Max CPU value. Signed-off-by: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com> --- ui/css/kimchi.css | 4 -- ui/css/src/modules/_templates.scss | 3 -- ui/js/src/kimchi.guest_edit_main.js | 2 +- ui/js/src/kimchi.template_edit_main.js | 77 +++++++++++++++++++++++----------- ui/pages/template-edit.html.tmpl | 1 - 5 files changed, 54 insertions(+), 33 deletions(-) diff --git a/ui/css/kimchi.css b/ui/css/kimchi.css index 61d8dc0..1b2c1dd 100644 --- a/ui/css/kimchi.css +++ b/ui/css/kimchi.css @@ -1669,10 +1669,6 @@ body.wok-gallery { display: inline; } -#template-edit-window #guest-max-processor-panel { - display: none; -} - #template-edit-window #guest-show-max-processor { display: inline-block; } diff --git a/ui/css/src/modules/_templates.scss b/ui/css/src/modules/_templates.scss index eec5878..f72efe9 100644 --- a/ui/css/src/modules/_templates.scss +++ b/ui/css/src/modules/_templates.scss @@ -126,9 +126,6 @@ $kimchi-icon-path: '../images'; width: 308px !important; display: inline; } - #guest-max-processor-panel { - display: none; - } #guest-show-max-processor { display: inline-block; } diff --git a/ui/js/src/kimchi.guest_edit_main.js b/ui/js/src/kimchi.guest_edit_main.js index 0ee0e87..91e5b13 100644 --- a/ui/js/src/kimchi.guest_edit_main.js +++ b/ui/js/src/kimchi.guest_edit_main.js @@ -1032,7 +1032,7 @@ kimchi.guest_edit_main = function() { setupPermission(); setupPCIDevice(); setupSnapshot(); - kimchi.init_processor_tab(guest.cpu_info); + kimchi.init_processor_tab(guest.cpu_info, $(saveButton)); wok.topic('kimchi/vmCDROMAttached').subscribe(onAttached); wok.topic('kimchi/vmCDROMReplaced').subscribe(onReplaced); diff --git a/ui/js/src/kimchi.template_edit_main.js b/ui/js/src/kimchi.template_edit_main.js index 36e6911..ecce151 100644 --- a/ui/js/src/kimchi.template_edit_main.js +++ b/ui/js/src/kimchi.template_edit_main.js @@ -16,31 +16,52 @@ * limitations under the License. */ -kimchi.init_processor_tab = function(cpu_info) { - var setCPUValue = function(){ +kimchi.init_processor_tab = function(cpu_info, save_form_button) { + + var getMaxVCpus = function() { if (!$('#sockets').hasClass("invalid-field") && !$('#cores').hasClass("invalid-field") && - $('#sockets').val()!="" && $('#cores').val()!="") { + $('#sockets').val() != "" && $('#cores').val() != "") { - var sockets = parseInt($("#sockets").val()); - var cores = parseInt($("#cores").val()); - var threads = parseInt($("#threads").val()); + var sockets = parseInt($("#sockets").val()); + var cores = parseInt($("#cores").val()); + var threads = parseInt($("#threads").val()); + var computedCpu = sockets * cores * threads; + + return computedCpu; + } + return undefined; + }; - var computedCpu = sockets * cores * threads; - $("#vcpus").val(computedCpu); - if ($("#cpus-check").prop("checked")) { - //If topology is checked, set maxcpu to be the same as # of cpu otherwise, backend gives error - $("#guest-edit-max-processor-textbox").val(computedCpu); + var setCPUValue = function() { + var computedCpu = getMaxVCpus(); + var vcpus = parseInt($("#vcpus").val()); + + if (computedCpu && $("#cpus-check").prop("checked")) { + // If topology is checked, set maxcpu to be the same as # of cpu otherwise, backend gives error + var threads = parseInt($("#threads").val()); + $("#guest-edit-max-processor-textbox").val(computedCpu); + if (vcpus % threads != 0) { + $("#vcpus").val(threads); + } else if (vcpus > computedCpu) { + $("#vcpus").val(computedCpu); } } else { - $("#vcpus").val(''); + var maxCpu = parseInt($("#guest-edit-max-processor-textbox").val()); + if (vcpus > maxCpu) { + $("#vcpus").val(maxCpu); + } } }; $("input:text", "#form-edit-processor").on('keyup', function() { - $(this).toggleClass("invalid-field", !$(this).val().match('^[0-9]*$')); + var invalid_field = !$(this).val().match('^[0-9]*$'); + $(this).toggleClass("invalid-field", invalid_field); + save_form_button.prop('disabled', invalid_field); + if ($(this).prop('id') == 'sockets' || - $(this).prop('id') == 'cores') { + $(this).prop('id') == 'cores') { + setCPUValue(); } }); @@ -48,7 +69,6 @@ kimchi.init_processor_tab = function(cpu_info) { $("input:checkbox", "#form-edit-processor").click(function() { $('#threads').selectpicker(); $(".topology", "#form-edit-processor").slideToggle(); - $("#vcpus").attr("disabled", $(this).prop("checked")); $("#guest-edit-max-processor-textbox").attr("disabled", $(this).prop("checked")); setCPUValue(); }); @@ -57,6 +77,23 @@ kimchi.init_processor_tab = function(cpu_info) { setCPUValue(); }); + $('#vcpus').change(function() { + var computedCpu = getMaxVCpus(); + var vcpus = parseInt($('#vcpus').val()); + + if (computedCpu && $("#cpus-check").prop("checked")) { + var threads = parseInt($("#threads").val()); + var invalid_vcpu = (vcpus % threads != 0) || (vcpus > computedCpu); + $(this).toggleClass("invalid-field", invalid_vcpu); + save_form_button.prop('disabled', invalid_vcpu); + } else { + var maxCpu = parseInt($("#guest-edit-max-processor-textbox").val()); + if (vcpus > maxCpu) { + $("#vcpus").val(maxCpu); + } + } + }); + kimchi.getCPUInfo(function(data) { var options = ""; var topo = cpu_info.topology; @@ -86,14 +123,6 @@ kimchi.init_processor_tab = function(cpu_info) { $("input:checkbox", "#form-edit-processor").trigger('click'); } }); - - $('#guest-show-max-processor').on('click', function(e) { - e.preventDefault; - $('#guest-max-processor-panel').slideToggle(); - var text = $('#guest-show-max-processor span.text').text(); - $('#guest-show-max-processor span.text').text(text == i18n['KCHVMED6008M'] ? i18n['KCHVMED6009M'] : i18n['KCHVMED6008M']); - $('#guest-show-max-processor i.fa').toggleClass('fa-plus-circle fa-minus-circle'); - }); }; @@ -748,7 +777,7 @@ kimchi.template_edit_main = function() { kimchi.listStoragePools(initStorage); } - kimchi.init_processor_tab(template.cpu_info); + kimchi.init_processor_tab(template.cpu_info, $('#tmpl-edit-button-save')); checkInvalids(); }; kimchi.retrieveTemplate(kimchi.selectedTemplate, initTemplate); diff --git a/ui/pages/template-edit.html.tmpl b/ui/pages/template-edit.html.tmpl index 90e06e4..0939ad8 100644 --- a/ui/pages/template-edit.html.tmpl +++ b/ui/pages/template-edit.html.tmpl @@ -156,7 +156,6 @@ <div id="guest-processor"> <label for="vcpus">$_("Current CPU Number")</label> <input id="vcpus" class="form-control" name="processor" type="number" min="1" /> - <button id="guest-show-max-processor" class="btn btn-primary" type="button"><i class="fa fa-plus-circle"></i> <span class="text">$_("More")</span></button> </div> <div id="guest-max-processor-panel" class="form-group"> <label for="guest-edit-max-processor-textbox">$_("Max CPU")</label> -- 2.7.4

From: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com> This patch adds help texts in both dialogs to explain the user the logic being used in the current CPU and maximum CPU values. Signed-off-by: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com> --- ui/pages/guest-edit.html.tmpl | 8 ++++++++ ui/pages/template-edit.html.tmpl | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/ui/pages/guest-edit.html.tmpl b/ui/pages/guest-edit.html.tmpl index 66e82ab..0aa2504 100644 --- a/ui/pages/guest-edit.html.tmpl +++ b/ui/pages/guest-edit.html.tmpl @@ -192,10 +192,18 @@ <div id="guest-processor"> <label for="vcpus">$_("Current CPU Number")</label> <input id="vcpus" class="form-control" name="processor" type="number" min="1" /> + <p class="help-block"> + <i class="fa fa-info-circle"></i> + $_("Current CPU must be equal or lower than the Maximum CPU value. If a topology is set, it must be also be a multiple of the 'threads' value.") + </p> </div> <div id="guest-max-processor-panel" class="form-group"> <label for="guest-edit-max-processor-textbox">$_("Max CPU")</label> <input id="guest-edit-max-processor-textbox" class="form-control" name="max-processor" type="number" min="1" /> + <p class="help-block"> + <i class="fa fa-info-circle"></i> + $_("If a topology is set, this value will be the product of sockets * times * cores.") + </p> </div> </div> <div class="manual form-group"> diff --git a/ui/pages/template-edit.html.tmpl b/ui/pages/template-edit.html.tmpl index 0939ad8..6e7f97b 100644 --- a/ui/pages/template-edit.html.tmpl +++ b/ui/pages/template-edit.html.tmpl @@ -156,10 +156,18 @@ <div id="guest-processor"> <label for="vcpus">$_("Current CPU Number")</label> <input id="vcpus" class="form-control" name="processor" type="number" min="1" /> + <p class="help-block"> + <i class="fa fa-info-circle"></i> + $_("Current CPU must be equal or lower than the Maximum CPU value. If a topology is set, it must be also be a multiple of the 'threads' value.") + </p> </div> <div id="guest-max-processor-panel" class="form-group"> <label for="guest-edit-max-processor-textbox">$_("Max CPU")</label> <input id="guest-edit-max-processor-textbox" class="form-control" name="max-processor" type="number" min="1" /> + <p class="help-block"> + <i class="fa fa-info-circle"></i> + $_("If a topology is set, this value will be the product of sockets * times * cores.") + </p> </div> </div> <div class="manual form-group"> -- 2.7.4

From: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com> Edit Guest does not work the same way as the Edit Template dialog - each tab has its own submit function and it is not possible to submit multiple tabs in the same dialog. This patch splits the logic to update the CPU configuration that was contained in the 'generalSubmit' function and put it into a new function called 'processorSubmit'. This function will be fired when the 'Save' button is pressed when the 'Processor' tab is active. This patch also further enhances the control of the 'Save' button state in the 'init_processor_tab' JS function by making it always enabled when there is no topology being set. If current CPU is set to a value above max CPU it will be rewrite to be equal to max CPU; if max CPU is set to a value below current CPU, current CPU is set to max CPU. Signed-off-by: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com> --- ui/js/src/kimchi.guest_edit_main.js | 83 +++++++++++++++++----------------- ui/js/src/kimchi.template_edit_main.js | 10 ++++ ui/pages/i18n.json.tmpl | 1 - 3 files changed, 52 insertions(+), 42 deletions(-) diff --git a/ui/js/src/kimchi.guest_edit_main.js b/ui/js/src/kimchi.guest_edit_main.js index 91e5b13..f06e0fa 100644 --- a/ui/js/src/kimchi.guest_edit_main.js +++ b/ui/js/src/kimchi.guest_edit_main.js @@ -48,7 +48,8 @@ kimchi.guest_edit_main = function() { // tap map, "general": 0, "storage": 1, "interface": 2, "permission": 3, "password": 4 var submit_map = { 0: generalSubmit, - 3: permissionSubmit + 3: permissionSubmit, + 6: processorSubmit }; var currentTab = $('#guest-edit-window li.active a[data-toggle="tab"]').data('id'); var toSubmit = parseInt($('#'+currentTab).index()); @@ -60,7 +61,6 @@ kimchi.guest_edit_main = function() { $(guestEditForm).on('submit', submitForm); $(saveButton).on('click', submitForm); - $('#guest-edit-window a[data-toggle="tab"]').on('shown.bs.tab', function(e) { var target = $(this).attr('href'); $(target).css('left', '-' + $(window).width() + 'px'); @@ -1053,41 +1053,14 @@ kimchi.guest_edit_main = function() { var data = $('#form-guest-edit-general').serializeObject(); data['memory'] = {current: Number(data['memory-ui']), maxmemory: Number(data['max-memory'])}; - var cpu = parseInt($('#vcpus').val()); - var maxCpu = parseInt($('#guest-edit-max-processor-textbox').val()); - var maxCpuFinal = cpu; - if (maxCpu >= cpu) { - maxCpuFinal = maxCpu; - } - if ($("input:checkbox", "#form-edit-processor").prop("checked")) { - data['cpu_info'] = { - vcpus: cpu, - maxvcpus: maxCpuFinal, - topology: { - sockets: parseInt($("#sockets").val()), - cores: parseInt($("#cores").val()), - threads: parseInt($("#threads").val()) - } - }; - } else { - data['cpu_info'] = { - vcpus: cpu, - maxvcpus: maxCpuFinal, - topology: {} - }; - } - var changedFields = {}; for (var key in data) { valueFromUI = data[key]; if (valueFromUI instanceof Object) { // Compare if Objects of original and data are identical // Handle special case when key is memory and guest is running as valueFromUI will return a null for max mem - // since it is disabled; for cpu_info, when guest is running, just skip it since no processing is required + // since it is disabled; if (kimchi.thisVMState === 'running' || kimchi.thisVMState === 'paused') { - if (key === 'cpu_info') { - continue; - } if (key === 'memory') { // Replace valueFromUI of max mem with one from original as otherwise the value is undefined data['memory']['maxmemory'] = org.memory.maxmemory; @@ -1137,17 +1110,6 @@ kimchi.guest_edit_main = function() { } } - if ('cpu_info' in changedFields) { - var currentCpu = data['cpu_info'].vcpus; - var currentMaxCpu = data['cpu_info'].maxvcpus; - - if (currentCpu > currentMaxCpu) { - wok.message.error(i18n['KCHVM0003E'], '#alert-modal-container'); - $(saveButton).prop('disabled', false); - return; - } - } - kimchi.updateVM(kimchi.selectedGuest, changedFields, function() { kimchi.listVmsAuto(); wok.window.close(); @@ -1203,6 +1165,45 @@ kimchi.guest_edit_main = function() { } }; + var processorSubmit = function(event) { + kimchi.retrieveVM(kimchi.selectedGuest, function(org) { + $(saveButton).prop('disabled', true); + var data = {}; + + var cpu = parseInt($('#vcpus').val()); + var maxCpu = parseInt($('#guest-edit-max-processor-textbox').val()); + var maxCpuFinal = cpu; + if (maxCpu >= cpu) { + maxCpuFinal = maxCpu; + } + if ($("input:checkbox", "#form-edit-processor").prop("checked")) { + data['cpu_info'] = { + vcpus: cpu, + maxvcpus: maxCpuFinal, + topology: { + sockets: parseInt($("#sockets").val()), + cores: parseInt($("#cores").val()), + threads: parseInt($("#threads").val()) + } + }; + } else { + data['cpu_info'] = { + vcpus: cpu, + maxvcpus: maxCpuFinal, + topology: {} + }; + } + + kimchi.updateVM(kimchi.selectedGuest, data, function() { + kimchi.listVmsAuto(); + wok.window.close(); + }, function(err) { + wok.message.error(err.responseJSON.reason, '#alert-modal-container'); + $(saveButton).prop('disabled', false); + }); + }); + }; + if(kimchi.hostarch === s390xArch){ $('#guest-edit-window ul li a[data-id="form-guest-edit-pci"],a[data-id="form-guest-edit-snapshot"]').parent().hide(); } diff --git a/ui/js/src/kimchi.template_edit_main.js b/ui/js/src/kimchi.template_edit_main.js index ecce151..f82b615 100644 --- a/ui/js/src/kimchi.template_edit_main.js +++ b/ui/js/src/kimchi.template_edit_main.js @@ -77,6 +77,15 @@ kimchi.init_processor_tab = function(cpu_info, save_form_button) { setCPUValue(); }); + $("#guest-edit-max-processor-textbox").change(function() { + save_form_button.prop('disabled', false); + var vcpus = parseInt($('#vcpus').val()); + var maxCpu = parseInt($("#guest-edit-max-processor-textbox").val()); + if (vcpus > maxCpu) { + $("#vcpus").val(maxCpu); + } + }); + $('#vcpus').change(function() { var computedCpu = getMaxVCpus(); var vcpus = parseInt($('#vcpus').val()); @@ -87,6 +96,7 @@ kimchi.init_processor_tab = function(cpu_info, save_form_button) { $(this).toggleClass("invalid-field", invalid_vcpu); save_form_button.prop('disabled', invalid_vcpu); } else { + save_form_button.prop('disabled', false); var maxCpu = parseInt($("#guest-edit-max-processor-textbox").val()); if (vcpus > maxCpu) { $("#vcpus").val(maxCpu); diff --git a/ui/pages/i18n.json.tmpl b/ui/pages/i18n.json.tmpl index 9580be1..0e644ed 100644 --- a/ui/pages/i18n.json.tmpl +++ b/ui/pages/i18n.json.tmpl @@ -71,7 +71,6 @@ "KCHVM0001E": "$_("Input is not a number")", "KCHVM0002E": "$_("Memory value cannot be higher than Max Memory value")", - "KCHVM0003E": "$_("Current CPUs value cannot be higher than Max CPU value")", "KCHVMCD6001M": "$_("This CDROM will be detached permanently and you can re-attach it. Continue to detach it?")", "KCHVMCD6002M": "$_("Attach")", -- 2.7.4

From: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com> This patch removes the limitation, in both backend and frontend, of the value 'threads' in the topology to be limited by the threads_per_core value of the host. This limitation was put in place to help the user pick a 'threads' value that provides a good performance, but it ended up being a problem to support VMs what were created outside of Kimchi and didn't impose such limitations. To compensate, a help text was added to warn the user about the recommended 'threads' values. Signed-off-by: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com> --- i18n.py | 1 - model/cpuinfo.py | 2 -- ui/js/src/kimchi.template_edit_main.js | 49 +++++++++++++++++----------------- ui/pages/guest-edit.html.tmpl | 6 ++++- ui/pages/i18n.json.tmpl | 1 + ui/pages/template-edit.html.tmpl | 6 ++++- 6 files changed, 36 insertions(+), 29 deletions(-) diff --git a/i18n.py b/i18n.py index 9d0abee..453ede8 100644 --- a/i18n.py +++ b/i18n.py @@ -358,7 +358,6 @@ messages = { "KCHCPUINF0003E": _("This host (or current configuration) does not allow CPU topology."), "KCHCPUINF0004E": _("The maximum number of vCPUs is too large for this system."), "KCHCPUINF0005E": _("When CPU topology is defined, CPUs must be a multiple of the 'threads' number defined."), - "KCHCPUINF0006E": _("The number of threads is too large for this system."), "KCHCPUINF0007E": _("When CPU topology is specified, sockets, cores and threads are required paramaters."), "KCHCPUINF0008E": _("Parameter 'cpu_info' expects an object with fields among: 'vcpus', 'maxvcpus', 'topology'."), "KCHCPUINF0009E": _("Parameter 'topology' expects an object with fields among: 'sockets', 'cores', 'threads'."), diff --git a/model/cpuinfo.py b/model/cpuinfo.py index 5f82320..cfdecaa 100644 --- a/model/cpuinfo.py +++ b/model/cpuinfo.py @@ -134,8 +134,6 @@ class CPUInfoModel(object): if not self.guest_threads_enabled: raise InvalidOperation("KCHCPUINF0003E") - if threads > self.threads_per_core: - raise InvalidParameter("KCHCPUINF0006E") if maxvcpus != sockets * cores * threads: raise InvalidParameter("KCHCPUINF0002E") if vcpus % threads != 0: diff --git a/ui/js/src/kimchi.template_edit_main.js b/ui/js/src/kimchi.template_edit_main.js index f82b615..414a108 100644 --- a/ui/js/src/kimchi.template_edit_main.js +++ b/ui/js/src/kimchi.template_edit_main.js @@ -21,7 +21,9 @@ kimchi.init_processor_tab = function(cpu_info, save_form_button) { var getMaxVCpus = function() { if (!$('#sockets').hasClass("invalid-field") && !$('#cores').hasClass("invalid-field") && - $('#sockets').val() != "" && $('#cores').val() != "") { + !$('#threads').hasClass("invalid-field") && + $('#sockets').val() != "" && $('#cores').val() != "" && + $('#threads').val() != "") { var sockets = parseInt($("#sockets").val()); var cores = parseInt($("#cores").val()); @@ -38,7 +40,6 @@ kimchi.init_processor_tab = function(cpu_info, save_form_button) { var vcpus = parseInt($("#vcpus").val()); if (computedCpu && $("#cpus-check").prop("checked")) { - // If topology is checked, set maxcpu to be the same as # of cpu otherwise, backend gives error var threads = parseInt($("#threads").val()); $("#guest-edit-max-processor-textbox").val(computedCpu); if (vcpus % threads != 0) { @@ -60,23 +61,19 @@ kimchi.init_processor_tab = function(cpu_info, save_form_button) { save_form_button.prop('disabled', invalid_field); if ($(this).prop('id') == 'sockets' || - $(this).prop('id') == 'cores') { + $(this).prop('id') == 'cores' || + $(this).prop('id') == 'threads') { setCPUValue(); } }); $("input:checkbox", "#form-edit-processor").click(function() { - $('#threads').selectpicker(); $(".topology", "#form-edit-processor").slideToggle(); $("#guest-edit-max-processor-textbox").attr("disabled", $(this).prop("checked")); setCPUValue(); }); - $('#threads').change(function() { - setCPUValue(); - }); - $("#guest-edit-max-processor-textbox").change(function() { save_form_button.prop('disabled', false); var vcpus = parseInt($('#vcpus').val()); @@ -108,12 +105,8 @@ kimchi.init_processor_tab = function(cpu_info, save_form_button) { var options = ""; var topo = cpu_info.topology; - for (var i = 0; Math.pow(2, i) <= data.threads_per_core; i++) { - var lastOne = Math.pow(2, i + 1) > data.threads_per_core ? " selected" : ""; - options += "<option" + lastOne + ">" + Math.pow(2, i) + "</option>"; - } - - $('#threads').append(options); + var threads_help_text = i18n['KCHVM0003E'].replace('%1', data.threads_per_core); + $('#threads-recommended-values').text(threads_help_text); if (cpu_info.vcpus) { $("#vcpus").val(cpu_info.vcpus); @@ -121,16 +114,24 @@ kimchi.init_processor_tab = function(cpu_info, save_form_button) { if (cpu_info.maxvcpus) { $("#guest-edit-max-processor-textbox").val(cpu_info.maxvcpus); } - if (topo && topo.sockets) { - $("#sockets").val(topo.sockets); - } - if (topo && topo.cores) { - $("#cores").val(topo.cores); - } - if (topo && topo.threads) { - $('#threads').val(topo.threads); - $('#threads').selectpicker(); - $("input:checkbox", "#form-edit-processor").trigger('click'); + + $("#sockets").val(data.sockets); + $("#cores").val(data.cores); + $('#threads').val(data.threads_per_core); + + if (topo) { + if (topo.sockets) { + $("#sockets").val(topo.sockets); + } + if (topo.cores) { + $("#cores").val(topo.cores); + } + if (topo.threads) { + $('#threads').val(topo.threads); + } + if (topo.sockets && topo.cores && topo.threads) { + $("input:checkbox", "#form-edit-processor").trigger('click'); + } } }); }; diff --git a/ui/pages/guest-edit.html.tmpl b/ui/pages/guest-edit.html.tmpl index 0aa2504..ce63471 100644 --- a/ui/pages/guest-edit.html.tmpl +++ b/ui/pages/guest-edit.html.tmpl @@ -221,7 +221,11 @@ </div> <div class="form-group"> <label for="threads">$_("Threads")</label> - <select id="threads" class="selectpicker col-md-12 col-lg-12"></select> + <input type="text" class="form-control" value="1" id="threads" /> + <p class="help-block"> + <i class="fa fa-info-circle"></i> + <spam class="text" id="threads-recommended-values" /> + </p> </div> </div> </form> diff --git a/ui/pages/i18n.json.tmpl b/ui/pages/i18n.json.tmpl index 0e644ed..cd23fcb 100644 --- a/ui/pages/i18n.json.tmpl +++ b/ui/pages/i18n.json.tmpl @@ -71,6 +71,7 @@ "KCHVM0001E": "$_("Input is not a number")", "KCHVM0002E": "$_("Memory value cannot be higher than Max Memory value")", + "KCHVM0003E": "$_("For better performance it is recommended a threads per core value not greater than %1.")", "KCHVMCD6001M": "$_("This CDROM will be detached permanently and you can re-attach it. Continue to detach it?")", "KCHVMCD6002M": "$_("Attach")", diff --git a/ui/pages/template-edit.html.tmpl b/ui/pages/template-edit.html.tmpl index 6e7f97b..728ce6d 100644 --- a/ui/pages/template-edit.html.tmpl +++ b/ui/pages/template-edit.html.tmpl @@ -185,7 +185,11 @@ </div> <div class="form-group"> <label for="threads">$_("Threads")</label> - <select id="threads" class="selectpicker col-md-12 col-lg-12"></select> + <input type="text" class="form-control" value="1" id="threads" /> + <p class="help-block"> + <i class="fa fa-info-circle"></i> + <spam class="text" id="threads-recommended-values" /> + </p> </div> </div> </form> -- 2.7.4
participants (2)
-
Aline Manera
-
dhbarboza82@gmail.com