def step_run(self): """ Execute actions specified by TestSteps list :return: False if any error was detected True otherwise """ # anything to do? if not self.test: return True # required for VNFs initialization loader = Loader() # initialize list with results self._step_result = [None] * len(self.test) # run test step by step... for i, step in enumerate(self.test): step_ok = not self._step_check step_check = self._step_check regex = None # configure step result mapping if step alias/label is detected if step[0].startswith('#'): key = step[0][1:] if key.isdigit(): raise RuntimeError( 'Step alias can\'t be an integer value {}'.format(key)) if key in self._step_result_mapping: raise RuntimeError( 'Step alias {} has been used already for step ' '{}'.format(key, self._step_result_mapping[key])) self._step_result_mapping[step[0][1:]] = i step = step[1:] # store regex filter if it is specified if isinstance(step[-1], str) and step[-1].startswith('|'): # evalute macros and variables used in regex regex = self.step_eval_params([step[-1][1:]], self._step_result[:i])[0] step = step[:-1] # check if step verification should be suppressed if step[0].startswith('!'): step_check = False step_ok = True step[0] = step[0][1:] if step[0] == 'vswitch': test_object = self._vswitch_ctl.get_vswitch() elif step[0] == 'namespace': test_object = namespace elif step[0] == 'veth': test_object = veth elif step[0] == 'settings': test_object = S elif step[0] == 'tools': test_object = TestStepsTools() step[1] = step[1].title() elif step[0] == 'trafficgen': test_object = self._traffic_ctl # in case of send_traffic or send_traffic_async methods, ensure # that specified traffic values are merged with existing self._traffic if step[1].startswith('send_traffic'): tmp_traffic = copy.deepcopy(self._traffic) tmp_traffic.update(step[2]) step[2] = tmp_traffic # store indication that traffic has been sent # so it is not sent again after the execution of teststeps self._step_send_traffic = True elif step[0].startswith('vnf'): # use vnf started within TestSteps if not self._step_vnf_list[step[0]]: # initialize new VM self._step_vnf_list[step[0]] = loader.get_vnf_class()() test_object = self._step_vnf_list[step[0]] elif step[0].startswith('VNF'): if step[1] in ('start', 'stop'): raise RuntimeError( "Cannot execute start() or stop() method of " "VNF deployed automatically by scenario.") # use vnf started by scenario deployment (e.g. pvp) vnf_index = int(step[0][3:]) try: test_object = self._vnf_list[vnf_index] except IndexError: raise RuntimeError( "VNF with index {} is not running.".format(vnf_index)) elif step[0] == 'wait': input(os.linesep + "Step {}: Press Enter to continue with " "the next step...".format(i) + os.linesep + os.linesep) continue elif step[0] == 'sleep': self._logger.debug("Sleep %s seconds", step[1]) time.sleep(int(step[1])) continue elif step[0] == 'log': test_object = self._logger # there isn't a need for validation of log entry step_check = False step_ok = True elif step[0] == 'pdb': import pdb pdb.set_trace() continue else: self._logger.error("Unsupported test object %s", step[0]) self._step_status = { 'status': False, 'details': ' '.join(step) } self.step_report_status("Step '{}'".format(' '.join(step)), self._step_status['status']) return False test_method = getattr(test_object, step[1]) if step_check: test_method_check = getattr(test_object, CHECK_PREFIX + step[1]) else: test_method_check = None step_params = [] try: # eval parameters, but use only valid step_results # to support negative indexes step_params = self.step_eval_params(step[2:], self._step_result[:i]) step_log = '{} {}'.format(' '.join(step[:2]), step_params) step_log += ' filter "{}"'.format(regex) if regex else '' self._logger.debug("Step %s '%s' start", i, step_log) self._step_result[i] = test_method(*step_params) if regex: # apply regex to step output self._step_result[i] = functions.filter_output( self._step_result[i], regex) self._logger.debug("Step %s '%s' results '%s'", i, step_log, self._step_result[i]) time.sleep(S.getValue('TEST_STEP_DELAY')) if step_check: step_ok = test_method_check(self._step_result[i], *step_params) except (AssertionError, AttributeError, IndexError) as ex: step_ok = False self._logger.error("Step %s raised %s", i, type(ex).__name__) if step_check: self.step_report_status("Step {} - '{}'".format(i, step_log), step_ok) if not step_ok: self._step_status = {'status': False, 'details': step_log} # Stop all VNFs started by TestSteps self.step_stop_vnfs() return False # all steps processed without any issue return True
def step_run(self): """ Execute actions specified by TestSteps list :return: False if any error was detected True otherwise """ # anything to do? if not self.test: return True # required for VNFs initialization loader = Loader() # initialize list with results self._step_result = [None] * len(self.test) # We have to suppress pylint report, because test_object has to be set according # to the test step definition # pylint: disable=redefined-variable-type # run test step by step... for i, step in enumerate(self.test): step_ok = not self._step_check if step[0] == 'vswitch': test_object = self._vswitch_ctl.get_vswitch() elif step[0] == 'namespace': test_object = namespace elif step[0] == 'veth': test_object = veth elif step[0] == 'settings': test_object = S elif step[0] == 'tools': test_object = TestStepsTools() step[1] = step[1].title() elif step[0] == 'trafficgen': test_object = self._traffic_ctl # in case of send_traffic or send_traffic_async methods, ensure # that specified traffic values are merged with existing self._traffic if step[1].startswith('send_traffic'): tmp_traffic = copy.deepcopy(self._traffic) tmp_traffic.update(step[2]) step[2] = tmp_traffic elif step[0].startswith('vnf'): if not self._step_vnf_list[step[0]]: # initialize new VM self._step_vnf_list[step[0]] = loader.get_vnf_class()() test_object = self._step_vnf_list[step[0]] elif step[0] == 'wait': input(os.linesep + "Step {}: Press Enter to continue with " "the next step...".format(i) + os.linesep + os.linesep) continue elif step[0] == 'sleep': self._logger.debug("Sleep %s seconds", step[1]) time.sleep(int(step[1])) continue else: self._logger.error("Unsupported test object %s", step[0]) self._step_status = { 'status': False, 'details': ' '.join(step) } self.step_report_status("Step '{}'".format(' '.join(step)), self._step_status['status']) return False test_method = getattr(test_object, step[1]) if self._step_check: test_method_check = getattr(test_object, CHECK_PREFIX + step[1]) else: test_method_check = None step_params = [] try: # eval parameters, but use only valid step_results # to support negative indexes step_params = TestCase.step_eval_params( step[2:], self._step_result[:i]) step_log = '{} {}'.format(' '.join(step[:2]), step_params) self._logger.debug("Step %s '%s' start", i, step_log) self._step_result[i] = test_method(*step_params) self._logger.debug("Step %s '%s' results '%s'", i, step_log, self._step_result[i]) time.sleep(S.getValue('TEST_STEP_DELAY')) if self._step_check: step_ok = test_method_check(self._step_result[i], *step_params) except (AssertionError, AttributeError, IndexError) as ex: step_ok = False self._logger.error("Step %s raised %s", i, type(ex).__name__) if self._step_check: self.step_report_status("Step {} - '{}'".format(i, step_log), step_ok) if not step_ok: self._step_status = {'status': False, 'details': step_log} # Stop all VNFs started by TestSteps self.step_stop_vnfs() return False # all steps processed without any issue return True
def run_initialize(self): """ Prepare test execution environment """ # mount hugepages if needed self._mount_hugepages() self._logger.debug("Controllers:") loader = Loader() self._traffic_ctl = component_factory.create_traffic( self._traffic['traffic_type'], loader.get_trafficgen_class()) self._vnf_ctl = component_factory.create_vnf(self.deployment, loader.get_vnf_class(), len(self._step_vnf_list)) self._vnf_list = self._vnf_ctl.get_vnfs() self._pod_ctl = component_factory.create_pod(self.deployment, loader.get_pod_class()) self._pod_list = self._pod_ctl.get_pods() # verify enough hugepages are free to run the testcase if not self._check_for_enough_hugepages(): raise RuntimeError('Not enough hugepages free to run test.') # perform guest related handling tmp_vm_count = self._vnf_ctl.get_vnfs_number() + len( self._step_vnf_list) if tmp_vm_count: # copy sources of l2 forwarding tools into VM shared dir if needed self._copy_fwd_tools_for_all_guests(tmp_vm_count) # in case of multi VM in parallel, set the number of streams to the number of VMs if self.deployment.startswith('pvpv'): # for each VM NIC pair we need an unique stream streams = 0 for vm_nic in S.getValue('GUEST_NICS_NR')[:tmp_vm_count]: streams += int(vm_nic / 2) if vm_nic > 1 else 1 self._logger.debug( "VMs with parallel connection were detected. " "Thus Number of streams was set to %s", streams) # update streams if needed; In case of additional VNFs deployed by TestSteps # user can define a proper stream count manually if 'multistream' not in self._traffic or self._traffic[ 'multistream'] < streams: self._traffic.update({'multistream': streams}) # OVS Vanilla requires guest VM MAC address and IPs to work if 'linux_bridge' in S.getValue('GUEST_LOOPBACK'): self._traffic['l2'].update({ 'srcmac': S.getValue('VANILLA_TGEN_PORT1_MAC'), 'dstmac': S.getValue('VANILLA_TGEN_PORT2_MAC') }) self._traffic['l3'].update({ 'srcip': S.getValue('VANILLA_TGEN_PORT1_IP'), 'dstip': S.getValue('VANILLA_TGEN_PORT2_IP') }) if self._vswitch_none: self._vswitch_ctl = component_factory.create_pktfwd( self.deployment, loader.get_pktfwd_class()) else: self._vswitch_ctl = component_factory.create_vswitch( self.deployment, loader.get_vswitch_class(), self._traffic, self._tunnel_operation) self._collector = component_factory.create_collector( loader.get_collector_class(), self._results_dir, self.name) self._loadgen = component_factory.create_loadgen( loader.get_loadgen_class(), self._load_cfg) self._output_file = os.path.join( self._results_dir, "result_{}_{}_{}.csv".format(str(S.getValue('_TEST_INDEX')), self.name, self.deployment)) self._step_status = {'status': True, 'details': ''} # Perform LLC-allocations if S.getValue('LLC_ALLOCATION'): self._rmd.setup_llc_allocation() self._logger.debug("Setup:")
def run(self): """Run the test All setup and teardown through controllers is included. """ self._logger.debug(self.name) # copy sources of l2 forwarding tools into VM shared dir if needed self._copy_fwd_tools_for_guest() self._logger.debug("Controllers:") loader = Loader() traffic_ctl = component_factory.create_traffic( self._traffic['traffic_type'], loader.get_trafficgen_class()) vnf_ctl = component_factory.create_vnf(self.deployment, loader.get_vnf_class()) vswitch_ctl = component_factory.create_vswitch( self.deployment, loader.get_vswitch_class(), self._traffic) collector = component_factory.create_collector( loader.get_collector_class(), self._results_dir, self.name) loadgen = component_factory.create_loadgen(self._loadgen, self._load_cfg) self._logger.debug("Setup:") with vswitch_ctl, loadgen: with vnf_ctl, collector: vswitch = vswitch_ctl.get_vswitch() # TODO BOM 15-08-07 the frame mod code assumes that the # physical ports are ports 1 & 2. The actual numbers # need to be retrived from the vSwitch and the metadata value # updated accordingly. bridge = S.getValue('VSWITCH_BRIDGE_NAME') if self._frame_mod == "vlan": # 0x8100 => VLAN ethertype self._logger.debug(" **** VLAN ***** ") flow = { 'table': '2', 'priority': '1000', 'metadata': '2', 'actions': ['push_vlan:0x8100', 'goto_table:3'] } vswitch.add_flow(bridge, flow) flow = { 'table': '2', 'priority': '1000', 'metadata': '1', 'actions': ['push_vlan:0x8100', 'goto_table:3'] } vswitch.add_flow(bridge, flow) elif self._frame_mod == "mpls": # 0x8847 => MPLS unicast ethertype self._logger.debug(" **** MPLS ***** ") flow = { 'table': '2', 'priority': '1000', 'metadata': '2', 'actions': ['push_mpls:0x8847', 'goto_table:3'] } vswitch.add_flow(bridge, flow) flow = { 'table': '2', 'priority': '1000', 'metadata': '1', 'actions': ['push_mpls:0x8847', 'goto_table:3'] } vswitch.add_flow(bridge, flow) elif self._frame_mod == "mac": flow = { 'table': '2', 'priority': '1000', 'metadata': '2', 'actions': ['mod_dl_src:22:22:22:22:22:22', 'goto_table:3'] } vswitch.add_flow(bridge, flow) flow = { 'table': '2', 'priority': '1000', 'metadata': '1', 'actions': ['mod_dl_src:11:11:11:11:11:11', 'goto_table:3'] } vswitch.add_flow(bridge, flow) elif self._frame_mod == "dscp": # DSCP 184d == 0x4E<<2 => 'Expedited Forwarding' flow = { 'table': '2', 'priority': '1000', 'metadata': '2', 'dl_type': '0x0800', 'actions': ['mod_nw_tos:184', 'goto_table:3'] } vswitch.add_flow(bridge, flow) flow = { 'table': '2', 'priority': '1000', 'metadata': '1', 'dl_type': '0x0800', 'actions': ['mod_nw_tos:184', 'goto_table:3'] } vswitch.add_flow(bridge, flow) elif self._frame_mod == "ttl": # 251 and 241 are the highest prime numbers < 255 flow = { 'table': '2', 'priority': '1000', 'metadata': '2', 'dl_type': '0x0800', 'actions': ['mod_nw_ttl:251', 'goto_table:3'] } vswitch.add_flow(bridge, flow) flow = { 'table': '2', 'priority': '1000', 'metadata': '1', 'dl_type': '0x0800', 'actions': ['mod_nw_ttl:241', 'goto_table:3'] } vswitch.add_flow(bridge, flow) elif self._frame_mod == "ip_addr": flow = { 'table': '2', 'priority': '1000', 'metadata': '2', 'dl_type': '0x0800', 'actions': [ 'mod_nw_src:10.10.10.10', 'mod_nw_dst:20.20.20.20', 'goto_table:3' ] } vswitch.add_flow(bridge, flow) flow = { 'table': '2', 'priority': '1000', 'metadata': '1', 'dl_type': '0x0800', 'actions': [ 'mod_nw_src:20.20.20.20', 'mod_nw_dst:10.10.10.10', 'goto_table:3' ] } vswitch.add_flow(bridge, flow) elif self._frame_mod == "ip_port": # TODO BOM 15-08-27 The traffic generated is assumed # to be UDP (nw_proto 17d) which is the default case but # we will need to pick up the actual traffic params in use. flow = { 'table': '2', 'priority': '1000', 'metadata': '2', 'dl_type': '0x0800', 'nw_proto': '17', 'actions': [ 'mod_tp_src:44444', 'mod_tp_dst:44444', 'goto_table:3' ] } vswitch.add_flow(bridge, flow) flow = { 'table': '2', 'priority': '1000', 'metadata': '1', 'dl_type': '0x0800', 'nw_proto': '17', 'actions': [ 'mod_tp_src:44444', 'mod_tp_dst:44444', 'goto_table:3' ] } vswitch.add_flow(bridge, flow) else: pass with traffic_ctl: traffic_ctl.send_traffic(self._traffic) # dump vswitch flows before they are affected by VNF termination vswitch_ctl.dump_vswitch_flows() self._logger.debug("Traffic Results:") traffic_ctl.print_results() self._logger.debug("Collector Results:") collector.print_results() output_file = os.path.join( self._results_dir, "result_" + self.name + "_" + self.deployment + ".csv") tc_results = self._append_results(traffic_ctl.get_results()) TestCase._write_result_to_file(tc_results, output_file) report.generate(output_file, tc_results, collector.get_results())