summaryrefslogtreecommitdiffstats
path: root/scripts/automation/trex_control_plane/common
diff options
context:
space:
mode:
authorDan Klein <danklein10@gmail.com>2015-12-20 00:07:44 +0200
committerDan Klein <danklein10@gmail.com>2015-12-20 00:07:44 +0200
commit4ca24cf31919870a684fe78f17c856e0d220e6d5 (patch)
treef40ab95e52adca3ac713d61eb9fa3fd0d136e4ea /scripts/automation/trex_control_plane/common
parent1895d21485621c3428d045fa0f5b9daf165c8260 (diff)
parent5cef472bcdc6c0b7e20e5cc42485ed5570c10f8c (diff)
Merge branch 'master' into dan_stateless
Diffstat (limited to 'scripts/automation/trex_control_plane/common')
-rwxr-xr-xscripts/automation/trex_control_plane/common/text_opts.py44
-rwxr-xr-xscripts/automation/trex_control_plane/common/trex_stats.py71
-rwxr-xr-xscripts/automation/trex_control_plane/common/trex_streams.py80
-rw-r--r--scripts/automation/trex_control_plane/common/trex_types.py68
4 files changed, 241 insertions, 22 deletions
diff --git a/scripts/automation/trex_control_plane/common/text_opts.py b/scripts/automation/trex_control_plane/common/text_opts.py
index 06c2c056..5a86149c 100755
--- a/scripts/automation/trex_control_plane/common/text_opts.py
+++ b/scripts/automation/trex_control_plane/common/text_opts.py
@@ -19,6 +19,50 @@ TEXT_CODES = {'bold': {'start': '\x1b[1m',
'end': '\x1b[24m'}}
+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 format_time (t_sec):
+ if t_sec < 0:
+ return "infinite"
+
+ if t_sec < 1:
+ # low numbers
+ for unit in ['ms', 'usec', 'ns']:
+ t_sec *= 1000.0
+ if t_sec >= 1.0:
+ return '{:,.2f} [{:}]'.format(t_sec, unit)
+
+ return "NaN"
+
+ else:
+ # seconds
+ if t_sec < 60.0:
+ return '{:,.2f} [{:}]'.format(t_sec, 'sec')
+
+ # minutes
+ t_sec /= 60.0
+ if t_sec < 60.0:
+ return '{:,.2f} [{:}]'.format(t_sec, 'minutes')
+
+ # hours
+ t_sec /= 60.0
+ if t_sec < 24.0:
+ return '{:,.2f} [{:}]'.format(t_sec, 'hours')
+
+ # days
+ t_sec /= 24.0
+ return '{:,.2f} [{:}]'.format(t_sec, 'days')
+
+
+def format_percentage (size):
+ return "%0.2f %%" % (size)
+
def bold(text):
return text_attribute(text, 'bold')
diff --git a/scripts/automation/trex_control_plane/common/trex_stats.py b/scripts/automation/trex_control_plane/common/trex_stats.py
index 1f9d59e3..9562f1f5 100755
--- a/scripts/automation/trex_control_plane/common/trex_stats.py
+++ b/scripts/automation/trex_control_plane/common/trex_stats.py
@@ -5,12 +5,15 @@ from common.text_opts import format_text
from client.trex_async_client import CTRexAsyncStats
import copy
import datetime
+import time
import re
GLOBAL_STATS = 'g'
PORT_STATS = 'p'
PORT_STATUS = 'ps'
ALL_STATS_OPTS = {GLOBAL_STATS, PORT_STATS, PORT_STATUS}
+COMPACT = {GLOBAL_STATS, PORT_STATS}
+
ExportableStats = namedtuple('ExportableStats', ['raw_data', 'text_table'])
@@ -54,15 +57,24 @@ class CTRexStatsGenerator(object):
return_stats_data = {}
per_field_stats = OrderedDict([("owner", []),
- ("active", []),
+ ("state", []),
+ ("--", []),
+ ("opackets", []),
+ ("obytes", []),
+ ("ipackets", []),
+ ("ibytes", []),
+ ("ierrors", []),
+ ("oerrors", []),
("tx-bytes", []),
("rx-bytes", []),
("tx-pkts", []),
("rx-pkts", []),
- ("tx-errors", []),
- ("rx-errors", []),
- ("tx-BW", []),
- ("rx-BW", [])
+ ("---", []),
+ ("Tx bps", []),
+ ("Rx bps", []),
+ ("----", []),
+ ("Tx pps", []),
+ ("Rx pps", [])
]
)
@@ -76,6 +88,9 @@ class CTRexStatsGenerator(object):
stats_table = text_tables.TRexTextTable()
stats_table.set_cols_align(["l"] + ["r"]*len(relevant_ports))
+ stats_table.set_cols_width([10] + [20] * len(relevant_ports))
+ stats_table.set_cols_dtype(['t'] + ['t'] * len(relevant_ports))
+
stats_table.add_rows([[k] + v
for k, v in per_field_stats.iteritems()],
header=False)
@@ -106,6 +121,8 @@ class CTRexStatsGenerator(object):
stats_table = text_tables.TRexTextTable()
stats_table.set_cols_align(["l"] + ["c"]*len(relevant_ports))
+ stats_table.set_cols_width([10] + [20] * len(relevant_ports))
+
stats_table.add_rows([[k] + v
for k, v in per_field_status.iteritems()],
header=False)
@@ -118,7 +135,8 @@ class CTRexStatsGenerator(object):
# 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]
+ if 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')
@@ -139,7 +157,7 @@ class CTRexStats(object):
def __init__(self):
self.reference_stats = None
self.latest_stats = {}
- self.last_update_ts = datetime.datetime.now()
+ self.last_update_ts = time.time()
def __getitem__(self, item):
@@ -176,6 +194,9 @@ class CTRexStats(object):
@staticmethod
def format_num(size, suffix = ""):
+ if type(size) == str:
+ return "N/A"
+
for unit in ['','K','M','G','T','P']:
if abs(size) < 1000.0:
return "%3.2f %s%s" % (size, unit, suffix)
@@ -188,16 +209,22 @@ class CTRexStats(object):
def update(self, snapshot):
# update
- self.last_update_ts = datetime.datetime.now()
-
self.latest_stats = snapshot
- if self.reference_stats == None:
+ diff_time = time.time() - self.last_update_ts
+
+ # 3 seconds is too much - this is the new reference
+ if (self.reference_stats == None) or (diff_time > 3):
self.reference_stats = self.latest_stats
+ self.last_update_ts = time.time()
+
def clear_stats(self):
self.reference_stats = self.latest_stats
+ def invalidate (self):
+ self.latest_stats = {}
+
def get(self, field, format=False, suffix=""):
if not field in self.latest_stats:
return "N/A"
@@ -209,6 +236,7 @@ class CTRexStats(object):
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:
@@ -216,7 +244,6 @@ class CTRexStats(object):
class CGlobalStats(CTRexStats):
- pass
def __init__(self, connection_info, server_version, ports_dict_ref):
super(CGlobalStats, self).__init__()
@@ -242,7 +269,6 @@ class CGlobalStats(CTRexStats):
)
class CPortStats(CTRexStats):
- pass
def __init__(self, port_obj):
super(CPortStats, self).__init__()
@@ -250,15 +276,26 @@ class CPortStats(CTRexStats):
def generate_stats(self):
return {"owner": self._port_obj.user,
- "active": "YES" if self._port_obj.is_active() else "NO",
+ "state": self._port_obj.get_port_state_name(),
+ "--": "",
+ "opackets" : self.get_rel("opackets"),
+ "obytes" : self.get_rel("obytes"),
+ "ipackets" : self.get_rel("ipackets"),
+ "ibytes" : self.get_rel("ibytes"),
+ "ierrors" : self.get_rel("ierrors"),
+ "oerrors" : self.get_rel("oerrors"),
+
"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")
+
+ "---": "",
+ "Tx bps": self.get("m_total_tx_bps", format = True, suffix = "bps"),
+ "Rx bps": self.get("m_total_rx_bps", format = True, suffix = "bps"),
+ "----": "",
+ "Tx pps": self.get("m_total_tx_pps", format = True, suffix = "pps"),
+ "Rx pps": self.get("m_total_rx_pps", format = True, suffix = "pps"),
}
diff --git a/scripts/automation/trex_control_plane/common/trex_streams.py b/scripts/automation/trex_control_plane/common/trex_streams.py
index bb4c72ca..86eee1f4 100755
--- a/scripts/automation/trex_control_plane/common/trex_streams.py
+++ b/scripts/automation/trex_control_plane/common/trex_streams.py
@@ -10,18 +10,31 @@ import copy
import os
StreamPack = namedtuple('StreamPack', ['stream_id', 'stream'])
+LoadedStreamList = namedtuple('LoadedStreamList', ['loaded', 'compiled'])
class CStreamList(object):
def __init__(self):
- self.streams_list = {}
+ self.streams_list = OrderedDict()
self.yaml_loader = CTRexYAMLLoader(os.path.join(os.path.dirname(os.path.realpath(__file__)),
"rpc_defaults.yaml"))
+ def generate_numbered_name (self, name):
+ prefix = name.rstrip('01234567890')
+ suffix = name[len(prefix):]
+ if suffix == "":
+ n = "_1"
+ else:
+ n = int(suffix) + 1
+ return prefix + str(n)
+
def append_stream(self, name, stream_obj):
assert isinstance(stream_obj, CStream)
- if name in self.streams_list:
- raise NameError("A stream with this name already exists on this list.")
+
+ # if name exists simply add numbered suffix to it
+ while name in self.streams_list:
+ name = self.generate_numbered_name(name)
+
self.streams_list[name]=stream_obj
return name
@@ -70,6 +83,7 @@ class CStreamList(object):
stream_ids = {}
for idx, stream_name in enumerate(self.streams_list):
stream_ids[stream_name] = idx
+
# next, iterate over the streams and transform them from working with names to ids.
# with that build a new dict with old stream_name as the key, and StreamPack as the stored value
compiled_streams = {}
@@ -241,5 +255,61 @@ class CStream(object):
raise RuntimeError("CStream object isn't loaded with data. Use 'load_data' method.")
-if __name__ == "__main__":
- pass
+
+# describes a stream DB
+class CStreamsDB(object):
+
+ def __init__(self):
+ self.stream_packs = {}
+
+ def load_yaml_file(self, filename):
+
+ stream_pack_name = filename
+ if stream_pack_name in self.get_loaded_streams_names():
+ self.remove_stream_packs(stream_pack_name)
+
+ stream_list = CStreamList()
+ loaded_obj = stream_list.load_yaml(filename)
+
+ try:
+ compiled_streams = stream_list.compile_streams()
+ rc = self.load_streams(stream_pack_name,
+ LoadedStreamList(loaded_obj,
+ [StreamPack(v.stream_id, v.stream.dump())
+ for k, v in compiled_streams.items()]))
+
+ except Exception as e:
+ return None
+
+ return self.get_stream_pack(stream_pack_name)
+
+ def load_streams(self, name, LoadedStreamList_obj):
+ if name in self.stream_packs:
+ return False
+ else:
+ self.stream_packs[name] = LoadedStreamList_obj
+ return True
+
+ def remove_stream_packs(self, *names):
+ removed_streams = []
+ for name in names:
+ removed = self.stream_packs.pop(name)
+ if removed:
+ removed_streams.append(name)
+ return removed_streams
+
+ def clear(self):
+ self.stream_packs.clear()
+
+ def get_loaded_streams_names(self):
+ return self.stream_packs.keys()
+
+ def stream_pack_exists (self, name):
+ return name in self.get_loaded_streams_names()
+
+ def get_stream_pack(self, name):
+ if not self.stream_pack_exists(name):
+ return None
+ else:
+ return self.stream_packs.get(name)
+
diff --git a/scripts/automation/trex_control_plane/common/trex_types.py b/scripts/automation/trex_control_plane/common/trex_types.py
new file mode 100644
index 00000000..7c3f04c5
--- /dev/null
+++ b/scripts/automation/trex_control_plane/common/trex_types.py
@@ -0,0 +1,68 @@
+
+from collections import namedtuple
+from common.text_opts import *
+
+RpcCmdData = namedtuple('RpcCmdData', ['method', 'params'])
+
+class RpcResponseStatus(namedtuple('RpcResponseStatus', ['success', 'id', 'msg'])):
+ __slots__ = ()
+ def __str__(self):
+ return "{id:^3} - {msg} ({stat})".format(id=self.id,
+ msg=self.msg,
+ stat="success" if self.success else "fail")
+
+# simple class to represent complex return value
+class RC():
+
+ def __init__ (self, rc = None, data = None):
+ self.rc_list = []
+
+ if (rc != None) and (data != None):
+ tuple_rc = namedtuple('RC', ['rc', 'data'])
+ self.rc_list.append(tuple_rc(rc, data))
+
+ def add (self, rc):
+ self.rc_list += rc.rc_list
+
+ def good (self):
+ return all([x.rc for x in self.rc_list])
+
+ def bad (self):
+ return not self.good()
+
+ def data (self):
+ d = [x.data if x.rc else "" for x in self.rc_list]
+ return (d if len(d) > 1 else d[0])
+
+ def err (self):
+ e = [x.data if not x.rc else "" for x in self.rc_list]
+ return (e if len(e) > 1 else e[0])
+
+ def annotate (self, desc = None, show_status = True):
+ if desc:
+ print format_text('\n{:<60}'.format(desc), 'bold'),
+ else:
+ print ""
+
+ if self.bad():
+ # print all the errors
+ print ""
+ for x in self.rc_list:
+ if not x.rc:
+ print format_text("\n{0}".format(x.data), 'bold')
+
+ print ""
+ if show_status:
+ print format_text("[FAILED]\n", 'red', 'bold')
+
+
+ else:
+ if show_status:
+ print format_text("[SUCCESS]\n", 'green', 'bold')
+
+
+def RC_OK(data = ""):
+ return RC(True, data)
+def RC_ERR (err):
+ return RC(False, err)
+