summaryrefslogtreecommitdiffstats
path: root/scripts/automation/trex_control_plane/console
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/automation/trex_control_plane/console')
-rw-r--r--scripts/automation/trex_control_plane/console/trex_console.py130
-rw-r--r--scripts/automation/trex_control_plane/console/trex_status.py403
2 files changed, 451 insertions, 82 deletions
diff --git a/scripts/automation/trex_control_plane/console/trex_console.py b/scripts/automation/trex_control_plane/console/trex_console.py
index 6514a51c..9478db5a 100644
--- a/scripts/automation/trex_control_plane/console/trex_console.py
+++ b/scripts/automation/trex_control_plane/console/trex_console.py
@@ -4,9 +4,13 @@ import cmd
import json
import ast
import argparse
+import random
+import string
+
import sys
import trex_root_path
-from client_utils.jsonrpc_client import JsonRpcClient
+
+from client_utils.jsonrpc_client import TrexStatelessClient
import trex_status
class TrexConsole(cmd.Cmd):
@@ -34,7 +38,7 @@ class TrexConsole(cmd.Cmd):
# set verbose on / off
def do_verbose (self, line):
- '''shows or set verbose mode\n'''
+ '''Shows or set verbose mode\n'''
if line == "":
print "\nverbose is " + ("on\n" if self.verbose else "off\n")
@@ -78,6 +82,98 @@ class TrexConsole(cmd.Cmd):
print "\n*** " + msg + "\n"
return
+ def do_force_acquire (self, line):
+ '''Acquires ports by force\n'''
+
+ self.do_acquire(line, True)
+
+ def parse_ports_from_line (self, line):
+ port_list = set()
+
+ if line:
+ for port_id in line.split(' '):
+ if (not port_id.isdigit()) or (int(port_id) < 0) or (int(port_id) >= self.rpc_client.get_port_count()):
+ print "Please provide a list of ports seperated by spaces between 0 and {0}".format(self.rpc_client.get_port_count() - 1)
+ return None
+
+ port_list.add(int(port_id))
+
+ port_list = list(port_list)
+
+ else:
+ port_list = [i for i in xrange(0, self.rpc_client.get_port_count())]
+
+ return port_list
+
+ def do_acquire (self, line, force = False):
+ '''Acquire ports\n'''
+
+ port_list = self.parse_ports_from_line(line)
+ if not port_list:
+ return
+
+ print "\nTrying to acquire ports: " + (" ".join(str(x) for x in port_list)) + "\n"
+
+ rc, resp_list = self.rpc_client.take_ownership(port_list, force)
+
+ if not rc:
+ print "\n*** " + resp_list + "\n"
+ return
+
+ for i, rc in enumerate(resp_list):
+ if rc[0]:
+ print "Port {0} - Acquired".format(port_list[i])
+ else:
+ print "Port {0} - ".format(port_list[i]) + rc[1]
+
+ print "\n"
+
+ def do_release (self, line):
+ '''Release ports\n'''
+
+ if line:
+ port_list = self.parse_ports_from_line(line)
+ else:
+ port_list = self.rpc_client.get_owned_ports()
+
+ if not port_list:
+ return
+
+ rc, resp_list = self.rpc_client.release_ports(port_list)
+
+
+ print "\n"
+
+ for i, rc in enumerate(resp_list):
+ if rc[0]:
+ print "Port {0} - Released".format(port_list[i])
+ else:
+ print "Port {0} - Failed to release port, probably not owned by you or port is under traffic"
+
+ print "\n"
+
+ def do_get_port_stats (self, line):
+ '''Get ports stats\n'''
+
+ port_list = self.parse_ports_from_line(line)
+ if not port_list:
+ return
+
+ rc, resp_list = self.rpc_client.get_port_stats(port_list)
+
+ if not rc:
+ print "\n*** " + resp_list + "\n"
+ return
+
+ for i, rc in enumerate(resp_list):
+ if rc[0]:
+ print "\nPort {0} stats:\n{1}\n".format(port_list[i], self.rpc_client.pretty_json(json.dumps(rc[1])))
+ else:
+ print "\nPort {0} - ".format(i) + rc[1] + "\n"
+
+ print "\n"
+
+
def do_connect (self, line):
'''Connects to the server\n'''
@@ -97,10 +193,7 @@ class TrexConsole(cmd.Cmd):
print "\n*** " + msg + "\n"
return
- rc, msg = self.rpc_client.query_rpc_server()
-
- if rc:
- self.supported_rpc = [str(x) for x in msg if x]
+ self.supported_rpc = self.rpc_client.get_supported_cmds()
def do_rpc (self, line):
'''Launches a RPC on the server\n'''
@@ -135,7 +228,7 @@ class TrexConsole(cmd.Cmd):
rc, msg = self.rpc_client.invoke_rpc_method(method, params)
if rc:
- print "\nServer Response:\n\n" + json.dumps(msg) + "\n"
+ print "\nServer Response:\n\n" + self.rpc_client.pretty_json(json.dumps(msg)) + "\n"
else:
print "\n*** " + msg + "\n"
#print "Please try 'reconnect' to reconnect to server"
@@ -151,7 +244,7 @@ class TrexConsole(cmd.Cmd):
trex_status.show_trex_status(self.rpc_client)
def do_quit(self, line):
- '''exit the client\n'''
+ '''Exit the client\n'''
return True
def do_disconnect (self, line):
@@ -166,6 +259,10 @@ class TrexConsole(cmd.Cmd):
else:
print msg + "\n"
+ def do_whoami (self, line):
+ '''Prints console user name\n'''
+ print "\n" + self.rpc_client.whoami() + "\n"
+
def postcmd(self, stop, line):
if self.rpc_client.is_connected():
self.prompt = "TRex > "
@@ -216,20 +313,31 @@ class TrexConsole(cmd.Cmd):
print "{:<30} {:<30}".format(cmd + " - ", help)
+ # do
+ #def do_snapshot (self, line):
+
+ #for key, value in self.rpc_client.snapshot()[1]['streams'].iteritems():
+ #print str(key) + " " + str(value)
+
+
# aliasing
do_exit = do_EOF = do_q = do_quit
def setParserOptions ():
parser = argparse.ArgumentParser(prog="trex_console.py")
- parser.add_argument("-s", "--server", help = "T-Rex Server [default is localhost]",
+ parser.add_argument("-s", "--server", help = "TRex Server [default is localhost]",
default = "localhost",
type = str)
- parser.add_argument("-p", "--port", help = "T-Rex Server Port [default is 5050]\n",
+ parser.add_argument("-p", "--port", help = "TRex Server Port [default is 5050]\n",
default = 5050,
type = int)
+ parser.add_argument("-u", "--user", help = "User Name [default is random generated]\n",
+ default = 'user_' + ''.join(random.choice(string.digits) for _ in range(5)),
+ type = str)
+
return parser
def main ():
@@ -237,7 +345,7 @@ def main ():
options = parser.parse_args(sys.argv[1:])
# RPC client
- rpc_client = JsonRpcClient(options.server, options.port)
+ rpc_client = TrexStatelessClient(options.server, options.port, options.user)
# console
try:
diff --git a/scripts/automation/trex_control_plane/console/trex_status.py b/scripts/automation/trex_control_plane/console/trex_status.py
index 54853ea3..b881f9f5 100644
--- a/scripts/automation/trex_control_plane/console/trex_status.py
+++ b/scripts/automation/trex_control_plane/console/trex_status.py
@@ -11,13 +11,21 @@ import datetime
g_curses_active = False
-#
+# simple percetange show
def percentage (a, total):
x = int ((float(a) / total) * 100)
return str(x) + "%"
+# simple float to human readable
+def float_to_human_readable (size, suffix = "bps"):
+ for unit in ['','K','M','G']:
+ if abs(size) < 1024.0:
+ return "%3.1f %s%s" % (size, unit, suffix)
+ size /= 1024.0
+ return "NaN"
+
# panel object
-class TrexStatusPanel():
+class TrexStatusPanel(object):
def __init__ (self, h, l, y, x, headline):
self.h = h
self.l = l
@@ -44,12 +52,245 @@ class TrexStatusPanel():
def getwin (self):
return self.win
-def float_to_human_readable (size, suffix = "bps"):
- for unit in ['','K','M','G']:
- if abs(size) < 1024.0:
- return "%3.1f %s%s" % (size, unit, suffix)
- size /= 1024.0
- return "NaN"
+
+# total stats (ports + global)
+class Stats():
+ def __init__ (self, rpc_client, port_list, interval = 100):
+
+ self.rpc_client = rpc_client
+
+ self.port_list = port_list
+ self.port_stats = {}
+
+ self.interval = interval
+ self.delay_count = 0
+
+ def get_port_stats (self, port_id):
+ if self.port_stats.get(port_id):
+ return self.port_stats[port_id]
+ else:
+ return None
+
+ def query_sync (self):
+ self.delay_count += 1
+ if self.delay_count < self.interval:
+ return
+
+ self.delay_count = 0
+
+ # query global stats
+
+ # query port stats
+
+ rc, resp_list = self.rpc_client.get_port_stats(self.port_list)
+ if not rc:
+ return
+
+ for i, rc in enumerate(resp_list):
+ if rc[0]:
+ self.port_stats[self.port_list[i]] = rc[1]
+
+
+# various kinds of panels
+
+# Server Info Panel
+class ServerInfoPanel(TrexStatusPanel):
+ def __init__ (self, h, l, y, x, status_obj):
+
+ super(ServerInfoPanel, self).__init__(h, l, y ,x ,"Server Info:")
+
+ self.status_obj = status_obj
+
+ def draw (self):
+
+ if self.status_obj.server_version == None:
+ return
+
+ self.clear()
+
+ connection_details = self.status_obj.rpc_client.get_connection_details()
+
+ self.getwin().addstr(3, 2, "{:<30} {:30}".format("Server:",self.status_obj.server_sys_info["hostname"] + ":" + str(connection_details['port'])))
+ self.getwin().addstr(4, 2, "{:<30} {:30}".format("Version:", self.status_obj.server_version["version"]))
+ self.getwin().addstr(5, 2, "{:<30} {:30}".format("Build:",
+ self.status_obj.server_version["build_date"] + " @ " +
+ self.status_obj.server_version["build_time"] + " by " +
+ self.status_obj.server_version["built_by"]))
+
+ self.getwin().addstr(6, 2, "{:<30} {:30}".format("Server Uptime:", self.status_obj.server_sys_info["uptime"]))
+ self.getwin().addstr(7, 2, "{:<30} {:<3} / {:<30}".format("DP Cores:", str(self.status_obj.server_sys_info["dp_core_count"]) +
+ " cores", self.status_obj.server_sys_info["core_type"]))
+
+ self.getwin().addstr(9, 2, "{:<30} {:<30}".format("Ports Count:", self.status_obj.server_sys_info["port_count"]))
+
+ ports_owned = " ".join(str(x) for x in self.status_obj.rpc_client.get_owned_ports())
+
+ if not ports_owned:
+ ports_owned = "None"
+
+ self.getwin().addstr(10, 2, "{:<30} {:<30}".format("Ports Owned:", ports_owned))
+
+# general info panel
+class GeneralInfoPanel(TrexStatusPanel):
+ def __init__ (self, h, l, y, x, status_obj):
+
+ super(GeneralInfoPanel, self).__init__(h, l, y ,x ,"General Info:")
+
+ self.status_obj = status_obj
+
+ def draw (self):
+ pass
+
+# all ports stats
+class PortsStatsPanel(TrexStatusPanel):
+ def __init__ (self, h, l, y, x, status_obj):
+
+ super(PortsStatsPanel, self).__init__(h, l, y ,x ,"Trex Ports:")
+
+ self.status_obj = status_obj
+
+ def draw (self):
+
+ self.clear()
+
+ owned_ports = self.status_obj.rpc_client.get_owned_ports()
+ if not owned_ports:
+ self.getwin().addstr(3, 2, "No Owned Ports - Please Acquire One Or More Ports")
+ return
+
+ # table header
+ self.getwin().addstr(3, 2, "{:^15} {:^15} {:^15} {:^15} {:^15} {:^15} {:^15}".format(
+ "Port ID", "Tx [pps]", "Tx [bps]", "Tx [bytes]", "Rx [pps]", "Rx [bps]", "Rx [bytes]"))
+
+ # port loop
+ self.status_obj.stats.query_sync()
+
+ for i, port_index in enumerate(owned_ports):
+
+ port_stats = self.status_obj.stats.get_port_stats(port_index)
+
+ if port_stats:
+ self.getwin().addstr(5 + (i * 4), 2, "{:^15} {:^15,} {:^15,} {:^15,} {:^15,} {:^15,} {:^15,}".format(
+ "{0} ({1})".format(str(port_index), self.status_obj.server_sys_info["ports"][port_index]["speed"]),
+ port_stats["tx_pps"],
+ port_stats["tx_bps"],
+ port_stats["total_tx_bytes"],
+ port_stats["rx_pps"],
+ port_stats["rx_bps"],
+ port_stats["total_rx_bytes"]))
+
+ else:
+ self.getwin().addstr(5 + (i * 4), 2, "{:^15} {:^15} {:^15} {:^15} {:^15} {:^15} {:^15}".format(
+ "{0} ({1})".format(str(port_index), self.status_obj.server_sys_info["ports"][port_index]["speed"]),
+ "N/A",
+ "N/A",
+ "N/A",
+ "N/A",
+ "N/A",
+ "N/A"))
+
+# control panel
+class ControlPanel(TrexStatusPanel):
+ def __init__ (self, h, l, y, x, status_obj):
+
+ super(ControlPanel, self).__init__(h, l, y, x, "")
+
+ self.status_obj = status_obj
+
+ def draw (self):
+ self.clear()
+
+ self.getwin().addstr(1, 2, "'g' - general, '0-{0}' - specific port, 'f' - freeze, 'c' - clear stats, 'p' - ping server, 'q' - quit"
+ .format(self.status_obj.rpc_client.get_port_count() - 1))
+
+ index = 3
+
+ cut = len(self.status_obj.log) - 4
+ if cut < 0:
+ cut = 0
+
+ for l in self.status_obj.log[cut:]:
+ self.getwin().addstr(index, 2, l)
+ index += 1
+
+# specific ports panels
+class SinglePortPanel(TrexStatusPanel):
+ def __init__ (self, h, l, y, x, status_obj, port_id):
+
+ super(SinglePortPanel, self).__init__(h, l, y, x, "Port {0}".format(port_id))
+
+ self.status_obj = status_obj
+ self.port_id = port_id
+
+ def draw (self):
+ y = 3
+
+ self.clear()
+
+ if not self.port_id in self.status_obj.rpc_client.get_owned_ports():
+ self.getwin().addstr(y, 2, "Port {0} is not owned by you, please acquire the port for more info".format(self.port_id))
+ return
+
+ # streams
+ self.getwin().addstr(y, 2, "Streams:", curses.A_UNDERLINE)
+ y += 2
+
+ # stream table header
+ self.getwin().addstr(y, 2, "{:^15} {:^15} {:^15} {:^15} {:^15} {:^15} {:^15}".format(
+ "Stream ID", "Enabled", "Type", "Self Start", "ISG", "Next Stream", "VM"))
+ y += 2
+
+ # streams
+ if 'streams' in self.status_obj.snapshot[self.port_id]:
+ for stream_id, stream in self.status_obj.snapshot[self.port_id]['streams'].iteritems():
+ self.getwin().addstr(y, 2, "{:^15} {:^15} {:^15} {:^15} {:^15} {:^15} {:^15}".format(
+ stream_id,
+ ("True" if stream['stream']['enabled'] else "False"),
+ stream['stream']['mode']['type'],
+ ("True" if stream['stream']['self_start'] else "False"),
+ stream['stream']['isg'],
+ (stream['stream']['next_stream_id'] if stream['stream']['next_stream_id'] != -1 else "None"),
+ ("{0} instr.".format(len(stream['stream']['vm'])) if stream['stream']['vm'] else "None")))
+
+ y += 1
+
+ # new section - traffic
+ y += 2
+
+ self.getwin().addstr(y, 2, "Traffic:", curses.A_UNDERLINE)
+ y += 2
+
+ self.status_obj.stats.query_sync()
+ port_stats = self.status_obj.stats.get_port_stats(self.port_id)
+
+
+ # table header
+ self.getwin().addstr(y, 2, "{:^15} {:^15} {:^15} {:^15} {:^15} {:^15} {:^15}".format(
+ "Port ID", "Tx [pps]", "Tx [bps]", "Tx [bytes]", "Rx [pps]", "Rx [bps]", "Rx [bytes]"))
+
+ y += 2
+
+ if port_stats:
+ self.getwin().addstr(y, 2, "{:^15} {:^15,} {:^15,} {:^15,} {:^15,} {:^15,} {:^15,}".format(
+ "{0} ({1})".format(str(self.port_id), self.status_obj.server_sys_info["ports"][self.port_id]["speed"]),
+ port_stats["tx_pps"],
+ port_stats["tx_bps"],
+ port_stats["total_tx_bytes"],
+ port_stats["rx_pps"],
+ port_stats["rx_bps"],
+ port_stats["total_rx_bytes"]))
+
+ else:
+ self.getwin().addstr(y, 2, "{:^15} {:^15} {:^15} {:^15} {:^15} {:^15} {:^15}".format(
+ "{0} ({1})".format(str(self.port_id), self.status_obj.server_sys_info["ports"][self.port_id]["speed"]),
+ "N/A",
+ "N/A",
+ "N/A",
+ "N/A",
+ "N/A",
+ "N/A"))
+
+ y += 2
# status object
class TrexStatus():
@@ -58,58 +299,78 @@ class TrexStatus():
self.log = []
self.rpc_client = rpc_client
+ self.snapshot = self.rpc_client.snapshot()
+
+ # fetch server info
self.get_server_info()
- def get_server_info (self):
- rc, msg = self.rpc_client.get_rpc_server_status()
+ # create stats objects
+ self.stats = Stats(rpc_client, self.rpc_client.get_owned_ports())
- if rc:
- self.server_status = msg
- else:
- self.server_status = None
+ # register actions
+ self.actions = {}
+ self.actions[ord('q')] = self.action_quit
+ self.actions[ord('p')] = self.action_ping
+ self.actions[ord('f')] = self.action_freeze
- def add_log_event (self, msg):
- self.log.append("[{0}] {1}".format(str(datetime.datetime.now().time()), msg))
+ self.actions[ord('g')] = self.action_show_ports_stats
- def add_panel (self, h, l, y, x, headline):
- win = curses.newwin(h, l, y, x)
- win.erase()
- win.box()
+ for port_id in xrange(0, self.rpc_client.get_port_count()):
+ self.actions[ord('0') + port_id] = self.action_show_port_generator(port_id)
- win.addstr(1, 2, headline)
- win.refresh()
+
+ # all ports stats
+ def action_show_ports_stats (self):
+ self.add_log_event("Switching to all ports view")
+ self.stats_panel = self.ports_stats_panel
+
+ return True
- panel.new_panel(win)
- panel1 = panel.new_panel(win)
- panel1.top()
+ # function generator for different ports requests
+ def action_show_port_generator (self, port_id):
+ def action_show_port():
+ self.add_log_event("Switching panel to port {0}".format(port_id))
+ self.stats_panel = self.ports_panels[port_id]
- return win, panel1
+ return True
- # static info panel
- def update_info (self):
- if self.server_status == None:
- return
+ return action_show_port
- self.info_panel.clear()
+ def action_freeze (self):
+ self.update_active = not self.update_active
+ self.add_log_event("Update continued" if self.update_active else "Update stopped")
- connection_details = self.rpc_client.get_connection_details()
+ return True
- self.info_panel.getwin().addstr(3, 2, "{:<30} {:30}".format("Server:", connection_details['server'] + ":" + str(connection_details['port'])))
- self.info_panel.getwin().addstr(4, 2, "{:<30} {:30}".format("Version:", self.server_status["general"]["version"]))
- self.info_panel.getwin().addstr(5, 2, "{:<30} {:30}".format("Build:",
- self.server_status["general"]["build_date"] + " @ " + self.server_status["general"]["build_time"] + " by " + self.server_status["general"]["version_user"]))
+ def action_quit(self):
+ return False
- self.info_panel.getwin().addstr(6, 2, "{:<30} {:30}".format("Server Uptime:", self.server_status["general"]["uptime"]))
+ def action_ping (self):
+ self.add_log_event("Pinging RPC server")
+
+ rc, msg = self.rpc_client.ping_rpc_server()
+ if rc:
+ self.add_log_event("Server replied: '{0}'".format(msg))
+ else:
+ self.add_log_event("Failed to get reply")
+
+ return True
+
+ def get_server_info (self):
+
+ self.server_version = self.rpc_client.get_rpc_server_version()
+ self.server_sys_info = self.rpc_client.get_system_info()
- # general stats
- def update_general (self, gen_stats):
- pass
+
+ def add_log_event (self, msg):
+ self.log.append("[{0}] {1}".format(str(datetime.datetime.now().time()), msg))
# control panel
def update_control (self):
self.control_panel.clear()
- self.control_panel.getwin().addstr(1, 2, "'f' - freeze, 'c' - clear stats, 'p' - ping server, 'q' - quit")
+ self.control_panel.getwin().addstr(1, 2, "'g' - general, '0-{0}' - specific port, 'f' - freeze, 'c' - clear stats, 'p' - ping server, 'q' - quit"
+ .format(self.rpc_client.get_port_count() - 1))
index = 3
@@ -125,42 +386,37 @@ class TrexStatus():
self.max_y = self.stdscr.getmaxyx()[0]
self.max_x = self.stdscr.getmaxyx()[1]
- # create cls panel
- self.main_panel = TrexStatusPanel(int(self.max_y * 0.8), self.max_x / 2, 0,0, "Trex Ports:")
+ self.server_info_panel = ServerInfoPanel(int(self.max_y * 0.3), self.max_x / 2, int(self.max_y * 0.5), self.max_x /2, self)
+ self.general_info_panel = GeneralInfoPanel(int(self.max_y * 0.5), self.max_x / 2, 0, self.max_x /2, self)
+ self.control_panel = ControlPanel(int(self.max_y * 0.2), self.max_x , int(self.max_y * 0.8), 0, self)
- self.general_panel = TrexStatusPanel(int(self.max_y * 0.6), self.max_x / 2, 0, self.max_x /2, "General Statistics:")
+ # those can be switched on the same place
+ self.ports_stats_panel = PortsStatsPanel(int(self.max_y * 0.8), self.max_x / 2, 0, 0, self)
- self.info_panel = TrexStatusPanel(int(self.max_y * 0.2), self.max_x / 2, int(self.max_y * 0.6), self.max_x /2, "Server Info:")
+ self.ports_panels = {}
+ for i in xrange(0, self.rpc_client.get_port_count()):
+ self.ports_panels[i] = SinglePortPanel(int(self.max_y * 0.8), self.max_x / 2, 0, 0, self, i)
- self.control_panel = TrexStatusPanel(int(self.max_y * 0.2), self.max_x , int(self.max_y * 0.8), 0, "")
+ # at start time we point to the main one
+ self.stats_panel = self.ports_stats_panel
+ self.stats_panel.panel.top()
panel.update_panels(); self.stdscr.refresh()
+ return
+
def wait_for_key_input (self):
ch = self.stdscr.getch()
- if (ch != curses.ERR):
- # stop/start status
- if (ch == ord('f')):
- self.update_active = not self.update_active
- self.add_log_event("Update continued" if self.update_active else "Update stopped")
-
- elif (ch == ord('p')):
- self.add_log_event("Pinging RPC server")
- rc, msg = self.rpc_client.ping_rpc_server()
- if rc:
- self.add_log_event("Server replied: '{0}'".format(msg))
- else:
- self.add_log_event("Failed to get reply")
-
- # c - clear stats
- elif (ch == ord('c')):
- self.add_log_event("Statistics cleared")
-
- elif (ch == ord('q')):
- return False
- else:
- self.add_log_event("Unknown key pressed {0}".format("'" + chr(ch) + "'" if chr(ch).isalpha() else ""))
+ # no key , continue
+ if ch == curses.ERR:
+ return True
+
+ # check for registered function
+ if ch in self.actions:
+ return self.actions[ch]()
+ else:
+ self.add_log_event("Unknown key pressed, please see legend")
return True
@@ -185,12 +441,17 @@ class TrexStatus():
if not rc:
break
- self.update_control()
- self.update_info()
+ self.server_info_panel.draw()
+ self.general_info_panel.draw()
+ self.control_panel.draw()
+
+ # can be different kinds of panels
+ self.stats_panel.panel.top()
+ self.stats_panel.draw()
panel.update_panels();
self.stdscr.refresh()
- sleep(0.1)
+ sleep(0.01)
def show_trex_status_internal (stdscr, rpc_client):