From a2a634fc8b5bac450ea37f29dde521b7d9e740c8 Mon Sep 17 00:00:00 2001 From: Dan Klein Date: Thu, 22 Oct 2015 13:44:25 +0300 Subject: minor updates --- .../automation/trex_control_plane/console/trex_console.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'scripts/automation/trex_control_plane/console') diff --git a/scripts/automation/trex_control_plane/console/trex_console.py b/scripts/automation/trex_control_plane/console/trex_console.py index a9ac040b..0f5c30af 100755 --- a/scripts/automation/trex_control_plane/console/trex_console.py +++ b/scripts/automation/trex_control_plane/console/trex_console.py @@ -17,6 +17,8 @@ See the License for the specific language governing permissions and limitations under the License. """ +__version__ = "1.0" + import cmd import json import ast @@ -38,7 +40,7 @@ LoadedStreamList = namedtuple('LoadedStreamList', ['loaded', 'compiled']) # -def readch (choices = []): +def readch(choices=[]): fd = sys.stdin.fileno() old_settings = termios.tcgetattr(fd) @@ -119,7 +121,7 @@ class AddStreamMenu(CmdMenu): self.add_menu('Please select ISG', ['d', 'e', 'f']) # main console object -class TrexConsole(cmd.Cmd): +class TRexConsole(cmd.Cmd): """Trex Console""" def __init__(self, rpc_client): @@ -129,7 +131,7 @@ class TrexConsole(cmd.Cmd): self.do_connect("") - self.intro = "\n-=TRex Console V1.0=-\n" + self.intro = "\n-=TRex Console v{ver}=-\n".format(ver=__version__) self.intro += "\nType 'help' or '?' for supported actions\n" self.verbose = False @@ -473,7 +475,7 @@ class TrexConsole(cmd.Cmd): def complete_load_stream_list(self, text, line, begidx, endidx): arg_num = len(line.split()) - 1 if arg_num == 2: - return TrexConsole.tree_autocomplete(line.split()[-1]) + return TRexConsole.tree_autocomplete(line.split()[-1]) else: return [text] @@ -581,7 +583,7 @@ def main (): # console try: - console = TrexConsole(rpc_client) + console = TRexConsole(rpc_client) console.cmdloop() except KeyboardInterrupt as e: print "\n\n*** Caught Ctrl + C... Exiting...\n\n" -- cgit From ebb0b48faca96bad7bfe8da0bf80df7c7c80350d Mon Sep 17 00:00:00 2001 From: Dan Klein Date: Sun, 25 Oct 2015 11:33:48 +0200 Subject: HLTAPI progress... --- scripts/automation/trex_control_plane/console/trex_console.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'scripts/automation/trex_control_plane/console') diff --git a/scripts/automation/trex_control_plane/console/trex_console.py b/scripts/automation/trex_control_plane/console/trex_console.py index 0f5c30af..4f9743f4 100755 --- a/scripts/automation/trex_control_plane/console/trex_console.py +++ b/scripts/automation/trex_control_plane/console/trex_console.py @@ -17,7 +17,6 @@ See the License for the specific language governing permissions and limitations under the License. """ -__version__ = "1.0" import cmd import json @@ -36,6 +35,8 @@ from client_utils.jsonrpc_client import TrexStatelessClient import trex_status from collections import namedtuple +__version__ = "1.0" + LoadedStreamList = namedtuple('LoadedStreamList', ['loaded', 'compiled']) # -- cgit From 0c2b3c83f9cc0c25277c39660dce132aad55c3d7 Mon Sep 17 00:00:00 2001 From: Dan Klein Date: Wed, 28 Oct 2015 07:28:37 +0200 Subject: updated more HLTAPI functionality and fixed found bugs. Working: Start/stop traffic, traffic config (semi), connect, clean Missing: stats Next: boost console --- scripts/automation/trex_control_plane/console/trex_console.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'scripts/automation/trex_control_plane/console') diff --git a/scripts/automation/trex_control_plane/console/trex_console.py b/scripts/automation/trex_control_plane/console/trex_console.py index 4f9743f4..2ea29473 100755 --- a/scripts/automation/trex_control_plane/console/trex_console.py +++ b/scripts/automation/trex_control_plane/console/trex_console.py @@ -449,10 +449,10 @@ class TRexConsole(cmd.Cmd): try: compiled_streams = stream_list.compile_streams() self.user_streams[name] = LoadedStreamList(loaded_obj, - [StreamPack(v.stream_id, v.stream.dump_compiled()) + [StreamPack(v.stream_id, v.stream.dump()) for k, v in compiled_streams.items()]) - print "Stream '{0}' loaded successfully".format(name) + print "Stream list '{0}' loaded successfully".format(name) except Exception as e: raise return -- cgit From f963facdc949c087c863b8ad81aae537bcf3767b Mon Sep 17 00:00:00 2001 From: Dan Klein Date: Wed, 28 Oct 2015 23:59:11 +0200 Subject: console progress, still SHAKY! --- .../trex_control_plane/console/trex_console.py | 238 ++++++++++++--------- 1 file changed, 132 insertions(+), 106 deletions(-) (limited to 'scripts/automation/trex_control_plane/console') diff --git a/scripts/automation/trex_control_plane/console/trex_console.py b/scripts/automation/trex_control_plane/console/trex_console.py index 2ea29473..241d46b9 100755 --- a/scripts/automation/trex_control_plane/console/trex_console.py +++ b/scripts/automation/trex_control_plane/console/trex_console.py @@ -29,6 +29,7 @@ import sys import tty, termios import trex_root_path from common.trex_streams import * +from client.trex_stateless_client import CTRexStatelessClient from client_utils.jsonrpc_client import TrexStatelessClient @@ -75,6 +76,25 @@ class YesNoMenu(object): else: return False +class CStreamsDB(object): + + def __init__(self): + self.loaded_streams = {} + + def load_streams(self, name, LoadedStreamList_obj): + if name in self.loaded_streams: + return False + else: + self.loaded_streams[name] = LoadedStreamList_obj + return True + + def remove_streams(self, name): + return self.loaded_streams.pop(name) + + def get_loaded_streams(self): + return self.loaded_streams.keys() + + # multi level cmd menu class CmdMenu(object): def __init__ (self): @@ -125,10 +145,10 @@ class AddStreamMenu(CmdMenu): class TRexConsole(cmd.Cmd): """Trex Console""" - def __init__(self, rpc_client): + def __init__(self, stateless_client, verbose): cmd.Cmd.__init__(self) - self.rpc_client = rpc_client + self.stateless_client = stateless_client self.do_connect("") @@ -140,6 +160,7 @@ class TRexConsole(cmd.Cmd): self.postcmd(False, "") self.user_streams = {} + self.streams_db = CStreamsDB() # a cool hack - i stole this function and added space @@ -155,12 +176,12 @@ class TRexConsole(cmd.Cmd): elif line == "on": self.verbose = True - self.rpc_client.set_verbose(True) + self.stateless_client.set_verbose(True) print "\nverbose set to on\n" elif line == "off": self.verbose = False - self.rpc_client.set_verbose(False) + self.stateless_client.set_verbose(False) print "\nverbose set to off\n" else: @@ -170,7 +191,7 @@ class TRexConsole(cmd.Cmd): def do_query_server(self, line): '''query the RPC server for supported remote commands\n''' - rc, msg = self.rpc_client.query_rpc_server() + rc, msg = self.stateless_client.query_rpc_server() if not rc: print "\n*** " + msg + "\n" return @@ -186,8 +207,8 @@ class TRexConsole(cmd.Cmd): print "\n-> Pinging RPC server" - rc, msg = self.rpc_client.ping_rpc_server() - if rc: + res_ok, msg = self.stateless_client.ping() + if res_ok: print "[SUCCESS]\n" else: print "\n*** " + msg + "\n" @@ -198,13 +219,15 @@ class TRexConsole(cmd.Cmd): self.do_acquire(line, True) + def extract_port_ids_from_line(self, line): + return {int(x) for x in line.split()} + 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) + if (not port_id.isdigit()) or (int(port_id) < 0) or (int(port_id) >= self.stateless_client.get_port_count()): + print "Please provide a list of ports separated by spaces between 0 and {0}".format(self.stateless_client.get_port_count() - 1) return None port_list.add(int(port_id)) @@ -212,106 +235,86 @@ class TRexConsole(cmd.Cmd): port_list = list(port_list) else: - port_list = [i for i in xrange(0, self.rpc_client.get_port_count())] + port_list = [i for i in xrange(0, self.stateless_client.get_port_count())] return port_list - def do_acquire (self, line, force = False): + def do_acquire (self, line, force=False): '''Acquire ports\n''' # make sure that the user wants to acquire all - if line == "": - ask = YesNoMenu('Do you want to acquire all ports ? ') + args = line.split() + if len(args) < 1: + print "Please provide a list of ports separated by spaces, or specify 'all' to acquire all available ports" + if args[0] == "all": + ask = YesNoMenu('Are you sure you want to acquire all ports ? ') rc = ask.show() if rc == False: return - - port_list = self.parse_ports_from_line(line) - if not port_list: - return + else: + port_list = self.stateless_client.get_port_ids() + else: + port_list = self.extract_port_ids_from_line(line) 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" + # rc, resp_list = self.stateless_client.take_ownership(port_list, force) + res_ok, log = self.stateless_client.acquire(port_list, force) + self.prompt_response(log) + if not res_ok: + print "[FAILED]\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" + print "[SUCCESS]\n" + return 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]) + # if line: + # port_list = self.parse_ports_from_line(line) + # else: + # port_list = self.stateless_client.get_owned_ports() + args = line.split() + if len(args) < 1: + print "Please provide a list of ports separated by spaces, or specify 'all' to acquire all available ports" + if args[0] == "all": + ask = YesNoMenu('Are you sure you want to release all acquired ports ? ') + rc = ask.show() + if rc == False: + return 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) + port_list = self.stateless_client.get_acquired_ports() + else: + port_list = self.extract_port_ids_from_line(line) - if not rc: - print "\n*** " + resp_list + "\n" + res_ok, log = self.stateless_client.release(port_list) + self.prompt_response(log) + if not res_ok: + print "[FAILED]\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" - + print "[SUCCESS]\n" + return def do_connect (self, line): '''Connects to the server\n''' if line == "": - rc, msg = self.rpc_client.connect() + res_ok, msg = self.stateless_client.connect() else: sp = line.split() if (len(sp) != 2): print "\n[usage] connect [server] [port] or without parameters\n" return - rc, msg = self.rpc_client.connect(sp[0], sp[1]) + res_ok, msg = self.stateless_client.connect(sp[0], sp[1]) - if rc: + if res_ok: print "[SUCCESS]\n" else: print "\n*** " + msg + "\n" return - self.supported_rpc = self.rpc_client.get_supported_cmds() + self.supported_rpc = self.stateless_client.get_supported_cmds().data def do_rpc (self, line): '''Launches a RPC on the server\n''' @@ -344,9 +347,9 @@ class TRexConsole(cmd.Cmd): print "Example: rpc test_add {'x': 12, 'y': 17}\n" return - rc, msg = self.rpc_client.invoke_rpc_method(method, params) - if rc: - print "\nServer Response:\n\n" + self.rpc_client.pretty_json(json.dumps(msg)) + "\n" + res_ok, msg = self.stateless_client.invoke_rpc_method(method, params) + if res_ok: + print "\nServer Response:\n\n" + self.stateless_client.pretty_json(json.dumps(msg)) + "\n" else: print "\n*** " + msg + "\n" #print "Please try 'reconnect' to reconnect to server" @@ -359,7 +362,7 @@ class TRexConsole(cmd.Cmd): '''Shows a graphical console\n''' self.do_verbose('off') - trex_status.show_trex_status(self.rpc_client) + trex_status.show_trex_status(self.stateless_client) def do_quit(self, line): '''Exit the client\n''' @@ -367,22 +370,22 @@ class TRexConsole(cmd.Cmd): def do_disconnect (self, line): '''Disconnect from the server\n''' - if not self.rpc_client.is_connected(): + if not self.stateless_client.is_connected(): print "Not connected to server\n" return - rc, msg = self.rpc_client.disconnect() - if rc: + res_ok, msg = self.stateless_client.disconnect() + if res_ok: print "[SUCCESS]\n" else: print msg + "\n" def do_whoami (self, line): '''Prints console user name\n''' - print "\n" + self.rpc_client.whoami() + "\n" + print "\n" + self.stateless_client.user + "\n" def postcmd(self, stop, line): - if self.rpc_client.is_connected(): + if self.stateless_client.is_connected(): self.prompt = "TRex > " else: self.supported_rpc = None @@ -430,7 +433,7 @@ class TRexConsole(cmd.Cmd): print "{:<30} {:<30}".format(cmd + " - ", help) - def do_load_stream_list(self, line): + def do_stream_db_add(self, line): '''Loads a YAML stream list serialization into user console \n''' args = line.split() if args >= 2: @@ -442,19 +445,31 @@ class TRexConsole(cmd.Cmd): multiplier = 1 stream_list = CStreamList() loaded_obj = stream_list.load_yaml(yaml_path, multiplier) - # print self.rpc_client.pretty_json(json.dumps(loaded_obj)) - if name in self.user_streams: - print "Picked name already exist. Please pick another name." - else: - try: - compiled_streams = stream_list.compile_streams() - self.user_streams[name] = LoadedStreamList(loaded_obj, - [StreamPack(v.stream_id, v.stream.dump()) - for k, v in compiled_streams.items()]) - + # print self.stateless_client.pretty_json(json.dumps(loaded_obj)) + try: + compiled_streams = stream_list.compile_streams() + res_ok = self.streams_db.load_streams(name, LoadedStreamList(loaded_obj, + [StreamPack(v.stream_id, v.stream.dump()) + for k, v in compiled_streams.items()])) + if res_ok: print "Stream list '{0}' loaded successfully".format(name) - except Exception as e: - raise + else: + print "Picked name already exist. Please pick another name." + except Exception as e: + print "adding new stream failed due to the following error:\n", str(e) + + # if name in self.user_streams: + # print "Picked name already exist. Please pick another name." + # else: + # try: + # compiled_streams = stream_list.compile_streams() + # self.user_streams[name] = LoadedStreamList(loaded_obj, + # [StreamPack(v.stream_id, v.stream.dump()) + # for k, v in compiled_streams.items()]) + # + # print "Stream list '{0}' loaded successfully".format(name) + # except Exception as e: + # raise return else: print "please provide load name and YAML path, separated by space.\n" \ @@ -473,7 +488,7 @@ class TRexConsole(cmd.Cmd): if x.startswith(start_string)] - def complete_load_stream_list(self, text, line, begidx, endidx): + def complete_stream_db_add(self, text, line, begidx, endidx): arg_num = len(line.split()) - 1 if arg_num == 2: return TRexConsole.tree_autocomplete(line.split()[-1]) @@ -488,9 +503,9 @@ class TRexConsole(cmd.Cmd): try: stream = self.user_streams[list_name] if len(args) >= 2 and args[1] == "full": - print self.rpc_client.pretty_json(json.dumps(stream.compiled)) + print self.stateless_client.pretty_json(json.dumps(stream.compiled)) else: - print self.rpc_client.pretty_json(json.dumps(stream.loaded)) + print self.stateless_client.pretty_json(json.dumps(stream.loaded)) except KeyError as e: print "Unknown stream list name provided" else: @@ -508,9 +523,9 @@ class TRexConsole(cmd.Cmd): try: stream_list = self.user_streams[args[0]] port_list = self.parse_ports_from_line(' '.join(args[1:])) - owned = set(self.rpc_client.get_owned_ports()) + owned = set(self.stateless_client.get_owned_ports()) if set(port_list).issubset(owned): - rc, resp_list = self.rpc_client.add_stream(port_list, stream_list.compiled) + rc, resp_list = self.stateless_client.add_stream(port_list, stream_list.compiled) if not rc: print "\n*** " + resp_list + "\n" return @@ -528,6 +543,12 @@ class TRexConsole(cmd.Cmd): print "Please provide list name and ports to attach to, or leave empty to attach to all ports." + def prompt_response(self, response_obj): + resp_list = response_obj if isinstance(response_obj, list) else [response_obj] + for response in resp_list: + print response + + @@ -549,9 +570,9 @@ class TRexConsole(cmd.Cmd): stream_id = int(params[1]) packet = [0xFF,0xFF,0xFF] - rc, msg = self.rpc_client.add_stream(port_id = port_id, stream_id = stream_id, isg = 1.1, next_stream_id = -1, packet = packet) + rc, msg = self.stateless_client.add_stream(port_id = port_id, stream_id = stream_id, isg = 1.1, next_stream_id = -1, packet = packet) if rc: - print "\nServer Response:\n\n" + self.rpc_client.pretty_json(json.dumps(msg)) + "\n" + print "\nServer Response:\n\n" + self.stateless_client.pretty_json(json.dumps(msg)) + "\n" else: print "\n*** " + msg + "\n" @@ -573,18 +594,23 @@ def setParserOptions (): default = 'user_' + ''.join(random.choice(string.digits) for _ in range(5)), type = str) + parser.add_argument("--verbose", dest="verbose", + action="store_true", help="Switch ON verbose option. Default is: OFF.", + default = False) + return parser def main (): parser = setParserOptions() - options = parser.parse_args(sys.argv[1:]) + options = parser.parse_args()#sys.argv[1:]) - # RPC client - rpc_client = TrexStatelessClient(options.server, options.port, options.user) + # Stateless client connection + # stateless_client = TrexStatelessClient(options.server, options.port, options.user) + stateless_client = CTRexStatelessClient(options.user, options.server, options.port) # console try: - console = TRexConsole(rpc_client) + console = TRexConsole(stateless_client, options.verbose) console.cmdloop() except KeyboardInterrupt as e: print "\n\n*** Caught Ctrl + C... Exiting...\n\n" -- cgit From aa37a0abb00cbf4cb1611f9c0eefcb1ab850bc45 Mon Sep 17 00:00:00 2001 From: Dan Klein Date: Thu, 29 Oct 2015 11:34:03 +0200 Subject: Console redesign using trex_stateless_client module --- .../trex_control_plane/console/trex_console.py | 234 +++++++++++++++------ 1 file changed, 173 insertions(+), 61 deletions(-) (limited to 'scripts/automation/trex_control_plane/console') diff --git a/scripts/automation/trex_control_plane/console/trex_console.py b/scripts/automation/trex_control_plane/console/trex_console.py index 241d46b9..d2050f09 100755 --- a/scripts/automation/trex_control_plane/console/trex_console.py +++ b/scripts/automation/trex_control_plane/console/trex_console.py @@ -30,6 +30,8 @@ import tty, termios import trex_root_path from common.trex_streams import * from client.trex_stateless_client import CTRexStatelessClient +from common.text_opts import * +from client_utils.general_utils import user_input from client_utils.jsonrpc_client import TrexStatelessClient @@ -43,7 +45,7 @@ LoadedStreamList = namedtuple('LoadedStreamList', ['loaded', 'compiled']) # def readch(choices=[]): - + fd = sys.stdin.fileno() old_settings = termios.tcgetattr(fd) try: @@ -69,30 +71,51 @@ class YesNoMenu(object): ch = readch(choices = ['y', 'Y', 'n', 'N']) if ch == None: return None - - print "\n" + + print "\n" if ch == 'y' or ch == 'Y': return True else: return False +class ConfirmMenu(object): + def __init__ (self, caption): + self.caption = "{cap} [confirm] : ".format(cap=caption) + + def show(self): + sys.stdout.write(self.caption) + + + + class CStreamsDB(object): def __init__(self): - self.loaded_streams = {} + self.stream_packs = {} def load_streams(self, name, LoadedStreamList_obj): - if name in self.loaded_streams: + if name in self.stream_packs: return False else: - self.loaded_streams[name] = LoadedStreamList_obj + self.stream_packs[name] = LoadedStreamList_obj return True - def remove_streams(self, name): - return self.loaded_streams.pop(name) + 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(self): - return self.loaded_streams.keys() + def get_loaded_streams_names(self): + return self.stream_packs.keys() + + def get_stream_pack(self, name): + return self.stream_packs.get(name) # multi level cmd menu @@ -144,7 +167,7 @@ class AddStreamMenu(CmdMenu): # main console object class TRexConsole(cmd.Cmd): """Trex Console""" - + def __init__(self, stateless_client, verbose): cmd.Cmd.__init__(self) @@ -153,7 +176,7 @@ class TRexConsole(cmd.Cmd): self.do_connect("") self.intro = "\n-=TRex Console v{ver}=-\n".format(ver=__version__) - self.intro += "\nType 'help' or '?' for supported actions\n" + self.intro += "\nType 'help' or '?' for supported actions\n" self.verbose = False @@ -161,7 +184,7 @@ class TRexConsole(cmd.Cmd): self.user_streams = {} self.streams_db = CStreamsDB() - + # a cool hack - i stole this function and added space def completenames(self, text, *ignored): @@ -209,7 +232,7 @@ class TRexConsole(cmd.Cmd): res_ok, msg = self.stateless_client.ping() if res_ok: - print "[SUCCESS]\n" + print format_text("[SUCCESS]\n", 'green', 'bold') else: print "\n*** " + msg + "\n" return @@ -262,9 +285,9 @@ class TRexConsole(cmd.Cmd): res_ok, log = self.stateless_client.acquire(port_list, force) self.prompt_response(log) if not res_ok: - print "[FAILED]\n" + print format_text("[FAILED]\n", 'red', 'bold') return - print "[SUCCESS]\n" + print format_text("[SUCCESS]\n", 'green', 'bold') return def do_release (self, line): @@ -290,9 +313,9 @@ class TRexConsole(cmd.Cmd): res_ok, log = self.stateless_client.release(port_list) self.prompt_response(log) if not res_ok: - print "[FAILED]\n" + print format_text("[FAILED]\n", 'red', 'bold') return - print "[SUCCESS]\n" + print format_text("[SUCCESS]\n", 'green', 'bold') return def do_connect (self, line): @@ -356,7 +379,9 @@ class TRexConsole(cmd.Cmd): def complete_rpc (self, text, line, begidx, endidx): - return [x for x in self.supported_rpc if x.startswith(text)] + return [x + for x in self.supported_rpc + if x.startswith(text)] def do_status (self, line): '''Shows a graphical console\n''' @@ -376,14 +401,14 @@ class TRexConsole(cmd.Cmd): res_ok, msg = self.stateless_client.disconnect() if res_ok: - print "[SUCCESS]\n" + print format_text("[SUCCESS]\n", 'green', 'bold') else: print msg + "\n" def do_whoami (self, line): '''Prints console user name\n''' print "\n" + self.stateless_client.user + "\n" - + def postcmd(self, stop, line): if self.stateless_client.is_connected(): self.prompt = "TRex > " @@ -452,11 +477,12 @@ class TRexConsole(cmd.Cmd): [StreamPack(v.stream_id, v.stream.dump()) for k, v in compiled_streams.items()])) if res_ok: - print "Stream list '{0}' loaded successfully".format(name) + print green("Stream list '{0}' loaded and added successfully".format(name)) else: - print "Picked name already exist. Please pick another name." + print magenta("Picked name already exist. Please pick another name.") except Exception as e: print "adding new stream failed due to the following error:\n", str(e) + print format_text("[FAILED]\n", 'red', 'bold') # if name in self.user_streams: # print "Picked name already exist. Please pick another name." @@ -495,71 +521,157 @@ class TRexConsole(cmd.Cmd): else: return [text] - def do_show_stream_list(self, line): + def do_stream_db_show(self, line): '''Shows the loaded stream list named [name] \n''' args = line.split() if args: list_name = args[0] try: - stream = self.user_streams[list_name] + stream = self.streams_db.get_stream_pack(list_name)#user_streams[list_name] if len(args) >= 2 and args[1] == "full": - print self.stateless_client.pretty_json(json.dumps(stream.compiled)) + print pretty_json(json.dumps(stream.compiled)) else: - print self.stateless_client.pretty_json(json.dumps(stream.loaded)) + print pretty_json(json.dumps(stream.loaded)) except KeyError as e: print "Unknown stream list name provided" else: - print "\nAvailable stream lists:\n{0}".format(', '.join([x - for x in self.user_streams.keys()])) + print "\nAvailable stream lists:\n{0}".format(', '.join(sorted(self.streams_db.get_loaded_streams_names()))) - def complete_show_stream_list(self, text, line, begidx, endidx): + def complete_stream_db_show(self, text, line, begidx, endidx): return [x - for x in self.user_streams.keys() + for x in self.streams_db.get_loaded_streams_names() if x.startswith(text)] - def do_attach(self, line): + def do_stream_db_remove(self, line): args = line.split() - if len(args) >= 1: - try: - stream_list = self.user_streams[args[0]] - port_list = self.parse_ports_from_line(' '.join(args[1:])) - owned = set(self.stateless_client.get_owned_ports()) - if set(port_list).issubset(owned): - rc, resp_list = self.stateless_client.add_stream(port_list, stream_list.compiled) - if not rc: - print "\n*** " + resp_list + "\n" - return - else: - print "Not all desired ports are aquired.\n" \ - "Acquired ports are: {acq}\n" \ - "Requested ports: {req}\n" \ - "Missing ports: {miss}".format(acq=list(owned), - req=port_list, - miss=list(set(port_list).difference(owned))) - except KeyError as e: - cause = e.args[0] - print "Provided stream list name '{0}' doesn't exists.".format(cause) + if args: + removed_streams = self.streams_db.remove_stream_packs(args) + if removed_streams: + print green("The following stream packs were removed:") + print bold(", ".join(sorted(removed_streams))) + print format_text("[SUCCESS]\n", 'green', 'bold') + else: + print red("No streams were removed. Make sure to provide valid stream pack names.") else: - print "Please provide list name and ports to attach to, or leave empty to attach to all ports." + print magenta("Please provide stream pack name(s), separated with spaces.") + def do_stream_db_clear(self, line): + self.streams_db.clear() + print format_text("[SUCCESS]\n", 'green', 'bold') - def prompt_response(self, response_obj): - resp_list = response_obj if isinstance(response_obj, list) else [response_obj] - for response in resp_list: - print response + def complete_stream_db_remove(self, text, line, begidx, endidx): + return [x + for x in self.streams_db.get_loaded_streams_names() + if x.startswith(text)] + def do_attach(self, line): + args = line.split() + if len(args) >= 2: + stream_pack_name = args[0] + stream_list = self.streams_db.get_stream_pack(stream_pack_name) #user_streams[args[0]] + if not stream_list: + print "Provided stream list name '{0}' doesn't exists.".format(stream_pack_name) + print format_text("[FAILED]\n", 'red', 'bold') + return + if args[0] == "all": + ask = YesNoMenu('Are you sure you want to release all acquired ports ? ') + rc = ask.show() + if rc == False: + return + else: + port_list = self.stateless_client.get_acquired_ports() + else: + port_list = self.extract_port_ids_from_line(' '.join(args[1:])) + owned = set(self.stateless_client.get_owned_ports()) + if set(port_list).issubset(owned): + res_ok, log = self.stateless_client.add_stream_pack(port_list, stream_list.compiled) + # res_ok, msg = self.stateless_client.add_stream(port_list, stream_list.compiled) + self.prompt_response(log) + if not res_ok: + print format_text("[FAILED]\n", 'red', 'bold') + return + print format_text("[SUCCESS]\n", 'green', 'bold') + return + else: + print "Not all desired ports are acquired.\n" \ + "Acquired ports are: {acq}\n" \ + "Requested ports: {req}\n" \ + "Missing ports: {miss}".format(acq=list(owned), + req=port_list, + miss=list(set(port_list).difference(owned))) + print format_text("[FAILED]\n", 'red', 'bold') + else: + print "Please provide list name and ports to attach to, " \ + "or specify 'all' to attach all owned ports." + + def complete_attach(self, text, line, begidx, endidx): + arg_num = len(line.split()) - 1 + if arg_num == 1: + # return optional streams packs + return [x + for x in self.streams_db.get_loaded_streams_names() + if x.startswith(text)] + elif arg_num >= 2: + # return optional ports to attach to + return [x + for x in self.stateless_client.get_acquired_ports() + if str(x).startswith(text)] + else: + return [text] + def prompt_response(self, response_obj): + resp_list = response_obj if isinstance(response_obj, list) else [response_obj] + def format_return_status(return_status): + if return_status: + return green("OK") + else: + return green("fail") + for response in resp_list: + response_str = "{id:^3} - {msg} ({stat})".format(id=response.id, + msg=response.msg, + stat=format_return_status(response.success)) + print response_str + return + def do_remove_all_streams(self, line): + '''Acquire ports\n''' + # make sure that the user wants to acquire all + args = line.split() + if len(args) < 1: + print "Please provide a list of ports separated by spaces, " \ + "or specify 'all' to remove from all acquired ports" + if args[0] == "all": + ask = YesNoMenu('Are you sure you want to remove all stream packs from all acquired ports? ') + rc = ask.show() + if rc == False: + return + else: + port_list = self.stateless_client.get_port_ids() + else: + port_list = self.extract_port_ids_from_line(line) + print "\nTrying to remove all streams at ports: " + (" ".join(str(x) for x in port_list)) + "\n" + # rc, resp_list = self.stateless_client.take_ownership(port_list, force) + res_ok, log = self.stateless_client.remove_all_streams(port_list) + self.prompt_response(log) + if not res_ok: + print format_text("[FAILED]\n", 'red', 'bold') + return + print format_text("[SUCCESS]\n", 'green', 'bold') + return + def complete_remove_all_streams(self, text, line, begidx, endidx): + return [x + for x in self.stateless_client.get_acquired_ports() + if str(x).startswith(text)] # adds a very simple stream - def do_add_simple_stream (self, line): + def do_add_simple_stream(self, line): if line == "": add_stream = AddStreamMenu() add_stream.show() @@ -572,14 +684,14 @@ class TRexConsole(cmd.Cmd): packet = [0xFF,0xFF,0xFF] rc, msg = self.stateless_client.add_stream(port_id = port_id, stream_id = stream_id, isg = 1.1, next_stream_id = -1, packet = packet) if rc: - print "\nServer Response:\n\n" + self.stateless_client.pretty_json(json.dumps(msg)) + "\n" + print "\nServer Response:\n\n" + pretty_json(json.dumps(msg)) + "\n" else: print "\n*** " + msg + "\n" # aliasing do_exit = do_EOF = do_q = do_quit -def setParserOptions (): +def setParserOptions(): parser = argparse.ArgumentParser(prog="trex_console.py") parser.add_argument("-s", "--server", help = "TRex Server [default is localhost]", @@ -600,7 +712,7 @@ def setParserOptions (): return parser -def main (): +def main(): parser = setParserOptions() options = parser.parse_args()#sys.argv[1:]) -- cgit From 13c353b9e4f3f0177458c5bef729de31ec03135d Mon Sep 17 00:00:00 2001 From: Dan Klein Date: Thu, 29 Oct 2015 03:59:43 +0200 Subject: fixed console issues after testsing them --- .../trex_control_plane/console/trex_console.py | 69 +++++++++++++++------- 1 file changed, 47 insertions(+), 22 deletions(-) (limited to 'scripts/automation/trex_control_plane/console') diff --git a/scripts/automation/trex_control_plane/console/trex_console.py b/scripts/automation/trex_control_plane/console/trex_console.py index d2050f09..b2eac88e 100755 --- a/scripts/automation/trex_control_plane/console/trex_console.py +++ b/scripts/automation/trex_control_plane/console/trex_console.py @@ -84,10 +84,14 @@ class ConfirmMenu(object): def show(self): sys.stdout.write(self.caption) + input = user_input() + if input: + return False + else: + # user hit Enter + return True - - class CStreamsDB(object): def __init__(self): @@ -242,6 +246,9 @@ class TRexConsole(cmd.Cmd): self.do_acquire(line, True) + def complete_force_acquire(self, text, line, begidx, endidx): + return self.port_auto_complete(text, line, begidx, endidx, acquired=False) + def extract_port_ids_from_line(self, line): return {int(x) for x in line.split()} @@ -262,7 +269,7 @@ class TRexConsole(cmd.Cmd): return port_list - def do_acquire (self, line, force=False): + def do_acquire(self, line, force=False): '''Acquire ports\n''' # make sure that the user wants to acquire all @@ -270,7 +277,7 @@ class TRexConsole(cmd.Cmd): if len(args) < 1: print "Please provide a list of ports separated by spaces, or specify 'all' to acquire all available ports" if args[0] == "all": - ask = YesNoMenu('Are you sure you want to acquire all ports ? ') + ask = ConfirmMenu('Are you sure you want to acquire all ports ? ') rc = ask.show() if rc == False: return @@ -290,6 +297,23 @@ class TRexConsole(cmd.Cmd): print format_text("[SUCCESS]\n", 'green', 'bold') return + + def port_auto_complete(self, text, line, begidx, endidx, acquired=True): + if acquired: + ret_list = [x + for x in map(str, self.stateless_client.get_acquired_ports()) + if x.startswith(text)] + else: + ret_list = [x + for x in map(str, self.stateless_client.get_port_ids()) + if x.startswith(text)] + ret_list.append("all") + return ret_list + + + def complete_acquire(self, text, line, begidx, endidx): + return self.port_auto_complete(text, line, begidx, endidx, acquired=False) + def do_release (self, line): '''Release ports\n''' @@ -301,7 +325,7 @@ class TRexConsole(cmd.Cmd): if len(args) < 1: print "Please provide a list of ports separated by spaces, or specify 'all' to acquire all available ports" if args[0] == "all": - ask = YesNoMenu('Are you sure you want to release all acquired ports ? ') + ask = ConfirmMenu('Are you sure you want to release all acquired ports? ') rc = ask.show() if rc == False: return @@ -318,6 +342,9 @@ class TRexConsole(cmd.Cmd): print format_text("[SUCCESS]\n", 'green', 'bold') return + def complete_release(self, text, line, begidx, endidx): + return self.port_auto_complete(text, line, begidx, endidx) + def do_connect (self, line): '''Connects to the server\n''' @@ -332,9 +359,10 @@ class TRexConsole(cmd.Cmd): res_ok, msg = self.stateless_client.connect(sp[0], sp[1]) if res_ok: - print "[SUCCESS]\n" + print format_text("[SUCCESS]\n", 'green', 'bold') else: print "\n*** " + msg + "\n" + print format_text("[FAILED]\n", 'red', 'bold') return self.supported_rpc = self.stateless_client.get_supported_cmds().data @@ -477,9 +505,9 @@ class TRexConsole(cmd.Cmd): [StreamPack(v.stream_id, v.stream.dump()) for k, v in compiled_streams.items()])) if res_ok: - print green("Stream list '{0}' loaded and added successfully".format(name)) + print green("Stream pack '{0}' loaded and added successfully\n".format(name)) else: - print magenta("Picked name already exist. Please pick another name.") + print magenta("Picked name already exist. Please pick another name.\n") except Exception as e: print "adding new stream failed due to the following error:\n", str(e) print format_text("[FAILED]\n", 'red', 'bold') @@ -535,7 +563,7 @@ class TRexConsole(cmd.Cmd): except KeyError as e: print "Unknown stream list name provided" else: - print "\nAvailable stream lists:\n{0}".format(', '.join(sorted(self.streams_db.get_loaded_streams_names()))) + print "Available stream packs:\n{0}".format(', '.join(sorted(self.streams_db.get_loaded_streams_names()))) def complete_stream_db_show(self, text, line, begidx, endidx): return [x @@ -584,9 +612,9 @@ class TRexConsole(cmd.Cmd): port_list = self.stateless_client.get_acquired_ports() else: port_list = self.extract_port_ids_from_line(' '.join(args[1:])) - owned = set(self.stateless_client.get_owned_ports()) + owned = set(self.stateless_client.get_acquired_ports()) if set(port_list).issubset(owned): - res_ok, log = self.stateless_client.add_stream_pack(port_list, stream_list.compiled) + res_ok, log = self.stateless_client.add_stream_pack(port_list, *stream_list.compiled) # res_ok, msg = self.stateless_client.add_stream(port_list, stream_list.compiled) self.prompt_response(log) if not res_ok: @@ -615,9 +643,7 @@ class TRexConsole(cmd.Cmd): if x.startswith(text)] elif arg_num >= 2: # return optional ports to attach to - return [x - for x in self.stateless_client.get_acquired_ports() - if str(x).startswith(text)] + return self.port_auto_complete(text, line, begidx, endidx) else: return [text] @@ -627,7 +653,7 @@ class TRexConsole(cmd.Cmd): if return_status: return green("OK") else: - return green("fail") + return red("FAIL") for response in resp_list: response_str = "{id:^3} - {msg} ({stat})".format(id=response.id, @@ -642,15 +668,16 @@ class TRexConsole(cmd.Cmd): # make sure that the user wants to acquire all args = line.split() if len(args) < 1: - print "Please provide a list of ports separated by spaces, " \ - "or specify 'all' to remove from all acquired ports" + print magenta("Please provide a list of ports separated by spaces, " + "or specify 'all' to remove from all acquired ports") + return if args[0] == "all": - ask = YesNoMenu('Are you sure you want to remove all stream packs from all acquired ports? ') + ask = ConfirmMenu('Are you sure you want to remove all stream packs from all acquired ports? ') rc = ask.show() if rc == False: return else: - port_list = self.stateless_client.get_port_ids() + port_list = self.stateless_client.get_acquired_ports() else: port_list = self.extract_port_ids_from_line(line) @@ -666,9 +693,7 @@ class TRexConsole(cmd.Cmd): return def complete_remove_all_streams(self, text, line, begidx, endidx): - return [x - for x in self.stateless_client.get_acquired_ports() - if str(x).startswith(text)] + return self.port_auto_complete(text, line, begidx, endidx) # adds a very simple stream def do_add_simple_stream(self, line): -- cgit From d78150a66de591a77df2496e5de828d3232a931a Mon Sep 17 00:00:00 2001 From: Dan Klein Date: Thu, 29 Oct 2015 06:18:54 +0200 Subject: Awesome working start/stop traffic console Fixed more stability issues :) Ready for merging. --- .../trex_control_plane/console/trex_console.py | 162 ++++++++++++--------- 1 file changed, 95 insertions(+), 67 deletions(-) (limited to 'scripts/automation/trex_control_plane/console') diff --git a/scripts/automation/trex_control_plane/console/trex_console.py b/scripts/automation/trex_control_plane/console/trex_console.py index b2eac88e..5c3668c0 100755 --- a/scripts/automation/trex_control_plane/console/trex_console.py +++ b/scripts/automation/trex_control_plane/console/trex_console.py @@ -42,41 +42,6 @@ __version__ = "1.0" LoadedStreamList = namedtuple('LoadedStreamList', ['loaded', 'compiled']) -# - -def readch(choices=[]): - - fd = sys.stdin.fileno() - old_settings = termios.tcgetattr(fd) - try: - tty.setraw(sys.stdin.fileno()) - while True: - ch = sys.stdin.read(1) - if (ord(ch) == 3) or (ord(ch) == 4): - return None - if ch in choices: - return ch - finally: - termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) - - return None - -class YesNoMenu(object): - def __init__ (self, caption): - self.caption = caption - - def show (self): - print "{0}".format(self.caption) - sys.stdout.write("[Y/y/N/n] : ") - ch = readch(choices = ['y', 'Y', 'n', 'N']) - if ch == None: - return None - - print "\n" - if ch == 'y' or ch == 'Y': - return True - else: - return False class ConfirmMenu(object): def __init__ (self, caption): @@ -280,14 +245,13 @@ class TRexConsole(cmd.Cmd): ask = ConfirmMenu('Are you sure you want to acquire all ports ? ') rc = ask.show() if rc == False: + print yellow("[ABORTED]\n") return else: port_list = self.stateless_client.get_port_ids() else: port_list = self.extract_port_ids_from_line(line) - print "\nTrying to acquire ports: " + (" ".join(str(x) for x in port_list)) + "\n" - # rc, resp_list = self.stateless_client.take_ownership(port_list, force) res_ok, log = self.stateless_client.acquire(port_list, force) self.prompt_response(log) @@ -298,11 +262,16 @@ class TRexConsole(cmd.Cmd): return - def port_auto_complete(self, text, line, begidx, endidx, acquired=True): + def port_auto_complete(self, text, line, begidx, endidx, acquired=True, active=False): if acquired: - ret_list = [x - for x in map(str, self.stateless_client.get_acquired_ports()) - if x.startswith(text)] + if not active: + ret_list = [x + for x in map(str, self.stateless_client.get_acquired_ports()) + if x.startswith(text)] + else: + ret_list = [x + for x in map(str, self.stateless_client.get_active_ports()) + if x.startswith(text)] else: ret_list = [x for x in map(str, self.stateless_client.get_port_ids()) @@ -328,19 +297,24 @@ class TRexConsole(cmd.Cmd): ask = ConfirmMenu('Are you sure you want to release all acquired ports? ') rc = ask.show() if rc == False: + print yellow("[ABORTED]\n") return else: port_list = self.stateless_client.get_acquired_ports() else: port_list = self.extract_port_ids_from_line(line) - res_ok, log = self.stateless_client.release(port_list) - self.prompt_response(log) - if not res_ok: + try: + res_ok, log = self.stateless_client.release(port_list) + self.prompt_response(log) + if not res_ok: + print format_text("[FAILED]\n", 'red', 'bold') + return + print format_text("[SUCCESS]\n", 'green', 'bold') + except ValueError as e: + print magenta(str(e)) print format_text("[FAILED]\n", 'red', 'bold') return - print format_text("[SUCCESS]\n", 'green', 'bold') - return def complete_release(self, text, line, begidx, endidx): return self.port_auto_complete(text, line, begidx, endidx) @@ -489,7 +463,7 @@ class TRexConsole(cmd.Cmd): def do_stream_db_add(self, line): '''Loads a YAML stream list serialization into user console \n''' args = line.split() - if args >= 2: + if len(args) >= 2: name = args[0] yaml_path = args[1] try: @@ -512,22 +486,10 @@ class TRexConsole(cmd.Cmd): print "adding new stream failed due to the following error:\n", str(e) print format_text("[FAILED]\n", 'red', 'bold') - # if name in self.user_streams: - # print "Picked name already exist. Please pick another name." - # else: - # try: - # compiled_streams = stream_list.compile_streams() - # self.user_streams[name] = LoadedStreamList(loaded_obj, - # [StreamPack(v.stream_id, v.stream.dump()) - # for k, v in compiled_streams.items()]) - # - # print "Stream list '{0}' loaded successfully".format(name) - # except Exception as e: - # raise return else: - print "please provide load name and YAML path, separated by space.\n" \ - "Optionally, you may provide a third argument to specify multiplier." + print magenta("please provide load name and YAML path, separated by space.\n" + "Optionally, you may provide a third argument to specify multiplier.\n") @staticmethod def tree_autocomplete(text): @@ -573,7 +535,7 @@ class TRexConsole(cmd.Cmd): def do_stream_db_remove(self, line): args = line.split() if args: - removed_streams = self.streams_db.remove_stream_packs(args) + removed_streams = self.streams_db.remove_stream_packs(*args) if removed_streams: print green("The following stream packs were removed:") print bold(", ".join(sorted(removed_streams))) @@ -604,9 +566,10 @@ class TRexConsole(cmd.Cmd): print format_text("[FAILED]\n", 'red', 'bold') return if args[0] == "all": - ask = YesNoMenu('Are you sure you want to release all acquired ports ? ') + ask = ConfirmMenu('Are you sure you want to release all acquired ports? ') rc = ask.show() if rc == False: + print yellow("[ABORTED]\n") return else: port_list = self.stateless_client.get_acquired_ports() @@ -631,13 +594,15 @@ class TRexConsole(cmd.Cmd): miss=list(set(port_list).difference(owned))) print format_text("[FAILED]\n", 'red', 'bold') else: - print "Please provide list name and ports to attach to, " \ - "or specify 'all' to attach all owned ports." + print magenta("Please provide list name and ports to attach to, " + "or specify 'all' to attach all owned ports.\n") def complete_attach(self, text, line, begidx, endidx): arg_num = len(line.split()) - 1 if arg_num == 1: # return optional streams packs + if line.endswith(" "): + return self.port_auto_complete(text, line, begidx, endidx) return [x for x in self.streams_db.get_loaded_streams_names() if x.startswith(text)] @@ -675,14 +640,13 @@ class TRexConsole(cmd.Cmd): ask = ConfirmMenu('Are you sure you want to remove all stream packs from all acquired ports? ') rc = ask.show() if rc == False: + print yellow("[ABORTED]\n") return else: port_list = self.stateless_client.get_acquired_ports() else: port_list = self.extract_port_ids_from_line(line) - print "\nTrying to remove all streams at ports: " + (" ".join(str(x) for x in port_list)) + "\n" - # rc, resp_list = self.stateless_client.take_ownership(port_list, force) res_ok, log = self.stateless_client.remove_all_streams(port_list) self.prompt_response(log) @@ -695,6 +659,70 @@ class TRexConsole(cmd.Cmd): def complete_remove_all_streams(self, text, line, begidx, endidx): return self.port_auto_complete(text, line, begidx, endidx) + def do_start_traffic(self, line): + # make sure that the user wants to acquire all + args = line.split() + if len(args) < 1: + print magenta("Please provide a list of ports separated by spaces, " + "or specify 'all' to start traffic on all acquired ports") + return + if args[0] == "all": + ask = ConfirmMenu('Are you sure you want to start traffic at all acquired ports? ') + rc = ask.show() + if rc == False: + print yellow("[ABORTED]\n") + return + else: + port_list = self.stateless_client.get_acquired_ports() + else: + port_list = self.extract_port_ids_from_line(line) + + try: + res_ok, log = self.stateless_client.start_traffic(port_list) + self.prompt_response(log) + if not res_ok: + print format_text("[FAILED]\n", 'red', 'bold') + return + print format_text("[SUCCESS]\n", 'green', 'bold') + except ValueError as e: + print magenta(str(e)) + print format_text("[FAILED]\n", 'red', 'bold') + + def complete_start_traffic(self, text, line, begidx, endidx): + return self.port_auto_complete(text, line, begidx, endidx) + + def do_stop_traffic(self, line): + # make sure that the user wants to acquire all + args = line.split() + if len(args) < 1: + print magenta("Please provide a list of ports separated by spaces, " + "or specify 'all' to stop traffic on all acquired ports") + return + if args[0] == "all": + ask = ConfirmMenu('Are you sure you want to start traffic at all acquired ports? ') + rc = ask.show() + if rc == False: + print yellow("[ABORTED]\n") + return + else: + port_list = self.stateless_client.get_active_ports() + else: + port_list = self.extract_port_ids_from_line(line) + + try: + res_ok, log = self.stateless_client.stop_traffic(port_list) + self.prompt_response(log) + if not res_ok: + print format_text("[FAILED]\n", 'red', 'bold') + return + print format_text("[SUCCESS]\n", 'green', 'bold') + except ValueError as e: + print magenta(str(e)) + print format_text("[FAILED]\n", 'red', 'bold') + + def complete_stop_traffic(self, text, line, begidx, endidx): + return self.port_auto_complete(text, line, begidx, endidx, active=True) + # adds a very simple stream def do_add_simple_stream(self, line): if line == "": -- cgit From 2636c09cfb74c7981c27d84bcc72d00929fdbbbb Mon Sep 17 00:00:00 2001 From: Dan Klein Date: Thu, 29 Oct 2015 07:14:58 +0200 Subject: Fixed verbose mode More stability fixes removed irrelevand methods --- .../trex_control_plane/console/trex_console.py | 123 ++++++++++++--------- 1 file changed, 69 insertions(+), 54 deletions(-) (limited to 'scripts/automation/trex_control_plane/console') diff --git a/scripts/automation/trex_control_plane/console/trex_console.py b/scripts/automation/trex_control_plane/console/trex_console.py index 5c3668c0..51a1f8cc 100755 --- a/scripts/automation/trex_control_plane/console/trex_console.py +++ b/scripts/automation/trex_control_plane/console/trex_console.py @@ -43,6 +43,23 @@ __version__ = "1.0" LoadedStreamList = namedtuple('LoadedStreamList', ['loaded', 'compiled']) +def readch(choices=[]): + + fd = sys.stdin.fileno() + old_settings = termios.tcgetattr(fd) + try: + tty.setraw(sys.stdin.fileno()) + while True: + ch = sys.stdin.read(1) + if (ord(ch) == 3) or (ord(ch) == 4): + return None + if ch in choices: + return ch + finally: + termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) + + return None + class ConfirmMenu(object): def __init__ (self, caption): self.caption = "{cap} [confirm] : ".format(cap=caption) @@ -169,30 +186,31 @@ class TRexConsole(cmd.Cmd): elif line == "on": self.verbose = True self.stateless_client.set_verbose(True) - print "\nverbose set to on\n" + print green("\nverbose set to on\n") elif line == "off": self.verbose = False self.stateless_client.set_verbose(False) - print "\nverbose set to off\n" + print green("\nverbose set to off\n") else: - print "\nplease specify 'on' or 'off'\n" + print magenta("\nplease specify 'on' or 'off'\n") # query the server for registered commands def do_query_server(self, line): '''query the RPC server for supported remote commands\n''' - rc, msg = self.stateless_client.query_rpc_server() - if not rc: - print "\n*** " + msg + "\n" + res_ok, msg = self.stateless_client.get_supported_cmds() + if not res_ok: + print format_text("[FAILED]\n", 'red', 'bold') return - - print "\nRPC server supports the following commands: \n\n" + print "\nRPC server supports the following commands:\n" for func in msg: if func: print func - print "\n" + print '' + print format_text("[SUCCESS]\n", 'green', 'bold') + return def do_ping (self, line): '''Pings the RPC server\n''' @@ -253,13 +271,16 @@ class TRexConsole(cmd.Cmd): port_list = self.extract_port_ids_from_line(line) # rc, resp_list = self.stateless_client.take_ownership(port_list, force) - res_ok, log = self.stateless_client.acquire(port_list, force) - self.prompt_response(log) - if not res_ok: + try: + res_ok, log = self.stateless_client.acquire(port_list, force) + self.prompt_response(log) + if not res_ok: + print format_text("[FAILED]\n", 'red', 'bold') + return + print format_text("[SUCCESS]\n", 'green', 'bold') + except ValueError as e: + print magenta(str(e)) print format_text("[FAILED]\n", 'red', 'bold') - return - print format_text("[SUCCESS]\n", 'green', 'bold') - return def port_auto_complete(self, text, line, begidx, endidx, acquired=True, active=False): @@ -533,6 +554,7 @@ class TRexConsole(cmd.Cmd): if x.startswith(text)] def do_stream_db_remove(self, line): + '''Removes a single loaded stream packs from loaded stream pack repository\n''' args = line.split() if args: removed_streams = self.streams_db.remove_stream_packs(*args) @@ -546,6 +568,7 @@ class TRexConsole(cmd.Cmd): print magenta("Please provide stream pack name(s), separated with spaces.") def do_stream_db_clear(self, line): + '''Clears all loaded stream packs from loaded stream pack repository\n''' self.streams_db.clear() print format_text("[SUCCESS]\n", 'green', 'bold') @@ -557,6 +580,7 @@ class TRexConsole(cmd.Cmd): def do_attach(self, line): + '''Assign loaded stream pack into specified ports on TRex\n''' args = line.split() if len(args) >= 2: stream_pack_name = args[0] @@ -576,22 +600,26 @@ class TRexConsole(cmd.Cmd): else: port_list = self.extract_port_ids_from_line(' '.join(args[1:])) owned = set(self.stateless_client.get_acquired_ports()) - if set(port_list).issubset(owned): - res_ok, log = self.stateless_client.add_stream_pack(port_list, *stream_list.compiled) - # res_ok, msg = self.stateless_client.add_stream(port_list, stream_list.compiled) - self.prompt_response(log) - if not res_ok: - print format_text("[FAILED]\n", 'red', 'bold') + try: + if set(port_list).issubset(owned): + res_ok, log = self.stateless_client.add_stream_pack(port_list, *stream_list.compiled) + # res_ok, msg = self.stateless_client.add_stream(port_list, stream_list.compiled) + self.prompt_response(log) + if not res_ok: + print format_text("[FAILED]\n", 'red', 'bold') + return + print format_text("[SUCCESS]\n", 'green', 'bold') return - print format_text("[SUCCESS]\n", 'green', 'bold') - return - else: - print "Not all desired ports are acquired.\n" \ - "Acquired ports are: {acq}\n" \ - "Requested ports: {req}\n" \ - "Missing ports: {miss}".format(acq=list(owned), - req=port_list, - miss=list(set(port_list).difference(owned))) + else: + print "Not all desired ports are acquired.\n" \ + "Acquired ports are: {acq}\n" \ + "Requested ports: {req}\n" \ + "Missing ports: {miss}".format(acq=list(owned), + req=port_list, + miss=list(set(port_list).difference(owned))) + print format_text("[FAILED]\n", 'red', 'bold') + except ValueError as e: + print magenta(str(e)) print format_text("[FAILED]\n", 'red', 'bold') else: print magenta("Please provide list name and ports to attach to, " @@ -648,18 +676,22 @@ class TRexConsole(cmd.Cmd): port_list = self.extract_port_ids_from_line(line) # rc, resp_list = self.stateless_client.take_ownership(port_list, force) - res_ok, log = self.stateless_client.remove_all_streams(port_list) - self.prompt_response(log) - if not res_ok: + try: + res_ok, log = self.stateless_client.remove_all_streams(port_list) + self.prompt_response(log) + if not res_ok: + print format_text("[FAILED]\n", 'red', 'bold') + return + print format_text("[SUCCESS]\n", 'green', 'bold') + except ValueError as e: + print magenta(str(e)) print format_text("[FAILED]\n", 'red', 'bold') - return - print format_text("[SUCCESS]\n", 'green', 'bold') - return def complete_remove_all_streams(self, text, line, begidx, endidx): return self.port_auto_complete(text, line, begidx, endidx) def do_start_traffic(self, line): + '''Start pre-submitted traffic in specified ports on TRex\n''' # make sure that the user wants to acquire all args = line.split() if len(args) < 1: @@ -692,6 +724,7 @@ class TRexConsole(cmd.Cmd): return self.port_auto_complete(text, line, begidx, endidx) def do_stop_traffic(self, line): + '''Stop active traffic in specified ports on TRex\n''' # make sure that the user wants to acquire all args = line.split() if len(args) < 1: @@ -723,24 +756,6 @@ class TRexConsole(cmd.Cmd): def complete_stop_traffic(self, text, line, begidx, endidx): return self.port_auto_complete(text, line, begidx, endidx, active=True) - # adds a very simple stream - def do_add_simple_stream(self, line): - if line == "": - add_stream = AddStreamMenu() - add_stream.show() - return - - params = line.split() - port_id = int(params[0]) - stream_id = int(params[1]) - - packet = [0xFF,0xFF,0xFF] - rc, msg = self.stateless_client.add_stream(port_id = port_id, stream_id = stream_id, isg = 1.1, next_stream_id = -1, packet = packet) - if rc: - print "\nServer Response:\n\n" + pretty_json(json.dumps(msg)) + "\n" - else: - print "\n*** " + msg + "\n" - # aliasing do_exit = do_EOF = do_q = do_quit -- cgit From 7d7767e17b1a4e54a8934ded724f54dc5b6228ce Mon Sep 17 00:00:00 2001 From: imarom Date: Sun, 1 Nov 2015 18:03:17 +0200 Subject: added support for a new RPC command : sync_user provides a way to sync a console / GUI to the server for a specific user --- scripts/automation/trex_control_plane/console/trex_console.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'scripts/automation/trex_control_plane/console') diff --git a/scripts/automation/trex_control_plane/console/trex_console.py b/scripts/automation/trex_control_plane/console/trex_console.py index 51a1f8cc..ec23eb0c 100755 --- a/scripts/automation/trex_control_plane/console/trex_console.py +++ b/scripts/automation/trex_control_plane/console/trex_console.py @@ -393,9 +393,9 @@ class TRexConsole(cmd.Cmd): print "Example: rpc test_add {'x': 12, 'y': 17}\n" return - res_ok, msg = self.stateless_client.invoke_rpc_method(method, params) + res_ok, msg = self.stateless_client.transmit(method, params) if res_ok: - print "\nServer Response:\n\n" + self.stateless_client.pretty_json(json.dumps(msg)) + "\n" + print "\nServer Response:\n\n" + pretty_json(json.dumps(msg)) + "\n" else: print "\n*** " + msg + "\n" #print "Please try 'reconnect' to reconnect to server" -- cgit From 1586ab131f28c03ea65373d9e702e4051ffb9a56 Mon Sep 17 00:00:00 2001 From: imarom Date: Mon, 2 Nov 2015 16:14:02 +0200 Subject: status is back online + ZMQ async stats --- .../trex_control_plane/console/trex_console.py | 11 +- .../trex_control_plane/console/trex_status.py | 284 ++++++++++----------- 2 files changed, 146 insertions(+), 149 deletions(-) (limited to 'scripts/automation/trex_control_plane/console') diff --git a/scripts/automation/trex_control_plane/console/trex_console.py b/scripts/automation/trex_control_plane/console/trex_console.py index ec23eb0c..bd79cb42 100755 --- a/scripts/automation/trex_control_plane/console/trex_console.py +++ b/scripts/automation/trex_control_plane/console/trex_console.py @@ -34,7 +34,6 @@ from common.text_opts import * from client_utils.general_utils import user_input -from client_utils.jsonrpc_client import TrexStatelessClient import trex_status from collections import namedtuple @@ -177,6 +176,7 @@ class TRexConsole(cmd.Cmd): dotext = 'do_'+text return [a[3:]+' ' for a in self.get_names() if a.startswith(dotext)] + # set verbose on / off def do_verbose (self, line): '''Shows or set verbose mode\n''' @@ -770,6 +770,10 @@ def setParserOptions(): default = 5050, type = int) + parser.add_argument("-z", "--pub", help = "TRex Async Publisher Port [default is 4500]\n", + default = 4500, + 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) @@ -782,11 +786,10 @@ def setParserOptions(): def main(): parser = setParserOptions() - options = parser.parse_args()#sys.argv[1:]) + options = parser.parse_args() # Stateless client connection - # stateless_client = TrexStatelessClient(options.server, options.port, options.user) - stateless_client = CTRexStatelessClient(options.user, options.server, options.port) + stateless_client = CTRexStatelessClient(options.user, options.server, options.port, options.pub) # 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 2c5a648f..4cd07358 100644 --- a/scripts/automation/trex_control_plane/console/trex_status.py +++ b/scripts/automation/trex_control_plane/console/trex_status.py @@ -11,6 +11,8 @@ import datetime g_curses_active = False +################### utils ################# + # simple percetange show def percentage (a, total): x = int ((float(a) / total) * 100) @@ -18,15 +20,25 @@ def percentage (a, total): # 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 + for unit in ['','K','M','G','T']: + if abs(size) < 1000.0: + return "%3.2f %s%s" % (size, unit, suffix) + size /= 1000.0 return "NaN" + +################### panels ################# + # panel object class TrexStatusPanel(object): - def __init__ (self, h, l, y, x, headline): + def __init__ (self, h, l, y, x, headline, status_obj): + + self.status_obj = status_obj + + self.log = status_obj.log + self.stateless_client = status_obj.stateless_client + self.general_stats = status_obj.general_stats + self.h = h self.l = l self.y = y @@ -53,64 +65,26 @@ class TrexStatusPanel(object): return self.win -# 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 + super(ServerInfoPanel, self).__init__(h, l, y ,x ,"Server Info:", status_obj) def draw (self): - if self.status_obj.server_version == None: + if not self.status_obj.server_version : return - self.clear() + if not self.status_obj.server_sys_info: + return - 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.clear() + + self.getwin().addstr(3, 2, "{:<30} {:30}".format("Server:",self.status_obj.server_sys_info["hostname"] + ":" + str(self.stateless_client.get_connection_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"] + " @ " + @@ -123,7 +97,7 @@ class ServerInfoPanel(TrexStatusPanel): 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()) + ports_owned = " ".join(str(x) for x in self.status_obj.owned_ports) if not ports_owned: ports_owned = "None" @@ -134,26 +108,39 @@ class ServerInfoPanel(TrexStatusPanel): 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 + super(GeneralInfoPanel, self).__init__(h, l, y ,x ,"General Info:", status_obj) def draw (self): - pass + self.clear() + + self.getwin().addstr(3, 2, "{:<30} {:0.2f} %".format("CPU util.:", self.general_stats.get("m_cpu_util"))) + + self.getwin().addstr(5, 2, "{:<30} {:} / {:}".format("Total Tx. rate:", + float_to_human_readable(self.general_stats.get("m_tx_bps")), + float_to_human_readable(self.general_stats.get("m_tx_pps"), suffix = "pps"))) + + # missing RX field + #self.getwin().addstr(5, 2, "{:<30} {:} / {:}".format("Total Rx. rate:", + # float_to_human_readable(self.general_stats.get("m_rx_bps")), + # float_to_human_readable(self.general_stats.get("m_rx_pps"), suffix = "pps"))) + + self.getwin().addstr(7, 2, "{:<30} {:} / {:}".format("Total Tx:", + float_to_human_readable(self.general_stats.get_rel("m_total_tx_bytes"), suffix = "B"), + float_to_human_readable(self.general_stats.get_rel("m_total_tx_pkts"), suffix = "pkts"))) # 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:") + super(PortsStatsPanel, self).__init__(h, l, y ,x ,"Trex Ports:", status_obj) - self.status_obj = status_obj def draw (self): self.clear() + return - owned_ports = self.status_obj.rpc_client.get_owned_ports() + owned_ports = self.status_obj.owned_ports if not owned_ports: self.getwin().addstr(3, 2, "No Owned Ports - Please Acquire One Or More Ports") return @@ -193,33 +180,23 @@ class PortsStatsPanel(TrexStatusPanel): class ControlPanel(TrexStatusPanel): def __init__ (self, h, l, y, x, status_obj): - super(ControlPanel, self).__init__(h, l, y, x, "") + super(ControlPanel, self).__init__(h, l, y, x, "", status_obj) - 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)) + .format(self.status_obj.stateless_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 + self.log.draw(self.getwin(), 2, 3) # 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)) + super(SinglePortPanel, self).__init__(h, l, y, x, "Port {0}".format(port_id), status_obj) - self.status_obj = status_obj self.port_id = port_id def draw (self): @@ -227,7 +204,7 @@ class SinglePortPanel(TrexStatusPanel): self.clear() - if not self.port_id in self.status_obj.rpc_client.get_owned_ports(): + if not self.port_id in self.status_obj.stateless_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 @@ -292,96 +269,119 @@ class SinglePortPanel(TrexStatusPanel): y += 2 -# status object -class TrexStatus(): - def __init__ (self, stdscr, rpc_client): - self.stdscr = stdscr +################### main objects ################# + +# status log +class TrexStatusLog(): + def __init__ (self): self.log = [] - self.rpc_client = rpc_client - self.snapshot = self.rpc_client.snapshot() + def add_event (self, msg): + self.log.append("[{0}] {1}".format(str(datetime.datetime.now().time()), msg)) - # fetch server info - self.get_server_info() + def draw (self, window, x, y, max_lines = 4): + index = y + + cut = len(self.log) - max_lines + if cut < 0: + cut = 0 + + for msg in self.log[cut:]: + window.addstr(index, x, msg) + index += 1 + +# status commands +class TrexStatusCommands(): + def __init__ (self, status_object): + + self.status_object = status_object - # create stats objects - self.stats = Stats(rpc_client, self.rpc_client.get_owned_ports()) + self.stateless_client = status_object.stateless_client + self.log = self.status_object.log - # 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 + self.actions[ord('q')] = self._quit + self.actions[ord('p')] = self._ping + self.actions[ord('f')] = self._freeze - self.actions[ord('g')] = self.action_show_ports_stats + self.actions[ord('g')] = self._show_ports_stats - 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) + # register all the available ports shortcuts + for port_id in xrange(0, self.stateless_client.get_port_count()): + self.actions[ord('0') + port_id] = self._show_port_generator(port_id) + + + # handle a key pressed + def handle (self, ch): + if ch in self.actions: + return self.actions[ch]() + else: + self.log.add_event("Unknown key pressed, please see legend") + return True + + # show all ports + def _show_ports_stats (self): + self.log.add_event("Switching to all ports view") + self.status_object.stats_panel = self.status_object.ports_stats_panel - - # 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 - # 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] + + # function generator for different ports requests + def _show_port_generator (self, port_id): + def _show_port(): + self.log.add_event("Switching panel to port {0}".format(port_id)) + self.status_object.stats_panel = self.status_object.ports_panels[port_id] return True - return action_show_port + return _show_port - def action_freeze (self): - self.update_active = not self.update_active - self.add_log_event("Update continued" if self.update_active else "Update stopped") + def _freeze (self): + self.status_object.update_active = not self.status_object.update_active + self.log.add_event("Update continued" if self.status_object.update_active else "Update stopped") return True - def action_quit(self): + def _quit(self): return False - def action_ping (self): - self.add_log_event("Pinging RPC server") + def _ping (self): + self.log.add_event("Pinging RPC server") - rc, msg = self.rpc_client.ping_rpc_server() + rc, msg = self.stateless_client.ping() if rc: - self.add_log_event("Server replied: '{0}'".format(msg)) + self.log.add_event("Server replied: '{0}'".format(msg)) else: - self.add_log_event("Failed to get reply") + self.log.add_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() - - - 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() +# status object +# +# +# +class TrexStatus(): + def __init__ (self, stdscr, stateless_client): + self.stdscr = stdscr - 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)) + self.stateless_client = stateless_client + self.general_stats = stateless_client.get_stats_async().get_general_stats() - index = 3 + # fetch server info + rc, self.server_sys_info = self.stateless_client.get_system_info() + if not rc: + return - cut = len(self.log) - 4 - if cut < 0: - cut = 0 + rc, self.server_version = self.stateless_client.get_version() + if not rc: + return - for l in self.log[cut:]: - self.control_panel.getwin().addstr(index, 2, l) - index += 1 + self.owned_ports = self.stateless_client.get_acquired_ports() + self.log = TrexStatusLog() + self.cmds = TrexStatusCommands(self) + def generate_layout (self): self.max_y = self.stdscr.getmaxyx()[0] self.max_x = self.stdscr.getmaxyx()[1] @@ -394,7 +394,7 @@ class TrexStatus(): self.ports_stats_panel = PortsStatsPanel(int(self.max_y * 0.8), self.max_x / 2, 0, 0, self) self.ports_panels = {} - for i in xrange(0, self.rpc_client.get_port_count()): + for i in xrange(0, self.stateless_client.get_port_count()): self.ports_panels[i] = SinglePortPanel(int(self.max_y * 0.8), self.max_x / 2, 0, 0, self, i) # at start time we point to the main one @@ -411,14 +411,8 @@ class TrexStatus(): # 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 + + return self.cmds.handle(ch) # main run entry point def run (self): @@ -454,14 +448,14 @@ class TrexStatus(): sleep(0.01) -def show_trex_status_internal (stdscr, rpc_client): - trex_status = TrexStatus(stdscr, rpc_client) +def show_trex_status_internal (stdscr, stateless_client): + trex_status = TrexStatus(stdscr, stateless_client) trex_status.run() -def show_trex_status (rpc_client): +def show_trex_status (stateless_client): try: - curses.wrapper(show_trex_status_internal, rpc_client) + curses.wrapper(show_trex_status_internal, stateless_client) except KeyboardInterrupt: curses.endwin() -- cgit From 3fb4e4c130da10e58af07e1f783f093515e90f96 Mon Sep 17 00:00:00 2001 From: imarom Date: Mon, 2 Nov 2015 16:40:34 +0200 Subject: few bug fixes for last commit --- scripts/automation/trex_control_plane/console/trex_console.py | 4 ++++ scripts/automation/trex_control_plane/console/trex_status.py | 11 +++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) (limited to 'scripts/automation/trex_control_plane/console') diff --git a/scripts/automation/trex_control_plane/console/trex_console.py b/scripts/automation/trex_control_plane/console/trex_console.py index bd79cb42..549262c5 100755 --- a/scripts/automation/trex_control_plane/console/trex_console.py +++ b/scripts/automation/trex_control_plane/console/trex_console.py @@ -409,6 +409,10 @@ class TRexConsole(cmd.Cmd): def do_status (self, line): '''Shows a graphical console\n''' + if not self.stateless_client.is_connected(): + print "Not connected to server\n" + return + self.do_verbose('off') trex_status.show_trex_status(self.stateless_client) diff --git a/scripts/automation/trex_control_plane/console/trex_status.py b/scripts/automation/trex_control_plane/console/trex_status.py index 4cd07358..4e73e0bb 100644 --- a/scripts/automation/trex_control_plane/console/trex_status.py +++ b/scripts/automation/trex_control_plane/console/trex_status.py @@ -113,6 +113,10 @@ class GeneralInfoPanel(TrexStatusPanel): def draw (self): self.clear() + if not self.general_stats.is_online(): + self.getwin().addstr(3, 2, "No Published Data From TRex Server") + return + self.getwin().addstr(3, 2, "{:<30} {:0.2f} %".format("CPU util.:", self.general_stats.get("m_cpu_util"))) self.getwin().addstr(5, 2, "{:<30} {:} / {:}".format("Total Tx. rate:", @@ -366,6 +370,10 @@ class TrexStatus(): self.stdscr = stdscr self.stateless_client = stateless_client + + self.log = TrexStatusLog() + self.cmds = TrexStatusCommands(self) + self.general_stats = stateless_client.get_stats_async().get_general_stats() # fetch server info @@ -379,8 +387,7 @@ class TrexStatus(): self.owned_ports = self.stateless_client.get_acquired_ports() - self.log = TrexStatusLog() - self.cmds = TrexStatusCommands(self) + def generate_layout (self): self.max_y = self.stdscr.getmaxyx()[0] -- cgit From 274bca264036d9cf01b9fcbbb3923b0f28654d82 Mon Sep 17 00:00:00 2001 From: Dan Klein Date: Tue, 3 Nov 2015 09:36:59 +0200 Subject: Added parsing file for console advanced options --- scripts/automation/trex_control_plane/console/line_parsing.py | 1 + 1 file changed, 1 insertion(+) create mode 100644 scripts/automation/trex_control_plane/console/line_parsing.py (limited to 'scripts/automation/trex_control_plane/console') diff --git a/scripts/automation/trex_control_plane/console/line_parsing.py b/scripts/automation/trex_control_plane/console/line_parsing.py new file mode 100644 index 00000000..f97bce4c --- /dev/null +++ b/scripts/automation/trex_control_plane/console/line_parsing.py @@ -0,0 +1 @@ +__author__ = 'danklei' -- cgit From 0ceddc74c938a023c515be4ed2c37198fd66e87e Mon Sep 17 00:00:00 2001 From: Dan Klein Date: Tue, 3 Nov 2015 09:37:42 +0200 Subject: first commit for advnaced options --- scripts/automation/trex_control_plane/console/line_parsing.py | 4 ++++ scripts/automation/trex_control_plane/console/trex_console.py | 7 +++---- 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'scripts/automation/trex_control_plane/console') diff --git a/scripts/automation/trex_control_plane/console/line_parsing.py b/scripts/automation/trex_control_plane/console/line_parsing.py index f97bce4c..34776424 100644 --- a/scripts/automation/trex_control_plane/console/line_parsing.py +++ b/scripts/automation/trex_control_plane/console/line_parsing.py @@ -1 +1,5 @@ __author__ = 'danklei' + + +if __name__ == "__main__": + pass \ No newline at end of file diff --git a/scripts/automation/trex_control_plane/console/trex_console.py b/scripts/automation/trex_control_plane/console/trex_console.py index 549262c5..e707a9e1 100755 --- a/scripts/automation/trex_control_plane/console/trex_console.py +++ b/scripts/automation/trex_control_plane/console/trex_console.py @@ -31,8 +31,7 @@ import trex_root_path from common.trex_streams import * from client.trex_stateless_client import CTRexStatelessClient from common.text_opts import * -from client_utils.general_utils import user_input - +from client_utils.general_utils import user_input, get_current_user import trex_status from collections import namedtuple @@ -778,8 +777,8 @@ def setParserOptions(): default = 4500, 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)), + parser.add_argument("-u", "--user", help = "User Name [default is currently logged in user]\n", + default = get_current_user(), type = str) parser.add_argument("--verbose", dest="verbose", -- cgit From c2928039f199d3cef6d130201cf825d5b6b67937 Mon Sep 17 00:00:00 2001 From: imarom Date: Tue, 3 Nov 2015 10:10:52 +0200 Subject: fields for specific ports on the status screen --- .../trex_control_plane/console/trex_status.py | 44 +++++++++------------- 1 file changed, 18 insertions(+), 26 deletions(-) (limited to 'scripts/automation/trex_control_plane/console') diff --git a/scripts/automation/trex_control_plane/console/trex_status.py b/scripts/automation/trex_control_plane/console/trex_status.py index 4e73e0bb..ac8e7411 100644 --- a/scripts/automation/trex_control_plane/console/trex_status.py +++ b/scripts/automation/trex_control_plane/console/trex_status.py @@ -18,15 +18,6 @@ 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','T']: - if abs(size) < 1000.0: - return "%3.2f %s%s" % (size, unit, suffix) - size /= 1000.0 - return "NaN" - - ################### panels ################# # panel object @@ -37,6 +28,8 @@ class TrexStatusPanel(object): self.log = status_obj.log self.stateless_client = status_obj.stateless_client + + self.stats = status_obj.stats self.general_stats = status_obj.general_stats self.h = h @@ -120,17 +113,17 @@ class GeneralInfoPanel(TrexStatusPanel): self.getwin().addstr(3, 2, "{:<30} {:0.2f} %".format("CPU util.:", self.general_stats.get("m_cpu_util"))) self.getwin().addstr(5, 2, "{:<30} {:} / {:}".format("Total Tx. rate:", - float_to_human_readable(self.general_stats.get("m_tx_bps")), - float_to_human_readable(self.general_stats.get("m_tx_pps"), suffix = "pps"))) + self.general_stats.get("m_tx_bps", format = True, suffix = "bps"), + self.general_stats.get("m_tx_pps", format = True, suffix = "pps"))) # missing RX field #self.getwin().addstr(5, 2, "{:<30} {:} / {:}".format("Total Rx. rate:", - # float_to_human_readable(self.general_stats.get("m_rx_bps")), - # float_to_human_readable(self.general_stats.get("m_rx_pps"), suffix = "pps"))) + # self.general_stats.get("m_rx_bps"), + # self.general_stats.get("m_rx_pps"), suffix = "pps")) self.getwin().addstr(7, 2, "{:<30} {:} / {:}".format("Total Tx:", - float_to_human_readable(self.general_stats.get_rel("m_total_tx_bytes"), suffix = "B"), - float_to_human_readable(self.general_stats.get_rel("m_total_tx_pkts"), suffix = "pkts"))) + self.general_stats.get_rel("m_total_tx_bytes", format = True, suffix = "B"), + self.general_stats.get_rel("m_total_tx_pkts", format = True, suffix = "pkts"))) # all ports stats class PortsStatsPanel(TrexStatusPanel): @@ -142,7 +135,6 @@ class PortsStatsPanel(TrexStatusPanel): def draw (self): self.clear() - return owned_ports = self.status_obj.owned_ports if not owned_ports: @@ -153,23 +145,22 @@ class PortsStatsPanel(TrexStatusPanel): 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,.2f} {:^15,.2f} {:^15,} {:^15,.2f} {:^15,.2f} {:^15,}".format( + 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"])) - + port_stats.get("m_total_tx_pps", format = True, suffix = "pps"), + port_stats.get("m_total_tx_bps", format = True, suffix = "bps"), + port_stats.get_rel("obytes", format = True, suffix = "B"), + port_stats.get("m_total_rx_pps", format = True, suffix = "pps"), + port_stats.get("m_total_rx_bps", format = True, suffix = "bps"), + port_stats.get_rel("ibytes", format = True, suffix = "B"))) + 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"]), @@ -374,6 +365,7 @@ class TrexStatus(): self.log = TrexStatusLog() self.cmds = TrexStatusCommands(self) + self.stats = stateless_client.get_stats_async() self.general_stats = stateless_client.get_stats_async().get_general_stats() # fetch server info -- cgit From 30b87959dc2d8da7f2f2a471a53485d600d8735a Mon Sep 17 00:00:00 2001 From: imarom Date: Wed, 4 Nov 2015 11:31:30 +0200 Subject: some fields were missing from the ZMQ publisher --- .../trex_control_plane/console/trex_console.py | 4 +++- .../trex_control_plane/console/trex_status.py | 19 ++++++++++++------- 2 files changed, 15 insertions(+), 8 deletions(-) (limited to 'scripts/automation/trex_control_plane/console') diff --git a/scripts/automation/trex_control_plane/console/trex_console.py b/scripts/automation/trex_control_plane/console/trex_console.py index e707a9e1..8a5b29cc 100755 --- a/scripts/automation/trex_control_plane/console/trex_console.py +++ b/scripts/automation/trex_control_plane/console/trex_console.py @@ -257,7 +257,9 @@ class TRexConsole(cmd.Cmd): # make sure that the user wants to acquire all args = line.split() if len(args) < 1: - print "Please provide a list of ports separated by spaces, or specify 'all' to acquire all available ports" + print magenta("Please provide a list of ports separated by spaces, or specify 'all' to acquire all available ports") + return + if args[0] == "all": ask = ConfirmMenu('Are you sure you want to acquire all ports ? ') rc = ask.show() diff --git a/scripts/automation/trex_control_plane/console/trex_status.py b/scripts/automation/trex_control_plane/console/trex_status.py index ac8e7411..a19587a3 100644 --- a/scripts/automation/trex_control_plane/console/trex_status.py +++ b/scripts/automation/trex_control_plane/console/trex_status.py @@ -112,19 +112,24 @@ class GeneralInfoPanel(TrexStatusPanel): self.getwin().addstr(3, 2, "{:<30} {:0.2f} %".format("CPU util.:", self.general_stats.get("m_cpu_util"))) - self.getwin().addstr(5, 2, "{:<30} {:} / {:}".format("Total Tx. rate:", + self.getwin().addstr(6, 2, "{:<30} {:} / {:}".format("Total Tx. rate:", self.general_stats.get("m_tx_bps", format = True, suffix = "bps"), self.general_stats.get("m_tx_pps", format = True, suffix = "pps"))) - # missing RX field - #self.getwin().addstr(5, 2, "{:<30} {:} / {:}".format("Total Rx. rate:", - # self.general_stats.get("m_rx_bps"), - # self.general_stats.get("m_rx_pps"), suffix = "pps")) - - self.getwin().addstr(7, 2, "{:<30} {:} / {:}".format("Total Tx:", + + self.getwin().addstr(8, 2, "{:<30} {:} / {:}".format("Total Tx:", self.general_stats.get_rel("m_total_tx_bytes", format = True, suffix = "B"), self.general_stats.get_rel("m_total_tx_pkts", format = True, suffix = "pkts"))) + self.getwin().addstr(11, 2, "{:<30} {:} / {:}".format("Total Rx. rate:", + self.general_stats.get("m_rx_bps", format = True, suffix = "bps"), + self.general_stats.get("m_rx_pps", format = True, suffix = "pps"))) + + + self.getwin().addstr(13, 2, "{:<30} {:} / {:}".format("Total Rx:", + self.general_stats.get_rel("m_total_rx_bytes", format = True, suffix = "B"), + self.general_stats.get_rel("m_total_rx_pkts", format = True, suffix = "pkts"))) + # all ports stats class PortsStatsPanel(TrexStatusPanel): def __init__ (self, h, l, y, x, status_obj): -- cgit From 530625493e92ac300b8a1135d061a3ecd428008d Mon Sep 17 00:00:00 2001 From: imarom Date: Wed, 4 Nov 2015 13:35:08 +0200 Subject: new format for the status per port --- .../trex_control_plane/console/trex_status.py | 45 ++++++++++++++++------ 1 file changed, 33 insertions(+), 12 deletions(-) (limited to 'scripts/automation/trex_control_plane/console') diff --git a/scripts/automation/trex_control_plane/console/trex_status.py b/scripts/automation/trex_control_plane/console/trex_status.py index a19587a3..c410e7c5 100644 --- a/scripts/automation/trex_control_plane/console/trex_status.py +++ b/scripts/automation/trex_control_plane/console/trex_status.py @@ -147,8 +147,8 @@ class PortsStatsPanel(TrexStatusPanel): 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]")) + self.getwin().addstr(3, 2, "{:^15} {:^30} {:^30} {:^30}".format( + "Port ID", "Tx Rate [bps/pps]", "Rx Rate [bps/pps]", "Total Bytes [tx/rx]")) @@ -157,25 +157,46 @@ class PortsStatsPanel(TrexStatusPanel): 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( + self.getwin().addstr(5 + (i * 4), 2, "{:^15} {:^30} {:^30} {:^30}".format( "{0} ({1})".format(str(port_index), self.status_obj.server_sys_info["ports"][port_index]["speed"]), - port_stats.get("m_total_tx_pps", format = True, suffix = "pps"), - port_stats.get("m_total_tx_bps", format = True, suffix = "bps"), - port_stats.get_rel("obytes", format = True, suffix = "B"), - port_stats.get("m_total_rx_pps", format = True, suffix = "pps"), - port_stats.get("m_total_rx_bps", format = True, suffix = "bps"), - port_stats.get_rel("ibytes", format = True, suffix = "B"))) + "{0} / {1}".format(port_stats.get("m_total_tx_bps", format = True, suffix = "bps"), + port_stats.get("m_total_tx_pps", format = True, suffix = "pps")), + + "{0} / {1}".format(port_stats.get("m_total_rx_bps", format = True, suffix = "bps"), + port_stats.get("m_total_rx_pps", format = True, suffix = "pps")), + "{0} / {1}".format(port_stats.get_rel("obytes", format = True, suffix = "B"), + port_stats.get_rel("ibytes", format = True, suffix = "B")))) else: - self.getwin().addstr(5 + (i * 4), 2, "{:^15} {:^15} {:^15} {:^15} {:^15} {:^15} {:^15}".format( + self.getwin().addstr(5 + (i * 4), 2, 2, "{:^15} {:^30} {:^30} {:^30}".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")) + + # old format +# 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.get("m_total_tx_pps", format = True, suffix = "pps"), +# port_stats.get("m_total_tx_bps", format = True, suffix = "bps"), +# port_stats.get_rel("obytes", format = True, suffix = "B"), +# port_stats.get("m_total_rx_pps", format = True, suffix = "pps"), +# port_stats.get("m_total_rx_bps", format = True, suffix = "bps"), +# port_stats.get_rel("ibytes", format = True, suffix = "B"))) +# +# 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): -- cgit From 36a9677c0abc038235e7bf706cb2b3dc9e720284 Mon Sep 17 00:00:00 2001 From: Dan Klein Date: Thu, 5 Nov 2015 07:35:15 +0200 Subject: added custom line parsing class and methods --- .../trex_control_plane/console/line_parsing.py | 47 +++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) (limited to 'scripts/automation/trex_control_plane/console') diff --git a/scripts/automation/trex_control_plane/console/line_parsing.py b/scripts/automation/trex_control_plane/console/line_parsing.py index 34776424..c1227a39 100644 --- a/scripts/automation/trex_control_plane/console/line_parsing.py +++ b/scripts/automation/trex_control_plane/console/line_parsing.py @@ -1,5 +1,50 @@ -__author__ = 'danklei' +import argparse +from collections import namedtuple +import sys +ArgumentPack = namedtuple('ArgumentPack', ['name_or_flags', 'options']) +# class ArgumentPack(namedtuple('ArgumentPack', ['name_or_flags', 'options'])): +# +# @property +# def name_or_flags(self): +# return self.name_or_flags +# +# @name_or_flags.setter +# def name_or_flags(self, val): +# print "bla" +# if not isinstance(val, list): +# self.name_or_flags = [val] +# else: +# self.name_or_flags = val + + +OPTIONS_DB = {'-m': ArgumentPack(['-m', '--multiplier'], + {'help': "Set multiplier for stream", 'dest':"mult"}), + 'file_path': ArgumentPack(['file'], + {'help': "File path to yaml file"})} + + +class CCmdArgParser(argparse.ArgumentParser): + + def __init__(self, *args, **kwargs): + super(CCmdArgParser, self).__init__(*args, **kwargs) + pass + + def error(self, message): + # self.print_usage(sys.stderr) + self.print_help() + return + +def gen_parser(op_name, *args): + parser = CCmdArgParser(prog=op_name, conflict_handler='resolve') + for param in args: + try: + parser.add_argument(*OPTIONS_DB[param].name_or_flags, + **OPTIONS_DB[param].options) + except KeyError, e: + cause = e.args[0] + raise KeyError("The attribute '{0}' is missing as a field of the {1} option.\n".format(cause, param)) + return parser if __name__ == "__main__": pass \ No newline at end of file -- cgit From e92507617ed8069b674fa5729b1e6a0c5d4b2662 Mon Sep 17 00:00:00 2001 From: imarom Date: Thu, 5 Nov 2015 09:55:03 +0200 Subject: bug fixes in status window --- .../trex_control_plane/console/trex_console.py | 1 + .../trex_control_plane/console/trex_status.py | 122 ++++++++++++++------- 2 files changed, 82 insertions(+), 41 deletions(-) (limited to 'scripts/automation/trex_control_plane/console') diff --git a/scripts/automation/trex_control_plane/console/trex_console.py b/scripts/automation/trex_control_plane/console/trex_console.py index 8a5b29cc..52effa7e 100755 --- a/scripts/automation/trex_control_plane/console/trex_console.py +++ b/scripts/automation/trex_control_plane/console/trex_console.py @@ -251,6 +251,7 @@ class TRexConsole(cmd.Cmd): return port_list + def do_acquire(self, line, force=False): '''Acquire ports\n''' diff --git a/scripts/automation/trex_control_plane/console/trex_status.py b/scripts/automation/trex_control_plane/console/trex_status.py index c410e7c5..2b97d7d3 100644 --- a/scripts/automation/trex_control_plane/console/trex_status.py +++ b/scripts/automation/trex_control_plane/console/trex_status.py @@ -90,7 +90,7 @@ class ServerInfoPanel(TrexStatusPanel): 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.owned_ports) + ports_owned = " ".join(str(x) for x in self.status_obj.owned_ports_list) if not ports_owned: ports_owned = "None" @@ -141,7 +141,7 @@ class PortsStatsPanel(TrexStatusPanel): self.clear() - owned_ports = self.status_obj.owned_ports + owned_ports = self.status_obj.owned_ports_list if not owned_ports: self.getwin().addstr(3, 2, "No Owned Ports - Please Acquire One Or More Ports") return @@ -225,7 +225,7 @@ class SinglePortPanel(TrexStatusPanel): self.clear() - if not self.port_id in self.status_obj.stateless_client.get_owned_ports(): + if not self.port_id in self.status_obj.owned_ports_list: self.getwin().addstr(y, 2, "Port {0} is not owned by you, please acquire the port for more info".format(self.port_id)) return @@ -239,16 +239,19 @@ class SinglePortPanel(TrexStatusPanel): 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(): + + if 'streams' in self.status_obj.owned_ports[str(self.port_id)]: + stream_info = self.status_obj.owned_ports[str(self.port_id)]['streams'] + + for stream_id, stream in sorted(stream_info.iteritems(), key=operator.itemgetter(0)): 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"))) + ("True" if stream['enabled'] else "False"), + stream['mode']['type'], + ("True" if stream['self_start'] else "False"), + stream['isg'], + (stream['next_stream_id'] if stream['next_stream_id'] != -1 else "None"), + ("{0} instr.".format(len(stream['vm'])) if stream['vm'] else "None"))) y += 1 @@ -258,37 +261,36 @@ class SinglePortPanel(TrexStatusPanel): 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]")) + # table header + self.getwin().addstr(y, 2, "{:^15} {:^30} {:^30} {:^30}".format( + "Port ID", "Tx Rate [bps/pps]", "Rx Rate [bps/pps]", "Total Bytes [tx/rx]")) + 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"])) + port_stats = self.status_obj.stats.get_port_stats(self.port_id) + if port_stats: + self.getwin().addstr(y, 2, "{:^15} {:^30} {:^30} {:^30}".format( + "{0} ({1})".format(str(self.port_id), self.status_obj.server_sys_info["ports"][self.port_id]["speed"]), + "{0} / {1}".format(port_stats.get("m_total_tx_bps", format = True, suffix = "bps"), + port_stats.get("m_total_tx_pps", format = True, suffix = "pps")), + + "{0} / {1}".format(port_stats.get("m_total_rx_bps", format = True, suffix = "bps"), + port_stats.get("m_total_rx_pps", format = True, suffix = "pps")), + "{0} / {1}".format(port_stats.get_rel("obytes", format = True, suffix = "B"), + port_stats.get_rel("ibytes", format = True, suffix = "B")))) + else: - self.getwin().addstr(y, 2, "{:^15} {:^15} {:^15} {:^15} {:^15} {:^15} {:^15}".format( + self.getwin().addstr(y + (i * 4), 2, 2, "{:^15} {:^30} {:^30} {:^30}".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 ################### main objects ################# @@ -388,7 +390,7 @@ class TrexStatus(): self.stateless_client = stateless_client - self.log = TrexStatusLog() + self.log = TrexStatusLog() self.cmds = TrexStatusCommands(self) self.stats = stateless_client.get_stats_async() @@ -403,9 +405,35 @@ class TrexStatus(): if not rc: return - self.owned_ports = self.stateless_client.get_acquired_ports() + # list of owned ports + self.owned_ports_list = self.stateless_client.get_acquired_ports() + + # data per port + self.owned_ports = {} + + for port_id in self.owned_ports_list: + self.owned_ports[str(port_id)] = {} + self.owned_ports[str(port_id)]['streams'] = {} + + rc, stream_list = self.stateless_client.get_all_streams(port_id) + if not rc: + raise Exception("unable to get streams") + self.owned_ports[str(port_id)] = stream_list + + try: + curses.curs_set(0) + except: + pass + + curses.use_default_colors() + self.stdscr.nodelay(1) + curses.nonl() + curses.noecho() + + self.generate_layout() + def generate_layout (self): self.max_y = self.stdscr.getmaxyx()[0] @@ -441,17 +469,22 @@ class TrexStatus(): # main run entry point def run (self): - try: - curses.curs_set(0) - except: - pass - curses.use_default_colors() - self.stdscr.nodelay(1) - curses.nonl() - curses.noecho() + # list of owned ports + self.owned_ports_list = self.stateless_client.get_acquired_ports() - self.generate_layout() + # data per port + self.owned_ports = {} + + for port_id in self.owned_ports_list: + self.owned_ports[str(port_id)] = {} + self.owned_ports[str(port_id)]['streams'] = {} + + rc, stream_list = self.stateless_client.get_all_streams(port_id) + if not rc: + raise Exception("unable to get streams") + + self.owned_ports[str(port_id)] = stream_list self.update_active = True while (True): @@ -473,8 +506,15 @@ class TrexStatus(): sleep(0.01) +# global container +trex_status = None + def show_trex_status_internal (stdscr, stateless_client): - trex_status = TrexStatus(stdscr, stateless_client) + global trex_status + + if trex_status == None: + trex_status = TrexStatus(stdscr, stateless_client) + trex_status.run() def show_trex_status (stateless_client): -- cgit From 953a250e6cbaea3040920e7441d2d019705efe51 Mon Sep 17 00:00:00 2001 From: Dan Klein Date: Sat, 7 Nov 2015 13:37:31 +0200 Subject: Extended line parsing options, didn't apply all changes on console YET --- .../trex_control_plane/console/line_parsing.py | 50 ---------- .../trex_control_plane/console/parsing_opts.py | 103 +++++++++++++++++++ .../trex_control_plane/console/trex_console.py | 111 +++++++++++++-------- 3 files changed, 175 insertions(+), 89 deletions(-) delete mode 100644 scripts/automation/trex_control_plane/console/line_parsing.py create mode 100755 scripts/automation/trex_control_plane/console/parsing_opts.py (limited to 'scripts/automation/trex_control_plane/console') diff --git a/scripts/automation/trex_control_plane/console/line_parsing.py b/scripts/automation/trex_control_plane/console/line_parsing.py deleted file mode 100644 index c1227a39..00000000 --- a/scripts/automation/trex_control_plane/console/line_parsing.py +++ /dev/null @@ -1,50 +0,0 @@ -import argparse -from collections import namedtuple -import sys - -ArgumentPack = namedtuple('ArgumentPack', ['name_or_flags', 'options']) -# class ArgumentPack(namedtuple('ArgumentPack', ['name_or_flags', 'options'])): -# -# @property -# def name_or_flags(self): -# return self.name_or_flags -# -# @name_or_flags.setter -# def name_or_flags(self, val): -# print "bla" -# if not isinstance(val, list): -# self.name_or_flags = [val] -# else: -# self.name_or_flags = val - - -OPTIONS_DB = {'-m': ArgumentPack(['-m', '--multiplier'], - {'help': "Set multiplier for stream", 'dest':"mult"}), - 'file_path': ArgumentPack(['file'], - {'help': "File path to yaml file"})} - - -class CCmdArgParser(argparse.ArgumentParser): - - def __init__(self, *args, **kwargs): - super(CCmdArgParser, self).__init__(*args, **kwargs) - pass - - def error(self, message): - # self.print_usage(sys.stderr) - self.print_help() - return - -def gen_parser(op_name, *args): - parser = CCmdArgParser(prog=op_name, conflict_handler='resolve') - for param in args: - try: - parser.add_argument(*OPTIONS_DB[param].name_or_flags, - **OPTIONS_DB[param].options) - except KeyError, e: - cause = e.args[0] - raise KeyError("The attribute '{0}' is missing as a field of the {1} option.\n".format(cause, param)) - return parser - -if __name__ == "__main__": - pass \ No newline at end of file diff --git a/scripts/automation/trex_control_plane/console/parsing_opts.py b/scripts/automation/trex_control_plane/console/parsing_opts.py new file mode 100755 index 00000000..c94a7461 --- /dev/null +++ b/scripts/automation/trex_control_plane/console/parsing_opts.py @@ -0,0 +1,103 @@ +import argparse +from collections import namedtuple +import sys + +ArgumentPack = namedtuple('ArgumentPack', ['name_or_flags', 'options']) +ArgumentGroup = namedtuple('ArgumentGroup', ['type', 'args', 'options']) + + +# list of available parsing options +MULTIPLIER = 1 +PORT_LIST = 2 +ALL_PORTS = 3 +PORT_LIST_WITH_ALL = 4 +FILE_PATH = 5 +FILE_FROM_DB = 6 +STREAM_FROM_PATH_OR_FILE = 7 + +# list of ArgumentGroup types +MUTEX = 1 + + + + +OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'], + {'help': "Set multiplier for stream", 'dest': "mult", 'type': float}), + PORT_LIST: ArgumentPack(['--port'], + {"nargs": '+', + # "action": "store_" + 'help': "A list of ports on which to apply the command", + 'default': []}), + ALL_PORTS: ArgumentPack(['-a'], + {"action": "store_true", + "dest": "all", + 'help': "Set this flag to apply the command on all available ports"}), + + FILE_PATH: ArgumentPack(['-f'], + {'help': "File path to YAML file that describes a stream pack"}), + FILE_FROM_DB: ArgumentPack(['--db'], + {'help': "A stream pack which already loaded into console cache."}), + # advanced options + PORT_LIST_WITH_ALL: ArgumentGroup(MUTEX, [PORT_LIST, + ALL_PORTS], + {'required': True}), + STREAM_FROM_PATH_OR_FILE: ArgumentGroup(MUTEX, [FILE_PATH, + FILE_FROM_DB], + {'required': True}) + } + + +class CCmdArgParser(argparse.ArgumentParser): + + def __init__(self, *args, **kwargs): + super(CCmdArgParser, self).__init__(*args, **kwargs) + pass + + # def error(self, message): + # try: + # super(CCmdArgParser, self).error(message) # this will trigger system exit! + # except SystemExit: + # return -1 + # + # # self.print_usage(sys.stderr) + # # print ('%s: error: %s\n') % (self.prog, message) + # # self.print_help() + # return + + def exit(self, status=0, message=None): + try: + super(CCmdArgParser, self).exit(status, message) # this will trigger system exit! + except SystemExit: + return -1 + return + +def gen_parser(op_name, description, *args): + parser = CCmdArgParser(prog=op_name, conflict_handler='resolve', + # add_help=False, + description=description) + for param in args: + try: + argument = OPTIONS_DB[param] + if isinstance(argument, ArgumentGroup): + if argument.type == MUTEX: + # handle as mutually exclusive group + group = parser.add_mutually_exclusive_group(**argument.options) + for sub_argument in argument.args: + group.add_argument(*OPTIONS_DB[sub_argument].name_or_flags, + **OPTIONS_DB[sub_argument].options) + else: + # ignore invalid objects + continue + elif isinstance(argument, ArgumentPack): + parser.add_argument(*argument.name_or_flags, + **argument.options) + else: + # ignore invalid objects + continue + except KeyError as e: + cause = e.args[0] + raise KeyError("The attribute '{0}' is missing as a field of the {1} option.\n".format(cause, param)) + return parser + +if __name__ == "__main__": + pass \ No newline at end of file diff --git a/scripts/automation/trex_control_plane/console/trex_console.py b/scripts/automation/trex_control_plane/console/trex_console.py index 8a5b29cc..33b4e164 100755 --- a/scripts/automation/trex_control_plane/console/trex_console.py +++ b/scripts/automation/trex_control_plane/console/trex_console.py @@ -32,7 +32,7 @@ from common.trex_streams import * from client.trex_stateless_client import CTRexStatelessClient from common.text_opts import * from client_utils.general_utils import user_input, get_current_user - +import parsing_opts import trex_status from collections import namedtuple @@ -234,6 +234,9 @@ class TRexConsole(cmd.Cmd): def extract_port_ids_from_line(self, line): return {int(x) for x in line.split()} + def extract_port_ids_from_list(self, port_list): + return {int(x) for x in port_list} + def parse_ports_from_line (self, line): port_list = set() if line: @@ -449,42 +452,42 @@ class TRexConsole(cmd.Cmd): def default(self, line): print "'{0}' is an unrecognized command. type 'help' or '?' for a list\n".format(line) - def do_help (self, line): - '''Shows This Help Screen\n''' - if line: - try: - func = getattr(self, 'help_' + line) - except AttributeError: - try: - doc = getattr(self, 'do_' + line).__doc__ - if doc: - self.stdout.write("%s\n"%str(doc)) - return - except AttributeError: - pass - self.stdout.write("%s\n"%str(self.nohelp % (line,))) - return - func() - return - - print "\nSupported Console Commands:" - print "----------------------------\n" - - cmds = [x[3:] for x in self.get_names() if x.startswith("do_")] - for cmd in cmds: - if cmd == "EOF": - continue - - try: - doc = getattr(self, 'do_' + cmd).__doc__ - if doc: - help = str(doc) - else: - help = "*** Undocumented Function ***\n" - except AttributeError: - help = "*** Undocumented Function ***\n" - - print "{:<30} {:<30}".format(cmd + " - ", help) + # def do_help (self, line): + # '''Shows This Help Screen\n''' + # if line: + # try: + # func = getattr(self, 'help_' + line) + # except AttributeError: + # try: + # doc = getattr(self, 'do_' + line).__doc__ + # if doc: + # self.stdout.write("%s\n"%str(doc)) + # return + # except AttributeError: + # pass + # self.stdout.write("%s\n"%str(self.nohelp % (line,))) + # return + # func() + # return + # + # print "\nSupported Console Commands:" + # print "----------------------------\n" + # + # cmds = [x[3:] for x in self.get_names() if x.startswith("do_")] + # for cmd in cmds: + # if cmd == "EOF": + # continue + # + # try: + # doc = getattr(self, 'do_' + cmd).__doc__ + # if doc: + # help = str(doc) + # else: + # help = "*** Undocumented Function ***\n" + # except AttributeError: + # help = "*** Undocumented Function ***\n" + # + # print "{:<30} {:<30}".format(cmd + " - ", help) def do_stream_db_add(self, line): '''Loads a YAML stream list serialization into user console \n''' @@ -594,7 +597,7 @@ class TRexConsole(cmd.Cmd): print "Provided stream list name '{0}' doesn't exists.".format(stream_pack_name) print format_text("[FAILED]\n", 'red', 'bold') return - if args[0] == "all": + if args[1] == "all": ask = ConfirmMenu('Are you sure you want to release all acquired ports? ') rc = ask.show() if rc == False: @@ -698,6 +701,33 @@ class TRexConsole(cmd.Cmd): def do_start_traffic(self, line): '''Start pre-submitted traffic in specified ports on TRex\n''' # make sure that the user wants to acquire all + # parser = parsing_opts.gen_parser("start_traffic", self.do_start_traffic.__doc__, + # parsing_opts.PORT_LIST_WITH_ALL, parsing_opts.MULTIPLIER) + # opts = parser.parse_args(line.split()) + # + # print opts + # return + # # return + # # if not opts.port_list: + # # print magenta("Please provide a list of ports separated by spaces, " + # # "or specify 'all' to start traffic on all acquired ports") + # # return + # + # if "all" in opts.port_list: + # ask = ConfirmMenu('Are you sure you want to start traffic at all acquired ports? ') + # rc = ask.show() + # if rc == False: + # print yellow("[ABORTED]\n") + # return + # else: + # port_list = self.stateless_client.get_acquired_ports() + # else: + # try: + # port_list = self.extract_port_ids_from_list(opts.port_list) + # except ValueError as e: + # print magenta(e) + # return + args = line.split() if len(args) < 1: print magenta("Please provide a list of ports separated by spaces, " @@ -715,7 +745,7 @@ class TRexConsole(cmd.Cmd): port_list = self.extract_port_ids_from_line(line) try: - res_ok, log = self.stateless_client.start_traffic(port_list) + res_ok, log = self.stateless_client.start_traffic(1.0, port_id=port_list) self.prompt_response(log) if not res_ok: print format_text("[FAILED]\n", 'red', 'bold') @@ -728,6 +758,9 @@ class TRexConsole(cmd.Cmd): def complete_start_traffic(self, text, line, begidx, endidx): return self.port_auto_complete(text, line, begidx, endidx) + def help_start_traffic(self): + self.do_start_traffic("-h") + def do_stop_traffic(self, line): '''Stop active traffic in specified ports on TRex\n''' # make sure that the user wants to acquire all -- cgit