summaryrefslogtreecommitdiffstats
path: root/scripts/automation/trex_control_plane/server/trex_server.py
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/automation/trex_control_plane/server/trex_server.py')
-rwxr-xr-xscripts/automation/trex_control_plane/server/trex_server.py640
1 files changed, 640 insertions, 0 deletions
diff --git a/scripts/automation/trex_control_plane/server/trex_server.py b/scripts/automation/trex_control_plane/server/trex_server.py
new file mode 100755
index 00000000..2b718a69
--- /dev/null
+++ b/scripts/automation/trex_control_plane/server/trex_server.py
@@ -0,0 +1,640 @@
+#!/usr/bin/python
+
+
+import os
+import stat
+import sys
+import time
+import outer_packages
+import zmq
+from jsonrpclib.SimpleJSONRPCServer import SimpleJSONRPCServer
+import jsonrpclib
+from jsonrpclib import Fault
+import binascii
+import socket
+import errno
+import signal
+from common.trex_status_e import TRexStatus
+from common.trex_exceptions import *
+import subprocess
+from random import randrange
+import logging
+import threading
+import CCustomLogger
+from trex_launch_thread import AsynchronousTRexSession
+from zmq_monitor_thread import ZmqMonitorSession
+from argparse import ArgumentParser, RawTextHelpFormatter
+from json import JSONEncoder
+import re
+import shlex
+import tempfile
+
+try:
+ from .singleton_daemon import register_socket, run_command
+except:
+ from singleton_daemon import register_socket, run_command
+
+
+# setup the logger
+CCustomLogger.setup_custom_logger('TRexServer')
+logger = logging.getLogger('TRexServer')
+
+class CTRexServer(object):
+ """This class defines the server side of the RESTfull interaction with TRex"""
+ DEFAULT_TREX_PATH = '/auto/proj-pcube-b/apps/PL-b/tools/bp_sim2/v1.55/' #'/auto/proj-pcube-b/apps/PL-b/tools/nightly/trex_latest'
+ TREX_START_CMD = './t-rex-64'
+ DEFAULT_FILE_PATH = '/tmp/trex_files/'
+
+ def __init__(self, trex_path, trex_files_path, trex_host='0.0.0.0', trex_daemon_port=8090, trex_zmq_port=4500, trex_nice=-19):
+ """
+ Parameters
+ ----------
+ trex_host : str
+ a string of the TRex ip address or hostname.
+ default value: machine hostname as fetched from socket.gethostname()
+ trex_daemon_port : int
+ the port number on which the trex-daemon server can be reached
+ default value: 8090
+ trex_zmq_port : int
+ the port number on which trex's zmq module will interact with daemon server
+ default value: 4500
+ nice: int
+ priority of the TRex process
+
+ Instantiate a TRex client object, and connecting it to listening daemon-server
+ """
+ self.TREX_PATH = os.path.abspath(os.path.dirname(trex_path+'/'))
+ self.trex_files_path = os.path.abspath(os.path.dirname(trex_files_path+'/'))
+ self.__check_trex_path_validity()
+ self.__check_files_path_validity()
+ self.trex = CTRex()
+ self.trex_version = None
+ self.trex_host = trex_host
+ self.trex_daemon_port = trex_daemon_port
+ self.trex_zmq_port = trex_zmq_port
+ self.trex_server_path = "http://{hostname}:{port}".format( hostname = trex_host, port = trex_daemon_port )
+ self.start_lock = threading.Lock()
+ self.__reservation = None
+ self.zmq_monitor = ZmqMonitorSession(self.trex, self.trex_zmq_port) # intiate single ZMQ monitor thread for server usage
+ self.trex_nice = int(trex_nice)
+ if self.trex_nice < -20 or self.trex_nice > 19:
+ err = "Parameter 'nice' should be integer in range [-20, 19]"
+ print(err)
+ logger.error(err)
+ raise Exception(err)
+
+ def add(self, x, y):
+ logger.info("Processing add function. Parameters are: {0}, {1} ".format( x, y ))
+ return x + y
+ # return Fault(-10, "")
+
+ def push_file (self, filename, bin_data):
+ logger.info("Processing push_file() command.")
+ try:
+ filepath = os.path.join(self.trex_files_path, os.path.basename(filename))
+ with open(filepath, 'wb') as f:
+ f.write(binascii.a2b_base64(bin_data))
+ logger.info("push_file() command finished. File is saved as %s" % filepath)
+ return True
+ except IOError as inst:
+ logger.error("push_file method failed. " + str(inst))
+ return False
+
+ def connectivity_check (self):
+ logger.info("Processing connectivity_check function.")
+ return True
+
+ def start(self):
+ """This method fires up the daemon server based on initialized parameters of the class"""
+ # initialize the server instance with given resources
+ register_socket('trex_daemon_server')
+ try:
+ print("Firing up TRex REST daemon @ port {trex_port} ...\n".format( trex_port = self.trex_daemon_port ))
+ logger.info("Firing up TRex REST daemon @ port {trex_port} ...".format( trex_port = self.trex_daemon_port ))
+ logger.info("current working dir is: {0}".format(self.TREX_PATH) )
+ logger.info("current files dir is : {0}".format(self.trex_files_path) )
+ logger.debug("Starting TRex server. Registering methods to process.")
+ logger.info(self.get_trex_version(base64 = False))
+ self.server = SimpleJSONRPCServer( (self.trex_host, self.trex_daemon_port) )
+ except socket.error as e:
+ if e.errno == errno.EADDRINUSE:
+ logger.error("TRex server requested address already in use. Aborting server launching.")
+ print("TRex server requested address already in use. Aborting server launching.")
+ raise socket.error(errno.EADDRINUSE, "TRex daemon requested address already in use. "
+ "Server launch aborted. Please make sure no other process is "
+ "using the desired server properties.")
+ elif isinstance(e, socket.gaierror) and e.errno == -3:
+ # handling Temporary failure in name resolution exception
+ raise socket.gaierror(-3, "Temporary failure in name resolution.\n"
+ "Make sure provided hostname has DNS resolving.")
+ else:
+ raise
+
+ # set further functionality and peripherals to server instance
+ self.server.register_function(self.add)
+ self.server.register_function(self.cancel_reservation)
+ self.server.register_function(self.connectivity_check)
+ self.server.register_function(self.connectivity_check, 'check_connectivity') # alias
+ self.server.register_function(self.force_trex_kill)
+ self.server.register_function(self.get_file)
+ self.server.register_function(self.get_files_list)
+ self.server.register_function(self.get_files_path)
+ self.server.register_function(self.get_running_info)
+ self.server.register_function(self.get_running_status)
+ self.server.register_function(self.get_trex_cmds)
+ self.server.register_function(self.get_trex_config)
+ self.server.register_function(self.get_trex_daemon_log)
+ self.server.register_function(self.get_trex_log)
+ self.server.register_function(self.get_trex_version)
+ self.server.register_function(self.is_reserved)
+ self.server.register_function(self.is_running)
+ self.server.register_function(self.kill_all_trexes)
+ self.server.register_function(self.push_file)
+ self.server.register_function(self.reserve_trex)
+ self.server.register_function(self.start_trex)
+ self.server.register_function(self.stop_trex)
+ self.server.register_function(self.wait_until_kickoff_finish)
+ signal.signal(signal.SIGTSTP, self.stop_handler)
+ signal.signal(signal.SIGTERM, self.stop_handler)
+ try:
+ self.zmq_monitor.start()
+ self.server.serve_forever()
+ except KeyboardInterrupt:
+ logger.info("Daemon shutdown request detected." )
+ finally:
+ self.zmq_monitor.join() # close ZMQ monitor thread resources
+ self.server.shutdown()
+ #self.server.server_close()
+
+
+ # get files from Trex server and return their content (mainly for logs)
+ @staticmethod
+ def _pull_file(filepath):
+ try:
+ with open(filepath, 'rb') as f:
+ file_content = f.read()
+ return binascii.b2a_base64(file_content).decode(errors='replace')
+ except Exception as e:
+ err_str = "Can't get requested file %s: %s" % (filepath, e)
+ logger.error(err_str)
+ return Fault(-33, err_str)
+
+ # returns True if given path is under TRex package or under /tmp/trex_files
+ def _check_path_under_TRex_or_temp(self, path):
+ if not os.path.relpath(path, self.trex_files_path).startswith(os.pardir):
+ return True
+ if not os.path.relpath(path, self.TREX_PATH).startswith(os.pardir):
+ return True
+ return False
+
+ # gets the file content encoded base64 either from /tmp/trex_files or TRex server dir
+ def get_file(self, filepath):
+ try:
+ logger.info("Processing get_file() command.")
+ if not self._check_path_under_TRex_or_temp(filepath):
+ raise Exception('Given path should be under current TRex package or /tmp/trex_files')
+ return self._pull_file(filepath)
+ except Exception as e:
+ err_str = "Can't get requested file %s: %s" % (filepath, e)
+ logger.error(err_str)
+ return Fault(-33, err_str)
+
+ # get tuple (dirs, files) with directories and files lists from given path (limited under TRex package or /tmp/trex_files)
+ def get_files_list(self, path):
+ try:
+ logger.info("Processing get_files_list() command, given path: %s" % path)
+ if not self._check_path_under_TRex_or_temp(path):
+ raise Exception('Given path should be under current TRex package or /tmp/trex_files')
+ return os.walk(path).next()[1:3]
+ except Exception as e:
+ err_str = "Error processing get_files_list(): %s" % e
+ logger.error(err_str)
+ return Fault(-33, err_str)
+
+ # get Trex log /tmp/trex.txt
+ def get_trex_log(self):
+ logger.info("Processing get_trex_log() command.")
+ return self._pull_file('/tmp/trex.txt')
+
+ # get /etc/trex_cfg.yaml
+ def get_trex_config(self):
+ logger.info("Processing get_trex_config() command.")
+ return self._pull_file('/etc/trex_cfg.yaml')
+
+ # get daemon log /var/log/trex/trex_daemon_server.log
+ def get_trex_daemon_log (self):
+ logger.info("Processing get_trex_daemon_log() command.")
+ return self._pull_file('/var/log/trex/trex_daemon_server.log')
+
+ # get Trex version from ./t-rex-64 --help (last lines starting with "Version : ...")
+ def get_trex_version (self, base64 = True):
+ try:
+ logger.info("Processing get_trex_version() command.")
+ if not self.trex_version:
+ ret_code, stdout, stderr = run_command('./t-rex-64 --help', cwd = self.TREX_PATH)
+ search_result = re.search('\n\s*(Version\s*:.+)', stdout, re.DOTALL)
+ if not search_result:
+ raise Exception('Could not determine version from ./t-rex-64 --help')
+ self.trex_version = binascii.b2a_base64(search_result.group(1).encode(errors='replace'))
+ if base64:
+ return self.trex_version.decode(errors='replace')
+ else:
+ return binascii.a2b_base64(self.trex_version).decode(errors='replace')
+ except Exception as e:
+ err_str = "Can't get trex version, error: %s" % e
+ logger.error(err_str)
+ return Fault(-33, err_str)
+
+ def stop_handler (self, *args, **kwargs):
+ logger.info("Daemon STOP request detected.")
+ if self.is_running():
+ # in case TRex process is currently running, stop it before terminating server process
+ self.stop_trex(self.trex.get_seq())
+ sys.exit(0)
+
+ def assert_zmq_ok(self):
+ if self.trex.zmq_error:
+ raise Exception('ZMQ thread got error: %s' % self.trex.zmq_error)
+ if not self.zmq_monitor.is_alive():
+ if self.trex.get_status() != TRexStatus.Idle:
+ self.force_trex_kill()
+ raise Exception('ZMQ thread is dead.')
+
+ def is_running (self):
+ run_status = self.trex.get_status()
+ logger.info("Processing is_running() command. Running status is: {stat}".format(stat = run_status) )
+ if run_status==TRexStatus.Running:
+ return True
+ else:
+ return False
+
+ def is_reserved (self):
+ logger.info("Processing is_reserved() command.")
+ return bool(self.__reservation)
+
+ def get_running_status (self):
+ run_status = self.trex.get_status()
+ logger.info("Processing get_running_status() command. Running status is: {stat}".format(stat = run_status) )
+ return { 'state' : run_status.value, 'verbose' : self.trex.get_verbose_status() }
+
+ def get_files_path (self):
+ logger.info("Processing get_files_path() command." )
+ return self.trex_files_path
+
+ def reserve_trex (self, user):
+ if user == "":
+ logger.info("TRex reservation cannot apply to empty string user. Request denied.")
+ return Fault(-33, "TRex reservation cannot apply to empty string user. Request denied.")
+
+ with self.start_lock:
+ logger.info("Processing reserve_trex() command.")
+ if self.is_reserved():
+ if user == self.__reservation['user']:
+ # return True is the same user is asking and already has the resrvation
+ logger.info("the same user is asking and already has the resrvation. Re-reserving TRex.")
+ return True
+
+ logger.info("TRex is already reserved to another user ({res_user}), cannot reserve to another user.".format( res_user = self.__reservation['user'] ))
+ return Fault(-33, "TRex is already reserved to another user ({res_user}). Please make sure TRex is free before reserving it.".format(
+ res_user = self.__reservation['user']) ) # raise at client TRexInUseError
+ elif self.trex.get_status() != TRexStatus.Idle:
+ logger.info("TRex is currently running, cannot reserve TRex unless in Idle state.")
+ return Fault(-13, 'TRex is currently running, cannot reserve TRex unless in Idle state. Please try again when TRex run finished.') # raise at client TRexInUseError
+ else:
+ logger.info("TRex is now reserved for user ({res_user}).".format( res_user = user ))
+ self.__reservation = {'user' : user, 'since' : time.ctime()}
+ logger.debug("Reservation details: "+ str(self.__reservation))
+ return True
+
+ def cancel_reservation (self, user):
+ with self.start_lock:
+ logger.info("Processing cancel_reservation() command.")
+ if self.is_reserved():
+ if self.__reservation['user'] == user:
+ logger.info("TRex reservation to {res_user} has been canceled successfully.".format(res_user = self.__reservation['user']))
+ self.__reservation = None
+ return True
+ else:
+ logger.warning("TRex is reserved to different user than the provided one. Reservation wasn't canceled.")
+ return Fault(-33, "Cancel reservation request is available to the user that holds the reservation. Request denied") # raise at client TRexRequestDenied
+
+ else:
+ logger.info("TRex is not reserved to anyone. No need to cancel anything")
+ assert(self.__reservation is None)
+ return False
+
+ def start_trex(self, trex_cmd_options, user, block_to_success = True, timeout = 40, stateless = False, debug_image = False, trex_args = ''):
+ self.assert_zmq_ok()
+ with self.start_lock:
+ logger.info("Processing start_trex() command.")
+ if self.is_reserved():
+ # check if this is not the user to which TRex is reserved
+ if self.__reservation['user'] != user:
+ logger.info("TRex is reserved to another user ({res_user}). Only that user is allowed to initiate new runs.".format(res_user = self.__reservation['user']))
+ return Fault(-33, "TRex is reserved to another user ({res_user}). Only that user is allowed to initiate new runs.".format(res_user = self.__reservation['user'])) # raise at client TRexRequestDenied
+ elif self.trex.get_status() != TRexStatus.Idle:
+ logger.info("TRex is already taken, cannot create another run until done.")
+ return Fault(-13, '') # raise at client TRexInUseError
+
+ try:
+ server_cmd_data = self.generate_run_cmd(stateless = stateless, debug_image = debug_image, trex_args = trex_args, **trex_cmd_options)
+ self.zmq_monitor.first_dump = True
+ self.trex.start_trex(self.TREX_PATH, server_cmd_data)
+ logger.info("TRex session has been successfully initiated.")
+ if block_to_success:
+ # delay server response until TRex is at 'Running' state.
+ start_time = time.time()
+ trex_state = None
+ while (time.time() - start_time) < timeout :
+ trex_state = self.trex.get_status()
+ if trex_state != TRexStatus.Starting:
+ break
+ else:
+ time.sleep(0.5)
+ self.assert_zmq_ok()
+
+ # check for TRex run started normally
+ if trex_state == TRexStatus.Starting: # reached timeout
+ logger.warning("TimeoutError: TRex initiation outcome could not be obtained, since TRex stays at Starting state beyond defined timeout.")
+ return Fault(-12, 'TimeoutError: TRex initiation outcome could not be obtained, since TRex stays at Starting state beyond defined timeout.') # raise at client TRexWarning
+ elif trex_state == TRexStatus.Idle:
+ return Fault(-11, self.trex.get_verbose_status()) # raise at client TRexError
+
+ # reach here only if TRex is at 'Running' state
+ self.trex.gen_seq()
+ return self.trex.get_seq() # return unique seq number to client
+
+ except TypeError as e:
+ logger.error("TRex command generation failed, probably because either -f (traffic generation .yaml file) and -c (num of cores) was not specified correctly.\nReceived params: {params}".format( params = trex_cmd_options) )
+ raise TypeError('TRex -f (traffic generation .yaml file) and -c (num of cores) must be specified. %s' % e)
+
+
+ def stop_trex(self, seq):
+ logger.info("Processing stop_trex() command.")
+ if self.trex.get_seq()== seq:
+ logger.debug("Abort request legit since seq# match")
+ return self.trex.stop_trex()
+ else:
+ if self.trex.get_status() != TRexStatus.Idle:
+ logger.warning("Abort request is only allowed to process initiated the run. Request denied.")
+
+ return Fault(-33, 'Abort request is only allowed to process initiated the run. Request denied.') # raise at client TRexRequestDenied
+ else:
+ return False
+
+ def force_trex_kill (self):
+ logger.info("Processing force_trex_kill() command. --> Killing TRex session indiscriminately.")
+ return self.trex.stop_trex()
+
+ # returns list of tuples (pid, command line) of running TRex(es)
+ def get_trex_cmds(self):
+ logger.info('Processing get_trex_cmds() command.')
+ ret_code, stdout, stderr = run_command('ps -u root --format pid,comm,cmd')
+ if ret_code:
+ raise Exception('Failed to determine running processes, stderr: %s' % stderr)
+ trex_cmds_list = []
+ for line in stdout.splitlines():
+ pid, proc_name, full_cmd = line.strip().split(' ', 2)
+ pid = pid.strip()
+ full_cmd = full_cmd.strip()
+ if proc_name.find('t-rex-64') >= 0:
+ trex_cmds_list.append((pid, full_cmd))
+ return trex_cmds_list
+
+
+ # Silently tries to kill TRexes with given signal.
+ # Responsibility of client to verify with get_trex_cmds.
+ def kill_all_trexes(self, signal_name):
+ logger.info('Processing kill_all_trexes() command.')
+ trex_cmds_list = self.get_trex_cmds()
+ for pid, cmd in trex_cmds_list:
+ logger.info('Killing with signal %s process %s %s' % (signal_name, pid, cmd))
+ os.kill(int(pid), signal_name)
+
+
+ def wait_until_kickoff_finish (self, timeout = 40):
+ # block until TRex exits Starting state
+ logger.info("Processing wait_until_kickoff_finish() command.")
+ trex_state = None
+ start_time = time.time()
+ while (time.time() - start_time) < timeout :
+ self.assert_zmq_ok()
+ trex_state = self.trex.get_status()
+ if trex_state != TRexStatus.Starting:
+ return
+ sleep(0.1)
+ return Fault(-12, 'TimeoutError: TRex initiation outcome could not be obtained, since TRex stays at Starting state beyond defined timeout.') # raise at client TRexWarning
+
+ def get_running_info (self):
+ self.assert_zmq_ok()
+ logger.info("Processing get_running_info() command.")
+ return self.trex.get_running_info()
+
+
+ def generate_run_cmd (self, iom = 0, export_path="/tmp/trex.txt", stateless = False, debug_image = False, trex_args = '', **kwargs):
+ """ generate_run_cmd(self, iom, export_path, kwargs) -> str
+
+ Generates a custom running command for the kick-off of the TRex traffic generator.
+ Returns a tuple of command (string) and export path (string) to be issued on the trex server
+
+ Parameters
+ ----------
+ iom: int
+ 0 = don't print stats screen to log, 1 = print stats (can generate huge logs)
+ stateless: boolean
+ True = run as stateless, False = require -f and -d arguments
+ kwargs: dictionary
+ Dictionary of parameters for trex. For example: (c=1, nc=True, l_pkt_mode=3).
+ Notice that when sending command line parameters that has -, you need to replace it with _.
+ for example, to have on command line "--l-pkt-mode 3", you need to send l_pkt_mode=3
+ export_path : str
+ Full system path to which the results of the trex-run will be logged.
+
+ """
+ if 'results_file_path' in kwargs:
+ export_path = kwargs['results_file_path']
+ del kwargs['results_file_path']
+ if stateless:
+ kwargs['i'] = True
+
+ # adding additional options to the command
+ trex_cmd_options = ''
+ for key, value in kwargs.items():
+ tmp_key = key.replace('_','-').lstrip('-')
+ dash = ' -' if (len(key)==1) else ' --'
+ if value is True:
+ trex_cmd_options += (dash + tmp_key)
+ elif value is False:
+ continue
+ else:
+ trex_cmd_options += (dash + '{k} {val}'.format( k = tmp_key, val = value ))
+ if trex_args:
+ trex_cmd_options += ' %s' % trex_args
+
+ if not stateless:
+ if 'f' not in kwargs:
+ raise Exception('Argument -f should be specified in stateful command')
+ if 'd' not in kwargs:
+ raise Exception('Argument -d should be specified in stateful command')
+
+ cmd = "{nice}{run_command}{debug_image} --iom {io} {cmd_options} --no-key".format( # -- iom 0 disables the periodic log to the screen (not needed)
+ nice = '' if self.trex_nice == 0 else 'nice -n %s ' % self.trex_nice,
+ run_command = self.TREX_START_CMD,
+ debug_image = '-debug' if debug_image else '',
+ cmd_options = trex_cmd_options,
+ io = iom)
+
+ logger.info("TREX FULL COMMAND: {command}".format(command = cmd) )
+
+ return (cmd, export_path, kwargs.get('d', 0))
+
+
+ def __check_trex_path_validity(self):
+ # check for executable existance
+ if not os.path.exists(self.TREX_PATH+'/t-rex-64'):
+ print("The provided TRex path do not contain an executable TRex file.\nPlease check the path and retry.")
+ logger.error("The provided TRex path do not contain an executable TRex file")
+ exit(-1)
+ # check for executable permissions
+ st = os.stat(self.TREX_PATH+'/t-rex-64')
+ if not bool(st.st_mode & (stat.S_IXUSR ) ):
+ print("The provided TRex path do not contain an TRex file with execution privileges.\nPlease check the files permissions and retry.")
+ logger.error("The provided TRex path do not contain an TRex file with execution privileges")
+ exit(-1)
+ else:
+ return
+
+ def __check_files_path_validity(self):
+ # first, check for path existance. otherwise, try creating it with appropriate credentials
+ if not os.path.exists(self.trex_files_path):
+ try:
+ os.makedirs(self.trex_files_path, 0o660)
+ return
+ except os.error as inst:
+ print("The provided files path does not exist and cannot be created with needed access credentials using root user.\nPlease check the path's permissions and retry.")
+ logger.error("The provided files path does not exist and cannot be created with needed access credentials using root user.")
+ exit(-1)
+ elif os.access(self.trex_files_path, os.W_OK):
+ return
+ else:
+ print("The provided files path has insufficient access credentials for root user.\nPlease check the path's permissions and retry.")
+ logger.error("The provided files path has insufficient access credentials for root user")
+ exit(-1)
+
+class CTRex(object):
+ def __init__(self):
+ self.status = TRexStatus.Idle
+ self.verbose_status = 'TRex is Idle'
+ self.errcode = None
+ self.session = None
+ self.zmq_monitor = None
+ self.zmq_dump = None
+ self.zmq_error = None
+ self.seq = None
+ self.expect_trex = threading.Event()
+ self.encoder = JSONEncoder()
+
+ def get_status(self):
+ return self.status
+
+ def set_status(self, new_status):
+ self.status = new_status
+
+ def get_verbose_status(self):
+ return self.verbose_status
+
+ def set_verbose_status(self, new_status):
+ self.verbose_status = new_status
+
+ def gen_seq (self):
+ self.seq = randrange(1,1000)
+
+ def get_seq (self):
+ return self.seq
+
+ def get_running_info (self):
+ if self.status == TRexStatus.Running:
+ return self.encoder.encode(self.zmq_dump)
+ else:
+ logger.info("TRex isn't running. Running information isn't available.")
+ if self.status == TRexStatus.Idle:
+ if self.errcode is not None: # some error occured
+ logger.info("TRex is in Idle state, with errors. returning fault")
+ return Fault(self.errcode, self.verbose_status) # raise at client relevant exception, depending on the reason the error occured
+ else:
+ logger.info("TRex is in Idle state, no errors. returning {}")
+ return u'{}'
+
+ return Fault(-12, self.verbose_status) # raise at client TRexWarning, indicating TRex is back to Idle state or still in Starting state
+
+ def stop_trex(self):
+ if self.status == TRexStatus.Idle:
+ # TRex isn't running, nothing to abort
+ logger.info("TRex isn't running. No need to stop anything.")
+ if self.errcode is not None: # some error occurred, notify client despite TRex already stopped
+ return Fault(self.errcode, self.verbose_status) # raise at client relevant exception, depending on the reason the error occured
+ return False
+ else:
+ # handle stopping TRex's run
+ self.session.join()
+ logger.info("TRex session has been successfully aborted.")
+ return True
+
+ def start_trex(self, trex_launch_path, trex_cmd):
+ self.set_status(TRexStatus.Starting)
+ logger.info("TRex running state changed to 'Starting'.")
+ self.set_verbose_status('TRex is starting (data is not available yet)')
+
+ self.errcode = None
+ self.session = AsynchronousTRexSession(self, trex_launch_path, trex_cmd)
+ self.session.start()
+ self.expect_trex.set()
+# self.zmq_monitor= ZmqMonitorSession(self, zmq_port)
+# self.zmq_monitor.start()
+
+
+
+def generate_trex_parser ():
+ default_path = os.path.abspath(os.path.join(outer_packages.CURRENT_PATH, os.pardir, os.pardir, os.pardir))
+ default_files_path = os.path.abspath(CTRexServer.DEFAULT_FILE_PATH)
+
+ parser = ArgumentParser(description = 'Run server application for TRex traffic generator',
+ formatter_class = RawTextHelpFormatter,
+ usage = """
+trex_daemon_server [options]
+""" )
+
+ parser.add_argument('-v', '--version', action='version', version='%(prog)s 1.0')
+ parser.add_argument("-p", "--daemon-port", type=int, default = 8090, metavar="PORT", dest="daemon_port",
+ help="Select port on which the daemon runs.\nDefault port is 8090.", action="store")
+ parser.add_argument("-z", "--zmq-port", dest="zmq_port", type=int,
+ action="store", help="Select port on which the ZMQ module listens to TRex.\nDefault port is 4500.", metavar="PORT",
+ default = 4500)
+ parser.add_argument("-t", "--trex-path", dest="trex_path",
+ action="store", help="Specify the compiled TRex directory from which TRex would run.\nDefault path is: {def_path}.".format( def_path = default_path ),
+ metavar="PATH", default = default_path )
+ parser.add_argument("-f", "--files-path", dest="files_path",
+ action="store", help="Specify a path to directory on which pushed files will be saved at.\nDefault path is: {def_path}.".format( def_path = default_files_path ),
+ metavar="PATH", default = default_files_path )
+ parser.add_argument("--trex-host", dest="trex_host",
+ action="store", help="Specify a hostname to be registered as the TRex server.\n"
+ "Default is to bind all IPs using '0.0.0.0'.",
+ metavar="HOST", default = '0.0.0.0')
+ parser.add_argument('-n', '--nice', dest='nice', action="store", default = -19, type = int,
+ help="Determine the priority TRex process [-20, 19] (lower = higher priority)\nDefault is -19.")
+ return parser
+
+trex_parser = generate_trex_parser()
+
+def do_main_program ():
+
+ args = trex_parser.parse_args()
+ server = CTRexServer(trex_path = args.trex_path, trex_files_path = args.files_path,
+ trex_host = args.trex_host, trex_daemon_port = args.daemon_port,
+ trex_zmq_port = args.zmq_port, trex_nice = args.nice)
+ server.start()
+
+
+if __name__ == "__main__":
+ do_main_program()
+