[PATCH] [Kimchi 0/9] (STABLE-2.3.x VERSION) CPU topology setup enhancements

From: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com> This patch set is a backport of the patch set '[PATCH v3] [Kimchi 0/8] CPU topology setup enhancements' that were accepted and pushed to the master branch. Daniel Henrique Barboza (9): 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 Edit Guest: block CPU settings when guest is running or paused 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 | 109 ++++++++++--------- ui/js/src/kimchi.template_edit_main.js | 187 ++++++++++++++++++++++----------- ui/pages/guest-edit.html.tmpl | 58 ++++++++-- ui/pages/i18n.json.tmpl | 2 +- ui/pages/template-edit.html.tmpl | 27 +++-- 11 files changed, 315 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 321516c..4d31439 100644 --- a/i18n.py +++ b/i18n.py @@ -347,7 +347,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 1657fdc..9ccbd3b 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -1261,23 +1261,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 | 22 ++++++++++++++++++---- ui/pages/template-edit.html.tmpl | 12 +++++++----- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/ui/js/src/kimchi.template_edit_main.js b/ui/js/src/kimchi.template_edit_main.js index 99e4601..be53701 100644 --- a/ui/js/src/kimchi.template_edit_main.js +++ b/ui/js/src/kimchi.template_edit_main.js @@ -270,8 +270,16 @@ 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 @@ -283,7 +291,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(); @@ -309,6 +320,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); } @@ -416,7 +430,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 6cac885..f1a0eee 100644 --- a/ui/pages/template-edit.html.tmpl +++ b/ui/pages/template-edit.html.tmpl @@ -149,14 +149,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 | 159 +++++++++++++++++---------------- ui/pages/template-edit.html.tmpl | 2 +- 2 files changed, 85 insertions(+), 76 deletions(-) diff --git a/ui/js/src/kimchi.template_edit_main.js b/ui/js/src/kimchi.template_edit_main.js index be53701..6fd257b 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; @@ -268,79 +350,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') { @@ -356,7 +365,7 @@ kimchi.template_edit_main = function() { kimchi.listNetworks(initInterface); kimchi.listStoragePools(initStorage); - initProcessor(); + kimchi.init_processor_tab(template.cpu_info); checkInvalids(); }; kimchi.retrieveTemplate(kimchi.selectedTemplate, initTemplate); @@ -424,7 +433,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 f1a0eee..5d712d3 100644 --- a/ui/pages/template-edit.html.tmpl +++ b/ui/pages/template-edit.html.tmpl @@ -131,7 +131,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 | 43 +++++++++++++++------ 4 files changed, 121 insertions(+), 57 deletions(-) diff --git a/ui/css/kimchi.css b/ui/css/kimchi.css index 9a9ff25..b4b2603 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 fde25a7..e9eab0a 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 d720cf0..cda132b 100644 --- a/ui/js/src/kimchi.guest_edit_main.js +++ b/ui/js/src/kimchi.guest_edit_main.js @@ -730,8 +730,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)); @@ -762,14 +760,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()); @@ -791,6 +781,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); @@ -810,7 +801,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]; @@ -841,12 +856,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) { @@ -874,34 +885,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 a9a468e..8513dc1 100644 --- a/ui/pages/guest-edit.html.tmpl +++ b/ui/pages/guest-edit.html.tmpl @@ -37,6 +37,8 @@ <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 +47,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" /> @@ -182,6 +173,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 b4b2603..9ae9f56 100644 --- a/ui/css/kimchi.css +++ b/ui/css/kimchi.css @@ -1651,10 +1651,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 27df464..0c57532 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 cda132b..54a305d 100644 --- a/ui/js/src/kimchi.guest_edit_main.js +++ b/ui/js/src/kimchi.guest_edit_main.js @@ -781,7 +781,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 6fd257b..108ea12 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'); - }); }; @@ -365,7 +394,7 @@ kimchi.template_edit_main = function() { kimchi.listNetworks(initInterface); 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 5d712d3..cac96b8 100644 --- a/ui/pages/template-edit.html.tmpl +++ b/ui/pages/template-edit.html.tmpl @@ -136,7 +136,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 8513dc1..107964b 100644 --- a/ui/pages/guest-edit.html.tmpl +++ b/ui/pages/guest-edit.html.tmpl @@ -178,10 +178,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 cac96b8..8658d18 100644 --- a/ui/pages/template-edit.html.tmpl +++ b/ui/pages/template-edit.html.tmpl @@ -136,10 +136,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 54a305d..dbeb5b9 100644 --- a/ui/js/src/kimchi.guest_edit_main.js +++ b/ui/js/src/kimchi.guest_edit_main.js @@ -43,7 +43,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()); @@ -55,7 +56,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'); @@ -802,41 +802,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; @@ -886,17 +859,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(); @@ -951,4 +913,43 @@ 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); + }); + }); + }; }; diff --git a/ui/js/src/kimchi.template_edit_main.js b/ui/js/src/kimchi.template_edit_main.js index 108ea12..6aaa3fa 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 43c3af2..f53fa77 100644 --- a/ui/pages/i18n.json.tmpl +++ b/ui/pages/i18n.json.tmpl @@ -70,7 +70,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 4d31439..4a754b6 100644 --- a/i18n.py +++ b/i18n.py @@ -348,7 +348,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 6aaa3fa..0f6ec45 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 107964b..e0e1a5a 100644 --- a/ui/pages/guest-edit.html.tmpl +++ b/ui/pages/guest-edit.html.tmpl @@ -207,7 +207,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 f53fa77..39003a8 100644 --- a/ui/pages/i18n.json.tmpl +++ b/ui/pages/i18n.json.tmpl @@ -70,6 +70,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 8658d18..3947799 100644 --- a/ui/pages/template-edit.html.tmpl +++ b/ui/pages/template-edit.html.tmpl @@ -165,7 +165,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

