1
0
mirror of https://github.com/OpenNebula/one.git synced 2024-12-24 21:34:01 +03:00

F #4506: nic alias in sunstone service dialog (#4537)

This commit is contained in:
Sergio Betanzos 2020-04-16 12:57:53 +02:00 committed by GitHub
parent fcc6018667
commit 4a6dad81ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 356 additions and 139 deletions

View File

@ -107,10 +107,14 @@ define(function(require) {
{value: 'id', text: 'Existing', select: 'networks', extra: false },
]
this.roleTabObjects = {};
this.numberOfNetworks = 0;
var that = this;
$(".add_service_network", context).unbind("click");
$(".add_service_network", context).bind("click", function() {
var nic_index = $(".service_network_name", context).length;
var nic_index = that.numberOfNetworks;
that.numberOfNetworks++;
$(".service_networks tbody").append(
'<tr id="network'+nic_index+'">\
@ -120,7 +124,7 @@ define(function(require) {
<label class="switch-paddle" for="service_network_mandatory'+nic_index+'" style="cursor: pointer;"></label>\
</td>\
<td>\
<input class="service_network_name" type="text" />\
<input class="service_network_name" type="text" data-index="'+nic_index+'" />\
<small class="form-error"><br/>'+Locale.tr("Can only contain alphanumeric and underscore characters, and be unique")+'</small>\
</td>\
<td>\
@ -148,55 +152,57 @@ define(function(require) {
$(".service_network_type", "tr#network"+nic_index).append($("<option/>", {
"value": type.value
}).text(type.text))
})
});
});
//$(".add_service_network", context).click();
$("tr#network"+nic_index+" .service_network_name", context).unbind("keyup");
$("tr#network"+nic_index+" .service_network_name", context).bind("keyup", function(){
// update pattern regex
var otherNames = $("input.service_network_name").not($(this)).map(function() {
return $(this).val();
}).get().join("|");
$(this).attr("pattern", "^(?!(" + otherNames + ")$)(^\\w+$)");
_redo_service_networks_selector(context, that);
});
context.on("keyup", ".service_network_name", function(){
// update pattern regex
var otherNames = $("input.service_network_name").not($(this)).map(function() {
return $(this).val();
}).get().join("|");
$("tr#network"+nic_index+" .service_network_type", context).unbind("change");
$("tr#network"+nic_index+" .service_network_type", context).bind("change", function(){
var selectedType = $(this).val()
var serviceNetwork = $(this).closest('tr')
$(this).attr("pattern", "^(?!(" + otherNames + ")$)(^\\w+$)");
var data = _get_networks()
_redo_service_networks_selector(context, that);
});
// 1. if val = reserve/existing or create
$(".service_network_id", serviceNetwork).empty().append($("<option/>").text(""))
// 2. create and fill selector
var type = that.networksType.find(function(type) { return type.value === selectedType })
// 3. append selector after type
type && data[type.select].map(function(net) {
$(".service_network_id", serviceNetwork).append($("<option/>", {
"value": net.ID
}).text(net.NAME))
})
// 4. append extra after selector if reserve/create
var disabled = type ? !type.extra : true;
!disabled && $(".service_network_extra", serviceNetwork).empty();
$(".service_network_extra", serviceNetwork).prop('disabled', disabled);
});
context.on("change", ".service_network_type", function(){
var selectedType = $(this).val()
var serviceNetwork = $(this).closest('tr')
var data = _get_networks()
// 1. if val = reserve/existing or create
$(".service_network_id", serviceNetwork).empty().append($("<option/>").text(""))
// 2. create and fill selector
var type = that.networksType.find(function(type) { return type.value === selectedType })
// 3. append selector after type
type && data[type.select].map(function(net) {
$(".service_network_id", serviceNetwork).append($("<option/>", {
"value": net.ID
}).text(net.NAME))
})
// 4. append extra after selector if reserve/create
var disabled = type ? !type.extra : true;
!disabled && $(".service_network_extra", serviceNetwork).empty();
$(".service_network_extra", serviceNetwork).prop('disabled', disabled);
});
context.on("click", ".service_networks i.remove-tab", function(){
var tr = $(this).closest('tr');
tr.remove();
_redo_service_networks_selector(context, that, $(this).data("index"));
$("tr#network"+nic_index+" i.remove-tab", context).unbind("click");
$("tr#network"+nic_index+" i.remove-tab", context).bind("click", function(){
var tr = $(this).closest('tr');
tr.remove();
_redo_service_networks_selector(context, that, $(this).data("index"));
});
});
that.roles_index = 0;
//$("#tf_btn_roles", context).unbind("click");
$("#tf_btn_roles", context).bind("click", function(){
that.addRoleTab(that.roles_index, context);
that.roles_index++;
@ -206,6 +212,7 @@ define(function(require) {
// Each time a tab is clicked the table is filled with existing tabs (roles)
// Selected roles are kept
// TODO If the name of a role is changed and is selected, selection will be lost
$("#roles_tabs", context).off("click", "a");
$("#roles_tabs", context).on("click", "a", function() {
var tab_id = "#"+this.id+"Tab";
var str = "";
@ -217,7 +224,7 @@ define(function(require) {
if ($(this).val() && ($(this).val() != $(tab_id+" #role_name", context).val())) {
parent_role_available = true;
str += "<tr>\
<td style='width:10%'>\
<td style='width:20px;text-align:center;'>\
<input class='check_item' type='checkbox' value='"+$(this).val()+"' id='"+$(this).val()+"'/>\
</td>\
<td>"+$(this).val()+"</td>\
@ -243,8 +250,6 @@ define(function(require) {
Foundation.reflow(context, 'tabs');
// Add first role
$("#tf_btn_roles", context).click();
Tips.setup(context);
UserInputs.setup(context);
return false;
@ -352,6 +357,9 @@ define(function(require) {
var role_id = $(this).attr("role_id");
that.roleTabObjects[role_id].onShow();
});
// Add first role
$("#tf_btn_roles", context).click();
}
function _fill(context, element) {
@ -437,6 +445,8 @@ define(function(require) {
that.roleTabObjects[role_id].fill(role_context, value, network_names);
});
//_redo_service_networks_selector(context, that);
$.each(element.TEMPLATE.BODY.roles, function(index, value){
var role_context = $('.role_content', context)[index];
var str = "";
@ -444,7 +454,7 @@ define(function(require) {
$.each(roles_names, function(){
if (this != value.name) {
str += "<tr>\
<td style='width:10%'>\
<td style='width:20px;'>\
<input class='check_item' type='checkbox' value='"+this+"' id='"+this+"'/>\
</td>\
<td>"+this+"</td>\
@ -473,32 +483,62 @@ define(function(require) {
function _redo_service_networks_selector_role(dialog, role_section, template, nicToDelete){
var checked_networks = [];
$(".service_network_checkbox:checked", role_section).each(function(){
checked_networks.push($(this).data("index"))
var netIndex = $(this).data("index");
var netName = $(this).val();
checked_networks[netIndex] = { name: netName };
});
$(".alias_network_checkbox:checked", role_section).each(function(){
var netIndex = $(this).data("index");
if (checked_networks[netIndex]) {
checked_networks[netIndex]["alias"] = true;
}
});
var role_tab_id = $(role_section).attr('id');
var str = "";
$(".service_networks .service_network_name", dialog).each(function(index, _){
$(".service_networks .service_network_name", dialog).each(function(){
var index = $(this).data('index');
var name = $(this).val();
var regexp = new RegExp($(this).attr("pattern"), "gi");
var wasChecked = checked_networks.includes(index) ? 'checked="checked"' : '';
var checked = checked_networks[index];
var wasChecked = checked ? 'checked="checked"' : '';
var wasAlias = checked && checked["alias"] ? 'checked="checked"' : '';
var canBeAlias = !checked ? 'disabled="disabled"' : '';
// Condition 1: Be unique
// Condition 2: Can only contain alphanumeric and underscore characters
if (name && name !== "" && regexp.test(name)) {
var idNetwork = role_tab_id + "_" + index;
var idName = idNetwork + "_name";
checked && (checked["name"] = name);
str += "<tr id='"+idNetwork+"'>\
<td style='width:10%'>\
<input class='service_network_checkbox check_item'\
type='checkbox' value='"+name+"' id='"+idName+"' data-index='"+index+"' "+wasChecked+" />\
</td>\
<td>\
<label for='"+idName+"'>"+name+"</label>\
</td>\
</tr>";
<td style='width:20px;text-align:center;vertical-align:middle;'>\
<input class='service_network_checkbox check_item'\
type='checkbox' value='"+name+"' id='"+idName+"' data-index='"+index+"' "+wasChecked+" />\
</td>\
<td style='vertical-align:middle;'>\
<label for='"+idName+"'>"+name+"</label>\
</td>";
str += "<td style='width:20px;text-align:center;vertical-align:middle;'>\
<input class='alias_network_checkbox check_item' "+canBeAlias+"\
type='checkbox' value='"+name+"' id='alias_"+idName+"' data-index='"+index+"' "+wasAlias+" />\
</td>\
<td style='width:100px;vertical-align:middle;'>\
<label for='alias_"+idName+"'>As nic alias</label>\
</td>";
str += "<td class='parent_selector' style='width:50%;'>\
<select class='form-control' " + (!wasAlias ? "hidden" : "") + "\
id='parent_"+idName+"' data-index='"+index+"' style='box-sizing:border-box;' required>\
<option value=''></option>\
</select>\
</td>";
str += "</tr>";
}
});
@ -510,7 +550,7 @@ define(function(require) {
if (template && template.roleTabObjects) {
$(Object.values(template.roleTabObjects)).each(function() {
this.refresh(nicToDelete);
this.refresh(checked_networks, nicToDelete);
});
}
}
@ -558,6 +598,7 @@ define(function(require) {
$('a', ul.children('li').last()).click();
}
delete that.roleTabObjects[role_id];
_redo_service_networks_selector(dialog, that);
return false;
});
role_tab.setup(role_section);

View File

@ -28,6 +28,9 @@ define(function(require) {
function RoleTab(html_role_id) {
this.html_role_id = html_role_id;
this.global_template = {};
this.nics_template = {};
this.alias_template = {};
this.rest_template = "";
this.refresh = _refreshVMTemplate;
return this;
@ -66,7 +69,8 @@ define(function(require) {
this.templatesTable.initialize();
this.templatesTable.idInput().attr("required", "");
role_section.on("keyup", "#role_name", function(){
$("#role_name", role_section).unbind("keyup");
$("#role_name", role_section).bind("keyup", function(){
$("#" + that.html_role_id +" #role_name_text").html($(this).val());
});
@ -105,32 +109,123 @@ define(function(require) {
var index = $(this).data("index");
var name = $(this).val();
updateOptionsRDP(role_section, that.global_template);
if (this.checked) {
that.nics_template[index] = { "NAME": "NIC"+index, "NETWORK_ID": "$"+name };
$("#alias_"+this.id, role_section).prop("disabled", false);
$("td.parent_selector select:visible", role_section).each(function() {
updateOptionsParents(this, that.nics_template, that.alias_template);
});
}
else {
delete that.nics_template[index];
delete that.alias_template[index];
$("#alias_"+this.id, role_section).prop("disabled", true).prop("checked", false).change();
}
updateOptionsRDP(role_section, $.extend({}, that.nics_template, that.alias_template));
updateRemoveTabs(role_section, index);
});
role_section.on("change", ".alias_network_checkbox", role_section, function(){
var index = $(this).data("index");
var select = $('td.parent_selector select[data-index='+index+']', role_section);
toogleNicUsedAsAlias(role_section, select, select.val(), null)
select.prop("hidden", !this.checked);
if (this.checked && that.nics_template[index]) {
that.alias_template[index] = that.nics_template[index];
delete that.nics_template[index];
}
else if (!this.checked && that.alias_template[index]) {
that.nics_template[index] = that.alias_template[index];
that.nics_template[index] && (delete that.nics_template[index]["PARENT"]);
delete that.alias_template[index];
}
$("td.parent_selector select:visible", role_section).each(function() {
updateOptionsParents(this, that.nics_template, that.alias_template);
});
});
role_section.on('focusin', ".parent_selector select", function(){
// save value after change
$(this).data('prev', $(this).val());
}).on("change", ".parent_selector select", function(){
var index = $(this).data('index');
var prevIndexParent = $(this).data('prev');
var indexParent = $(this).val();
toogleNicUsedAsAlias(role_section, this, prevIndexParent, indexParent)
(this.checked)
? that.global_template[index] = { "NETWORK_ID": "$"+name }
: delete that.global_template[index];
if (that.nics_template[indexParent] && that.alias_template[index]) {
that.alias_template[index]["PARENT"] = "NIC"+indexParent;
}
});
role_section.on("change", ".networks_role_rdp select#rdp", role_section, function(){
var valueSelected = this.value;
var allTemplate = $.extend({}, that.nics_template, that.alias_template);
// delete RDP in global template when is
$.each(Object.entries(that.global_template), function(_, network) {
// remove RDP option in all nics
$.each(Object.entries(allTemplate), function(_, network) {
var nicIndex = network[0];
var nicTemplate = network[1];
if (nicIndex !== valueSelected && nicTemplate["RDP"]) {
delete that.global_template[nicIndex]["RDP"];
(that.nics_template[nicIndex])
? delete that.nics_template[nicIndex]["RDP"]
: delete that.alias_template[nicIndex]["RDP"];
}
});
if (valueSelected !== "" && that.global_template[valueSelected]) {
that.global_template[valueSelected]["RDP"] = "yes";
// then assign if exists
if (valueSelected !== "") {
if(that.nics_template[valueSelected]) {
that.nics_template[valueSelected]["RDP"] = "YES";
}
else if(that.alias_template[valueSelected]) {
that.alias_template[valueSelected]["RDP"] = "YES";
}
}
});
}
function updateRemoveTabs(role_section, index) {
var form = $(role_section).closest("#createServiceTemplateFormWizard");
var networkIsUsed = $(".service_network_checkbox[data-index="+index+"]:checked", form);
(networkIsUsed.length > 0)
? $("#network"+index+" i.remove-tab", form)
.prop("style", "color:currentColor;cursor:not-allowed;opacity:0.5;")
: $("#network"+index+" i.remove-tab", form).prop("style", "");
}
function toogleNicUsedAsAlias(context, currentSelector, prevIndex, index) {
var prevNicCb = $(".service_network_checkbox[data-index='"+prevIndex+"']", context);
var prevAliasCb = $(".alias_network_checkbox[data-index='"+prevIndex+"']", context);
var nicCb = $(".service_network_checkbox[data-index='"+index+"']", context);
var aliasCb = $(".alias_network_checkbox[data-index='"+index+"']", context);
var prevOthers = $(".parent_selector select:visible", context).not(currentSelector)
.children("option[value='"+prevIndex+"']:selected");
var others = $(".parent_selector select", context).children("option[value='"+index+"']:selected");
if (prevOthers.length === 0) {
prevNicCb.prop("disabled", false);
prevAliasCb.prop("disabled", false);
}
if (others.length === 0) {
nicCb.prop("disabled", false);
aliasCb.prop("disabled", false);
}
else {
aliasCb.prop("disabled", true).prop("checked", false);
nicCb.prop("disabled", true).prop("checked", true);
}
}
function updateOptionsRDP(context, currentTemplate) {
var selectRDP = $(".networks_role_rdp select#rdp", context);
// empty all options in select rdp
@ -143,17 +238,51 @@ define(function(require) {
selectRDP.append("<option value='"+index+"'>"+name+"</option>")
});
// if some nic has RDP, update selector
// if some nic has RDP, update selector value
$.each(Object.entries(currentTemplate), function(_, nic) {
var nicIndex = nic[0];
var nicTemplate = nic[1];
if (nicTemplate["RDP"] && nicTemplate["RDP"] === "yes") {
selectRDP.val(nicIndex);
if (nicTemplate["RDP"] && String(nicTemplate["RDP"]).toLowerCase() === "yes") {
selectRDP.val(nicIndex).change();
}
});
}
function updateOptionsParents(select, nicsTemplate, aliasTemplate) {
select = $(select);
var nicIndex = $(select).data('index');
// empty all options in select alias parent
select.empty();
select.append("<option value=''></option>");
// possible parents
var possibleParents = filterByNicIndex(nicsTemplate, nicIndex);
$.each(Object.entries(possibleParents), function (_, nic) {
select.append("<option value='"+nic[0]+"'>"+nic[1].NETWORK_ID.substring(1)+"</option>")
});
// update selector parent value
$.each(Object.entries(aliasTemplate), function(_, nic) {
var nicTemplate = nic[1];
if (nicTemplate["PARENT"]) {
var indexParent = nicTemplate["PARENT"].replace("NIC", "");
select.val(indexParent).change();
}
});
}
function filterByNicIndex(object, index) {
const obj = {};
for (const key in object) {
if (key !== String(index)) {
obj[key] = object[key];
}
}
return obj;
}
function _onShow(){
this.templatesTable.refreshResourceTableSelect();
}
@ -165,7 +294,9 @@ define(function(require) {
role['vm_template'] = this.templatesTable.retrieveResourceTableSelect();
role['shutdown_action'] = $('select[name="shutdown_action_role"]', context).val();
role['parents'] = [];
role['vm_template_contents'] = TemplateUtils.templateToString({ NIC: Object.values(this.global_template) });
role['vm_template_contents'] = TemplateUtils.templateToString({ NIC: Object.values(this.nics_template) });
role['vm_template_contents'] += TemplateUtils.templateToString({ NIC_ALIAS: Object.values(this.alias_template) });
role['vm_template_contents'] += this.rest_template;
$('.parent_roles_body input.check_item:checked', context).each(function(){
role['parents'].push($(this).val());
@ -234,37 +365,57 @@ define(function(require) {
$("#cardinality", context).val(value.cardinality);
that.templatesTable.selectResourceTableSelect({ids : value.vm_template});
this.templatesTable.selectResourceTableSelect({ids : value.vm_template});
if (value.vm_template_contents){
// check all networks appear in vm template
$(network_names).each(function(){
var reg = new RegExp("\\$"+this+"\\b");
if(reg.exec(value.vm_template_contents) != null){
$(".service_network_checkbox[value='"+this+"']", context).attr('checked', true).change();
}
});
// map template with index checkbox
var nics = TemplateUtils.stringToTemplate(value.vm_template_contents)["NIC"];
var vmTemplate = TemplateUtils.stringToTemplate(value.vm_template_contents);
// map nics with index checkbox
var nics = vmTemplate["NIC"];
if (nics) {
// if not array, transform it
nics = Array.isArray(nics) ? nics : [nics];
$(network_names).each(function(index, name) {
var nicTemplate = $.grep(nics, function(nic) {
return (nic["NETWORK_ID"] === "$"+name) && nic;
})
if (nicTemplate && nicTemplate[0]) {
that.global_template[String(index)] = nicTemplate[0];
}
$.each(network_names, function(index, name) {
$.each(nics, function(_, nic) {
if (nic["NETWORK_ID"] === "$"+name){
nic["NAME"] = "NIC"+index;
$(".service_network_checkbox[data-index='"+index+"']", context).attr('checked', true).change();
that.nics_template[String(index)] = nic;
}
});
});
}
// map alias with index checkbox
var alias = vmTemplate["NIC_ALIAS"];
if (alias) {
alias = Array.isArray(alias) ? alias : [alias];
// update options for RDP
updateOptionsRDP(context, that.global_template);
$.each(network_names, function(index, name) {
$.each(alias, function(_, nic) {
if (nic["NETWORK_ID"] === "$"+name){
nic["NAME"] = "NIC"+index;
$(".service_network_checkbox[data-index='"+index+"']", context).attr('checked', true).change();
$(".alias_network_checkbox[data-index='"+index+"']", context).attr('checked', true).change();
that.alias_template[String(index)] = nic;
}
});
});
$.each(that.alias_template, function(index) {
$("select[data-index="+index+"]", context).each(function() {
updateOptionsParents(this, that.nics_template, that.alias_template);
});
});
}
// copy rest of template
delete vmTemplate["NIC"];
delete vmTemplate["NIC_ALIAS"];
this.rest_template = TemplateUtils.templateToString(vmTemplate);
// update selector options for RDP
updateOptionsRDP(context, $.extend({}, that.nics_template, that.alias_template));
}
$("select[name='shutdown_action_role']", context).val(value.shutdown_action);
@ -316,13 +467,40 @@ define(function(require) {
}
}
function _refreshVMTemplate(nicToDelete) {
if (this.role_section && this.global_template && nicToDelete) {
if (nicToDelete) {
delete this.global_template[nicToDelete];
}
function _refreshVMTemplate(checkedNetworks, nicToDelete) {
var that = this;
updateOptionsRDP(this.role_section, this.global_template);
if (that.role_section && that.nics_template) {
if (nicToDelete) {
delete that.nics_template[nicToDelete];
delete that.alias_template[nicToDelete];
}
// update all NAMES and NETWORK IDs
$.each(checkedNetworks, function(index, nic) {
if (nic && that.nics_template[index]) {
if (that.nics_template[index]) {
that.nics_template[index]["NAME"] = "NIC"+index;
that.nics_template[index]["NETWORK_ID"] = "$"+nic.name;
}
else if (nic && that.alias_template[index]) {
that.alias_template[index]["NAME"] = "NIC"+index;
that.alias_template[index]["NETWORK_ID"] = "$"+nic.name;
}
}
});
var allTemplate = $.extend({}, that.nics_template, that.alias_template);
updateOptionsRDP(that.role_section, allTemplate);
$.each(that.alias_template, function(index) {
$("select[data-index="+index+"]", that.role_section).each(function() {
updateOptionsParents(this, that.nics_template, that.alias_template);
});
});
// Update remove-tabs state (unabled/disabled)
var form = $(that.role_section).closest("#createServiceTemplateFormWizard");
$("table.service_networks i.remove-tab", form).each(function() {
updateRemoveTabs(that.role_section, $(this).data("index"));
});
}
}

View File

@ -39,43 +39,41 @@
</div>
</div>
<div class="row">
<div class="large-12 columns networks_accordion">
<div class="service_template_param service_role large-12 columns">
<table class="parent_roles dataTable">
<thead>
<tr>
<th colspan="2">
{{tr "Parent roles"}}
</th>
</tr>
</thead>
<tbody class="parent_roles_body">
</tbody>
</table>
</div>
<div class="networks_accordion large-12 columns ">
{{#advancedSection (tr "Role network") }}
<div class="row">
<div class="service_template_param service_role medium-6 columns">
<table class="networks_role dataTable">
<thead>
<tr>
<th colspan="2">
<label for="interfaces_role">
<i class="fas fa-lg fa-fw fa-globe off-color"/>{{tr "Network Interfaces"}}
<span class="tip">{{tr "This network interface will be configured as an ALIAS in the VM without context configuration."}}</span>
</label>
</th>
</tr>
</thead>
<tbody class="networks_role_body">
</tbody>
</table>
<div class="form-group networks_role_rdp">
<label for="rdp">RDP</label>
<select class="form-control" id="rdp">
<option value=""></option>
</select>
</div>
</div>
<div class="service_template_param service_role medium-6 columns">
<table class="parent_roles dataTable">
<thead>
<tr>
<th colspan="2">
{{tr "Parent roles"}}
</th>
</tr>
</thead>
<tbody class="parent_roles_body">
</tbody>
</table>
<div class="service_template_param service_role">
<table class="networks_role dataTable">
<thead>
<tr>
<th colspan="4">
<label for="interfaces_role">
<i class="fas fa-lg fa-fw fa-globe off-color"/>{{tr "Network Interfaces"}}
<span class="tip">{{tr "This network interface will be configured as an ALIAS in the VM without context configuration."}}</span>
</label>
</th>
</tr>
</thead>
<tbody class="networks_role_body">
</tbody>
</table>
<div class="form-group networks_role_rdp" style="padding:0.6rem;">
<label for="rdp">RDP</label>
<select class="form-control" id="rdp">
<option value=""></option>
</select>
</div>
</div>
{{/advancedSection}}