Reviewed by: Archana Singh <archus@linux.vnet.ibm.com>
From: Rajat Gupta <rajgupta@linux.vnet.ibm.com> Introducing s390x UI Interfaces module for Edit Template under virtualization Signed-off-by: Rajat Gupta <rajgupta@linux.vnet.ibm.com> --- ui/js/src/kimchi.api.js | 44 ++++++ ui/js/src/kimchi.main.js | 5 + ui/js/src/kimchi.template_edit_main.js | 257 +++++++++++++++++++++++++++++++-- ui/pages/template-edit.html.tmpl | 29 ++++ 4 files changed, 319 insertions(+), 16 deletions(-) diff --git a/ui/js/src/kimchi.api.js b/ui/js/src/kimchi.api.js index 2f127aa..950ca00 100644 --- a/ui/js/src/kimchi.api.js +++ b/ui/js/src/kimchi.api.js @@ -596,6 +596,34 @@ var kimchi = { }); }, + listmacvtapNetworks: function(suc, err) { + wok.requestJSON({ + url: 'plugins/kimchi/interfaces?type=^nic|bonding|vlan$', + type: 'GET', + contentType: 'application/json', + dataType: 'json', + resend: true, + success: suc, + error: err ? err : function(data) { + wok.message.error(data.responseJSON.reason); + } + }); + }, + + listovsNetworks: function(suc, err) { + wok.requestJSON({ + url: 'plugins/kimchi/ovsbridges', + type: 'GET', + contentType: 'application/json', + dataType: 'json', + resend: true, + success: suc, + error: err ? err : function(data) { + wok.message.error(data.responseJSON.reason); + } + }); + }, + toggleNetwork : function(name, on, suc, err) { var action = on ? "activate" : "deactivate"; wok.requestJSON({ @@ -1271,3 +1299,19 @@ var kimchi = { }); } }; + + /** + * Get the host information. + */ + + kimchi.getHostDetails = function(suc, err) { + wok.requestJSON({ + url: 'plugins/gingerbase/host', + type: 'GET', + resend: true, + contentType: 'application/json', + dataType: 'json', + success: suc, + error: err + }); + } diff --git a/ui/js/src/kimchi.main.js b/ui/js/src/kimchi.main.js index b6de2cf..f3078ec 100644 --- a/ui/js/src/kimchi.main.js +++ b/ui/js/src/kimchi.main.js @@ -33,6 +33,11 @@ kimchi.getCapabilities(function(result) { kimchi.capabilities = {}; }); +kimchi.hostarch = undefined; +kimchi.getHostDetails(function(result) { + kimchi.hostarch = result["architecture"]; +}); + $(function(){ $('body').removeClass('wok-list wok-gallery'); }); diff --git a/ui/js/src/kimchi.template_edit_main.js b/ui/js/src/kimchi.template_edit_main.js index a2032cc..9ccf9cc 100644 --- a/ui/js/src/kimchi.template_edit_main.js +++ b/ui/js/src/kimchi.template_edit_main.js @@ -19,8 +19,13 @@ kimchi.template_edit_main = function() { var templateEditMain = $('#edit-template-tabs'); var origDisks; var origNetworks; + var origInterfaces; + var origmacvtapNetworks; + var origovsNetworks; var templateDiskSize; var baseImageTemplate; + var s390xArch = 's390x'; + $('#template-name', templateEditMain).val(kimchi.selectedTemplate); $('#edit-template-tabs a[data-toggle="tab"]').on('shown.bs.tab', function(e) { $('.tab-content').css('overflow', 'hidden'); @@ -47,6 +52,7 @@ kimchi.template_edit_main = function() { var initTemplate = function(template) { origDisks = template.disks; origNetworks = template.networks; + origInterfaces = template.interfaces; for (var i = 0; i < template.disks.length; i++) { if (template.disks[i].base) { template["vm-image"] = template.disks[i].base; @@ -268,10 +274,170 @@ 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()); + var initInterface_s390x = function(result) { + $('#form-template-interface-s390x').show(); + $('#form-template-interface').hide(); + var networkItemNum = 0; + var addInterfaceItem = function(networkData) { + var networkName = networkData.networkV; + var nodeInterface = $.parseHTML(wok.substitute($('#template-interface-s390x-tmpl').html(), networkData)); + $('.template-tab-body', '#form-template-interface-s390x').append(nodeInterface); + $('.delete', '#form-template-interface-s390x').on("click", function(event) { + event.preventDefault(); + $(this).parent().parent().remove(); + }); + + //initialize type option + var typeOptionsdata = {}; + var typeOptions = ''; + typeOptionsdata.macvtap = 'macvtap'; + typeOptionsdata.ovs = 'ovs'; + typeOptionsdata.network = 'network'; + + $.each(typeOptionsdata, function(key, value) { + if (value === networkData.type) { + typeOptions += '<option value="' + key + '" selected="selected">' + networkData.type + '</option>'; + } else { + typeOptions += '<option value="' + key + '">' + value + '</option>'; + } + }); + + $('select', '#form-template-interface-s390x #networkID' + networkItemNum + ' span.type').append(typeOptions); + $('select', '#form-template-interface-s390x #networkID' + networkItemNum + ' span.type').on('change', function() { + var itemNode = $(this).closest('div.item'); + + switch ($(this).val()) { + case 'macvtap': + $('span.mode .label-mode', itemNode).addClass('hide'); + $('span.mode .bootstrap-select', itemNode).toggleClass("hide", false); + + var networkOptions = ''; + for (var i = 0; i < origmacvtapNetworks.length; i++) { + networkOptions += '<option>' + origmacvtapNetworks[i].name + '</option>'; + } + + $('span.network select', itemNode).empty().append(networkOptions); + $('span.network select', itemNode).selectpicker('refresh'); + + break; + case 'ovs': + $('span.mode .label-mode', itemNode).removeClass('hide'); + $('span.mode .bootstrap-select', itemNode).toggleClass("hide", true); + var networkOptions = ''; + for (var i = 0; i < origovsNetworks.length; i++) { + networkOptions += '<option>' + origovsNetworks[i] + '</option>'; + } + + $('span.network select', itemNode).empty().append(networkOptions); + $('span.network select', itemNode).selectpicker('refresh'); + + break; + case 'network': + $('span.mode .label-mode', itemNode).removeClass('hide'); + $('span.mode .bootstrap-select', itemNode).toggleClass("hide", true); + + var networkOptions = ''; + for (var i = 0; i < result.length; i++) { + if (result[i].state === "active") { + networkOptions += '<option>' + result[i].name + '</option>'; + } + } + $('span.network select', itemNode).empty().append(networkOptions); + $('span.network select', itemNode).selectpicker('refresh'); + break; + } + }); + + switch (networkData.type) { + case 'macvtap': + //initialize network option + var networkOptions = ''; + for (var i = 0; i < origmacvtapNetworks.length; i++) { + if (networkName === origmacvtapNetworks[i].name) { + networkOptions += '<option selected="selected">' + origmacvtapNetworks[i].name + '</option>'; + } + networkOptions += '<option>' + origmacvtapNetworks[i].name + '</option>'; + } + $('select', '#form-template-interface-s390x #networkID' + networkItemNum + ' span.network').append(networkOptions); + + //initialize Mode option for Macvtap + $('select', '#form-template-interface-s390x #networkID' + networkItemNum + ' span.mode').val(networkData.mode); + $('select', '#form-template-interface-s390x #networkID' + networkItemNum + ' span.mode').selectpicker('refresh'); + + $('span.mode .label-mode', nodeInterface).addClass('hide'); + $('span.mode .bootstrap-select', nodeInterface).removeClass("hide"); + + break; + case 'ovs': + var networkOptions = ''; + for (var i = 0; i < origovsNetworks.length; i++) { + if (networkName === origovsNetworks[i]) { + networkOptions += '<option selected="selected">' + origovsNetworks[i] + '</option>'; + } + networkOptions += '<option>' + origovsNetworks[i] + '</option>'; + } + $('select', '#form-template-interface-s390x #networkID' + networkItemNum + ' span.network').append(networkOptions); + + //initialize Mode option for ovs + $('select', '#form-template-interface-s390x #networkID' + networkItemNum + ' span.mode').selectpicker('refresh'); + $('span.mode .label-mode', nodeInterface).removeClass('hide'); + $('span.mode .bootstrap-select', nodeInterface).addClass("hide"); + break; + case 'network': + var networkOptions = ''; + for (var i = 0; i < result.length; i++) { + if (networkName === result[i].name) { + networkOptions += '<option selected="selected">' + result[i].name + '</option>'; + } + if (result[i].state === "active" && networkName !== result[i].name) { + networkOptions += '<option>' + result[i].name + '</option>'; + } + } + $('select', '#form-template-interface-s390x #networkID' + networkItemNum + ' span.network').append(networkOptions); + + //initialize Mode option for Network + $('select', '#form-template-interface-s390x #networkID' + networkItemNum + ' span.mode').selectpicker('refresh'); + $('span.mode .label-mode', nodeInterface).removeClass('hide'); + $('span.mode .bootstrap-select', nodeInterface).addClass("hide"); + break; + } + $('select', '#form-template-interface-s390x #networkID' + networkItemNum).selectpicker(); + networkItemNum += 1; + }; + if (origInterfaces && origInterfaces.length > 0) { + for (var i = 0; i < origInterfaces.length; i++) { + addInterfaceItem({ + networkID: 'networkID' + networkItemNum, + networkV: origInterfaces[i].name, + type: origInterfaces[i].type, + mode: origInterfaces[i].mode + }); + } + } + if (result && result.length > 0) { + for (var i = 0; i < origNetworks.length; i++) { + addInterfaceItem({ + networkID: 'networkID' + networkItemNum, + networkV: origNetworks[i], + type: 'network' + }); + } + } + $('#template-edit-interface-add-button-s390x').on("click", function(event) { + event.preventDefault(); + addInterfaceItem({ + networkID: 'networkID' + networkItemNum, + networkV: 'default', + type: 'network', + mode: 'None' + }); + }); + }; + + var initProcessor = function(){ + var setCPUValue = function(){ + if(!$('#cores').hasClass("invalid-field")&&$('#cores').val()!=""){ + var computedCpu = parseInt($("#cores").val())*parseInt($("#threads").val()); $("#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 @@ -340,11 +506,23 @@ kimchi.template_edit_main = function() { }); } - kimchi.listNetworks(initInterface); + if(kimchi.hostarch === s390xArch){ + kimchi.listmacvtapNetworks(function(macvtapnet){ + origmacvtapNetworks = macvtapnet; + kimchi.listovsNetworks(function(ovsnet){ + origovsNetworks = ovsnet; + kimchi.listNetworks(initInterface_s390x); + }); + }); + }else { + kimchi.listNetworks(initInterface); + } + kimchi.listStoragePools(initStorage); initProcessor(); checkInvalids(); }; + kimchi.retrieveTemplate(kimchi.selectedTemplate, initTemplate); $('#tmpl-edit-button-save').on('click', function() { @@ -432,18 +610,65 @@ kimchi.template_edit_main = function() { topology: {} }; } - var networks = $('.template-tab-body .item', '#form-template-interface'); - var networkForUpdate = new Array(); - $.each(networks, function(index, networkEntities) { - var thisValue = $('select', networkEntities).val(); - networkForUpdate.push(thisValue); + + if(kimchi.hostarch === s390xArch){ + var interfaces = $('.template-tab-body .item', '#form-template-interface-s390x'); + var networkForUpdate = new Array(); + var interfacceForUpdate = new Array(); + + $.each(interfaces, function(index, interfaceEntities) { + var fields = $('span.type select', interfaceEntities); + switch(fields.val()){ + case 'network': + var thisValue = $('span.network select', interfaceEntities).val(); + networkForUpdate.push(thisValue); + break; + case 'macvtap': + var thisdata = {}; + thisdata.type = $('span.type select', interfaceEntities).val(); + thisdata.name = $('span.network select', interfaceEntities).val(); + thisdata.mode = $('span.mode select', interfaceEntities).val(); + interfacceForUpdate.push(thisdata); + break; + case 'ovs': + var thisdata = {}; + thisdata.type = $('span.type select', interfaceEntities).val(); + thisdata.name = $('span.network select', interfaceEntities).val(); + interfacceForUpdate.push(thisdata); + break; + } + + if (networkForUpdate instanceof Array) { + data.networks = networkForUpdate; + } else if (networkForUpdate != null) { + data.networks = [networkForUpdate]; + } else { + data.networks = []; + } + + if (networkForUpdate instanceof Array) { + data.interfaces = interfacceForUpdate; + } else if (interfacceForUpdate != null) { + data.interfaces = [interfacceForUpdate]; + } else { + data.interfaces = []; + } }); - if (networkForUpdate instanceof Array) { - data.networks = networkForUpdate; - } else if (networkForUpdate != null) { - data.networks = [networkForUpdate]; - } else { - data.networks = []; + }else { + var networks = $('.template-tab-body .item', '#form-template-interface'); + var networkForUpdate = new Array(); + $.each(networks, function(index, networkEntities) { + var thisValue = $('select', networkEntities).val(); + networkForUpdate.push(thisValue); + }); + + if (networkForUpdate instanceof Array) { + data.networks = networkForUpdate; + } else if (networkForUpdate != null) { + data.networks = [networkForUpdate]; + } else { + data.networks = []; + } } if ($('.has-error', '#form-template-storage').length) { diff --git a/ui/pages/template-edit.html.tmpl b/ui/pages/template-edit.html.tmpl index 6cac885..8591561 100644 --- a/ui/pages/template-edit.html.tmpl +++ b/ui/pages/template-edit.html.tmpl @@ -129,6 +129,15 @@ </div> <div class="template-tab-body"></div> </form> + <form id="form-template-interface-s390x" style="display:none"> + <div class="template-tab-header"> + <span class="template-interface-cell type">$_("Type")</span> + <span class="template-interface-cell network">$_("Network/Interface")</span> + <span class="template-interface-cell mode">$_("Mode")</span> + <button type="button" id="template-edit-interface-add-button-s390x" class="pull-right btn btn-primary"><i class="fa fa-plus-circle"></i> $_("Add Interface")</button> + </div> + <div class="template-tab-body"></div> + </form> </div> <div role="tabpanel" class="tab-pane" id="processor"> <form id="form-template-processor"> @@ -221,5 +230,25 @@ </span> </div> </script> +<script id="template-interface-s390x-tmpl" type="text/html"> + <div class="item" id={networkID}> + <span class="template-interface-cell type"> + <select></select> + </span> + <span class="template-interface-cell network"> + <select></select> + </span> + <span class="template-interface-cell mode"> + <span class="label-mode hide">None</span> + <select> + <option value="bridge">bridge</option> + <option value="vepa">vepa</option> + </select> + </span> + <span class="pull-right"> + <button class="delete btn-primary btn"><i class="fa fa-minus-circle"></i> $_("Delete")</button> + </span> + </div> +</script> </body> </html>