From 330cf8f7950027efe7b4bbc96a7ee1af3ee0b10a Mon Sep 17 00:00:00 2001 From: Dan Klein Date: Sat, 9 Apr 2016 13:34:35 +0300 Subject: basic modifications for TRex tui to support toggle filtering on ports --- .../trex_control_plane/stl/console/trex_tui.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'scripts/automation/trex_control_plane/stl') diff --git a/scripts/automation/trex_control_plane/stl/console/trex_tui.py b/scripts/automation/trex_control_plane/stl/console/trex_tui.py index 88c53d10..975017a5 100644 --- a/scripts/automation/trex_control_plane/stl/console/trex_tui.py +++ b/scripts/automation/trex_control_plane/stl/console/trex_tui.py @@ -13,6 +13,8 @@ else: from trex_stl_lib.utils.text_opts import * from trex_stl_lib.utils import text_tables from trex_stl_lib import trex_stl_stats +import trex_root_path +from common.filters import ToggleFilter # for STL exceptions from trex_stl_lib.api import * @@ -65,10 +67,10 @@ class TrexTUIDashBoard(TrexTUIPanel): self.key_actions['-'] = {'action': self.action_lower, 'legend': 'low 5%', 'show': True} self.ports = self.stateless_client.get_all_ports() - + self.toggle_filter = ToggleFilter(self.ports) def show (self): - stats = self.stateless_client._get_formatted_stats(self.ports) + stats = self.stateless_client._get_formatted_stats(self.toggle_filter.filter_items()) # print stats to screen for stat_type, stat_data in stats.items(): text_tables.print_table_with_header(stat_data.text_table, stat_type) @@ -289,7 +291,7 @@ class TrexTUIPanelManager(): self.key_actions['s'] = {'action': self.action_show_sstats, 'legend': 'streams stats', 'show': True} for port_id in self.ports: - self.key_actions[str(port_id)] = {'action': self.action_show_port(port_id), 'legend': 'port {0}'.format(port_id), 'show': False} + self.key_actions[str(port_id)] = {'action': self.action_toggle_port(port_id), 'legend': 'port {0}'.format(port_id), 'show': False} self.panels['port {0}'.format(port_id)] = TrexTUIPort(self, port_id) # start with dashboard @@ -387,6 +389,15 @@ class TrexTUIPanelManager(): return action_show_port_x + def action_toggle_port(self, port_id): + def action_toggle_port_x(): + self.panels['dashboard'].toggle_filter.toggle_item(port_id) + self.init() + return "" + + return action_toggle_port_x + + def action_show_sstats (self): self.main_panel = self.panels['sstats'] -- cgit From 882bc200c58a18a1eabd7b5db6c0ee7e6e5068f1 Mon Sep 17 00:00:00 2001 From: imarom Date: Sun, 17 Apr 2016 14:30:58 +0300 Subject: TUI might crash - do not include unicode chars if stdout encoding is not 'UTF-8' also, some fixes for the TUI port screen --- scripts/automation/trex_control_plane/stl/console/trex_tui.py | 11 ++++++++--- .../trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py | 11 ++++++++++- 2 files changed, 18 insertions(+), 4 deletions(-) (limited to 'scripts/automation/trex_control_plane/stl') diff --git a/scripts/automation/trex_control_plane/stl/console/trex_tui.py b/scripts/automation/trex_control_plane/stl/console/trex_tui.py index effcf55e..cbaae392 100644 --- a/scripts/automation/trex_control_plane/stl/console/trex_tui.py +++ b/scripts/automation/trex_control_plane/stl/console/trex_tui.py @@ -73,7 +73,10 @@ class TrexTUIDashBoard(TrexTUIPanel): self.key_actions['o'] = {'action': self.action_show_owned, 'legend': 'owned ports', 'show': True} self.key_actions['a'] = {'action': self.action_show_all, 'legend': 'all ports', 'show': True} - self.ports_filter = self.FILTER_ALL + if self.stateless_client.get_acquired_ports(): + self.ports_filter = self.FILTER_ACQUIRED + else: + self.ports_filter = self.FILTER_ALL def get_ports (self): @@ -99,7 +102,7 @@ class TrexTUIDashBoard(TrexTUIPanel): allowed['o'] = self.key_actions['o'] allowed['a'] = self.key_actions['a'] - if self.ports_filter == self.FILTER_ALL: + if self.ports_filter == self.FILTER_ALL and self.stateless_client.get_acquired_ports() != self.stateless_client.get_all_ports(): return allowed if len(self.stateless_client.get_transmitting_ports()) > 0: @@ -201,7 +204,7 @@ class TrexTUIPort(TrexTUIPanel): allowed['c'] = self.key_actions['c'] allowed['t'] = self.key_actions['t'] - if self.stateless_client.is_all_ports_acquired(): + if self.port_id not in self.stateless_client.get_acquired_ports(): return allowed if self.port.state == self.port.STATE_TX: @@ -535,7 +538,9 @@ class TrexTUI(): sys.stdout = old_stdout self.clear_screen() + print(mystdout.getvalue()) + sys.stdout.flush() self.draw_policer = 0 diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py index 6b1185ef..4057c50d 100644 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py @@ -201,6 +201,10 @@ class CTRexInfoGenerator(object): def _get_rational_block_char(value, range_start, interval): # in Konsole, utf-8 is sometimes printed with artifacts, return ascii for now #return 'X' if value >= range_start + float(interval) / 2 else ' ' + + if sys.__stdout__.encoding != 'UTF-8': + return 'X' if value >= range_start + float(interval) / 2 else ' ' + value -= range_start ratio = float(value) / interval if ratio <= 0.0625: @@ -532,7 +536,12 @@ class CTRexStats(object): v = self.get_trend(field, use_raw) value = abs(v) - arrow = u'\u25b2' if v > 0 else u'\u25bc' + + # use arrows if utf-8 is supported + if sys.__stdout__.encoding == 'UTF-8': + arrow = u'\u25b2' if v > 0 else u'\u25bc' + else: + arrow = '' if sys.version_info < (3,0): arrow = arrow.encode('utf-8') -- cgit From 1fa7b64c13e6c485926eba5c40bd198af738e365 Mon Sep 17 00:00:00 2001 From: imarom Date: Mon, 18 Apr 2016 13:13:00 +0300 Subject: simple intro while connecting to the server --- .../trex_control_plane/stl/console/trex_console.py | 29 ++++++++++++++++++++-- .../stl/trex_stl_lib/trex_stl_client.py | 5 ++++ .../stl/trex_stl_lib/utils/text_opts.py | 13 +++------- 3 files changed, 35 insertions(+), 12 deletions(-) (limited to 'scripts/automation/trex_control_plane/stl') diff --git a/scripts/automation/trex_control_plane/stl/console/trex_console.py b/scripts/automation/trex_control_plane/stl/console/trex_console.py index 2b53b7ec..00d2a028 100755 --- a/scripts/automation/trex_control_plane/stl/console/trex_console.py +++ b/scripts/automation/trex_control_plane/stl/console/trex_console.py @@ -289,7 +289,7 @@ class TRexConsole(TRexGeneralCmd): @verify_connected def do_ping (self, line): '''Ping the server\n''' - self.stateless_client.ping() + self.stateless_client.ping_line(line) # set verbose on / off @@ -774,7 +774,29 @@ def setParserOptions(): return parser - +# a simple info printed on log on +def show_intro (logger, c): + x = c.get_server_system_info() + ver = c.get_server_version().get('version', 'N/A') + + # find out which NICs the server has + port_types = {} + for port in x['ports']: + key = (port['speed'], port['driver']) + if not key in port_types: + port_types[key] = 0 + port_types[key] += 1 + + port_line = '' + for k, v in port_types.items(): + port_line += "{0} x {1}Gbps @ {2}".format(v, k[0], k[1]) + + logger.log(format_text("\nServer Info:\n", 'underline')) + logger.log("Server version: {:>}".format(format_text(ver, 'bold'))) + logger.log("Server CPU: {:>}".format(format_text("{:>} x {:>}".format(x.get('dp_core_count'), x.get('core_type')), 'bold'))) + logger.log("Ports count: {:>}".format(format_text(port_line, 'bold'))) + + def main(): parser = setParserOptions() options = parser.parse_args() @@ -824,6 +846,9 @@ def main(): if options.readonly: logger.log(format_text("\nRead only mode - only few commands will be available", 'bold')) + show_intro(logger, stateless_client) + + # a script mode if options.batch: cont = run_script_file(options.batch[0], stateless_client) diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py index aa95f037..12ed1f81 100755 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py @@ -2038,6 +2038,11 @@ class STLClient(object): return wrap + @__console + def ping_line (self, line): + '''pings the server''' + self.ping() + return True @__console def connect_line (self, line): diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/text_opts.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/text_opts.py index bc2d44f4..5c0dfb14 100644 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/text_opts.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/text_opts.py @@ -124,16 +124,9 @@ def underline(text): def text_attribute(text, attribute): - if isinstance(text, str): - return "{start}{txt}{stop}".format(start=TEXT_CODES[attribute]['start'], - txt=text, - stop=TEXT_CODES[attribute]['end']) - elif isinstance(text, unicode): - return u"{start}{txt}{stop}".format(start=TEXT_CODES[attribute]['start'], - txt=text, - stop=TEXT_CODES[attribute]['end']) - else: - raise Exception("not a string") + return "{start}{txt}{stop}".format(start=TEXT_CODES[attribute]['start'], + txt=text, + stop=TEXT_CODES[attribute]['end']) FUNC_DICT = {'blue': blue, -- cgit From 7e5993941829e5fd1bb9ab3c6ac624d9aa800c37 Mon Sep 17 00:00:00 2001 From: imarom Date: Mon, 18 Apr 2016 15:12:05 +0300 Subject: support for reacquire command also better sync with the server about ownership of ports --- .../trex_control_plane/stl/console/trex_console.py | 3 + .../stl/trex_stl_lib/trex_stl_client.py | 70 ++++++++++++++++++---- .../stl/trex_stl_lib/trex_stl_port.py | 12 +++- 3 files changed, 70 insertions(+), 15 deletions(-) (limited to 'scripts/automation/trex_control_plane/stl') diff --git a/scripts/automation/trex_control_plane/stl/console/trex_console.py b/scripts/automation/trex_control_plane/stl/console/trex_console.py index 00d2a028..589f1d35 100755 --- a/scripts/automation/trex_control_plane/stl/console/trex_console.py +++ b/scripts/automation/trex_control_plane/stl/console/trex_console.py @@ -421,6 +421,9 @@ class TRexConsole(TRexGeneralCmd): '''Release ports\n''' self.stateless_client.release_line(line) + def do_reacquire (self, line): + '''reacquire all the ports under your logged user name''' + self.stateless_client.reacquire_line(line) def help_acquire (self): self.do_acquire("-h") diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py index 12ed1f81..76fbf3b8 100755 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py @@ -264,22 +264,55 @@ class EventsHandler(object): self.__async_event_port_job_done(port_id) show_event = True - # port was stolen... + # port was acquired - maybe stolen... elif (type == 5): session_id = data['session_id'] - # false alarm, its us + port_id = int(data['port_id']) + who = data['who'] + force = data['force'] + + # if we hold the port and it was not taken by this session - show it + if port_id in self.client.get_acquired_ports() and session_id != self.client.session_id: + show_event = True + + # format the thief/us... if session_id == self.client.session_id: - return + user = 'you' + elif who == self.client.username: + user = 'another session of you' + else: + user = "'{0}'".format(who) - port_id = int(data['port_id']) - who = data['who'] + if force: + ev = "Port {0} was forcely taken by {1}".format(port_id, user) + else: + ev = "Port {0} was taken by {1}".format(port_id, user) - ev = "Port {0} was forcely taken by '{1}'".format(port_id, who) + # call the handler in case its not this session + if session_id != self.client.session_id: + self.__async_event_port_acquired(port_id, who) + + + # port was released + elif (type == 6): + port_id = int(data['port_id']) + who = data['who'] + session_id = data['session_id'] + + if session_id == self.client.session_id: + user = 'you' + elif who == self.client.username: + user = 'another session of you' + else: + user = "'{0}'".format(who) + + ev = "Port {0} was released by {1}".format(port_id, user) + + # call the handler in case its not this session + if session_id != self.client.session_id: + self.__async_event_port_released(port_id) - # call the handler - self.__async_event_port_forced_acquired(port_id, who) - show_event = True # server stopped elif (type == 100): @@ -317,9 +350,11 @@ class EventsHandler(object): self.client.ports[port_id].async_event_port_resumed() - def __async_event_port_forced_acquired (self, port_id, who): - self.client.ports[port_id].async_event_forced_acquired(who) + def __async_event_port_acquired (self, port_id, who): + self.client.ports[port_id].async_event_acquired(who) + def __async_event_port_released (self, port_id): + self.client.ports[port_id].async_event_released() def __async_event_server_stopped (self): self.client.connected = False @@ -506,7 +541,7 @@ class STLClient(object): # API classes - self.api_vers = [ {'type': 'core', 'major': 1, 'minor':1 } + self.api_vers = [ {'type': 'core', 'major': 1, 'minor':2 } ] self.api_h = {'core': None} @@ -2121,6 +2156,17 @@ class STLClient(object): return True + @__console + def reacquire_line (self, line): + '''reacquire all the ports under your username''' + my_unowned_ports = list_difference([k for k, v in self.ports.items() if v.get_owner() == self.username], self.get_acquired_ports()) + if not my_unowned_ports: + self.logger.log("reacquire - no unowned ports under '{0}'".format(self.username)) + return + + self.acquire(ports = my_unowned_ports, force = True) + return True + @__console def disconnect_line (self, line): self.disconnect() diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py index 6f6f50b1..16e55d73 100644 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py @@ -96,9 +96,12 @@ class Port(object): "handler": self.handler} rc = self.transmit("release", params) - self.handler = None - + if rc.good(): + + self.handler = None + self.owner = '' + return self.ok() else: return self.err(rc.err()) @@ -679,7 +682,10 @@ class Port(object): if not self.is_acquired(): self.state = self.STATE_TX - def async_event_forced_acquired (self, who): + def async_event_acquired (self, who): self.handler = None self.owner = who + def async_event_released (self): + self.owner = '' + -- cgit From b12cc7fda4f8c488800696abdb2fba7c3cfc82a4 Mon Sep 17 00:00:00 2001 From: imarom Date: Mon, 18 Apr 2016 15:18:59 +0300 Subject: minor fix --- .../trex_control_plane/stl/console/trex_console.py | 3 +++ .../trex_control_plane/stl/trex_stl_lib/trex_stl_client.py | 13 ++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) (limited to 'scripts/automation/trex_control_plane/stl') diff --git a/scripts/automation/trex_control_plane/stl/console/trex_console.py b/scripts/automation/trex_control_plane/stl/console/trex_console.py index 589f1d35..a126bf35 100755 --- a/scripts/automation/trex_control_plane/stl/console/trex_console.py +++ b/scripts/automation/trex_control_plane/stl/console/trex_console.py @@ -431,6 +431,9 @@ class TRexConsole(TRexGeneralCmd): def help_release (self): self.do_release("-h") + def help_reacquire (self): + self.do_reacquire("-h") + ############### start def complete_start(self, text, line, begidx, endidx): diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py index 76fbf3b8..63d77637 100755 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py @@ -2158,7 +2158,17 @@ class STLClient(object): @__console def reacquire_line (self, line): - '''reacquire all the ports under your username''' + '''reacquire all the ports under your username which are not acquired by your session''' + + parser = parsing_opts.gen_parser(self, + "reacquire", + self.reacquire_line.__doc__) + + opts = parser.parse_args(line.split()) + if opts is None: + return + + # find all the on-owned ports under your name my_unowned_ports = list_difference([k for k, v in self.ports.items() if v.get_owner() == self.username], self.get_acquired_ports()) if not my_unowned_ports: self.logger.log("reacquire - no unowned ports under '{0}'".format(self.username)) @@ -2167,6 +2177,7 @@ class STLClient(object): self.acquire(ports = my_unowned_ports, force = True) return True + @__console def disconnect_line (self, line): self.disconnect() -- cgit From e6d1ca8bc126b2efc5a15268cd2d9926f1be3ab9 Mon Sep 17 00:00:00 2001 From: imarom Date: Mon, 18 Apr 2016 15:40:17 +0300 Subject: portattr console command fix --- .../trex_control_plane/stl/trex_stl_lib/trex_stl_client.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'scripts/automation/trex_control_plane/stl') diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py index 63d77637..77fa40bb 100755 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py @@ -2553,15 +2553,20 @@ class STLClient(object): '''Sets port attributes ''' parser = parsing_opts.gen_parser(self, - "port", + "port_attr", self.set_port_attr_line.__doc__, parsing_opts.PORT_LIST_WITH_ALL, parsing_opts.PROMISCUOUS_SWITCH) - opts = parser.parse_args(line.split()) + opts = parser.parse_args(line.split(), default_ports = self.get_acquired_ports(), verify_acquired = True) if opts is None: return + # if no attributes - fall back to printing the status + if opts.prom is None: + self.show_stats_line("--ps --port {0}".format(' '.join(str(port) for port in opts.ports))) + return + self.set_port_attr(opts.ports, opts.prom) @@ -2654,5 +2659,4 @@ class STLClient(object): if opts.clear: self.clear_events() - self.logger.log(format_text("\nEvent log was cleared\n")) - + \ No newline at end of file -- cgit From f0d4ff5c450489c3ec6adb7f79896df75df2bd6b Mon Sep 17 00:00:00 2001 From: imarom Date: Tue, 19 Apr 2016 13:30:25 +0300 Subject: minor fix to TUI with no ports --- .../trex_control_plane/stl/console/trex_tui.py | 36 ++++++++-------------- 1 file changed, 13 insertions(+), 23 deletions(-) (limited to 'scripts/automation/trex_control_plane/stl') diff --git a/scripts/automation/trex_control_plane/stl/console/trex_tui.py b/scripts/automation/trex_control_plane/stl/console/trex_tui.py index 231eff93..0c3ea8d6 100644 --- a/scripts/automation/trex_control_plane/stl/console/trex_tui.py +++ b/scripts/automation/trex_control_plane/stl/console/trex_tui.py @@ -70,10 +70,9 @@ class TrexTUIDashBoard(TrexTUIPanel): self.key_actions['c'] = {'action': self.action_clear, 'legend': 'clear', 'show': True} self.key_actions['p'] = {'action': self.action_pause, 'legend': 'pause', 'show': True, 'color': 'red'} self.key_actions['r'] = {'action': self.action_resume, 'legend': 'resume', 'show': True, 'color': 'blue'} - self.key_actions['+'] = {'action': self.action_raise, 'legend': 'up 5%', 'show': True} - self.key_actions['-'] = {'action': self.action_lower, 'legend': 'low 5%', 'show': True} self.key_actions['o'] = {'action': self.action_show_owned, 'legend': 'owned ports', 'show': True} + self.key_actions['n'] = {'action': self.action_reset_view, 'legend': 'reset view', 'show': True} self.key_actions['a'] = {'action': self.action_show_all, 'legend': 'all ports', 'show': True} # register all the ports to the toggle action @@ -103,25 +102,29 @@ class TrexTUIDashBoard(TrexTUIPanel): def get_key_actions (self): allowed = OrderedDict() - allowed['c'] = self.key_actions['c'] + + allowed['n'] = self.key_actions['n'] allowed['o'] = self.key_actions['o'] allowed['a'] = self.key_actions['a'] for i in self.ports: allowed[str(i)] = self.key_actions[str(i)] + if self.get_showed_ports(): + allowed['c'] = self.key_actions['c'] + # if not all ports are acquired - no operations if not (set(self.get_showed_ports()) <= set(self.stateless_client.get_acquired_ports())): return allowed + # if any/some ports can be resumed + if set(self.get_showed_ports()) & set(self.stateless_client.get_paused_ports()): + allowed['r'] = self.key_actions['r'] + # if any/some ports are transmitting - support those actions if set(self.get_showed_ports()) & set(self.stateless_client.get_transmitting_ports()): allowed['p'] = self.key_actions['p'] - allowed['+'] = self.key_actions['+'] - allowed['-'] = self.key_actions['-'] - if set(self.get_showed_ports()) & set(self.stateless_client.get_paused_ports()): - allowed['r'] = self.key_actions['r'] return allowed @@ -146,24 +149,10 @@ class TrexTUIDashBoard(TrexTUIPanel): return "" - def action_raise (self): - try: - self.stateless_client.update(mult = "5%+", ports = self.get_showed_ports()) - except STLError: - pass - - return "" - - - def action_lower (self): - try: - self.stateless_client.update(mult = "5%-", ports = self.get_showed_ports()) - except STLError: - pass - + def action_reset_view (self): + self.toggle_filter.reset() return "" - def action_show_owned (self): self.toggle_filter.reset() self.toggle_filter.toggle_items(*self.stateless_client.get_acquired_ports()) @@ -280,6 +269,7 @@ class TrexTUIPanelManager(): self.legend += "\n{:<12}".format(self.main_panel.get_name() + ":") + for k, v in self.main_panel.get_key_actions().items(): if v['show']: x = "'{0}' - {1}, ".format(k, v['legend']) -- cgit From e831a539aebac71d8f00c400416f4bef51108610 Mon Sep 17 00:00:00 2001 From: Yaroslav Brustinov Date: Fri, 29 Apr 2016 17:07:14 +0300 Subject: regression: add GA --- .../stl/trex_stl_lib/utils/GAObjClass.py | 295 +++++++++++++++++++++ 1 file changed, 295 insertions(+) create mode 100755 scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/GAObjClass.py (limited to 'scripts/automation/trex_control_plane/stl') diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/GAObjClass.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/GAObjClass.py new file mode 100755 index 00000000..3101b45d --- /dev/null +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/GAObjClass.py @@ -0,0 +1,295 @@ +#import requests # need external lib for that +try: # Python2 + import Queue + from urllib2 import * +except: # Python3 + import queue as Queue + from urllib.request import * + from urllib.error import * +import threading +import sys +from time import sleep + +""" +GAObjClass is a class destined to send Google Analytics Information. + +cid - unique number per user. +command - the Event Category rubric appears on site. type: TEXT +action - the Event Action rubric appears on site - type: TEXT +label - the Event Label rubric - type: TEXT +value - the event value metric - type: INTEGER + +QUOTAS: +1 single payload - up to 8192Bytes +batched: +A maximum of 20 hits can be specified per request. +The total size of all hit payloads cannot be greater than 16K bytes. +No single hit payload can be greater than 8K bytes. +""" + +url_single = 'http://www.google-analytics.com/collect' #sending single event +url_batched = 'http://www.google-analytics.com/batch' #sending batched events +url_debug = 'http://www.google-analytics.com/debug/collect' #verifying hit is valid +url_conn = 'http://172.217.2.196' # testing internet connection to this address (google-analytics server) + + +#..................................................................class GA_EVENT_ObjClass................................................................ +class GA_EVENT_ObjClass: + def __init__(self,cid,trackerID,command,action,label,value,appName,appVer): + self.cid = cid + self.trackerID = trackerID + self.command = command + self.action = action + self.label = label + self.value = value + self.appName = appName + self.appVer = appVer + self.generate_payload() + self.size = sys.getsizeof(self.payload) + + def generate_payload(self): + self.payload ='v=1&t=event&tid='+str(self.trackerID) + self.payload+='&cid='+str(self.cid) + self.payload+='&ec='+str(self.command) + self.payload+='&ea='+str(self.action) + self.payload+='&el='+str(self.label) + self.payload+='&ev='+str(self.value) + self.payload+='&an='+str(self.appName) + self.payload+='&av='+str(self.appVer) + +#..................................................................class GA_EXCEPTION_ObjClass................................................................ +#ExceptionFatal - BOOLEAN +class GA_EXCEPTION_ObjClass: + def __init__(self,cid,trackerID,ExceptionName,ExceptionFatal,appName,appVer): + self.cid = cid + self.trackerID = trackerID + self.ExceptionName = ExceptionName + self.ExceptionFatal = ExceptionFatal + self.appName = appName + self.appVer = appVer + self.generate_payload() + + def generate_payload(self): + self.payload ='v=1&t=exception&tid='+str(self.trackerID) + self.payload+='&cid='+str(self.cid) + self.payload+='&exd='+str(self.ExceptionName) + self.payload+='&exf='+str(self.ExceptionFatal) + self.payload+='&an='+str(self.appName) + self.payload+='&av='+str(self.appVer) + +#.....................................................................class ga_Thread................................................................. +""" + +Google analytics thread manager: + +will report and empty queue of google analytics items to GA server, every Timeout (parameter given on initialization) +will perform connectivity check every timeout*10 seconds + + +""" + +class ga_Thread (threading.Thread): + def __init__(self,threadID,gManager): + threading.Thread.__init__(self) + self.threadID = threadID + self.gManager = gManager + + def run(self): + keepAliveCounter=0 + #sys.stdout.write('thread started \n') + #sys.stdout.flush() + while True: + if (keepAliveCounter==10): + keepAliveCounter=0 + if (self.gManager.internet_on()==True): + self.gManager.connectedToInternet=1 + else: + self.gManager.connectedToInternet=0 + sleep(self.gManager.Timeout) + keepAliveCounter+=1 + if not self.gManager.GA_q.empty(): + self.gManager.threadLock.acquire(1) +# sys.stdout.write('lock acquired: reporting to GA \n') +# sys.stdout.flush() + if (self.gManager.connectedToInternet==1): + self.gManager.emptyAndReportQ() + self.gManager.threadLock.release() +# sys.stdout.write('finished \n') +# sys.stdout.flush() + + + +#.....................................................................class GAmanager................................................................. +""" + +Google ID - specify tracker property, example: UA-75220362-2 (when the suffix '2' specifies the analytics property profile) + +UserID - unique userID, this will differ between users on GA + +appName - s string to determine app name + +appVer - a string to determine app version + +QueueSize - the size of the queue that holds reported items. once the Queue is full: + on blocking mode: + will block program until next submission to GA server, which will make new space + on non-blocking mode: + will drop new requests + +Timout - the timeout the queue uses between data transmissions. Timeout should be shorter than the time it takes to generate 20 events. MIN VALUE = 11 seconds + +User Permission - the user must accept data transmission, use this flag as 1/0 flag, when UserPermission=1 allows data collection + +BlockingMode - set to 1 if you wish every Google Analytic Object will be submitted and processed, with no drops allowed. + this will block the running of the program until every item is processed + +*** Restriction - Google's restriction for amount of packages being sent per session per second is: 1 event per second, per session. session length is 30min *** +""" +class GAmanager: + def __init__(self,GoogleID,UserID,appName,appVer,QueueSize,Timeout,UserPermission,BlockingMode): + self.UserID = UserID + self.GoogleID = GoogleID + self.QueueSize = QueueSize + self.Timeout = Timeout + self.appName = appName + self.appVer = appVer + self.UserPermission = UserPermission + self.GA_q = Queue.Queue(QueueSize) + self.thread = ga_Thread(UserID,self) + self.threadLock = threading.Lock() + self.BlockingMode = BlockingMode + self.connectedToInternet =0 + if (self.internet_on()==True): +# sys.stdout.write('internet connection active \n') +# sys.stdout.flush() + self.connectedToInternet=1 + else: + self.connectedToInternet=0 + + def gaAddAction(self,Event,action,label,value): + self.gaAddObject(GA_EVENT_ObjClass(self.UserID,self.GoogleID,Event,action,label,value,self.appName,self.appVer)) + + def gaAddException(self,ExceptionName,ExceptionFatal): + self.gaAddObject(GA_EXCEPTION_ObjClass(self.UserID,self.GoogleID,ExceptionName,ExceptionFatal,self.appName,self.appVer)) + + def gaAddObject(self,Object): + if self.BlockingMode==1: + while self.GA_q.full(): + sleep(self.Timeout) +# sys.stdout.write('blocking mode=1 \n queue full - sleeping for timeout \n') # within Timout, the thread will empty part of the queue +# sys.stdout.flush() + lockState = self.threadLock.acquire(self.BlockingMode) + if lockState==1: +# sys.stdout.write('got lock, adding item \n') +# sys.stdout.flush() + try: + self.GA_q.put_nowait(Object) +# sys.stdout.write('got lock, item added \n') +# sys.stdout.flush() + except Queue.Full: +# sys.stdout.write('Queue full \n') +# sys.stdout.flush() + pass + self.threadLock.release() + + def emptyQueueToList(self,obj_list): + items=0 + while ((not self.GA_q.empty()) and (items<20)): + obj_list.append(self.GA_q.get_nowait().payload) + items+=1 +# print items + + def reportBatched(self,batched): + req = Request(url_batched, data=batched) + urlopen(req) + #requests.post(url_batched,data=batched) + + def emptyAndReportQ(self): + obj_list = [] + self.emptyQueueToList(obj_list) + if not len(obj_list): + return + batched = '\n'.join(obj_list) +# print batched # - for debug + self.reportBatched(batched) + + def printSelf(self): + print('remaining in queue:') + while not self.GA_q.empty(): + obj = self.GA_q.get_nowait() + print(obj.payload) + + def internet_on(self): + try: + urlopen(url_conn,timeout=10) + return True + except URLError as err: pass + return False + + def activate(self): + if (self.UserPermission==1): + self.thread.start() + + + +#***************************************------TEST--------------************************************** + +if __name__ == '__main__': + g = GAmanager(GoogleID='UA-75220362-4',UserID="Foo",QueueSize=100,Timeout=5,UserPermission=1,BlockingMode=1,appName='TRex',appVer='1.11.232') #timeout in seconds +#for i in range(0,35,1): +#i = 42 + g.gaAddAction(Event='stl',action='stl/udp_1pkt_simple.py {packet_count:1000,packet_len:9000}',label='Boo',value=20) + #g.gaAddAction(Event='test',action='start',label='Boo1',value=20) + +#g.gaAddException('MEMFAULT',1) +#g.gaAddException('MEMFAULT',1) +#g.gaAddException('MEMFAULT',1) +#g.gaAddException('MEMFAULT',1) +#g.gaAddException('MEMFAULT',1) +#g.gaAddException('MEMFAULT',1) + g.emptyAndReportQ() +# g.printSelf() +#print g.payload +#print g.size + + + + +#g.activate() +#g.gaAddAction(Event='test',action='start',label='1',value='1') +#sys.stdout.write('element added \n') +#sys.stdout.flush() +#g.gaAddAction(Event='test',action='start',label='2',value='1') +#sys.stdout.write('element added \n') +#sys.stdout.flush() +#g.gaAddAction(Event='test',action='start',label='3',value='1') +#sys.stdout.write('element added \n') +#sys.stdout.flush() + +#testdata = "v=1&t=event&tid=UA-75220362-4&cid=2&ec=test&ea=testing&el=testpacket&ev=2" +#r = requests.post(url_debug,data=testdata) +#print r + +#thread1 = ga_Thread(1,g) +#thread1.start() +#thread1.join() +#for i in range(1,10,1): +# sys.stdout.write('yesh %d'% (i)) +# sys.stdout.flush() + + +# add timing mechanism - DONE +# add exception mechanism - DONE +# add version mechanism - DONE +# ask Itay for unique ID generation per user + + + + + + + + + + + -- cgit From 39aedd8ec2dd0313a097d78046445be11c7bc6d7 Mon Sep 17 00:00:00 2001 From: Yaroslav Brustinov Date: Fri, 29 Apr 2016 23:31:32 +0300 Subject: GA fix for python3 --- .../automation/trex_control_plane/stl/trex_stl_lib/utils/GAObjClass.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'scripts/automation/trex_control_plane/stl') diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/GAObjClass.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/GAObjClass.py index 3101b45d..164aae7a 100755 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/GAObjClass.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/GAObjClass.py @@ -200,7 +200,7 @@ class GAmanager: # print items def reportBatched(self,batched): - req = Request(url_batched, data=batched) + req = Request(url_batched, data=batched.encode('ascii')) urlopen(req) #requests.post(url_batched,data=batched) -- cgit From a9af319885a9416dc11d036b19921c7fdadc26e7 Mon Sep 17 00:00:00 2001 From: imarom Date: Mon, 2 May 2016 15:09:02 +0300 Subject: Python circular object reference - fix --- .../trex_control_plane/stl/trex_stl_lib/trex_stl_client.py | 10 ++++++---- .../stl/trex_stl_lib/trex_stl_jsonrpc_client.py | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-) (limited to 'scripts/automation/trex_control_plane/stl') diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py index 77fa40bb..864e00ad 100755 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py @@ -497,6 +497,11 @@ class STLClient(object): self.session_id = random.getrandbits(32) self.connected = False + # API classes + self.api_vers = [ {'type': 'core', 'major': 1, 'minor':2 } + ] + self.api_h = {'core': None} + # logger self.logger = DefaultLogger() if not logger else logger @@ -540,10 +545,7 @@ class STLClient(object): self.flow_stats) - # API classes - self.api_vers = [ {'type': 'core', 'major': 1, 'minor':2 } - ] - self.api_h = {'core': None} + ############# private functions - used by the class itself ########### diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_jsonrpc_client.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_jsonrpc_client.py index bd5ba8e7..fa04b9f6 100644 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_jsonrpc_client.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_jsonrpc_client.py @@ -47,7 +47,7 @@ class JsonRpcClient(object): MSG_COMPRESS_HEADER_MAGIC = 0xABE85CEA def __init__ (self, default_server, default_port, client): - self.client = client + self.client_api = client.api_h self.logger = client.logger self.connected = False @@ -104,7 +104,7 @@ class JsonRpcClient(object): # if this RPC has an API class - add it's handler if api_class: - msg["params"]["api_h"] = self.client.api_h[api_class] + msg["params"]["api_h"] = self.client_api[api_class] if encode: -- cgit From c227a2fff3e815c38cff89630e22c3b8485c32de Mon Sep 17 00:00:00 2001 From: imarom Date: Mon, 2 May 2016 16:35:17 +0300 Subject: two fixes: 1. history traversal with lock when adding stats objects 2. sync with ports only when you acquire the port, reset does not sync with the streams --- .../stl/trex_stl_lib/trex_stl_client.py | 15 +++++--- .../stl/trex_stl_lib/trex_stl_port.py | 42 +++++++++++++--------- .../stl/trex_stl_lib/trex_stl_stats.py | 13 +++---- 3 files changed, 42 insertions(+), 28 deletions(-) (limited to 'scripts/automation/trex_control_plane/stl') diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py index 864e00ad..862a9979 100755 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py @@ -582,13 +582,13 @@ class STLClient(object): return rc # acquire ports, if port_list is none - get all - def __acquire (self, port_id_list = None, force = False): + def __acquire (self, port_id_list = None, force = False, sync_streams = True): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: - rc.add(self.ports[port_id].acquire(force)) + rc.add(self.ports[port_id].acquire(force, sync_streams)) return rc @@ -1372,16 +1372,20 @@ class STLClient(object): @__api_check(True) - def acquire (self, ports = None, force = False): + def acquire (self, ports = None, force = False, sync_streams = True): """ Acquires ports for executing commands :parameters: ports : list Ports on which to execute the command + force : bool Force acquire the ports. + sync_streams: bool + sync with the server about the configured streams + :raises: + :exc:`STLError` @@ -1396,7 +1400,7 @@ class STLClient(object): else: self.logger.pre_cmd("Acquiring ports {0}:".format(ports)) - rc = self.__acquire(ports, force) + rc = self.__acquire(ports, force, sync_streams) self.logger.post_cmd(rc) @@ -1496,7 +1500,8 @@ class STLClient(object): ports = ports if ports is not None else self.get_all_ports() ports = self._validate_port_list(ports) - self.acquire(ports, force = True) + # force take the port and ignore any streams on it + self.acquire(ports, force = True, sync_streams = False) self.stop(ports, rx_delay_ms = 0) self.remove_all_streams(ports) self.clear_stats(ports) diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py index 5cf94bda..e8f89b27 100644 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py @@ -80,19 +80,39 @@ class Port(object): return "{0} Gbps".format(self.info['speed']) # take the port - def acquire(self, force = False): + def acquire(self, force = False, sync_streams = True): params = {"port_id": self.port_id, "user": self.user, "session_id": self.session_id, "force": force} rc = self.transmit("acquire", params) - if rc.good(): - self.handler = rc.data() - return self.ok() + if not rc: + return self.err(rc.err()) + + self.handler = rc.data() + + if sync_streams: + return self.sync_streams() else: + return self.ok() + + + # sync all the streams with the server + def sync_streams (self): + params = {"port_id": self.port_id} + + rc = self.transmit("get_all_streams", params) + if rc.bad(): return self.err(rc.err()) + for k, v in rc.data()['streams'].items(): + self.streams[k] = {'next_id': v['next_stream_id'], + 'pkt' : base64.b64decode(v['packet']['binary']), + 'mode' : v['mode']['type'], + 'rate' : STLStream.get_rate_from_field(v['mode']['rate'])} + return self.ok() + # release the port def release(self): params = {"port_id": self.port_id, @@ -157,19 +177,7 @@ class Port(object): # attributes self.attr = rc.data()['attr'] - # sync the streams - params = {"port_id": self.port_id} - - rc = self.transmit("get_all_streams", params) - if rc.bad(): - return self.err(rc.err()) - - for k, v in rc.data()['streams'].items(): - self.streams[k] = {'next_id': v['next_stream_id'], - 'pkt' : base64.b64decode(v['packet']['binary']), - 'mode' : v['mode']['type'], - 'rate' : STLStream.get_rate_from_field(v['mode']['rate'])} - + return self.ok() diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py index 42bef360..12c2c578 100644 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py @@ -698,12 +698,13 @@ class CPortStats(CTRexStats): else: self.__merge_dicts(self.reference_stats, x.reference_stats) - # history - if not self.history: - self.history = copy.deepcopy(x.history) - else: - for h1, h2 in zip(self.history, x.history): - self.__merge_dicts(h1, h2) + # history - should be traverse with a lock + with self.lock, x.lock: + if not self.history: + self.history = copy.deepcopy(x.history) + else: + for h1, h2 in zip(self.history, x.history): + self.__merge_dicts(h1, h2) return self -- cgit From 7007bf04481b76b51e30d42148df710bccc9aa35 Mon Sep 17 00:00:00 2001 From: Yaroslav Brustinov Date: Tue, 3 May 2016 04:28:08 +0300 Subject: bp_sim: correct description of supported stateful layers main_dpdk: send bw_per_core with json, return back precision of low values jsonrpcserver: disable logging regression: use bw_per_core from cpp calculation correct test name for GA --- .../automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'scripts/automation/trex_control_plane/stl') diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py index 12c2c578..c7513144 100644 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py @@ -212,7 +212,7 @@ class CTRexInfoGenerator(object): if ratio <= 0.1875: return u'\u2581' # 1/8 if ratio <= 0.3125: - return u'\u2582' # 2/4 + return u'\u2582' # 2/8 if ratio <= 0.4375: return u'\u2583' # 3/8 if ratio <= 0.5625: @@ -594,6 +594,7 @@ class CGlobalStats(CTRexStats): # absolute stats['cpu_util'] = self.get("m_cpu_util") stats['rx_cpu_util'] = self.get("m_rx_cpu_util") + stats['bw_per_core'] = self.get("m_bw_per_core") stats['tx_bps'] = self.get("m_tx_bps") stats['tx_pps'] = self.get("m_tx_pps") -- cgit