summaryrefslogtreecommitdiffstats
path: root/scripts/automation/trex_control_plane/common
diff options
context:
space:
mode:
authorimarom <imarom@cisco.com>2015-12-07 10:38:37 -0500
committerimarom <imarom@cisco.com>2015-12-07 10:38:37 -0500
commit24b895f6843210b1bbe8046c639ed9da436c8012 (patch)
treedb293baa76ed838d7828859301a07e79b9fc852a /scripts/automation/trex_control_plane/common
parent0fc30adae2fc5708baef74d36e97a174b078f332 (diff)
parent1895d21485621c3428d045fa0f5b9daf165c8260 (diff)
Merge branch 'dan_stateless' into a test branch
Conflicts: scripts/automation/trex_control_plane/client/trex_async_client.py scripts/automation/trex_control_plane/client/trex_stateless_client.py scripts/automation/trex_control_plane/client_utils/parsing_opts.py scripts/automation/trex_control_plane/console/trex_console.py
Diffstat (limited to 'scripts/automation/trex_control_plane/common')
-rwxr-xr-xscripts/automation/trex_control_plane/common/trex_stats.py275
1 files changed, 241 insertions, 34 deletions
diff --git a/scripts/automation/trex_control_plane/common/trex_stats.py b/scripts/automation/trex_control_plane/common/trex_stats.py
index b7e768c1..1f9d59e3 100755
--- a/scripts/automation/trex_control_plane/common/trex_stats.py
+++ b/scripts/automation/trex_control_plane/common/trex_stats.py
@@ -1,59 +1,266 @@
#!/router/bin/python
+from collections import namedtuple, OrderedDict
+from client_utils import text_tables
+from common.text_opts import format_text
+from client.trex_async_client import CTRexAsyncStats
import copy
+import datetime
+import re
+GLOBAL_STATS = 'g'
+PORT_STATS = 'p'
+PORT_STATUS = 'ps'
+ALL_STATS_OPTS = {GLOBAL_STATS, PORT_STATS, PORT_STATUS}
+ExportableStats = namedtuple('ExportableStats', ['raw_data', 'text_table'])
-class CTRexStatsManager(object):
- def __init__(self, *args):
- for stat_type in args:
- # register stat handler for each stats type
- setattr(self, stat_type, CTRexStatsManager.CSingleStatsHandler())
+class CTRexStatsGenerator(object):
+ """
+ This object is responsible of generating stats from objects maintained at
+ CTRexStatelessClient and the ports.
+ """
- def __getitem__(self, item):
- stats_obj = getattr(self, item)
- if stats_obj:
- return stats_obj.get_stats()
+ def __init__(self, global_stats_ref, ports_dict_ref):
+ self._global_stats = global_stats_ref
+ self._ports_dict = ports_dict_ref
+
+ def generate_single_statistic(self, port_id_list, statistic_type):
+ if statistic_type == GLOBAL_STATS:
+ return self._generate_global_stats()
+ elif statistic_type == PORT_STATS:
+ return self._generate_port_stats(port_id_list)
+ pass
+ elif statistic_type == PORT_STATUS:
+ return self._generate_port_status(port_id_list)
else:
- return None
+ # ignore by returning empty object
+ return {}
- class CSingleStatsHandler(object):
+ def _generate_global_stats(self):
+ # stats_obj = self._async_stats.get_general_stats()
+ stats_data = self._global_stats.generate_stats()
- def __init__(self):
- self._stats = {}
+ # build table representation
+ stats_table = text_tables.TRexTextInfo()
+ stats_table.set_cols_align(["l", "l"])
+ stats_table.add_rows([[k.replace("_", " ").title(), v]
+ for k, v in stats_data.iteritems()],
+ header=False)
+
+ return {"global_statistics": ExportableStats(stats_data, stats_table)}
+
+ def _generate_port_stats(self, port_id_list):
+ relevant_ports = self.__get_relevant_ports(port_id_list)
+
+ return_stats_data = {}
+ per_field_stats = OrderedDict([("owner", []),
+ ("active", []),
+ ("tx-bytes", []),
+ ("rx-bytes", []),
+ ("tx-pkts", []),
+ ("rx-pkts", []),
+ ("tx-errors", []),
+ ("rx-errors", []),
+ ("tx-BW", []),
+ ("rx-BW", [])
+ ]
+ )
+
+ for port_obj in relevant_ports:
+ # fetch port data
+ port_stats = port_obj.generate_port_stats()
+
+ # populate to data structures
+ return_stats_data[port_obj.port_id] = port_stats
+ self.__update_per_field_dict(port_stats, per_field_stats)
+
+ stats_table = text_tables.TRexTextTable()
+ stats_table.set_cols_align(["l"] + ["r"]*len(relevant_ports))
+ stats_table.add_rows([[k] + v
+ for k, v in per_field_stats.iteritems()],
+ header=False)
+ stats_table.header(["port"] + [port.port_id
+ for port in relevant_ports])
+
+ return {"port_statistics": ExportableStats(return_stats_data, stats_table)}
+
+ def _generate_port_status(self, port_id_list):
+ relevant_ports = self.__get_relevant_ports(port_id_list)
+
+ return_stats_data = {}
+ per_field_status = OrderedDict([("port-type", []),
+ ("maximum", []),
+ ("port-status", [])
+ ]
+ )
+
+ for port_obj in relevant_ports:
+ # fetch port data
+ # port_stats = self._async_stats.get_port_stats(port_obj.port_id)
+ port_status = port_obj.generate_port_status()
+
+ # populate to data structures
+ return_stats_data[port_obj.port_id] = port_status
+
+ self.__update_per_field_dict(port_status, per_field_status)
+
+ stats_table = text_tables.TRexTextTable()
+ stats_table.set_cols_align(["l"] + ["c"]*len(relevant_ports))
+ stats_table.add_rows([[k] + v
+ for k, v in per_field_status.iteritems()],
+ header=False)
+ stats_table.header(["port"] + [port.port_id
+ for port in relevant_ports])
+
+ return {"port_status": ExportableStats(return_stats_data, stats_table)}
+
+ def __get_relevant_ports(self, port_id_list):
+ # fetch owned ports
+ ports = [port_obj
+ for _, port_obj in self._ports_dict.iteritems()
+ if port_obj.is_acquired() and port_obj.port_id in port_id_list]
+ # display only the first FOUR options, by design
+ if len(ports) > 4:
+ print format_text("[WARNING]: ", 'magenta', 'bold'), format_text("displaying up to 4 ports", 'magenta')
+ ports = ports[:4]
+ return ports
+
+ def __update_per_field_dict(self, dict_src_data, dict_dest_ref):
+ for key, val in dict_src_data.iteritems():
+ if key in dict_dest_ref:
+ dict_dest_ref[key].append(val)
- def update(self, obj_id, stats_obj):
- assert isinstance(stats_obj, CTRexStats)
- self._stats[obj_id] = stats_obj
- def get_stats(self, obj_id=None):
- if obj_id:
- return copy.copy(self._stats.pop(obj_id))
- else:
- return copy.copy(self._stats)
class CTRexStats(object):
- def __init__(self, **kwargs):
- for k, v in kwargs.items():
- setattr(self, k, v)
+ """ This is an abstract class to represent a stats object """
+
+ def __init__(self):
+ self.reference_stats = None
+ self.latest_stats = {}
+ self.last_update_ts = datetime.datetime.now()
+
+
+ def __getitem__(self, item):
+ # override this to allow quick and clean access to fields
+ if not item in self.latest_stats:
+ return "N/A"
+
+ # item must exist
+ m = re.search('_(([a-z])ps)$', item)
+ if m:
+ # this is a non-relative item
+ unit = m.group(2)
+ if unit == "b":
+ return self.get(item, format=True, suffix="b/sec")
+ elif unit == "p":
+ return self.get(item, format=True, suffix="pkt/sec")
+ else:
+ return self.get(item, format=True, suffix=m.group(1))
+
+ m = re.search('^[i|o](a-z+)$', item)
+ if m:
+ # this is a non-relative item
+ type = m.group(1)
+ if type == "bytes":
+ return self.get_rel(item, format=True, suffix="B")
+ elif type == "packets":
+ return self.get_rel(item, format=True, suffix="pkts")
+ else:
+ # do not format with suffix
+ return self.get_rel(item, format=True)
+
+ # can't match to any known pattern, return N/A
+ return "N/A"
+
+ @staticmethod
+ def format_num(size, suffix = ""):
+ for unit in ['','K','M','G','T','P']:
+ if abs(size) < 1000.0:
+ return "%3.2f %s%s" % (size, unit, suffix)
+ size /= 1000.0
+ return "NaN"
+
+ def generate_stats(self):
+ # must be implemented by designated classes (such as port/ global stats)
+ raise NotImplementedError()
+
+ def update(self, snapshot):
+ # update
+ self.last_update_ts = datetime.datetime.now()
+
+ self.latest_stats = snapshot
+
+ if self.reference_stats == None:
+ self.reference_stats = self.latest_stats
+
+ def clear_stats(self):
+ self.reference_stats = self.latest_stats
+
+ def get(self, field, format=False, suffix=""):
+ if not field in self.latest_stats:
+ return "N/A"
+ if not format:
+ return self.latest_stats[field]
+ else:
+ return self.format_num(self.latest_stats[field], suffix)
+
+ def get_rel(self, field, format=False, suffix=""):
+ if not field in self.latest_stats:
+ return "N/A"
+ if not format:
+ return (self.latest_stats[field] - self.reference_stats[field])
+ else:
+ return self.format_num(self.latest_stats[field] - self.reference_stats[field], suffix)
class CGlobalStats(CTRexStats):
- def __init__(self, **kwargs):
- super(CGlobalStats, self).__init__(kwargs)
- pass
+ pass
+
+ def __init__(self, connection_info, server_version, ports_dict_ref):
+ super(CGlobalStats, self).__init__()
+ self.connection_info = connection_info
+ self.server_version = server_version
+ self._ports_dict = ports_dict_ref
+ def generate_stats(self):
+ return OrderedDict([("connection", "{host}, Port {port}".format(host=self.connection_info.get("server"),
+ port=self.connection_info.get("sync_port"))),
+ ("version", "{ver}, UUID: {uuid}".format(ver=self.server_version.get("version", "N/A"),
+ uuid="N/A")),
+ ("cpu_util", "{0}%".format(self.get("m_cpu_util"))),
+ ("total_tx", self.get("m_tx_bps", format=True, suffix="b/sec")),
+ ("total_rx", self.get("m_rx_bps", format=True, suffix="b/sec")),
+ ("total_pps", self.format_num(self.get("m_tx_pps") + self.get("m_rx_pps"),
+ suffix="pkt/sec")),
+ ("total_streams", sum([len(port_obj.streams)
+ for _, port_obj in self._ports_dict.iteritems()])),
+ ("active_ports", sum([port_obj.is_active()
+ for _, port_obj in self._ports_dict.iteritems()]))
+ ]
+ )
class CPortStats(CTRexStats):
- def __init__(self, **kwargs):
- super(CPortStats, self).__init__(kwargs)
- pass
+ pass
+
+ def __init__(self, port_obj):
+ super(CPortStats, self).__init__()
+ self._port_obj = port_obj
+ def generate_stats(self):
+ return {"owner": self._port_obj.user,
+ "active": "YES" if self._port_obj.is_active() else "NO",
+ "tx-bytes": self.get_rel("obytes", format = True, suffix = "B"),
+ "rx-bytes": self.get_rel("ibytes", format = True, suffix = "B"),
+ "tx-pkts": self.get_rel("opackets", format = True, suffix = "pkts"),
+ "rx-pkts": self.get_rel("ipackets", format = True, suffix = "pkts"),
+ "tx-errors": self.get_rel("oerrors", format = True),
+ "rx-errors": self.get_rel("ierrors", format = True),
+ "tx-BW": self.get("m_total_tx_bps", format = True, suffix = "bps"),
+ "rx-BW": self.get("m_total_rx_bps", format = True, suffix = "bps")
+ }
-class CStreamStats(CTRexStats):
- def __init__(self, **kwargs):
- super(CStreamStats, self).__init__(kwargs)
- pass
if __name__ == "__main__":