diff --git a/misc/acrn-config/config_app/controller.py b/misc/acrn-config/config_app/controller.py index d5aee2aad..a335b408d 100644 --- a/misc/acrn-config/config_app/controller.py +++ b/misc/acrn-config/config_app/controller.py @@ -208,6 +208,18 @@ class XmlConfig: new_node = ElementTree.SubElement(dest_node, key, attrib={'desc': desc}) new_node.text = value + def get_curr_elem(self, *args): + """ + get elements for current path. + :param args: the path of the element. + :return: current element. + """ + if self._curr_xml_tree is None: + return + + dest_node = self._get_dest_node(*args) + return dest_node + def clone_curr_elem(self, elem, *args): """ clone elements for current path. @@ -235,6 +247,18 @@ class XmlConfig: dest_node = self._get_dest_node(*args) dest_node.insert(index, elem) + def delete_curr_elem(self, *args): + """ + delete the element by its path. + :param args: the path of the element. + :return: None. + """ + if self._curr_xml_tree is None: + return + father_node = self._get_dest_node(*args[:-1]) + dest_node = self._get_dest_node(*args) + father_node.remove(dest_node) + def delete_curr_key(self, *args): """ delete the element by its path. diff --git a/misc/acrn-config/config_app/static/main.js b/misc/acrn-config/config_app/static/main.js index eb235ef70..86539d98d 100644 --- a/misc/acrn-config/config_app/static/main.js +++ b/misc/acrn-config/config_app/static/main.js @@ -401,6 +401,18 @@ $().ready(function(){ show_com_target(id, value); }); + $("select[ID$='FEATURES,RDT,CDP_ENABLED']").change(function(){ + var id = $(this).attr('id'); + var value = $(this).val(); + update_vcpu_clos_option(id, value); + }); + + $("select[ID$='FEATURES,RDT,CDP_ENABLED']").each(function(index, item) { + var id = $(this).attr('id'); + var value = $(item).val(); + update_vcpu_clos_option(id, value); + }); + $(document).on('click', "button:contains('+')", function() { if($(this).text() != '+') return; @@ -408,7 +420,21 @@ $().ready(function(){ var curr_id = curr_item_id.substr(curr_item_id.lastIndexOf('_')+1); var config_item = $(this).parent().parent(); var config_item_added = config_item.clone(); - var id_added = (parseInt(curr_id)+1).toString(); + var config_vm = config_item.parent(); + var vcpu_index_list = []; + config_vm.children().each(function(){ + if($(this).find("button:contains('+')").size() > 0) { + var btn_add_vm_id = $(this).find("button:contains('+')").attr('id'); + vcpu_index_list.push(parseInt(btn_add_vm_id.substr(btn_add_vm_id.lastIndexOf('_')+1))); + } + }); + var id_added = 0; + for (i=0; i<100; i++) { + if (!vcpu_index_list.includes(i)) { + id_added = i; + break + } + } var id_pre_added = curr_item_id.substr(0, curr_item_id.lastIndexOf('_')); config_item_added.find("button:contains('+')").attr('id', id_pre_added+'_'+id_added); config_item_added.find("button:contains('-')").attr('id', id_pre_added.replace('add_', 'remove_')+'_'+id_added); @@ -418,12 +444,50 @@ $().ready(function(){ config_item_added.find('.selectpicker').val('default').selectpicker('deselectAll');; config_item_added.find('.selectpicker').selectpicker('render'); config_item_added.insertAfter(config_item); + + if(curr_item_id.indexOf('add_vcpu')>=0) { + var config_vm = config_item.parent(); + var curr_vcpu_index = vcpu_index_list.indexOf(parseInt(curr_id)) + var vcpu_clos_item = config_vm.find("label:contains('vcpu_clos')").first().parent(); + while(curr_vcpu_index > 0) { + vcpu_clos_item = vcpu_clos_item.next(); + curr_vcpu_index -= 1; + } + + var vcpu_clos_item_added = vcpu_clos_item.clone(); + vcpu_clos_item_added.find("label:first").text(""); + vcpu_clos_item_added.find('.bootstrap-select').replaceWith(function() { return $('select', this); }); + vcpu_clos_item_added.find('.selectpicker').val('default').selectpicker('deselectAll');; + vcpu_clos_item_added.find('.selectpicker').selectpicker('render'); + vcpu_clos_item_added.insertAfter(vcpu_clos_item); + } }); $(document).on('click', "button:contains('-')", function() { if($(this).text() != '-') return; var config_item = $(this).parent().parent(); + var curr_item_id = $(this).attr('id'); + if(curr_item_id.indexOf('remove_vcpu')>=0) { + var config_vm = config_item.parent(); + var vcpu_index_list = []; + config_vm.children().each(function(){ + if($(this).find("button:contains('+')").size() > 0) { + var btn_del_vm_id = $(this).find("button:contains('+')").attr('id'); + vcpu_index_list.push(parseInt(btn_del_vm_id.substr(btn_del_vm_id.lastIndexOf('_')+1))); + } + }); + var curr_item_id = $(this).attr('id'); + var curr_id = parseInt(curr_item_id.substr(curr_item_id.lastIndexOf('_')+1)); + curr_vcpu_index = vcpu_index_list.indexOf(curr_id); + + var vcpu_clos_item = config_vm.find("label:contains('vcpu_clos')").first().parent(); + while(curr_vcpu_index > 0) { + vcpu_clos_item = vcpu_clos_item.next(); + curr_vcpu_index -= 1; + } + vcpu_clos_item.remove(); + } config_item.remove(); }); @@ -472,6 +536,35 @@ function show_com_target(id, value) { } } + +function update_vcpu_clos_option(id, value) { + if(value == 'y') { + $("select[ID$='clos,vcpu_clos']").each(function(){ + len = $(this).find('option').length; + option = $(this).find('option').first(); + for(i=0; i(len-1)/2){ + option.attr('disabled','disabled'); + } + option = option.next(); + } + $(this).selectpicker('render'); + }); + } else { + $("select[ID$='clos,vcpu_clos']").each(function(){ + len = $(this).find('option').length; + option = $(this).find('option').first(); + for(i=0; i(len-1)/2){ + option.removeAttr('disabled'); + } + option = option.next(); + } + $(this).selectpicker('render'); + }); + } +} + function create_setting(type, default_name, name, mode){ var board_info = $("text#board_type").text(); if (board_info==null || board_info=='') { @@ -570,7 +663,13 @@ function save_scenario(generator=null){ $("input").each(function(){ var id = $(this).attr('id'); var value = $(this).val(); - if(id!='new_scenario_name' && id!='new_scenario_name2' && id!='board_info_file' && id!='board_info_upload' + if(id.indexOf('CLOS_MASK')>=0 ) { + if(id in scenario_config) { + scenario_config[id].push(value); + } else { + scenario_config[id] = [value]; + } + } else if(id!='new_scenario_name' && id!='new_scenario_name2' && id!='board_info_file' && id!='board_info_upload' && id!='scenario_file' && id!='create_name' && id!='load_scenario_name2' && id!='load_launch_name2' && id!='src_path') { scenario_config[id] = value; @@ -586,7 +685,7 @@ function save_scenario(generator=null){ $("select").each(function(){ var id = $(this).attr('id'); var value = $(this).val(); - if(id.indexOf('pcpu_id')>=0 || id.indexOf('pci_dev')>=0) { + if(id.indexOf('pcpu_id')>=0 || id.indexOf('pci_dev')>=0 || id.indexOf('vcpu_clos')>=0) { if(id in scenario_config) { scenario_config[id].push(value); } else { diff --git a/misc/acrn-config/config_app/templates/base.html b/misc/acrn-config/config_app/templates/base.html index 1757f233a..69004bb9d 100644 --- a/misc/acrn-config/config_app/templates/base.html +++ b/misc/acrn-config/config_app/templates/base.html @@ -179,7 +179,7 @@ - + {{board_type if board_type != None else ''}}
@@ -207,4 +207,4 @@ - \ No newline at end of file + diff --git a/misc/acrn-config/config_app/templates/scenario.html b/misc/acrn-config/config_app/templates/scenario.html index 2608b6521..15f5416c3 100644 --- a/misc/acrn-config/config_app/templates/scenario.html +++ b/misc/acrn-config/config_app/templates/scenario.html @@ -210,6 +210,76 @@ the source files will be generated into default path and overwirte the previous {% set first_child = [] %} {% for sub_elem in elem.getchildren() %} {% set sub_elem_text = sub_elem.text if sub_elem.text != None else '' %} + + {% if sub_elem.tag == 'RDT' %} + {% for sub_elem_2 in sub_elem.getchildren() %} + {% if ','.join([vm.tag, elem.tag, sub_elem.tag, sub_elem_2.tag]) not in scenario_item_values %} +
+ + +
+ {% if 'readonly' in sub_elem_2.attrib and sub_elem_2.attrib['readonly'] == 'true' %} + + {% else %} + + {% endif %} +
+

+
+ {% elif sub_elem_2.tag != 'CLOS_MASK' %} +
+ + + +

+
+ {% else %} +
+ + +
+ +
+

+
+ {% endif %} + {% endfor %} + + {% else %} + {% if 'configurable' not in sub_elem.attrib or sub_elem.attrib['configurable'] != '0' %}
{% if 'id' not in elem.attrib %} @@ -222,6 +292,7 @@ the source files will be generated into default path and overwirte the previous title="{{elem.attrib['desc'] if 'desc' in elem.attrib else elem.tag}}"> {% endif %} + @@ -353,6 +424,7 @@ the source files will be generated into default path and overwirte the previous {% endif %}
{% endif %} + {% endif %} {% endfor %} {% elif 'configurable' not in elem.attrib or elem.attrib['configurable'] != '0' %}
diff --git a/misc/acrn-config/config_app/views.py b/misc/acrn-config/config_app/views.py index 0cdfe9c3e..b0191c4fd 100644 --- a/misc/acrn-config/config_app/views.py +++ b/misc/acrn-config/config_app/views.py @@ -147,7 +147,6 @@ def save_scenario(): :return: the error list for the edited scenario setting. """ scenario_config_data = request.json if request.method == "POST" else request.args - xml_configs = get_xml_configs() board_type = xml_configs[1] scenario_config = xml_configs[3] @@ -426,6 +425,7 @@ def create_setting(): create_name = create_config_data['create_name'] xml_configs = get_xml_configs(True) + board_info = xml_configs[0] board_type = xml_configs[1] scenario_config = xml_configs[2] launch_config = xml_configs[3] @@ -470,7 +470,16 @@ def create_setting(): copyfile(src_file_name, os.path.join(current_app.config.get('CONFIG_PATH'), board_type, 'user_defined', create_name + '.xml')) - + if mode == 'create': + # update RDT->CLOS_MASK according to board xml + scenario_config.set_curr(create_name) + rdt_clos_max = get_board_rdt_clos_max(board_info) + elem_clos_max = scenario_config.get_curr_elem('hv', 'FEATURES', 'RDT', 'CLOS_MASK') + if rdt_clos_max > 0: + for i in range(rdt_clos_max - 1): + scenario_config.clone_curr_elem(elem_clos_max, 'hv', 'FEATURES', 'RDT') + else: + scenario_config.delete_curr_elem('hv', 'FEATURES', 'RDT', 'CLOS_MASK') scenario_config.save(create_name) return {'status': 'success', 'setting': create_name, 'error_list': {}} @@ -616,6 +625,17 @@ def upload_board_info(): board_type)) xml_config.set_curr(generic_name[:-4]) xml_config.set_curr_attr('board', board_type) + # update RDT->CLOS_MASK according to board xml + xml_config_root = xml_config.get_curr_root() + if 'board' in xml_config_root.attrib and 'scenario' in xml_config_root.attrib \ + and 'uos_launcher' not in xml_config_root.attrib: + rdt_clos_max = get_board_rdt_clos_max(filename.rsplit('.', 1)[0]) + elem_clos_max = xml_config.get_curr_elem('hv', 'FEATURES', 'RDT', 'CLOS_MASK') + if rdt_clos_max > 0: + for i in range(rdt_clos_max-1): + xml_config.clone_curr_elem(elem_clos_max, 'hv', 'FEATURES', 'RDT') + else: + xml_config.delete_curr_elem('hv', 'FEATURES', 'RDT', 'CLOS_MASK') xml_config.save(generic_name[:-4], user_defined=False) board_info = os.path.splitext(file.filename)[0] @@ -924,7 +944,7 @@ def get_board_info(board_info): """ get board info type :param board_info: the board info file - :return: the board type + :return: the board info """ board_config = get_board_config(board_info) bios_info = None @@ -951,6 +971,32 @@ def get_board_info(board_info): return (bios_info, base_board_info) +def get_board_rdt_clos_max(board_info): + """ + get board info type + :param board_info: the board info file + :return: the rdt clos max + """ + board_config = get_board_config(board_info) + rdt_clos_max = 0 + + if board_config is not None: + board_info_root = board_config.get_curr_root() + if board_info_root: + for item in board_info_root.getchildren(): + if item.tag == 'CLOS_INFO': + for line in item.text.split('\n'): + line = line.strip() + if line.startswith('rdt resource clos max:'): + try: + rdt_clos_max = int(line.split(':')[1].strip()) + break + except: + pass + + return rdt_clos_max + + def assign_vm_id(scenario_config): """ assign vm ids for the scenario setting.