summaryrefslogtreecommitdiffstats
path: root/scripts/automation/trex_control_plane/stl
diff options
context:
space:
mode:
authorimarom <imarom@cisco.com>2016-04-19 13:16:17 +0300
committerimarom <imarom@cisco.com>2016-04-19 13:16:17 +0300
commitf9b624fd56bc9f23d0bc4191cff929556f5e42a0 (patch)
treef0384ca40ae2b24651f24bf9b0dc1d97812b6a99 /scripts/automation/trex_control_plane/stl
parent6840551a8733fefdd8b3f235e4a802524ecc39d9 (diff)
parent3bafb0394c07ef2abb4ce34c7fb4ec01eb09f2df (diff)
Merge git://github.com/danklein10/trex-core into danklein10-master
also adding some tweaks to the TUI Conflicts: scripts/automation/trex_control_plane/stl/console/trex_tui.py
Diffstat (limited to 'scripts/automation/trex_control_plane/stl')
-rwxr-xr-xscripts/automation/trex_control_plane/stl/console/trex_console.py2
-rw-r--r--scripts/automation/trex_control_plane/stl/console/trex_tui.py179
-rw-r--r--scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py3
-rw-r--r--scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py11
-rw-r--r--scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/filters.py144
5 files changed, 209 insertions, 130 deletions
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 a126bf35..f8161dcb 100755
--- a/scripts/automation/trex_control_plane/stl/console/trex_console.py
+++ b/scripts/automation/trex_control_plane/stl/console/trex_console.py
@@ -577,7 +577,7 @@ class TRexConsole(TRexGeneralCmd):
info = self.stateless_client.get_connection_info()
exe = './trex-console --top -t -q -s {0} -p {1} --async_port {2}'.format(info['server'], info['sync_port'], info['async_port'])
- cmd = ['/usr/bin/xterm', '-geometry', '111x48', '-sl', '0', '-title', 'trex_tui', '-e', exe]
+ cmd = ['/usr/bin/xterm', '-geometry', '111x49', '-sl', '0', '-title', 'trex_tui', '-e', exe]
# detach child
self.terminal = subprocess.Popen(cmd, preexec_fn = os.setpgrp)
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 cbaae392..231eff93 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,7 @@ 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
+from trex_stl_lib.utils.filters import ToggleFilter
# for STL exceptions
from trex_stl_lib.api import *
@@ -62,34 +63,38 @@ class TrexTUIDashBoard(TrexTUIPanel):
def __init__ (self, mng):
super(TrexTUIDashBoard, self).__init__(mng, "dashboard")
+ self.ports = self.stateless_client.get_all_ports()
+
self.key_actions = OrderedDict()
self.key_actions['c'] = {'action': self.action_clear, 'legend': 'clear', 'show': True}
- self.key_actions['p'] = {'action': self.action_pause, 'legend': 'pause', 'show': True}
- self.key_actions['r'] = {'action': self.action_resume, 'legend': 'resume', '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['a'] = {'action': self.action_show_all, 'legend': 'all ports', 'show': True}
+ # register all the ports to the toggle action
+ for port_id in self.ports:
+ self.key_actions[str(port_id)] = {'action': self.action_toggle_port(port_id), 'legend': 'port {0}'.format(port_id), 'show': False}
+
+
+ self.toggle_filter = ToggleFilter(self.ports)
+
if self.stateless_client.get_acquired_ports():
- self.ports_filter = self.FILTER_ACQUIRED
+ self.action_show_owned()
else:
- self.ports_filter = self.FILTER_ALL
-
+ self.action_show_all()
- def get_ports (self):
- if self.ports_filter == self.FILTER_ACQUIRED:
- return self.stateless_client.get_acquired_ports()
- elif self.ports_filter == self.FILTER_ALL:
- return self.stateless_client.get_all_ports()
+ def get_showed_ports (self):
+ return self.toggle_filter.filter_items()
- assert(0)
def show (self):
- stats = self.stateless_client._get_formatted_stats(self.get_ports())
+ stats = self.stateless_client._get_formatted_stats(self.get_showed_ports())
# print stats to screen
for stat_type, stat_data in stats.items():
text_tables.print_table_with_header(stat_data.text_table, stat_type)
@@ -101,17 +106,21 @@ class TrexTUIDashBoard(TrexTUIPanel):
allowed['c'] = self.key_actions['c']
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.ports_filter == self.FILTER_ALL and self.stateless_client.get_acquired_ports() != self.stateless_client.get_all_ports():
+ # 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 len(self.stateless_client.get_transmitting_ports()) > 0:
+ # 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 len(self.stateless_client.get_paused_ports()) > 0:
+ if set(self.get_showed_ports()) & set(self.stateless_client.get_paused_ports()):
allowed['r'] = self.key_actions['r']
return allowed
@@ -120,7 +129,7 @@ class TrexTUIDashBoard(TrexTUIPanel):
######### actions
def action_pause (self):
try:
- rc = self.stateless_client.pause(ports = self.mng.ports)
+ rc = self.stateless_client.pause(ports = self.get_showed_ports())
except STLError:
pass
@@ -130,7 +139,7 @@ class TrexTUIDashBoard(TrexTUIPanel):
def action_resume (self):
try:
- self.stateless_client.resume(ports = self.mng.ports)
+ self.stateless_client.resume(ports = self.get_showed_ports())
except STLError:
pass
@@ -139,7 +148,7 @@ class TrexTUIDashBoard(TrexTUIPanel):
def action_raise (self):
try:
- self.stateless_client.update(mult = "5%+", ports = self.mng.ports)
+ self.stateless_client.update(mult = "5%+", ports = self.get_showed_ports())
except STLError:
pass
@@ -148,7 +157,7 @@ class TrexTUIDashBoard(TrexTUIPanel):
def action_lower (self):
try:
- self.stateless_client.update(mult = "5%-", ports = self.mng.ports)
+ self.stateless_client.update(mult = "5%-", ports = self.get_showed_ports())
except STLError:
pass
@@ -156,116 +165,26 @@ class TrexTUIDashBoard(TrexTUIPanel):
def action_show_owned (self):
- self.ports_filter = self.FILTER_ACQUIRED
+ self.toggle_filter.reset()
+ self.toggle_filter.toggle_items(*self.stateless_client.get_acquired_ports())
return ""
def action_show_all (self):
- self.ports_filter = self.FILTER_ALL
+ self.toggle_filter.reset()
+ self.toggle_filter.toggle_items(*self.stateless_client.get_all_ports())
return ""
def action_clear (self):
- self.stateless_client.clear_stats(self.mng.ports)
+ self.stateless_client.clear_stats(self.toggle_filter.filter_items())
return "cleared all stats"
-# port panel
-class TrexTUIPort(TrexTUIPanel):
- def __init__ (self, mng, port_id):
- super(TrexTUIPort, self).__init__(mng, "port {0}".format(port_id))
-
- self.port_id = port_id
- self.port = self.mng.stateless_client.get_port(port_id)
-
- self.key_actions = OrderedDict()
-
- self.key_actions['c'] = {'action': self.action_clear, 'legend': 'clear', 'show': True}
- self.key_actions['p'] = {'action': self.action_pause, 'legend': 'pause', 'show': True}
- self.key_actions['r'] = {'action': self.action_resume, 'legend': 'resume', 'show': True}
- 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['t'] = {'action': self.action_toggle_graph, 'legend': 'toggle graph', 'show': True}
-
-
- def show (self):
- if self.mng.tui.is_graph is False:
- stats = self.stateless_client._get_formatted_stats([self.port_id])
- # print stats to screen
- for stat_type, stat_data in stats.items():
- text_tables.print_table_with_header(stat_data.text_table, stat_type)
- else:
- stats = self.stateless_client._get_formatted_stats([self.port_id], stats_mask = trex_stl_stats.GRAPH_PORT_COMPACT)
- for stat_type, stat_data in stats.items():
- text_tables.print_table_with_header(stat_data.text_table, stat_type)
-
- def get_key_actions (self):
-
- allowed = OrderedDict()
-
- allowed['c'] = self.key_actions['c']
- allowed['t'] = self.key_actions['t']
-
- if self.port_id not in self.stateless_client.get_acquired_ports():
- return allowed
-
- if self.port.state == self.port.STATE_TX:
- allowed['p'] = self.key_actions['p']
- allowed['+'] = self.key_actions['+']
- allowed['-'] = self.key_actions['-']
-
- elif self.port.state == self.port.STATE_PAUSE:
- allowed['r'] = self.key_actions['r']
-
-
- return allowed
-
- def action_toggle_graph(self):
- try:
- self.mng.tui.is_graph = not self.mng.tui.is_graph
- except Exception:
- pass
-
- return ""
-
- def action_pause (self):
- try:
- self.stateless_client.pause(ports = [self.port_id])
- except STLError:
- pass
-
- return ""
-
- def action_resume (self):
- try:
- self.stateless_client.resume(ports = [self.port_id])
- except STLError:
- pass
-
- return ""
-
-
- def action_raise (self):
- mult = {'type': 'percentage', 'value': 5, 'op': 'add'}
-
- try:
- self.stateless_client.update(mult = mult, ports = [self.port_id])
- except STLError:
- pass
-
- return ""
-
- def action_lower (self):
- mult = {'type': 'percentage', 'value': 5, 'op': 'sub'}
-
- try:
- self.stateless_client.update(mult = mult, ports = [self.port_id])
- except STLError:
- pass
-
- return ""
+ def action_toggle_port(self, port_id):
+ def action_toggle_port_x():
+ self.toggle_filter.toggle_item(port_id)
+ return ""
- def action_clear (self):
- self.stateless_client.clear_stats([self.port_id])
- return "port {0}: cleared stats".format(self.port_id)
+ return action_toggle_port_x
@@ -333,10 +252,6 @@ class TrexTUIPanelManager():
self.key_actions['g'] = {'action': self.action_show_dash, 'legend': 'dashboard', 'show': True}
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.panels['port {0}'.format(port_id)] = TrexTUIPort(self, port_id)
-
# start with dashboard
self.main_panel = self.panels['dashboard']
@@ -349,23 +264,30 @@ class TrexTUIPanelManager():
self.dis_bar = SimpleBar('status: ', ['X', ' '])
self.show_log = False
+
def generate_legend (self):
+
self.legend = "\n{:<12}".format("browse:")
for k, v in self.key_actions.items():
if v['show']:
x = "'{0}' - {1}, ".format(k, v['legend'])
- self.legend += "{:}".format(x)
-
- self.legend += "'0-{0}' - port display".format(len(self.ports) - 1)
+ if v.get('color'):
+ self.legend += "{:}".format(format_text(x, v.get('color')))
+ else:
+ self.legend += "{:}".format(x)
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'])
- self.legend += "{:}".format(x)
+
+ if v.get('color'):
+ self.legend += "{:}".format(format_text(x, v.get('color')))
+ else:
+ self.legend += "{:}".format(x)
def print_connection_status (self):
@@ -433,6 +355,7 @@ class TrexTUIPanelManager():
return action_show_port_x
+
def action_show_sstats (self):
self.main_panel = self.panels['sstats']
self.init(self.show_log)
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 16e55d73..5cf94bda 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
@@ -76,6 +76,9 @@ class Port(object):
def get_speed_bps (self):
return (self.info['speed'] * 1000 * 1000 * 1000)
+ def get_formatted_speed (self):
+ return "{0} Gbps".format(self.info['speed'])
+
# take the port
def acquire(self, force = False):
params = {"port_id": self.port_id,
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 4057c50d..42bef360 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
@@ -251,6 +251,7 @@ class CTRexInfoGenerator(object):
return_stats_data = {}
per_field_stats = OrderedDict([("owner", []),
("state", []),
+ ("speed", []),
("--", []),
("Tx bps L2", []),
("Tx bps L1", []),
@@ -767,9 +768,17 @@ class CPortStats(CTRexStats):
else:
state = format_text(state, 'bold')
+ # mark owned ports by color
+ if self._port_obj:
+ owner = self._port_obj.get_owner()
+ if self._port_obj.is_acquired():
+ owner = format_text(owner, 'green')
+ else:
+ owner = ''
- return {"owner": self._port_obj.get_owner() if self._port_obj else "",
+ return {"owner": owner,
"state": "{0}".format(state),
+ "speed": self._port_obj.get_formatted_speed() if self._port_obj else '',
"--": " ",
"---": " ",
diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/filters.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/filters.py
new file mode 100644
index 00000000..714f7807
--- /dev/null
+++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/filters.py
@@ -0,0 +1,144 @@
+
+def shallow_copy(x):
+ return type(x)(x)
+
+
+class ToggleFilter(object):
+ """
+ This class provides a "sticky" filter, that works by "toggling" items of the original database on and off.
+ """
+ def __init__(self, db_ref, show_by_default=True):
+ """
+ Instantiate a ToggleFilter object
+
+ :parameters:
+ db_ref : iterable
+ an iterable object (i.e. list, set etc) that would serve as the reference db of the instance.
+ Changes in that object will affect the output of ToggleFilter instance.
+
+ show_by_default: bool
+ decide if by default all the items are "on", i.e. these items will be presented if no other
+ toggling occurred.
+
+ default value : **True**
+
+ """
+ self._data = db_ref
+ self._toggle_db = set()
+ self._filter_method = filter
+ self.__set_initial_state(show_by_default)
+
+ def reset (self):
+ """
+ Toggles off all the items
+ """
+ self._toggle_db = set()
+
+
+ def toggle_item(self, item_key):
+ """
+ Toggle a single item in/out.
+
+ :parameters:
+ item_key :
+ an item the by its value the filter can decide to toggle or not.
+ Example: int, str and so on.
+
+ :return:
+ + **True** if item toggled **into** the filtered items
+ + **False** if item toggled **out from** the filtered items
+
+ :raises:
+ + KeyError, in case if item key is not part of the toggled list and not part of the referenced db.
+
+ """
+ if item_key in self._toggle_db:
+ self._toggle_db.remove(item_key)
+ return False
+ elif item_key in self._data:
+ self._toggle_db.add(item_key)
+ return True
+ else:
+ raise KeyError("Provided item key isn't a key of the referenced data structure.")
+
+ def toggle_items(self, *args):
+ """
+ Toggle multiple items in/out with a single call. Each item will be ha.
+
+ :parameters:
+ args : iterable
+ an iterable object containing all item keys to be toggled in/out
+
+ :return:
+ + **True** if all toggled items were toggled **into** the filtered items
+ + **False** if at least one of the items was toggled **out from** the filtered items
+
+ :raises:
+ + KeyError, in case if ont of the item keys was not part of the toggled list and not part of the referenced db.
+
+ """
+ # in python 3, 'map' returns an iterator, so wrapping with 'list' call creates same effect for both python 2 and 3
+ return all(list(map(self.toggle_item, args)))
+
+ def filter_items(self):
+ """
+ Filters the pointed database by showing only the items mapped at toggle_db set.
+
+ :returns:
+ Filtered data of the original object.
+
+ """
+ return self._filter_method(self.__toggle_filter, self._data)
+
+ # private methods
+
+ def __set_initial_state(self, show_by_default):
+ try:
+ _ = (x for x in self._data)
+ if isinstance(self._data, dict):
+ self._filter_method = ToggleFilter.dict_filter
+ if show_by_default:
+ self._toggle_db = set(self._data.keys())
+ return
+ elif isinstance(self._data, list):
+ self._filter_method = ToggleFilter.list_filter
+ elif isinstance(self._data, set):
+ self._filter_method = ToggleFilter.set_filter
+ elif isinstance(self._data, tuple):
+ self._filter_method = ToggleFilter.tuple_filter
+ if show_by_default:
+ self._toggle_db = set(shallow_copy(self._data)) # assuming all relevant data with unique identifier
+ return
+ except TypeError:
+ raise TypeError("provided data object is not iterable")
+
+ def __toggle_filter(self, x):
+ return (x in self._toggle_db)
+
+ # static utility methods
+
+ @staticmethod
+ def dict_filter(function, iterable):
+ assert isinstance(iterable, dict)
+ return {k: v
+ for k,v in iterable.items()
+ if function(k)}
+
+ @staticmethod
+ def list_filter(function, iterable):
+ # in python 3, filter returns an iterator, so wrapping with list creates same effect for both python 2 and 3
+ return list(filter(function, iterable))
+
+ @staticmethod
+ def set_filter(function, iterable):
+ return {x
+ for x in iterable
+ if function(x)}
+
+ @staticmethod
+ def tuple_filter(function, iterable):
+ return tuple(filter(function, iterable))
+
+
+if __name__ == "__main__":
+ pass