From: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com> This patch disables all CPU options in the 'Processor' tab when the guest is running or paused. Signed-off-by: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com> --- ui/js/src/kimchi.guest_edit_main.js | 45 ++++++++++++++++++++++++------------- ui/pages/guest-edit.html.tmpl | 5 ++++- 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/ui/js/src/kimchi.guest_edit_main.js b/ui/js/src/kimchi.guest_edit_main.js index dbeb5b9..7a0d02f 100644 --- a/ui/js/src/kimchi.guest_edit_main.js +++ b/ui/js/src/kimchi.guest_edit_main.js @@ -781,7 +781,18 @@ kimchi.guest_edit_main = function() { setupPermission(); setupPCIDevice(); setupSnapshot(); + kimchi.init_processor_tab(guest.cpu_info, $(saveButton)); + if ((kimchi.thisVMState === "running") || (kimchi.thisVMState === "paused")) { + $('#vcpus').attr("disabled", true); + $('#guest-edit-max-processor-textbox').attr("disabled", true); + $('#sockets').attr("disabled", true); + $('#cores').attr("disabled", true); + $('#threads').attr("disabled", true); + + $("#topology-checkbox").hide(); + $("#settings-readonly-help").removeClass('hidden'); + } wok.topic('kimchi/vmCDROMAttached').subscribe(onAttached); wok.topic('kimchi/vmCDROMReplaced').subscribe(onReplaced); @@ -925,22 +936,26 @@ kimchi.guest_edit_main = function() { 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()) - } - }; + if (kimchi.thisVMState === 'running' || kimchi.thisVMState === 'paused') { + data['cpu_info'] = {vcpus: cpu}; } else { - data['cpu_info'] = { - vcpus: cpu, - maxvcpus: maxCpuFinal, - topology: {} - }; + 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() { diff --git a/ui/pages/guest-edit.html.tmpl b/ui/pages/guest-edit.html.tmpl index e0e1a5a..61f010f 100644 --- a/ui/pages/guest-edit.html.tmpl +++ b/ui/pages/guest-edit.html.tmpl @@ -175,6 +175,9 @@ </form> <form role="tabpanel" class="tab-pane" id="form-edit-processor"> <div class="form-group"> + <div id="settings-readonly-help" class="hidden"> + <b>$_("Unable to edit CPU settings of a running or paused virtual machine.")</b> + </div> <div id="guest-processor"> <label for="vcpus">$_("Current CPU Number")</label> <input id="vcpus" class="form-control" name="processor" type="number" min="1" /> @@ -192,7 +195,7 @@ </p> </div> </div> - <div class="manual form-group"> + <div class="manual form-group" id="topology-checkbox"> <input type="checkbox" class="wok-checkbox" id="cpus-check" /> <label for="cpus-check">$_("Manually set CPU topology")</label> </div> -- 2.7.4
participants (2)
-
Aline Manera
-
dhbarboza82@gmail.com