def waitForComplete(self, request, response, timeout=128): if 'errors' in response.json(): raise TgnError(response.json()['errors'][0]) if response.json()['state'].lower() == 'error': result = ast.literal_eval(response.content.replace( 'null', '""'))['result'].strip() raise TgnError('wait for post {} failed - {}'.format( response.url, result)) if response.json()['state'].lower() == 'success': return progress_url = json.loads(response.content)[u'url'] if 'http' not in progress_url: # sometimes the progress url is relative, for example in version 8.50 linux loadconfig progress_url = self.server_url + progress_url for _ in range(timeout): response = self.get(progress_url) if type(response.json()) == dict: state = response.json()['state'] else: state = response.json()[0]['state'] if state.lower() not in ['in_progress', 'down']: return time.sleep(1) raise TgnError( '{} operation failed, state is {} after {} seconds'.format( self.session, response.json()['state'], timeout))
def init_stc( api: ApiType, logger: logging.Logger, install_dir: Optional[str] = None, rest_server: Optional[str] = None, rest_port: Optional[int] = 80, ) -> StcApp: """Helper function to create STC object. This helper supports only new sessions. In order to connect to existing session on Lab server create StcRestWrapper and StcApp directly. :param api: tcl/python/rest :param logger: python logger object :param install_dir: STC installation directory :param rest_server: rest server address (either stcweb or lab server) :param rest_port: rest server port (either stcweb or lab server) """ if api == ApiType.tcl: stc_api_wrapper = StcTclWrapper(logger, install_dir) elif api == ApiType.rest: stc_api_wrapper = StcRestWrapper(logger, rest_server, rest_port) else: raise TgnError(f"{api} API not supported - use Tcl or REST") return StcApp(logger, api_wrapper=stc_api_wrapper)
def wait_for_up(self, timeout=16, ports=None): """ Wait until ports reach up state. :param timeout: seconds to wait. :param ports: list of ports to wait for. :return: """ port_list = [] for port in ports: port_list.append(self.set_ports_list(port)) t_end = time.time() + timeout ports_not_in_up = [] ports_in_up = [] while time.time() < t_end: # ixCheckLinkState can take few seconds on some ports when link is down. for port in port_list: call = self.api.call('ixCheckLinkState {}'.format(port)) if call == '0': ports_in_up.append("{}".format(port)) else: pass ports_in_up = list(set(ports_in_up)) if len(port_list) == len(ports_in_up): return time.sleep(1) for port in port_list: if port not in ports_in_up: ports_not_in_up.append(port) raise TgnError('{}'.format(ports_not_in_up))
def init_stc(api, logger, install_dir=None, rest_server=None, rest_port=80): """ Helper function to create STC object. This helper supports only new sessions. In order to connect to existing session on Lab server create StcRestWrapper and StcApp directly. :param api: tcl/python/rest :type api: trafficgenerator.tgn_utils.ApiType :param logger: python logger object :param install_dir: STC installation directory :param rest_server: rest server address (either stcweb or lab server) :param rest_port: rest server port (either stcweb or lab server) :return: STC object """ if api == ApiType.tcl: stc_api_wrapper = StcTclWrapper(logger, install_dir) elif api == ApiType.python: stc_api_wrapper = StcPythonWrapper(logger, install_dir) elif api == ApiType.rest: stc_api_wrapper = StcRestWrapper(logger, rest_server, rest_port) else: raise TgnError( '{} API not supported - use Tcl, python or REST'.format(api)) return StcApp(logger, api_wrapper=stc_api_wrapper)
def reserve(self, location=None, force=False, wait_for_up=True, timeout=80): """ Reserve port and optionally wait for port to come up. :param location: port location as 'ip/module/port'. If None, the location will be taken from the configuration. :param force: whether to revoke existing reservation (True) or not (False). :param wait_for_up: True - wait for port to come up, False - return immediately. :param timeout: how long (seconds) to wait for port to come up. """ if not location or is_local_host(location): return hostname, card, port = location.split('/') chassis = self.root.hw.get_chassis(hostname) # todo - test if port owned by me. if force: chassis.get_card(int(card)).get_port(int(port)).release() try: phy_port = chassis.get_card(int(card)).get_port(int(port)) except KeyError as _: raise TgnError('Physical port {} unreachable'.format(location)) self.set_attributes(commit=True, connectedTo=phy_port.ref) while self.get_attribute('connectedTo') == '::ixNet::OBJ-null': time.sleep(1) if wait_for_up: self.wait_for_up(timeout)
def init_stc(api, logger, install_dir=None, rest_server=None, rest_port=80): """ Create STC object. :param api: tcl/python/rest :type api: trafficgenerator.tgn_utils.ApiType :param logger: python logger object :param install_dir: STC installation directory :param rest_server: rest server address (either stcweb or lab server) :param rest_port: rest server port (either stcweb or lab server) :return: STC object """ if api == ApiType.tcl: stc_api_wrapper = StcTclWrapper(logger, install_dir) elif api == ApiType.python: stc_api_wrapper = StcPythonWrapper(logger, install_dir) elif api == ApiType.rest: stc_api_wrapper = StcRestWrapper(logger, rest_server, rest_port, session_name='session' + str(randint(0, 99))) else: raise TgnError( '{} API not supported - use Tcl, python or REST'.format(api)) return StcApp(logger, api_wrapper=stc_api_wrapper)
def load_config(self, context, ixia_config_file_name): self.ixl.load_config(ixia_config_file_name) self.ixl.repository.test.set_attributes(enableForceOwnership=False) config_elements = self.ixl.repository.get_elements() reservation_ports = {} for port in get_resources_from_reservation(context, 'Generic Traffic Generator Port', f'{PERFECT_STORM_CHASSIS_MODEL}.GenericTrafficGeneratorPort', f'{IXIA_CHASSIS_MODEL}.GenericTrafficGeneratorPort', 'IxVM Virtual Traffic Chassis 2G.VirtualTrafficGeneratorPort'): reservation_ports[get_family_attribute(context, port.Name, 'Logical Name').strip()] = port perfectstorms = [ps.FullAddress for ps in get_resources_from_reservation(context, PERFECT_STORM_CHASSIS_MODEL)] for name, element in config_elements.items(): if name in reservation_ports: location = get_location(reservation_ports[name]) ip, module, port = location.split('/') if ip in perfectstorms: location = f'{ip}/{module}/{int(port) + 1}' self.logger.debug(f'Logical Port {name} will be reserved on Physical location {location}') element.reserve(location) else: elements = reservation_ports.keys() raise TgnError(f'Configuration element "{element}" not found in reservation elements {elements}') self.logger.info('Port Reservation Completed')
def get_statistics(self, context, view_name, output_type): stats_obj = StcStats(view_name) stats_obj.read_stats() statistics = OrderedDict() for obj, obj_values in stats_obj.statistics.items(): statistics[obj.name] = obj_values if output_type.strip().lower() == "json": statistics_str = json.dumps(statistics, indent=4, sort_keys=True, ensure_ascii=False) return json.loads(statistics_str) elif output_type.strip().lower() == "csv": captions = list(list(statistics.values())[0].keys()) output = io.StringIO() w = csv.DictWriter(output, captions) w.writeheader() for obj_values in statistics.values(): w.writerow(obj_values) attach_stats_csv(context, self.logger, view_name, output.getvalue().strip()) return output.getvalue().strip() else: raise TgnError( f'Output type should be CSV/JSON - got "{output_type}"')
def load_config(self, context, stc_config_file_name): self.stc.load_config(stc_config_file_name) config_ports = self.stc.project.get_ports() reservation_ports = {} for port in get_resources_from_reservation( context, f"{STC_CHASSIS_MODEL}.GenericTrafficGeneratorPort"): reservation_ports[get_family_attribute(context, port.Name, "Logical Name")] = port for name, port in config_ports.items(): if name in reservation_ports: address = get_location(reservation_ports[name]) self.logger.debug( f"Logical Port {name} will be reserved on Physical location {address}" ) if "offline-debug" not in reservation_ports[name].Name: port.reserve(address, force=True, wait_for_up=False) else: self.logger.debug( f"Offline debug port {address} - no actual reservation" ) else: raise TgnError( f'Configuration port "{port}" not found in reservation ports {reservation_ports.keys()}' ) self.logger.info("Port Reservation Completed")
def call(self, string, *args): if self.windows_server: result, io_output = self.socket_call(string, *args) if io_output and 'Error:' in io_output: raise TgnError(io_output) return result else: return self.ssh_call(string, *args)
def wait(self): status = self.status() while status != 'TEST_COMPLETED': time.sleep(1) status = self.status() error = self.error() if error: raise TgnError('Error while running test - {}'.format(error))
def wait_quick_test_status(self, name, status=False, timeout=3600): quick_test = self.root.get_quick_tests()[name] results = quick_test.get_child_static('results') for _ in range(timeout): if is_true(results.get_attribute('isRunning')) == status: return results.get_attribute('result') time.sleep(1) raise TgnError('Quick test failed, quick test running state is {} after {} seconds'. format(results.get_attribute('isRunning'), timeout))
def get_list_attribute(self, attribute): """ :return: attribute value as Python list. """ list_attribute = self.api.getListAttribute(self.obj_ref(), attribute) # IXN returns '::ixNet::OK' for invalid attributes. We want error. if list_attribute == ['::ixNet::OK']: raise TgnError(self.ref + ' does not have attribute ' + attribute) return list_attribute
def wait_traffic_state(self, state, timeout): for _ in range(timeout): if self.get_child_static('traffic').get_attribute( 'state') == state: return time.sleep(1) raise TgnError('Traffic failed, traffic is {} after {} seconds'.format( self.get_child_static('traffic').get_attribute('isTrafficRunning'), timeout))
def _wait_for(self, url, timeout): for _ in range(timeout): try: self.get(url) return except TgnError as _: time.sleep(1) raise TgnError('failed to connect - {}'.format( self.get(url).json()['errors']))
def wait_for_states(self, attribute, timeout=40, *states): for _ in range(timeout): if self.get_attribute(attribute).lower() in [ s.lower() for s in states ]: return time.sleep(1) raise TgnError( '{} failed to reach state {}, state is {} after {} seconds'.format( attribute, states, self.get_attribute(attribute), timeout))
def connect(self, ip, port, auth=None): client_version = self.getVersion() self.ixnCommand('connect ' + ip + ' -port ' + str(port) + ' -version ' + client_version) major_client_version = re.findall(r'^[\d]+.[\d]+', client_version)[0] client_version = client_version.split('.')[:2] buildNumber = self.getAttribute(self.getRoot() + '/globals', 'buildNumber') major_server_version = re.findall(r'^[\d]+.[\d]+', buildNumber)[0] if major_client_version != major_server_version: raise TgnError('Client version {} != Server version {}'.format(major_client_version, major_server_version)) return client_version
def action(self, action, timeout=64, *arguments): self.execute(action, (self.ref, ) + arguments) now = time.time() while self.get_attribute('status') != self.action_2_status[ action] and time.time() - now <= timeout: time.sleep(1) if time.time() - now > timeout: raise TgnError('Failed to {} protocols after {} seconds'.format( action, time.time() - now))
def _wait_traffic_states(self, timeout, *states): for _ in range(timeout): if self.get_child_static('traffic').get_attribute( 'state') in states: return time.sleep(1) raise TgnError( 'Traffic failed to reach {} state, traffic is {} after {} seconds'. format(states, self.get_child_static('traffic').get_attribute('state'), timeout))
def _get_pages(self): page = self.ixn_view.get_child_static('page') if is_false(page.get_attribute('isReady')): raise TgnError('"{}" not ready'.format(self.obj_type())) caption = page.get_list_attribute('columnCaptions') rows = [] page.set_attributes(pageSize=50) for page_num in range(1, int(page.get_attribute('totalPages')) + 1): page.set_attributes(commit=True, currentPage=page_num) rows += page.get_list_attribute('pageValues') return caption, rows
def get_attribute(self, attribute): """ :param attribute: requested attributes. :return: attribute value. :raise TgnError: if invalid attribute. """ value = self.api.getAttribute(self.ref, attribute) # IXN returns '::ixNet::OK' for invalid attributes. We want error. if value == '::ixNet::OK': raise TgnError(self.ref + ' does not have attribute ' + attribute) return str(value)
def loadConfig(self, config_file_name): basename = path.basename(config_file_name) with open(config_file_name, mode='rb') as f: configContent = f.read() urlHeadersData = {'content-type': 'application/octet-stream'} uploadUrl = self.root_url + 'ixnetwork/files/' + basename response = self.request(requests.post, uploadUrl, data=configContent, headers=urlHeadersData) if 'id' in response.json(): self.waitForComplete(response) data = {'arg1': basename} self.post(self.root_url + 'ixnetwork/operations/loadConfig', data) for _ in range(80): try: response = self.get(self.server_url + self.session + 'ixnetwork/globals') return except TgnError as _: pass time.sleep(1) raise TgnError('failed to connect - {}'.format( self.get(self.server_url + self.session + 'ixnetwork/globals').json()['errors'])) for _ in range(8): try: response = self.get(self.server_url + self.session + 'ixnetwork/vport') return except TgnError as _: pass time.sleep(1) raise TgnError('failed to connect - {}'.format( self.get(self.server_url + self.session + 'ixnetwork/vport').json()['errors']))
def reserve(self, force=False): """ Reserve port. :param force: True - take forcefully, False - fail if port is reserved by other user """ if not force: try: self.api.call_rc('ixPortTakeOwnership {}'.format(self.uri)) except Exception as _: raise TgnError('Failed to take ownership for port {} current owner is {}'.format(self, self.owner)) else: self.api.call_rc('ixPortTakeOwnership {} force'.format(self.uri))
def wait_for_up(self, timeout=40): """ Wait until port is up and running, including all parameters (admin state, oper state, license etc.). :param timeout: max time to wait for port up. """ self.wait_for_states(timeout, 'up') connectionStatus = self.get_attribute('connectionStatus').strip() if connectionStatus.split(':')[0] != self.get_attribute( 'assignedTo').split(':')[0]: raise TgnError( 'Failed to reach up state, port connection status is {} after {} seconds' .format(connectionStatus, timeout))
def wait_for_states(self, timeout=40, *states): """ Wait until port reaches requested state(s). :param timeout: how long (seconds) to wait for port to come up. :param states: list of requested states. """ for _ in range(timeout): if self.activephy.get_attribute('LinkStatus') in states: return time.sleep(1) raise TgnError('Failed to reserve port, port is {} after {} seconds'. format(self.activephy.get_attribute('LinkStatus'), timeout))
def waitForComplete(self, response, timeout=90): if 'errors' in response.json(): raise TgnError(response.json()['errors'][0]) if response.json()['state'].lower() == 'error': result = ast.literal_eval(response.content.replace( 'null', '""'))['result'].strip() raise TgnError('wait for post {} failed - {}'.format( response.url, result)) if response.json()['state'].lower() == 'success': return for _ in range(timeout): response = requests.get(self.root_url) if type(response.json()) == dict: state = response.json()['state'] else: state = response.json()[0]['state'] if state.lower() not in ['in_progress', 'down']: return time.sleep(1) raise TgnError( '{} operation failed, state is {} after {} seconds'.format( self.session, response.json()['state'], timeout))
def wait_for_states(self, timeout=40, *states): """ Wait until port reaches one of the requested states. :param timeout: max time to wait for requested port states. """ state = self.get_attribute('state') for _ in range(timeout): if state in states: return time.sleep(1) state = self.get_attribute('state') raise TgnError( 'Failed to reach states {}, port state is {} after {} seconds'. format(states, state, timeout))
def init_ixe(api, logger, host, port=4555, rsa_id=None): """ Connect to Tcl Server and Create IxExplorer object. :param api: socket/tcl :type api: trafficgenerator.tgn_utils.ApiType :param logger: python logger object :param host: host (IxTclServer) IP address :param port: Tcl Server port :param rsa_id: full path to RSA ID file for Linux based IxVM :return: IXE object """ if api == ApiType.tcl: raise TgnError('Tcl API not supported in this version.') return IxeApp(logger, IxTclHalApi(TclClient(logger, host, port, rsa_id)))
def connect(self, ip, port): self.server_url = 'http://{}:{}'.format(ip, port) response = self.post(self.server_url + '/api/v1/sessions') self.session = response.json()['links'][0]['href'] + '/' self.root_url = self.server_url + self.session for _ in range(80): try: response = self.get(self.server_url + self.session + 'ixnetwork') return except TgnError as _: pass time.sleep(1) raise TgnError('failed to connect - {}'.format( self.get(self.server_url + self.session + 'ixnetwork').json()['errors']))
def request(self, command, url, **kwargs): kwargs_to_print = copy.deepcopy(kwargs) if 'headers' in kwargs and kwargs['headers'].get( 'content-type', None) == 'application/octet-stream': kwargs_to_print['data'] = 'actual octet-stream not logged...' self.logger.debug('{} - {} - {}'.format(command.__name__, url, kwargs_to_print)) response = command(url, **kwargs) self.logger.debug('{}'.format(response)) if response.status_code >= 400: text = ast.literal_eval(response.text).get( 'errors', None) if response.text else None raise TgnError( 'failed to {} {} {} - status code {} - text - {}'.format( command.__name__, url, kwargs, response.status_code, text)) return response