<commit_before>#!/router/bin/python

# internal libs
import sys
import os
import socket
import errno
import time
import re
import copy
import binascii
from distutils.util import strtobool
from collections import deque, OrderedDict
from json import JSONDecoder
import traceback
import signal

try:
    from . import outer_packages
    from .trex_status_e import TRexStatus
    from .trex_exceptions import *
    from .trex_exceptions import exception_handler
    from .general_utils import *
except Exception as e: # is __main__
    import outer_packages
    from trex_status_e import TRexStatus
    from trex_exceptions import *
    from trex_exceptions import exception_handler
    from general_utils import *

# external libs
import jsonrpclib
from jsonrpclib import ProtocolError, AppError
from enum import Enum



class CTRexClient(object):
    """
    This class defines the client side of the RESTfull interaction with TRex
    """

    def __init__(self, trex_host, max_history_size = 100, filtered_latency_amount = 0.001, trex_daemon_port = 8090, master_daemon_port = 8091, trex_zmq_port = 4500, verbose = False, debug_image = False, trex_args = ''):
        """ 
        Instantiate a TRex client object, and connecting it to listening daemon-server

        :parameters:
             trex_host : str
                a string of the TRex ip address or hostname.
             max_history_size : int
                a number to set the maximum history size of a single TRex run. Each sampling adds a new item to history.

                default value : **100**

             filtered_latency_amount : float
                Ignore high latency for this ammount of packets. (by default take value of 99.9% measurements)

                default value : **0.001**

             trex_daemon_port : int
                the port number on which the trex-daemon server can be reached

                default value: **8090**
             master_daemon_port : int
                the port number on which the master-daemon server can be reached

                default value: **8091**
             trex_zmq_port : int
                the port number on which trex's zmq module will interact with daemon server

                default value: **4500**
             verbose : bool
                sets a verbose output on supported class method.

                default value : **False**
             trex_args : string
                additional arguments passed to TRex. For example, "-w 3 --no-watchdog"

        :raises:
            socket errors, in case server could not be reached.

        """
        try:
            self.trex_host          = socket.gethostbyname(trex_host)
        except: # give it another try
            self.trex_host          = socket.gethostbyname(trex_host)
        self.trex_daemon_port       = trex_daemon_port
        self.master_daemon_port     = master_daemon_port
        self.trex_zmq_port          = trex_zmq_port
        self.seq                    = None
        self._last_sample           = time.time()
        self.__default_user         = get_current_user()
        self.verbose                = verbose
        self.result_obj             = CTRexResult(max_history_size, filtered_latency_amount)
        self.decoder                = JSONDecoder()
        self.history                = jsonrpclib.history.History()
        self.master_daemon_path     = "http://{hostname}:{port}/".format( hostname = self.trex_host, port = master_daemon_port )
        self.master_daemon          = jsonrpclib.Server(self.master_daemon_path, history = self.history)
        self.trex_server_path       = "http://{hostname}:{port}/".format( hostname = self.trex_host, port = trex_daemon_port )
        self.server                 = jsonrpclib.Server(self.trex_server_path, history = self.history)
        self.debug_image            = debug_image
        self.trex_args              = trex_args
        self.sample_to_run_finish   = self.sample_until_finish # alias for legacy


    def add (self, x, y):
        try:
            return self.server.add(x,y)
        except AppError as err:
            self._handle_AppError_exception(err.args[0])
        except ProtocolError:
            raise
        finally:
            self.prompt_verbose_data()

    def start_trex (self, f, d, block_to_success = True, timeout = 40, user = None, trex_development = False, **trex_cmd_options):
        """
        Request to start a TRex run on server in stateful mode.
                
        :parameters:  
            f : str
                a path (on server) for the injected traffic data (.yaml file)
            d : int
                the desired duration of the test. must be at least 30 seconds long.
            block_to_success : bool
                determine if this method blocks until TRex changes state from 'Starting' to either 'Idle' or 'Running'

                default value : **True**
            timeout : int
                maximum time (in seconds) to wait in blocking state until TRex changes state from 'Starting' to either 'Idle' or 'Running'

                default value: **40**
            user : str
                the identity of the the run issuer.
            trex_cmd_options : key, val
                sets desired TRex options using key=val syntax, separated by comma.
                for keys with no value, state key=True

        :return: 
            **True** on success

        :raises:
            + :exc:`ValueError`, in case 'd' parameter inserted with wrong value.
            + :exc:`trex_exceptions.TRexError`, in case one of the trex_cmd_options raised an exception at server.
            + :exc:`trex_exceptions.TRexInUseError`, in case TRex is already taken.
            + :exc:`trex_exceptions.TRexRequestDenied`, in case TRex is reserved for another user than the one trying start TRex.
            + ProtocolError, in case of error in JSON-RPC protocol.
        
        """
        user = user or self.__default_user
        try:
            d = int(d)
        except ValueError:
            raise ValueError('d parameter must be integer, specifying how long TRex run.')

        trex_cmd_options.update( {'f' : f, 'd' : d} )
        if not trex_cmd_options.get('l'):
            self.result_obj.latency_checked = False
        if 'k' in trex_cmd_options:
            timeout += int(trex_cmd_options['k']) # during 'k' seconds TRex stays in 'Starting' state

        self.result_obj.clear_results()
        try:
            issue_time = time.time()
            retval = self.server.start_trex(trex_cmd_options, user, block_to_success, timeout, False, self.debug_image, self.trex_args)
        except AppError as err:
            self._handle_AppError_exception(err.args[0])
        except ProtocolError:
            raise
        finally:
            self.prompt_verbose_data()

        if retval!=0:   
            self.seq = retval   # update seq num only on successful submission
            return True
        else:   # TRex is has been started by another user
            raise TRexInUseError('TRex is already being used by another user or process. Try again once TRex is back in IDLE state.')


    def start_stateless(self, block_to_success = True, timeout = 40, user = None, **trex_cmd_options):
        """
        Request to start a TRex run on server in stateless mode.
                <commit_msg>STF API: fix latency check after it was not checked in previous run<commit_after>#!/router/bin/python

# internal libs
import sys
import os
import socket
import errno
import time
import re
import copy
import binascii
from distutils.util import strtobool
from collections import deque, OrderedDict
from json import JSONDecoder
import traceback
import signal

try:
    from . import outer_packages
    from .trex_status_e import TRexStatus
    from .trex_exceptions import *
    from .trex_exceptions import exception_handler
    from .general_utils import *
except Exception as e: # is __main__
    import outer_packages
    from trex_status_e import TRexStatus
    from trex_exceptions import *
    from trex_exceptions import exception_handler
    from general_utils import *

# external libs
import jsonrpclib
from jsonrpclib import ProtocolError, AppError
from enum import Enum



class CTRexClient(object):
    """
    This class defines the client side of the RESTfull interaction with TRex
    """

    def __init__(self, trex_host, max_history_size = 100, filtered_latency_amount = 0.001, trex_daemon_port = 8090, master_daemon_port = 8091, trex_zmq_port = 4500, verbose = False, debug_image = False, trex_args = ''):
        """ 
        Instantiate a TRex client object, and connecting it to listening daemon-server

        :parameters:
             trex_host : str
                a string of the TRex ip address or hostname.
             max_history_size : int
                a number to set the maximum history size of a single TRex run. Each sampling adds a new item to history.

                default value : **100**

             filtered_latency_amount : float
                Ignore high latency for this ammount of packets. (by default take value of 99.9% measurements)

                default value : **0.001**

             trex_daemon_port : int
                the port number on which the trex-daemon server can be reached

                default value: **8090**
             master_daemon_port : int
                the port number on which the master-daemon server can be reached

                default value: **8091**
             trex_zmq_port : int
                the port number on which trex's zmq module will interact with daemon server

                default value: **4500**
             verbose : bool
                sets a verbose output on supported class method.

                default value : **False**
             trex_args : string
                additional arguments passed to TRex. For example, "-w 3 --no-watchdog"

        :raises:
            socket errors, in case server could not be reached.

        """
        try:
            self.trex_host          = socket.gethostbyname(trex_host)
        except: # give it another try
            self.trex_host          = socket.gethostbyname(trex_host)
        self.trex_daemon_port       = trex_daemon_port
        self.master_daemon_port     = master_daemon_port
        self.trex_zmq_port          = trex_zmq_port
        self.seq                    = None
        self._last_sample           = time.time()
        self.__default_user         = get_current_user()
        self.verbose                = verbose
        self.result_obj             = CTRexResult(max_history_size, filtered_latency_amount)
        self.decoder                = JSONDecoder()
        self.history                = jsonrpclib.history.History()
        self.master_daemon_path     = "http://{hostname}:{port}/".format( hostname = self.trex_host, port = master_daemon_port )
        self.master_daemon          = jsonrpclib.Server(self.master_daemon_path, history = self.history)
        self.trex_server_path       = "http://{hostname}:{port}/".format( hostname = self.trex_host, port = trex_daemon_port )
        self.server                 = jsonrpclib.Server(self.trex_server_path, history = self.history)
        self.debug_image            = debug_image
        self.trex_args              = trex_args
        self.sample_to_run_finish   = self.sample_until_finish # alias for legacy


    def add (self, x, y):
        try:
            return self.server.add(x,y)
        except AppError as err:
            self._handle_AppError_exception(err.args[0])
        except ProtocolError:
            raise
        finally:
            self.prompt_verbose_data()

    def start_trex (self, f, d, block_to_success = True, timeout = 40, user = None, trex_development = False, **trex_cmd_options):
        """
        Request to start a TRex run on server in stateful mode.
                
        :parameters:  
            f : str
                a path (on server) for the injected traffic data (.yaml file)
            d : int
                the desired duration of the test. must be at least 30 seconds long.
            block_to_success : bool
                determine if this method blocks until TRex changes state from 'Starting' to either 'Idle' or 'Running'

                default value : **True**
            timeout : int
                maximum time (in seconds) to wait in blocking state until TRex changes state from 'Starting' to either 'Idle' or 'Running'

                default value: **40**
            user : str
                the identity of the the run issuer.
            trex_cmd_options : key, val
                sets desired TRex options using key=val syntax, separated by comma.
                for keys with no value, state key=True

        :return: 
            **True** on success

        :raises:
            + :exc:`ValueError`, in case 'd' parameter inserted with wrong value.
            + :exc:`trex_exceptions.TRexError`, in case one of the trex_cmd_options raised an exception at server.
            + :exc:`trex_exceptions.TRexInUseError`, in case TRex is already taken.
            + :exc:`trex_exceptions.TRexRequestDenied`, in case TRex is reserved for another user than the one trying start TRex.
            + ProtocolError, in case of error in JSON-RPC protocol.
        
        """
        user = user or self.__default_user
        try:
            d = int(d)
        except ValueError:
            raise ValueError('d parameter must be integer, specifying how long TRex run.')

        trex_cmd_options.update( {'f' : f, 'd' : d} )
        self.result_obj.latency_checked = 'l' in trex_cmd_options
        if 'k' in trex_cmd_options:
            timeout += int(trex_cmd_options['k']) # during 'k' seconds TRex stays in 'Starting' state

        self.result_obj.clear_results()
        try:
            issue_time = time.time()
            retval = self.server.start_trex(trex_cmd_options, user, block_to_success, timeout, False, self.debug_image, self.trex_args)
        except AppError as err:
            self._handle_AppError_exception(err.args[0])
        except ProtocolError:
            raise
        finally:
            self.prompt_verbose_data()

        if retval!=0:   
            self.seq = retval   # update seq num only on successful submission
            return True
        else:   # TRex is has been started by another user
            raise TRexInUseError('TRex is already being used by another user or process. Try again once TRex is back in IDLE state.')


    def start_stateless(self, block_to_success = True, timeout = 40, user = None, **trex_cmd_options):
        """
        Request to start a TRex run on server in stateless mode.
                
{'fraction_non_alphanumeric': 0.06650013502565487, 'fraction_numerical': 0.007156359708344585, 'mean_word_length': 2.0261491317671094, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6817281', 'n_tokens_mistral': 4149, 'n_tokens_neox': 3946, 'n_words': 1343}