From f2db605c67ce8c0b5caf93fb6548bd23565a0447 Mon Sep 17 00:00:00 2001 From: FarooqAbdulla02 <117059774+FarooqAbdulla02@users.noreply.github.com> Date: Wed, 13 Nov 2024 12:06:10 +0530 Subject: [PATCH] Dynamic inputfile code v1 : Added support for virtual devices vNIC, Veth, HNV (#341) * lib/virtual.py : API's added to collect virtual network device. This code commit contains library functions for vNIC, vETH and HNV. to support dynamic input file creation for Virtual Network devices. Signed-off-by: Shaik Abdulla * PCI conf : Template for virtual device parameters. Added vNIC, vETH and HNV mapping parameters to generate the input file parameters. Signed-off-by: Shaik Abdulla * README : Readme doc for virtual devices. Added readme support and help content for virtual devices like vNIC, vETH and HNV devices. Signed-off-by: Shaik Abdulla * Create config and input file : Dynamically generates device specific configuration and input files. This code supports to dynamically create "configuration file" and "input file" for virtual interface with few required parameters. Signed-off-by: Shaik Abdulla --------- Signed-off-by: Shaik Abdulla --- README.pci_info | 229 +++++++++++++++-------- config/wrapper/pci_input.conf | 30 +++ lib/virtual.py | 146 +++++++++++++++ pci_info.py | 341 +++++++++++++++++++++++----------- 4 files changed, 567 insertions(+), 179 deletions(-) create mode 100644 lib/virtual.py diff --git a/README.pci_info b/README.pci_info index c5ed56dc..08243cfb 100644 --- a/README.pci_info +++ b/README.pci_info @@ -11,6 +11,13 @@ optional arguments: -h, --help show this help message and exit --pci-address PCI_ADDR pci address, comma separated + --vnic vNIC_INT + vNIC interface name + --veth vETH_INT + vETH interface name + --hnv HNV_INT + HNV interface name + --show-info Show the pci details --create-config Create test config and input files --additional-params ADD_PARAMS @@ -18,7 +25,6 @@ optional arguments: space separated - ARGUMENT DETAILS: ----------------- @@ -28,6 +34,21 @@ ARGUMENT DETAILS: If not provided, collects details for all pci addresses in the system. + --vnic vNIC_INT + Use this option to specify for which vNIC interface the details should be collected. + If "vNIC_INT" not provided, then the first available vNIC interface from system will be used by default. + + + --veth vETH_INT + Use this option to specify for which vETH interface the details should be collected. + If "vETH_INT" not provided, then the first available vETH interface from system will be used by default. + + + --hnv HNV_INT + Use this option to specify for which vHNV interface the details should be collected. + If "HNV_INT" not provided, then the first available HNV interface from system will be used by default. + + --pci-address-blocklist PCI_ADDR_BLOCKLIST Use this option to leave out pci addresses from the list. Use comma separated values to provide multiple pci addresses. @@ -53,7 +74,7 @@ ARGUMENT DETAILS: Option to create config file if required. Suppose the system has one pci card, which is nvme: Then, a cfg file named io_nvme__fvt.cfg is generated in config/tests/host/ - + It also generates input file (Check --input-file section of main README). The details for input file is got via config file at config/wrapper/pci_input_cfg.txt The details are dynamic, and the dictionary values can be used to edit the input config @@ -88,78 +109,138 @@ ARGUMENT DETAILS: --additional-params "0005:60:00::a=b c=d" a = b is only for the specified pci address, and c = d is for all test configs. + Additional params for virtual interfaces is supported, if they are provided key=value + pair, separated by ",". - -EXAMPLE: --------- -# ./pci_info.py --pci-address "0202:60:00,0102:60:00" --show-info - -[{'adapter_description': 'Emulex Corporation Lancer Gen6: LPe32000 Fibre Channel Host Adapter', - 'adapter_id': '10df:e300:1014:0615', - 'adapter_type': 'fc', - 'class': 'scsi_host', - 'disks': ['/dev/sdaa', - '/dev/sdab', - '/dev/sdx', - '/dev/sdy', - '/dev/sdg', - '/dev/sdd', - '/dev/sde', - '/dev/sdc'], - 'driver': 'lpfc', - 'firmware': '11.4.415.5', - 'functions': ['0102:60:00.0', '0102:60:00.1'], - 'interfaces': ['host11', 'host13'], - 'is_root_disk': False, - 'mpath_disks': [], - 'mpath_wwids': [], - 'pci_root': '0102:60:00', - 'slot': 'U78CD.001.FZHV738-P1-C2'}, - {'adapter_description': 'QLogic Corp. ISP2532-based 8Gb Fibre Channel to PCI Express HBA', - 'adapter_id': '1077:2532:1014:f304', - 'adapter_type': 'fc', - 'class': 'scsi_host', - 'disks': ['/dev/sdbu', - '/dev/sdbt', - '/dev/sdbv', - '/dev/sdbq', - '/dev/sdar', - '/dev/sdas', - '/dev/sdz', - '/dev/sdj'], - 'driver': 'qla2xxx', - 'firmware': '8.07.00', - 'functions': ['0202:60:00.0', '0202:60:00.1'], - 'interfaces': ['host17', 'host15'], - 'is_root_disk': False, - 'mpath_disks': ['/dev/mapper/mpathac', - '/dev/mapper/mpathae'], - 'mpath_wwids': ['360050768028383d7f0000000000000a5', - '360050768028383d7f000000000000033'], - 'pci_root': '0202:60:00', - 'slot': 'U78CD.001.FZHV738-P2-C2'}] - - -# ./pci_info.py --pci-address "0202:60:00,0102:60:00" --create-config --additional-params "peer_ip=131.1.1.89 peer_interfaces=eth1,eth2" -peer_ip=131.1.1.89 peer_interfaces=eth1,eth2 -['peer_ip=131.1.1.89', 'peer_interfaces=eth1,eth2'] ---run-suite host_io_fc_0102_60_00_fvt,host_io_fc_0202_60_00_fvt --input-file io_input.txt - + Example: + --additional-params device_ip=192.168.100.184,peer_ip=192.168.100.104,netmask=255.255.255.0, + peer_ips="192.168.100.104 192.168.110.104",peer_interfaces="env4 env5" + + +EXAMPLES: +--------- +A. For pci devices +++++++++++++++++++ + + # ./pci_info.py --pci-address "0202:60:00,0102:60:00" --show-info + + [{'adapter_description': 'Emulex Corporation Lancer Gen6: LPe32000 Fibre Channel Host Adapter', + 'adapter_id': '10df:e300:1014:0615', + 'adapter_type': 'fc', + 'class': 'scsi_host', + 'disks': ['/dev/sdaa', + '/dev/sdab', + '/dev/sdx', + '/dev/sdy', + '/dev/sdg', + '/dev/sdd', + '/dev/sde', + '/dev/sdc'], + 'driver': 'lpfc', + 'firmware': '11.4.415.5', + 'functions': ['0102:60:00.0', '0102:60:00.1'], + 'interfaces': ['host11', 'host13'], + 'is_root_disk': False, + 'mpath_disks': [], + 'mpath_wwids': [], + 'pci_root': '0102:60:00', + 'slot': 'U78CD.001.FZHV738-P1-C2'}, + {'adapter_description': 'QLogic Corp. ISP2532-based 8Gb Fibre Channel to PCI Express HBA', + 'adapter_id': '1077:2532:1014:f304', + 'adapter_type': 'fc', + 'class': 'scsi_host', + 'disks': ['/dev/sdbu', + '/dev/sdbt', + '/dev/sdbv', + '/dev/sdbq', + '/dev/sdar', + '/dev/sdas', + '/dev/sdz', + '/dev/sdj'], + 'driver': 'qla2xxx', + 'firmware': '8.07.00', + 'functions': ['0202:60:00.0', '0202:60:00.1'], + 'interfaces': ['host17', 'host15'], + 'is_root_disk': False, + 'mpath_disks': ['/dev/mapper/mpathac', + '/dev/mapper/mpathae'], + 'mpath_wwids': ['360050768028383d7f0000000000000a5', + '360050768028383d7f000000000000033'], + 'pci_root': '0202:60:00', + 'slot': 'U78CD.001.FZHV738-P2-C2'}] + + + # ./pci_info.py --pci-address "0202:60:00,0102:60:00" --create-config --additional-params "peer_ip=131.1.1.89 peer_interfaces=eth1,eth2" + peer_ip=131.1.1.89 peer_interfaces=eth1,eth2 + ['peer_ip=131.1.1.89', 'peer_interfaces=eth1,eth2'] + --run-suite host_io_fc_0102_60_00_fvt,host_io_fc_0202_60_00_fvt --input-file io_input.txt + + + # cat io_input.txt + [io_fc_0102_60_00_fvt] + disks = "" + wwids = "" + pci_device = "0102:60:00.0" + MODULES = "lpfc" + peer_ip = "131.1.1.89" + peer_interfaces = "eth1,eth2" + + [io_fc_0202_60_00_fvt] + disk = "/dev/mapper/mpathac" + disks = "/dev/mapper/mpathac,/dev/mapper/mpathae" + wwids = "360050768028383d7f0000000000000a5,360050768028383d7f000000000000033" + pci_device = "0202:60:00.0" + MODULES = "qla2xxx" + peer_ip = "131.1.1.89" + peer_interfaces = "eth1,eth2" + + +B. For virtual devices +++++++++++++++++++++++ + +# ./pci_info.py --vnic env4 --show-info [ or ] ./pci_info.py --vnic --show-info + +[{'adapter_type': 'vnic', + 'driver': 'ibmvnic', + 'interfaces': ['env3', 'env4', 'env8'], + 'macaddress': 'ba:70:c4:97:1a:04', + 'public_interface_ip': '9.xxxxx'}] + + +# ./pci_info.py --vnic env4 --create-config +04:42:56 INFO : python avocado-setup.py --run-suite host_io_vnic_stress_fvt --input-file io_input.txt + + + +[io_vnic_stress_fvt] +host_interfaces = "env3 env4" +interfaces = "env3 env4" +bond_interfaces = "env3 env4" +htx_host_interfaces = "env3 env4" +host_public_ip = "9xxxx" +interface = "env3" +module = "ibmvnic" +macaddress = "ba:70:c4:97:1a:03" + + +# ./pci_info.py --vnic env4 --additional-params device_ip=192.168.100.184,peer_ip=192.168.100.104,netmask=255.255.255.0,host_ip=192.168.100.184,netmasks=255.255.255.0,peer_ips="192.168.100.104 192.168.110.104",peer_interfaces="env4 env5",hmc_username=hscroot,hmc_pwd=abcd --create-config # cat io_input.txt -[io_fc_0102_60_00_fvt] -disks = "" -wwids = "" -pci_device = "0102:60:00.0" -MODULES = "lpfc" -peer_ip = "131.1.1.89" -peer_interfaces = "eth1,eth2" - -[io_fc_0202_60_00_fvt] -disk = "/dev/mapper/mpathac" -disks = "/dev/mapper/mpathac,/dev/mapper/mpathae" -wwids = "360050768028383d7f0000000000000a5,360050768028383d7f000000000000033" -pci_device = "0202:60:00.0" -MODULES = "qla2xxx" -peer_ip = "131.1.1.89" -peer_interfaces = "eth1,eth2" +[io_vnic_stress_fvt] +host_interfaces = "env3 env4" +interfaces = "env3 env4" +bond_interfaces = "env3 env4" +htx_host_interfaces = "env3 env4" +host_public_ip = "9.xxxxx" +interface = "env3" +module = "ibmvnic" +macaddress = "ba:70:c4:97:1a:04" +hmc_pwd = abcd +hmc_username = hscroot +mac_id = "025dc3a7d703" +host_ip = 192.168.100.184 +netmask = 255.255.255.0 +netmasks = 255.255.255.0 +peer_ips = 192.168.100.104 192.168.110.104 +host_ips = "110.10.10.212 111.10.10.212" +peer_interfaces = env4 env5 diff --git a/config/wrapper/pci_input.conf b/config/wrapper/pci_input.conf index 7c495f7f..8247e4e8 100644 --- a/config/wrapper/pci_input.conf +++ b/config/wrapper/pci_input.conf @@ -100,6 +100,36 @@ pci_device,functions:0 pci_devices = functions:all module = driver +[io_vnic_fvt] +host_interfaces = interfaces:all +interfaces = interfaces:all +bond_interfaces = interfaces:all +htx_host_interfaces = interfaces:all +host_public_ip = public_interface_ip +interface = interfaces:0 +module = driver +macaddress = macaddress + +[io_veth_fvt] +host_interfaces = interfaces:all +interfaces = interfaces:all +bond_interfaces = interfaces:all +htx_host_interfaces = interfaces:all +host_public_ip = public_interface_ip +interface = interfaces:0 +module = driver +macaddress = macaddress + +[io_hnv_fvt] +host_interfaces = interfaces:all +interfaces = interfaces:all +bond_interfaces = interfaces:all +htx_host_interfaces = interfaces:all +host_public_ip = public_interface_ip +interface = interfaces:0 +module = driver +macaddress = macaddress + [io_ib_fvt] interface = interfaces:0 interfaces = interfaces:all diff --git a/lib/virtual.py b/lib/virtual.py new file mode 100644 index 00000000..45a20371 --- /dev/null +++ b/lib/virtual.py @@ -0,0 +1,146 @@ +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# See LICENSE for more details. +# +# Copyright: 2024 IBM +# Author: Shaik Abdulla + +""" +Module for all Virtual devices related functions. +""" + +import re +import os +import platform + +from .helper import runcmd +from lib.logger import logger_init +BASE_PATH = os.path.dirname(os.path.abspath(__file__)) +logger = logger_init(filepath=BASE_PATH).getlogger() + +def get_mac_address(interface): + ''' + Gets the mac_address of given interface. + parameter: interface: Name of Interface. + + :return: string of MAC address. + ''' + try: + for line in runcmd("ip a s dev %s" % interface)[1].splitlines(): + if 'link/ether' in line: + mac_address = line.split()[1] + return mac_address + except Exception as e: + logger.debug(f'Interface not found {e}') + + +def get_driver(interface): + ''' + Gets associated driver/module of given interface. + parameter: interface: Name of Interface. + + :return: string of driver name. + ''' + for line in runcmd("ethtool -i %s" % interface)[1].splitlines(): + if line.startswith('driver:'): + driver = line.split(': ')[1].strip() + return driver + + +def get_virtual_interface_names(interface_type): + ''' + Gets all virtual interface names of a given type. + + + :param interface_type: Type of interface (e.g. 'l-lan', 'vnic') + :return: list of virtual interface names. + ''' + try: + interface_list = [] + for input_string in runcmd("lsdevinfo -c")[1].splitlines(): + if interface_type in input_string: + pattern = r'name="([^"]+)"' + match = re.search(pattern, input_string) + if match: + name = match.group(1) + if interface_type == 'l-lan' and name == "net0": + continue + interface_list.append(name) + return interface_list + except Exception as e: + logger.debug(f"Error while getting interface list {e}") + + +def get_veth_interface_names(): + return get_virtual_interface_names('l-lan') + + +def get_vnic_interface_names(): + return get_virtual_interface_names('vnic') + + +def get_hnv_interface_names(): + ''' + Gets all HNV interface names. + + :return: list of HNV interface names. + ''' + hnv_interface_list = [] + bonding_dir = '/proc/net/bonding/' + if os.path.exists(bonding_dir): + bond_interfaces = os.listdir(bonding_dir) + hnv_interface_list.extend(bond_interfaces) + else: + logger.debug("No HNV interfaces found.") + + +def get_host_public_ip(): + ''' + Gets system's Public IP address. + + :return: string of Public IP address. + ''' + try: + lines = runcmd("ip a s dev net0")[1] + ip_pattern = r'inet\s+(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' + match = re.search(ip_pattern, lines) + if match: + return match.group(1) + except Exception as e: + logger.debug(f'Interface not found {e}') + + +def virtual_info(interface): + ''' + Get the information for given virtual interface. + + parameter: interface: Name of Interface. + :return: list of dictinaries of virtual interface information. + ''' + virtual_list = [] + virtual_dict = {} + virtual_dict['macaddress'] = get_mac_address(interface) + virtual_dict['public_interface_ip'] = get_host_public_ip() + virtual_dict['driver'] = get_driver(interface) + + if virtual_dict['driver'] == "ibmvnic": + virtual_dict['interfaces'] = get_vnic_interface_names() + virtual_dict['adapter_type'] = 'vnic' + + if virtual_dict['driver'] == "ibmveth": + virtual_dict['interfaces'] = get_veth_interface_names() + virtual_dict['adapter_type'] = 'veth' + + if virtual_dict['driver'] == "bonding": + virtual_dict['interfaces'] = get_hnv_interface_names() + virtual_dict['adapter_type'] = 'hnv' + + virtual_list.append(virtual_dict) + return virtual_list diff --git a/pci_info.py b/pci_info.py index 6f712da0..ee4e5d8f 100755 --- a/pci_info.py +++ b/pci_info.py @@ -14,9 +14,11 @@ # Copyright: 2023 IBM # Author: Narasimhan V # Author: Manvanthara Puttashankar +# Author: Shaik Abdulla from pprint import pprint from lib import pci +from lib import virtual import argparse import shutil import os @@ -38,109 +40,195 @@ logger = logger_init(filepath=BASE_PATH).getlogger() - -def create_config(pci_list): +def create_config_inputs(orig_cfg, new_cfg, inputfile, interface, config_type): """ - Creates avocado test suite / config file, and input file needed for yaml files in that config files. + 1. Creates modified configuration file name according to type of interface from original configuration file + 2. Generates string with "input file option" along with input file, + 3. Generates input parametes of specific device type interface. + + Parameters: + orig_cfg (str): The name of the original configuration file. + new_cfg (str): The name of the new configuration file to be generated with + according to interface type. + inputfile (str): The path to the input file containing configuration data. + interface (list): The details of Interface in list format. + config_type (str): The type of configuration to generate. Ex: PCI, vNIC etc. + + Returns: + test_suites :: A list, having configuration[cfg] files of different set. + input_file_string :: A string, with extension of "--input-file" option. + input_params:: A list, of different input parameters of specific interface. """ test_suites = [] input_file_string = "" input_params = [] additional_params = args.add_params.split() - for pci in pci_list: - if pci['is_root_disk']: - logger.debug( - "ignoring pci address %s as it contains root disk", pci['pci_root']) - continue + if len(additional_params) != 0: + additional_params = args.add_params.split(",") + + # Exclude input parameters when vNIC has been created manually, as these parameters are not needed. + # exclude_inputs_params = ["manageSystem","sriov", "hmc_pwd", "hmc_username", "vios_ip","vios_username", + # "vios_pwd","slot_num", "vios_names","sriov_adapters", "sriov_ports", + # "priority", "auto_failover", "bandwidth"] + + # Exclude test-cases from test bucket when vNIC created manually. + exclude_test_cases = ["NetworkVirtualization.test_add", "NetworkVirtualization.test_backingdevadd", + "NetworkVirtualization.test_backingdevremove", "NetworkVirtualization.test_remove"] + + # when vNIC created manually, Read the orignal configuration file and write only required test-cases in new configuration file. + if config_type == 'vnic': + test_cases = [] + with open("config/tests/host/%s.cfg" % orig_cfg, 'r') as file: + + lines = file.readlines() + for testcases in lines: + if not any(exclude_test_case in testcases for exclude_test_case in exclude_test_cases): + test_cases.append(testcases) + + with open("config/tests/host/%s.cfg" % new_cfg, 'w+') as output_file: + output_file.write("".join(test_cases)) + else: + shutil.copy("config/tests/host/%s.cfg" % orig_cfg, "config/tests/host/%s.cfg" % new_cfg) + + test_suites.append("host_%s" % new_cfg) + + # adding info to input file + if not CONFIGFILE.has_section(orig_cfg) and not additional_params: + return + input_params = CONFIGFILE.items(orig_cfg) + if not input_params: + return + + INPUTFILE.add_section(new_cfg) + + # read the input file content and store in dict + inputfile_dict = {} + with open(inputfile, 'r') as file: + for line in file: + # Check if the line starts with '#' or '[' and skip it + if line.startswith('#') or line.startswith('['): + continue - # copy template cfg files and create new ones - cfg_name = "_".join(pci['pci_root'].split(':')) - if pci['adapter_type'] == 'nvmf' and is_rhel8(): - orig_cfg = "io_%s_rhel8_fvt" % pci['adapter_type'] - new_cfg = "io_%s_rhel8_%s_fvt" % (pci['adapter_type'], cfg_name) - inputfile = "%s/io_%s_rhel8_input.txt" % ( - BASE_INPUTFILE_PATH, pci['adapter_type']) + # Split each line by '=' to separate key and value + parts = line.strip().split('=') + + # Ensure there are exactly two parts (key and value) + if len(parts) == 2: + inputkey, inputvalue = parts[0].strip(), parts[1].strip() + inputfile_dict[inputkey] = inputvalue + + # input params + for param in input_params: + try: + key = param[0] + if ':' not in param[1]: + value = interface[param[1]] + else: + index = param[1].split(':')[0] + index_exact = param[1].split(':')[1] + if index_exact == 'all': + + # adding only first two available vNIC interfaces when + # multiple vNIC interfaces are available in system. + if config_type in ('vnic', 'veth', 'hnv'): + value = " ".join(str(item) for item in interface[index][:2]) + else: + value = " ".join(interface[index]) + else: + value = interface[index][int(index_exact)] + if len(interface[index]) > 1: + del interface[index][int(index_exact)] + # remove the duplicate inputfile enteries + if key in inputfile_dict: + del inputfile_dict[key] + INPUTFILE.set(new_cfg, key, "\"%s\"" % value) + + except: + pass + + # exclude input parameters when vNIC has been created manually. + # if config_type == 'vnic': + # for key in list(inputfile_dict.keys()): + # if any(key.startswith(exclude) for exclude in exclude_inputs_params): + # del inputfile_dict[key] + + # additional params + for param in additional_params: + key = param.split('=')[0] + # handling additional params per pci + if '::' in key: + pci_root = key.split('::')[0].split('.')[0] + if pci_root != pci['pci_root']: + continue + key = key.split('::')[1] + + # check if the newly added additional param is same + # as inputfile assign the values directly + if key in inputfile_dict: + inputfile_dict[key] = param.split('=')[1] else: - orig_cfg = "io_%s_fvt" % pci['adapter_type'] - new_cfg = "io_%s_%s_fvt" % (pci['adapter_type'], cfg_name) - inputfile = "%s/io_%s_input.txt" % ( - BASE_INPUTFILE_PATH, pci['adapter_type']) + # if it is completly new then directly write to new input file + value = param.split('=')[1] + INPUTFILE.set(new_cfg, key, "\"%s\"" % value) + + # append the remaining input file entries to the new input file + for inputkey, inputvalue in inputfile_dict.items(): + INPUTFILE.set(new_cfg, inputkey, "%s" % inputvalue) + + return test_suites, input_file_string, input_params + + +def create_config_file(interface_details, config_type): + """ + Creates avocado test suite / config file, and input file needed for yaml files in that config files. + + Parameters: + interface_details(list): The detailed differnet Interface parameters in list format. + config_type (str): The type of configuration to generate. Ex: vNIC, HNV, vETH etc. + """ + for virtual in interface_details: + cfg_name = virtual['adapter_type'] + orig_cfg = "io_%s_fvt" % virtual['adapter_type'] + new_cfg = "io_%s_stress_fvt" % virtual['adapter_type'] + inputfile = "%s/io_%s_input.txt" % (BASE_INPUTFILE_PATH, virtual['adapter_type']) + if not os.path.exists("config/tests/host/%s.cfg" % orig_cfg): - logger.debug("ignoring pci address %s as there is no cfg for %s", - pci['pci_root'], pci['adapter_type']) + logger.debug("ignoring hnv address as there is no cfg for %s", virtual['adapter_type']) continue - shutil.copy("config/tests/host/%s.cfg" % - orig_cfg, "config/tests/host/%s.cfg" % new_cfg) - test_suites.append("host_%s" % new_cfg) - # adding info to input file - if not CONFIGFILE.has_section(orig_cfg) and not additional_params: - continue - input_params = CONFIGFILE.items(orig_cfg) - if not input_params: - continue - INPUTFILE.add_section(new_cfg) - - # read the input file content and store in dict - inputfile_dict = {} - with open(inputfile, 'r') as file: - for line in file: - # Check if the line starts with '#' or '[' and skip it - if line.startswith('#') or line.startswith('['): - continue - - # Split each line by '=' to separate key and value - parts = line.strip().split('=') - - # Ensure there are exactly two parts (key and value) - if len(parts) == 2: - inputkey, inputvalue = parts[0].strip(), parts[1].strip() - inputfile_dict[inputkey] = inputvalue - - # input params - for param in input_params: - try: - key = param[0] - if ':' not in param[1]: - value = pci[param[1]] - else: - index = param[1].split(':')[0] - index_exact = param[1].split(':')[1] - if index_exact == 'all': - value = " ".join(pci[index]) - else: - value = pci[index][int(index_exact)] - if len(pci[index]) > 1 and not key == 'pci_device': - del pci[index][int(index_exact)] - # remove the duplicate inputfile enteries - if key in inputfile_dict: - del inputfile_dict[key] - INPUTFILE.set(new_cfg, key, "\"%s\"" % value) - except: - pass - - # additional params - for param in additional_params: - key = param.split('=')[0] - # handling additional params per pci - if '::' in key: - pci_root = key.split('::')[0].split('.')[0] - if pci_root != pci['pci_root']: - continue - key = key.split('::')[1] - - # check if the newly added additional param is same - # as inputfile assign the values directly - if key in inputfile_dict: - inputfile_dict[key] = param.split('=')[1] + return create_config_inputs(orig_cfg, new_cfg, inputfile, virtual, config_type=config_type) + +def create_config(interface_details, config_type): + """ + Creates avocado test suite / config file, and input file needed for yaml files in that config files. + """ + if config_type == 'pci': + for pci in interface_details: + if pci['is_root_disk']: + logger.debug( + "ignoring pci address %s as it contains root disk", pci['pci_root']) + continue + + # copy template cfg files and create new ones + cfg_name = "_".join(pci['pci_root'].split(':')) + if pci['adapter_type'] == 'nvmf' and is_rhel8(): + orig_cfg = "io_%s_rhel8_fvt" % pci['adapter_type'] + new_cfg = "io_%s_rhel8_%s_fvt" % (pci['adapter_type'], cfg_name) + inputfile = "%s/io_%s_rhel8_input.txt" % ( + BASE_INPUTFILE_PATH, pci['adapter_type']) else: - # if it is completly new then directly write to new input file - value = param.split('=')[1] - INPUTFILE.set(new_cfg, key, "\"%s\"" % value) + orig_cfg = "io_%s_fvt" % pci['adapter_type'] + new_cfg = "io_%s_%s_fvt" % (pci['adapter_type'], cfg_name) + inputfile = "%s/io_%s_input.txt" % ( + BASE_INPUTFILE_PATH, pci['adapter_type']) + if not os.path.exists("config/tests/host/%s.cfg" % orig_cfg): + logger.debug("ignoring pci address %s as there is no cfg for %s", + pci['pci_root'], pci['adapter_type']) + continue + test_suites, input_file_string, input_params = create_config_inputs(orig_cfg, new_cfg, inputfile, pci, config_type='pci') - # append the remaining input file entries to the new input file - for inputkey, inputvalue in inputfile_dict.items(): - INPUTFILE.set(new_cfg, inputkey, "%s" % inputvalue) + if config_type in ('vnic', 'veth', 'hnv'): + test_suites, input_file_string, input_params = create_config_file(interface_details, config_type) test_suites = ",".join(test_suites) @@ -152,17 +240,21 @@ def create_config(pci_list): # generate avocado-setup command line if test_suites: - cmd = "python avocado-setup.py --run-suite %s %s" % ( - test_suites, input_file_string) + cmd = "python avocado-setup.py --run-suite %s %s" % (test_suites, input_file_string) return cmd return "" - if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument('--pci-address', dest='pci_addr', action='store', default='', help='pci address, comma separated') + parser.add_argument('--vnic', dest='vnic_int', action='store', nargs='?', const='vnic_default', default=None, + help='vNIC interface name') + parser.add_argument('--veth', dest='veth_int', action='store', nargs='?', const='veth_default', default=None, + help='vETH interface name') + parser.add_argument('--hnv', dest='hnv_int', action='store', nargs='?', const='hnv_default', default=None, + help='HNV interface name') parser.add_argument('--pci-address-blocklist', dest='pci_addr_blocklist', action='store', default='', help='pci address which need not be considered, comma separated') @@ -185,19 +277,58 @@ def create_config(pci_list): action='store', default='', help='Additional parameters(key=value) to the input file, space separated') args = parser.parse_args() - if args.pci_addr: - pci_details = pci.pci_info(args.pci_addr, pci_type=args.pci_type, - pci_blocklist=args.pci_addr_blocklist, type_blocklist=args.type_blocklist) - else: - pci_details = pci.all_pci_info( - pci_type=args.pci_type, pci_blocklist=args.pci_addr_blocklist, type_blocklist=args.type_blocklist) - if not pci_details: - logger.info("No PCI Found") + + #if no interfaces name is provided for vNIC ,vETH or HNV, get the first aavailable interface. + if args.vnic_int == 'vnic_default': + args.vnic_int = virtual.get_vnic_interface_names()[0] + + if args.veth_int == 'veth_default': + args.veth_int = virtual.get_veth_interface_names()[0] + + if args.hnv_int == 'hnv_default': + args.hnv_int = virtual.get_hnv_interface_names()[0] + + try: + if args.vnic_int: + vnic_details = virtual.virtual_info(args.vnic_int) + elif args.veth_int: + veth_details = virtual.virtual_info(args.veth_int) + elif args.hnv_int: + hnv_details = virtual.virtual_info(args.hnv_int) + elif args.pci_addr: + pci_details = pci.pci_info(args.pci_addr, pci_type=args.pci_type, pci_blocklist=args.pci_addr_blocklist, type_blocklist=args.type_blocklist) + else: + pci_details = pci.all_pci_info(pci_type=args.pci_type, pci_blocklist=args.pci_addr_blocklist, type_blocklist=args.type_blocklist) + except Exception as e: + if args.vnic_int: + logger.info("vNIC interface not found") + else: + logger.info("No PCI Found") sys.exit(0) + if args.show_info: - pprint(pci_details) + if args.pci_addr: + pprint(pci_details) + elif args.vnic_int: + pprint(vnic_details) + elif args.veth_int: + pprint(veth_details) + elif args.hnv_int: + pprint(hnv_details) + if args.create_cfg: - cmd = create_config(pci_details) - logger.info(cmd) + if args.vnic_int: + cmd = create_config(interface_details=vnic_details, config_type='vnic') + logger.info(cmd) + elif args.veth_int: + cmd = create_config(interface_details=veth_details, config_type='veth') + logger.info(cmd) + elif args.hnv_int: + cmd = create_config(interface_details=hnv_details, config_type='hnv') + logger.info(cmd) + else: + cmd = create_config(interface_details=pci_details, config_type='pci') + logger.info(cmd) + if args.run_test: - os.system(cmd) + os.system(cmd) \ No newline at end of file